Package voldemort.server.storage

Source Code of voldemort.server.storage.RepairJobTest

/*
* Copyright 2013 LinkedIn, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package voldemort.server.storage;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Test;

import voldemort.MockTime;
import voldemort.ServerTestUtils;
import voldemort.TestUtils;
import voldemort.VoldemortTestConstants;
import voldemort.client.ClientConfig;
import voldemort.client.protocol.RequestFormatType;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.common.service.SchedulerService;
import voldemort.routing.BaseStoreRoutingPlan;
import voldemort.server.RequestRoutingType;
import voldemort.server.StoreRepository;
import voldemort.server.VoldemortConfig;
import voldemort.server.VoldemortServer;
import voldemort.store.Store;
import voldemort.store.StoreDefinition;
import voldemort.store.metadata.MetadataStore;
import voldemort.store.socket.SocketStoreFactory;
import voldemort.store.socket.clientrequest.ClientRequestExecutorPool;
import voldemort.utils.ByteArray;
import voldemort.utils.ByteUtils;
import voldemort.versioning.Versioned;
import voldemort.xml.StoreDefinitionsMapper;

/*
* This class tests the repair job tool. The basic workflow is as follows : 1.
* Start a 9 node cluster with a single322 storedef. 2. Generate 1024 random
* <key,value> pairs and do puts of all these 1024 on all the servers. At this
* time every server will have all the data. 3. Run the repair job on all 9
* nodes. 4. Now, for each key check that the repair job deleted that key from
* nodes that do not belong to the preferenceList for that key. 5. Verify that
* the key exists on nodes that belong to preferenceList.
*/

public class RepairJobTest {

    private Cluster cluster;
    private StoreRepository storeRepository;
    private StorageService storage;
    private SchedulerService scheduler;
    private List<StoreDefinition> storeDefs;
    private MetadataStore metadataStore;
    private SocketStoreFactory socketStoreFactory;
    private Map<Integer, Store<ByteArray, byte[], byte[]>> storeMap;
    Map<Integer, VoldemortServer> serverMap;

    public void setUp() {

        File temp = TestUtils.createTempDir();
        VoldemortConfig config = new VoldemortConfig(0, temp.getAbsolutePath());
        new File(config.getMetadataDirectory()).mkdir();
        this.serverMap = new HashMap<Integer, VoldemortServer>();
        this.scheduler = new SchedulerService(1, new MockTime());
        this.cluster = VoldemortTestConstants.getNineNodeCluster();
        StoreDefinitionsMapper mapper = new StoreDefinitionsMapper();
        this.storeDefs = mapper.readStoreList(new StringReader((VoldemortTestConstants.getSingleStore322Xml())));
        this.storeRepository = new StoreRepository();
        this.metadataStore = ServerTestUtils.createMetadataStore(cluster, storeDefs);
        storage = new StorageService(storeRepository, metadataStore, scheduler, config);
        // Start the storage service
        storage.start();
        this.socketStoreFactory = new ClientRequestExecutorPool(2, 10000, 100000, 32 * 1024);
        String storeDefsString = mapper.writeStoreList(storeDefs);
        File file = null;
        try {
            file = File.createTempFile("single-store-", ".xml");
            FileUtils.writeStringToFile(file, storeDefsString);
            String storeDefFile = file.getAbsolutePath();
            List<Integer> nodesToStart = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8);
            // Start the servers
            startServers(cluster, storeDefFile, nodesToStart, null);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

    private Cluster startServers(Cluster cluster,
                                 String storeXmlFile,
                                 List<Integer> nodeToStart,
                                 Map<String, String> configProps) throws Exception {
        for(int node: nodeToStart) {
            Properties properties = new Properties();
            if(null != configProps) {
                for(Entry<String, String> property: configProps.entrySet()) {
                    properties.put(property.getKey(), property.getValue());
                }
            }
            VoldemortConfig config = ServerTestUtils.createServerConfig(true,
                                                                        node,
                                                                        TestUtils.createTempDir()
                                                                                 .getAbsolutePath(),
                                                                        null,
                                                                        storeXmlFile,
                                                                        properties);
            VoldemortServer server = ServerTestUtils.startVoldemortServer(socketStoreFactory,
                                                                          config,
                                                                          cluster);
            serverMap.put(node, server);
        }
        return cluster;
    }

    @After
    public void tearDown() throws Exception {
        for(VoldemortServer vs: serverMap.values()) {
            vs.stop();
        }
    }

    private Store<ByteArray, byte[], byte[]> getSocketStore(String storeName, String host, int port) {
        return socketStoreFactory.create(storeName,
                                         host,
                                         port,
                                         RequestFormatType.PROTOCOL_BUFFERS,
                                         RequestRoutingType.IGNORE_CHECKS);
    }

    private Map<Integer, Store<ByteArray, byte[], byte[]>> createSocketStore(StoreDefinition storeDef) {
        storeMap = new HashMap<Integer, Store<ByteArray, byte[], byte[]>>();
        for(Node node: cluster.getNodes()) {
            storeMap.put(node.getId(),
                         getSocketStore(storeDef.getName(), node.getHost(), node.getSocketPort()));
        }
        return storeMap;
    }

    private HashMap<String, String> populateData(HashMap<String, String> testEntries) {
        for(Entry<String, String> entry: testEntries.entrySet()) {
            ByteArray keyBytes = new ByteArray(ByteUtils.getBytes(entry.getKey(), "UTF-8"));
            List<Integer> allNodes = Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8);
            for(int nodeId: allNodes) {
                try {
                    storeMap.get(nodeId)
                            .put(keyBytes,
                                 new Versioned<byte[]>(ByteUtils.getBytes(entry.getValue(), "UTF-8")),
                                 null);
                } catch(Exception e) {
                    // Don't do anything with the exception. Exception are
                    // expected here as we are
                    // putting all keys on all nodes.
                }
            }
        }
        for(Store<ByteArray, byte[], byte[]> store: storeMap.values()) {
            store.close();
        }
        return testEntries;
    }

    @Test
    public void testRepairJob() {
        // start the servers
        setUp();
        // Create socket store
        storeMap = createSocketStore(storeDefs.get(0));
        // Generate random data, populate cluster with it.
        HashMap<String, String> testEntries = ServerTestUtils.createRandomKeyValueString(128);
        populateData(testEntries);

        // create admin client and run repair on all nodes
        AdminClient admin = new AdminClient(cluster, new AdminClientConfig(), new ClientConfig());
        for(int i = 0; i < 9; i++) {
            admin.storeMntOps.repairJob(i);
        }

        // wait for the repair to complete
        for(int i = 0; i < 9; i++) {
            ServerTestUtils.waitForAsyncOperationOnServer(serverMap.get(i), "Repair", 5000);
        }
        BaseStoreRoutingPlan storeInstance = new BaseStoreRoutingPlan(cluster, storeDefs.get(0));
        for(Entry<String, String> entry: testEntries.entrySet()) {
            ByteArray keyBytes = new ByteArray(ByteUtils.getBytes(entry.getKey(), "UTF-8"));
            List<Integer> preferenceNodes = storeInstance.getReplicationNodeList(keyBytes.get());
            List<Integer> allNodes = new ArrayList<Integer>(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8));

            // Repair job should have deleted the keys on the nodes that
            // shouldn't have been
            // hosting the key. Go over all these remaining nodes to make sure
            // that it's true.
            allNodes.removeAll(preferenceNodes);
            for(int nodeId: allNodes) {
                try {
                    List<Versioned<byte[]>> retVal = storeMap.get(nodeId).get(keyBytes, null);
                    assertEquals("Repair did not run properly as it left the key it should have"
                                 + " deleted", retVal.isEmpty(), true);
                } catch(Exception e) {
                    // We expect a bunch of invalidmetadata exceptions as we are
                    // asking for key
                    // that doesn't belong to the nodes. Hence leaving the catch
                    // empty.
                }
            }
            // The repair job should not have deleted the keys from nodes on the
            // pref list.
            for(int nodeId: preferenceNodes) {
                try {
                    List<Versioned<byte[]>> retVal = storeMap.get(nodeId).get(keyBytes, null);
                    assertEquals("Repair job has deleted keys that it should not have",
                                 retVal.isEmpty(),
                                 false);
                } catch(Exception e) {
                    e.printStackTrace();
                }
            }
        }
        for(Store<ByteArray, byte[], byte[]> store: storeMap.values()) {
            store.close();
        }
    }
}
TOP

Related Classes of voldemort.server.storage.RepairJobTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.