Package voldemort.utils

Source Code of voldemort.utils.ClusterForkLiftToolTest

package voldemort.utils;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import voldemort.ServerTestUtils;
import voldemort.client.ClientConfig;
import voldemort.client.SocketStoreClientFactory;
import voldemort.client.StoreClient;
import voldemort.client.StoreClientFactory;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.client.protocol.admin.AdminClientConfig;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.routing.StoreRoutingPlan;
import voldemort.server.VoldemortServer;
import voldemort.store.StoreDefinition;
import voldemort.store.StoreUtils;
import voldemort.store.routed.NodeValue;
import voldemort.store.socket.SocketStoreFactory;
import voldemort.store.socket.clientrequest.ClientRequestExecutorPool;
import voldemort.versioning.ClockEntry;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Versioned;
import voldemort.xml.StoreDefinitionsMapper;

import com.google.common.collect.Lists;

public class ClusterForkLiftToolTest {

    final static String STORES_XML = "test/common/voldemort/config/two-stores-replicated.xml";
    final static String PRIMARY_RESOLVING_STORE_NAME = "test";
    final static String GLOBALLY_RESOLVING_STORE_NAME = "best";
    final static String MULTIPLE_VERSIONS_STORE_NAME = "no-res";

    private String srcBootStrapUrl;
    private String dstBootStrapUrl;
    private Cluster srcCluster;
    private Cluster dstCluster;
    private VoldemortServer[] srcServers;
    private VoldemortServer[] dstServers;

    private StoreDefinition primaryResolvingStoreDef;
    private StoreDefinition globallyResolvingStoreDef;
    private StoreDefinition nonResolvingStoreDef;

    private HashMap<String, String> kvPairs;
    private String firstKey;
    private String lastKey;
    private String conflictKey;

    private AdminClient srcAdminClient;

    private StoreClientFactory srcfactory;
    private StoreClientFactory dstfactory;
    private StoreClient<String, String> srcPrimaryResolvingStoreClient;
    private StoreClient<String, String> dstPrimaryResolvingStoreClient;
    private StoreClient<String, String> srcGloballyResolvingStoreClient;
    private StoreClient<String, String> dstGloballyResolvingStoreClient;

    @Before
    public void setUpClusters() {
        // setup four nodes with one store and one partition
        final SocketStoreFactory socketStoreFactory = new ClientRequestExecutorPool(2,
                                                                                    10000,
                                                                                    100000,
                                                                                    32 * 1024);

        try {
            int srcPartitionMap[][] = { { 0 }, { 1 }, { 2 }, { 3 } };
            srcServers = new VoldemortServer[4];
            srcCluster = ServerTestUtils.startVoldemortCluster(4,
                                                               srcServers,
                                                               srcPartitionMap,
                                                               socketStoreFactory,
                                                               true,
                                                               null,
                                                               STORES_XML,
                                                               new Properties());
            Node node = srcCluster.getNodeById(0);
            srcBootStrapUrl = "tcp://" + node.getHost() + ":" + node.getSocketPort();

            int dstPartitionMap[][] = { { 0 }, { 1 }, { 2 } };
            dstServers = new VoldemortServer[3];
            dstCluster = ServerTestUtils.startVoldemortCluster(3,
                                                               dstServers,
                                                               dstPartitionMap,
                                                               socketStoreFactory,
                                                               true,
                                                               null,
                                                               STORES_XML,
                                                               new Properties());
            node = dstCluster.getNodeById(0);
            dstBootStrapUrl = "tcp://" + node.getHost() + ":" + node.getSocketPort();

            kvPairs = ServerTestUtils.createRandomKeyValueString(100);
            int keyCount = 0;
            for(String key: kvPairs.keySet()) {
                if(keyCount == 0)
                    firstKey = key;
                if(keyCount == kvPairs.size() - 1)
                    lastKey = key;
                if(keyCount == kvPairs.size() / 2)
                    conflictKey = key;
                keyCount++;
            }

            srcAdminClient = new AdminClient(srcCluster,
                                             new AdminClientConfig(),
                                             new ClientConfig());

            List<StoreDefinition> storeDefs = new StoreDefinitionsMapper().readStoreList(new File(STORES_XML));

            primaryResolvingStoreDef = StoreUtils.getStoreDef(storeDefs,
                                                              PRIMARY_RESOLVING_STORE_NAME);
            globallyResolvingStoreDef = StoreUtils.getStoreDef(storeDefs,
                                                               GLOBALLY_RESOLVING_STORE_NAME);

            nonResolvingStoreDef = StoreUtils.getStoreDef(storeDefs, MULTIPLE_VERSIONS_STORE_NAME);

            srcfactory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(srcBootStrapUrl)
                                                                        .setSelectors(1)
                                                                        .setRoutingTimeout(1000,
                                                                                           java.util.concurrent.TimeUnit.MILLISECONDS)
                                                                        .setSocketTimeout(1000,
                                                                                          java.util.concurrent.TimeUnit.MILLISECONDS)
                                                                        .setConnectionTimeout(1000,
                                                                                              java.util.concurrent.TimeUnit.MILLISECONDS)
                                                                        .setMaxConnectionsPerNode(1));
            srcPrimaryResolvingStoreClient = srcfactory.getStoreClient(PRIMARY_RESOLVING_STORE_NAME);
            srcGloballyResolvingStoreClient = srcfactory.getStoreClient(GLOBALLY_RESOLVING_STORE_NAME);

            dstfactory = new SocketStoreClientFactory(new ClientConfig().setBootstrapUrls(dstBootStrapUrl)
                                                                        .setSelectors(1)
                                                                        .setRoutingTimeout(1000,
                                                                                           java.util.concurrent.TimeUnit.MILLISECONDS)
                                                                        .setSocketTimeout(1000,
                                                                                          java.util.concurrent.TimeUnit.MILLISECONDS)
                                                                        .setConnectionTimeout(1000,
                                                                                              java.util.concurrent.TimeUnit.MILLISECONDS)
                                                                        .setMaxConnectionsPerNode(1));
            dstPrimaryResolvingStoreClient = dstfactory.getStoreClient(PRIMARY_RESOLVING_STORE_NAME);
            dstGloballyResolvingStoreClient = dstfactory.getStoreClient(GLOBALLY_RESOLVING_STORE_NAME);

        } catch(IOException e) {
            e.printStackTrace();
            fail("Unexpected exception");
        }
    }

    @Test
    public void testPrimaryResolvingForkLift() throws Exception {

        StoreRoutingPlan srcStoreInstance = new StoreRoutingPlan(srcCluster,
                                                                 primaryResolvingStoreDef);

        // populate data on the source cluster..
        for(Map.Entry<String, String> entry: kvPairs.entrySet()) {
            srcPrimaryResolvingStoreClient.put(entry.getKey(), entry.getValue());
        }

        // generate a conflict on the master partition
        int masterNode = srcStoreInstance.getNodeIdForPartitionId(srcStoreInstance.getMasterPartitionId(conflictKey.getBytes("UTF-8")));
        VectorClock losingClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 0, 5)),
                                                  System.currentTimeMillis());
        VectorClock winningClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 1, 5)),
                                                   losingClock.getTimestamp() + 1);
        srcAdminClient.storeOps.putNodeKeyValue(PRIMARY_RESOLVING_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(masterNode,
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("losing value".getBytes("UTF-8"),
                                                                                                       losingClock)));
        srcAdminClient.storeOps.putNodeKeyValue(PRIMARY_RESOLVING_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(masterNode,
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("winning value".getBytes("UTF-8"),
                                                                                                       winningClock)));

        // do a write to destination cluster
        dstPrimaryResolvingStoreClient.put(firstKey, "before forklift");

        // perform the forklifting..
        ClusterForkLiftTool forkLiftTool = new ClusterForkLiftTool(srcBootStrapUrl,
                                                                   dstBootStrapUrl,
                                                                   false,
                                                                   10000,
                                                                   1,
                                                                   1000,
                                                                   Lists.newArrayList(PRIMARY_RESOLVING_STORE_NAME),
                                                                   null,
                                                                   ClusterForkLiftTool.ForkLiftTaskMode.primary_resolution);
        forkLiftTool.run();

        // do a write to destination cluster
        dstPrimaryResolvingStoreClient.put(lastKey, "after forklift");

        // verify data on the destination is as expected
        for(Map.Entry<String, String> entry: kvPairs.entrySet()) {
            if(entry.getKey().equals(firstKey)) {
                assertEquals("Online write overwritten",
                             dstPrimaryResolvingStoreClient.get(firstKey).getValue(),
                             "before forklift");
            } else if(entry.getKey().equals(lastKey)) {
                assertEquals("can't update value after forklift",
                             dstPrimaryResolvingStoreClient.get(lastKey).getValue(),
                             "after forklift");
            } else if(entry.getKey().equals(conflictKey)) {
                assertEquals("Conflict resolution incorrect",
                             dstPrimaryResolvingStoreClient.get(conflictKey).getValue(),
                             "winning value");
            } else {
                assertEquals("fork lift data missing",
                             dstPrimaryResolvingStoreClient.get(entry.getKey()).getValue(),
                             entry.getValue());
            }
        }
    }

    @Test
    public void testGloballyResolvingForkLift() throws Exception {

        StoreRoutingPlan srcStoreInstance = new StoreRoutingPlan(srcCluster,
                                                                 globallyResolvingStoreDef);

        // populate data on the source cluster..
        for(Map.Entry<String, String> entry: kvPairs.entrySet()) {
            srcGloballyResolvingStoreClient.put(entry.getKey(), entry.getValue());
        }

        // generate a conflict on the primary and a secondary
        List<Integer> nodeList = srcStoreInstance.getReplicationNodeList(srcStoreInstance.getMasterPartitionId(conflictKey.getBytes("UTF-8")));
        VectorClock losingClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 0, 5)),
                                                  System.currentTimeMillis());
        VectorClock winningClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 1, 5)),
                                                   losingClock.getTimestamp() + 1);
        srcAdminClient.storeOps.putNodeKeyValue(GLOBALLY_RESOLVING_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(nodeList.get(0),
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("losing value".getBytes("UTF-8"),
                                                                                                       losingClock)));
        srcAdminClient.storeOps.putNodeKeyValue(GLOBALLY_RESOLVING_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(nodeList.get(1),
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("winning value".getBytes("UTF-8"),
                                                                                                       winningClock)));

        // do a write to destination cluster
        dstGloballyResolvingStoreClient.put(firstKey, "before forklift");

        // perform the forklifting..
        ClusterForkLiftTool forkLiftTool = new ClusterForkLiftTool(srcBootStrapUrl,
                                                                   dstBootStrapUrl,
                                                                   false,
                                                                   10000,
                                                                   1,
                                                                   1000,
                                                                   Lists.newArrayList(GLOBALLY_RESOLVING_STORE_NAME),
                                                                   null,
                                                                   ClusterForkLiftTool.ForkLiftTaskMode.global_resolution);
        forkLiftTool.run();

        // do a write to destination cluster
        dstGloballyResolvingStoreClient.put(lastKey, "after forklift");

        // verify data on the destination is as expected
        for(Map.Entry<String, String> entry: kvPairs.entrySet()) {
            if(entry.getKey().equals(firstKey)) {
                assertEquals("Online write overwritten",
                             dstGloballyResolvingStoreClient.get(firstKey).getValue(),
                             "before forklift");
            } else if(entry.getKey().equals(lastKey)) {
                assertEquals("can't update value after forklift",
                             dstGloballyResolvingStoreClient.get(lastKey).getValue(),
                             "after forklift");
            } else if(entry.getKey().equals(conflictKey)) {
                assertEquals("Conflict resolution incorrect",
                             dstGloballyResolvingStoreClient.get(conflictKey).getValue(),
                             "winning value");
            } else {
                assertEquals("fork lift data missing",
                             dstGloballyResolvingStoreClient.get(entry.getKey()).getValue(),
                             entry.getValue());
            }
        }
    }

    @Test
    public void testForkLiftOverWrite() throws Exception {

        StoreRoutingPlan srcStoreInstance = new StoreRoutingPlan(srcCluster,
                                                                 globallyResolvingStoreDef);

        // populate data on the source cluster..
        for(Map.Entry<String, String> entry: kvPairs.entrySet()) {
            srcGloballyResolvingStoreClient.put(entry.getKey(), entry.getValue());
        }

        // generate a conflict on the primary and a secondary
        List<Integer> nodeList = srcStoreInstance.getReplicationNodeList(srcStoreInstance.getMasterPartitionId(conflictKey.getBytes("UTF-8")));
        VectorClock losingClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 0, 5)),
                                                  System.currentTimeMillis());
        VectorClock winningClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 1, 5)),
                                                   losingClock.getTimestamp() + 1);
        srcAdminClient.storeOps.putNodeKeyValue(GLOBALLY_RESOLVING_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(nodeList.get(0),
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("losing value".getBytes("UTF-8"),
                                                                                                       losingClock)));
        srcAdminClient.storeOps.putNodeKeyValue(GLOBALLY_RESOLVING_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(nodeList.get(1),
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("winning value".getBytes("UTF-8"),
                                                                                                       winningClock)));

        // *** do a write to destination cluster ***
        // This is the main test , where after fork lift this value should be
        // overwritten. This is the only difference.
        dstGloballyResolvingStoreClient.put(firstKey, "before forklift");

        // Make the current thread sleep , so when the new clock is generated
        // using milliSeconds it is greater and must be overwritten.
        Thread.sleep(2);

        // perform the forklifting..
        ClusterForkLiftTool forkLiftTool = new ClusterForkLiftTool(srcBootStrapUrl,
                                                                   dstBootStrapUrl,
                                                                   true, // OverWrite
                                                                   10000,
                                                                   1,
                                                                   1000,
                                                                   Lists.newArrayList(GLOBALLY_RESOLVING_STORE_NAME),
                                                                   null,
                                                                   ClusterForkLiftTool.ForkLiftTaskMode.global_resolution);
        forkLiftTool.run();

        // do a write to destination cluster
        dstGloballyResolvingStoreClient.put(lastKey, "after forklift");

        // verify data on the destination is as expected
        for(Map.Entry<String, String> entry: kvPairs.entrySet()) {
            String dstClusterValue = dstGloballyResolvingStoreClient.get(entry.getKey()).getValue();
            if(entry.getKey().equals(lastKey)) {
                assertEquals("can't update value after forklift", dstClusterValue, "after forklift");
            } else if(entry.getKey().equals(conflictKey)) {
                assertEquals("Conflict resolution incorrect", dstClusterValue, "winning value");
            } else {
                if(!dstClusterValue.equals(entry.getValue())) {
                    assertEquals("fork lift data missing", dstClusterValue, entry.getValue());
                }
            }
        }
    }

    @Test
    public void testNoresolutionForkLift() throws Exception {

        int versions = 0;

        StoreRoutingPlan srcStoreInstance = new StoreRoutingPlan(srcCluster, nonResolvingStoreDef);

        // generate a conflict on the master partition
        int masterNode = srcStoreInstance.getNodeIdForPartitionId(srcStoreInstance.getMasterPartitionId(conflictKey.getBytes("UTF-8")));
        VectorClock losingClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 0, 5)),
                                                  System.currentTimeMillis());
        VectorClock winningClock = new VectorClock(Lists.newArrayList(new ClockEntry((short) 1, 5)),
                                                   losingClock.getTimestamp() + 1);
        srcAdminClient.storeOps.putNodeKeyValue(MULTIPLE_VERSIONS_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(masterNode,
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("losing value".getBytes("UTF-8"),
                                                                                                       losingClock)));
        srcAdminClient.storeOps.putNodeKeyValue(MULTIPLE_VERSIONS_STORE_NAME,
                                                new NodeValue<ByteArray, byte[]>(masterNode,
                                                                                 new ByteArray(conflictKey.getBytes("UTF-8")),
                                                                                 new Versioned<byte[]>("winning value".getBytes("UTF-8"),
                                                                                                       winningClock)));
        // perform the forklifting..
        ClusterForkLiftTool forkLiftTool = new ClusterForkLiftTool(srcBootStrapUrl,
                                                                   dstBootStrapUrl,
                                                                   false,
                                                                   10000,
                                                                   1,
                                                                   1000,
                                                                   Lists.newArrayList(MULTIPLE_VERSIONS_STORE_NAME),
                                                                   null,
                                                                   ClusterForkLiftTool.ForkLiftTaskMode.no_resolution);
        forkLiftTool.run();

        AdminClient dstAdminClient = new AdminClient(dstBootStrapUrl,
                                                     new AdminClientConfig(),
                                                     new ClientConfig());

        for(Node node: dstAdminClient.getAdminClientCluster().getNodes()) {

            Iterator<Pair<ByteArray, Versioned<byte[]>>> entryItr = dstAdminClient.bulkFetchOps.fetchEntries(node.getId(),
                                                                                                             MULTIPLE_VERSIONS_STORE_NAME,
                                                                                                             node.getPartitionIds(),
                                                                                                             null,
                                                                                                             true);

            while(entryItr.hasNext()) {
                Pair<ByteArray, Versioned<byte[]>> record = entryItr.next();
                ByteArray key = record.getFirst();
                Versioned<byte[]> versioned = record.getSecond();
                versions++;

            }

        }
        assertEquals("Both conflicting versions present", versions, 2);

    }

    @After
    public void tearDownClusters() {

        srcAdminClient.close();

        srcfactory.close();
        dstfactory.close();

        for(VoldemortServer server: srcServers)
            server.stop();
        for(VoldemortServer server: dstServers)
            server.stop();
    }
}
TOP

Related Classes of voldemort.utils.ClusterForkLiftToolTest

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.