Search in sources :

Example 1 with StoreRoutingPlan

use of voldemort.routing.StoreRoutingPlan in project voldemort by voldemort.

the class VoldemortAdminTool method executeShowRoutingPlan.

private static void executeShowRoutingPlan(AdminClient adminClient, String storeName, List<String> keyList) throws DecoderException {
    Cluster cluster = adminClient.getAdminClientCluster();
    List<StoreDefinition> storeDefs = adminClient.metadataMgmtOps.getRemoteStoreDefList().getValue();
    StoreDefinition storeDef = StoreDefinitionUtils.getStoreDefinitionWithName(storeDefs, storeName);
    StoreRoutingPlan routingPlan = new StoreRoutingPlan(cluster, storeDef);
    BaseStoreRoutingPlan bRoutingPlan = new BaseStoreRoutingPlan(cluster, storeDef);
    final int COLUMN_WIDTH = 30;
    for (String keyStr : keyList) {
        byte[] key = ByteUtils.fromHexString(keyStr);
        System.out.println("Key :" + keyStr);
        System.out.println("Replicating Partitions :" + routingPlan.getReplicatingPartitionList(key));
        System.out.println("Replicating Nodes :");
        List<Integer> nodeList = routingPlan.getReplicationNodeList(routingPlan.getMasterPartitionId(key));
        for (int i = 0; i < nodeList.size(); i++) {
            System.out.println(nodeList.get(i) + "\t" + cluster.getNodeById(nodeList.get(i)).getHost());
        }
        System.out.println("Zone Nary information :");
        HashMap<Integer, Integer> zoneRepMap = storeDef.getZoneReplicationFactor();
        for (Zone zone : cluster.getZones()) {
            System.out.println("\tZone #" + zone.getId());
            int numReplicas = -1;
            if (zoneRepMap == null) {
                // non zoned cluster
                numReplicas = storeDef.getReplicationFactor();
            } else {
                // zoned cluster
                if (!zoneRepMap.containsKey(zone.getId())) {
                    Utils.croak("Repfactor for Zone " + zone.getId() + " not found in storedef");
                }
                numReplicas = zoneRepMap.get(zone.getId());
            }
            String FormatString = "%s %s %s\n";
            System.out.format(FormatString, Utils.paddedString("REPLICA#", COLUMN_WIDTH), Utils.paddedString("PARTITION", COLUMN_WIDTH), Utils.paddedString("NODE", COLUMN_WIDTH));
            for (int i = 0; i < numReplicas; i++) {
                Integer nodeId = bRoutingPlan.getNodeIdForZoneNary(zone.getId(), i, key);
                Integer partitionId = routingPlan.getNodesPartitionIdForKey(nodeId, key);
                System.out.format(FormatString, Utils.paddedString(i + "", COLUMN_WIDTH), Utils.paddedString(partitionId.toString(), COLUMN_WIDTH), Utils.paddedString(nodeId + "(" + cluster.getNodeById(nodeId).getHost() + ")", COLUMN_WIDTH));
            }
            System.out.println();
        }
        System.out.println("-----------------------------------------------");
        System.out.println();
    }
}
Also used : BaseStoreRoutingPlan(voldemort.routing.BaseStoreRoutingPlan) StoreRoutingPlan(voldemort.routing.StoreRoutingPlan) Zone(voldemort.cluster.Zone) StoreDefinition(voldemort.store.StoreDefinition) Cluster(voldemort.cluster.Cluster) BaseStoreRoutingPlan(voldemort.routing.BaseStoreRoutingPlan)

Example 2 with StoreRoutingPlan

use of voldemort.routing.StoreRoutingPlan in project voldemort by voldemort.

the class PartitionBalanceUtils method analyzeInvalidMetadataRate.

// TODO: (refactor) separate analysis from pretty printing and add a unit
// test for the analysis sub-method.
/**
 * Compares current cluster with final cluster. Uses pertinent store defs
 * for each cluster to determine if a node that hosts a zone-primary in the
 * current cluster will no longer host any zone-nary in the final cluster.
 * This check is the precondition for a server returning an invalid metadata
 * exception to a client on a normal-case put or get. Normal-case being that
 * the zone-primary receives the pseudo-master put or the get operation.
 *
 * @param currentCluster
 * @param currentStoreDefs
 * @param finalCluster
 * @param finalStoreDefs
 * @return pretty-printed string documenting invalid metadata rates for each
 *         zone.
 */
public static String analyzeInvalidMetadataRate(final Cluster currentCluster, List<StoreDefinition> currentStoreDefs, final Cluster finalCluster, List<StoreDefinition> finalStoreDefs) {
    StringBuilder sb = new StringBuilder();
    sb.append("Dump of invalid metadata rates per zone").append(Utils.NEWLINE);
    HashMap<StoreDefinition, Integer> uniqueStores = StoreDefinitionUtils.getUniqueStoreDefinitionsWithCounts(currentStoreDefs);
    for (StoreDefinition currentStoreDef : uniqueStores.keySet()) {
        sb.append("Store exemplar: " + currentStoreDef.getName()).append(Utils.NEWLINE).append("\tThere are " + uniqueStores.get(currentStoreDef) + " other similar stores.").append(Utils.NEWLINE);
        StoreRoutingPlan currentSRP = new StoreRoutingPlan(currentCluster, currentStoreDef);
        StoreDefinition finalStoreDef = StoreUtils.getStoreDef(finalStoreDefs, currentStoreDef.getName());
        StoreRoutingPlan finalSRP = new StoreRoutingPlan(finalCluster, finalStoreDef);
        // Only care about existing zones
        for (int zoneId : currentCluster.getZoneIds()) {
            int zonePrimariesCount = 0;
            int invalidMetadata = 0;
            // Examine nodes in current cluster in existing zone.
            for (int nodeId : currentCluster.getNodeIdsInZone(zoneId)) {
                // For every zone-primary in current cluster
                for (int zonePrimaryPartitionId : currentSRP.getZonePrimaryPartitionIds(nodeId)) {
                    zonePrimariesCount++;
                    // InvalidMetadataException will fire.
                    if (!finalSRP.getZoneNAryPartitionIds(nodeId).contains(zonePrimaryPartitionId)) {
                        invalidMetadata++;
                    }
                }
            }
            float rate = invalidMetadata / (float) zonePrimariesCount;
            sb.append("\tZone " + zoneId).append(" : total zone primaries " + zonePrimariesCount).append(", # that trigger invalid metadata " + invalidMetadata).append(" => " + rate).append(Utils.NEWLINE);
        }
    }
    return sb.toString();
}
Also used : StoreRoutingPlan(voldemort.routing.StoreRoutingPlan) StoreDefinition(voldemort.store.StoreDefinition)

Example 3 with StoreRoutingPlan

use of voldemort.routing.StoreRoutingPlan in project voldemort by voldemort.

the class ClusterForkLiftTool method run.

@Override
public void run() {
    final Cluster srcCluster = srcAdminClient.getAdminClientCluster();
    try {
        // process stores one-by-one
        for (String store : storesList) {
            logger.info("Processing store " + store);
            dstStreamingClient.initStreamingSession(store, new Callable<Object>() {

                @Override
                public Object call() throws Exception {
                    return null;
                }
            }, new Callable<Object>() {

                @Override
                public Object call() throws Exception {
                    return null;
                }
            }, true);
            final CountDownLatch latch = new CountDownLatch(srcCluster.getNumberOfPartitions());
            StoreRoutingPlan storeInstance = new StoreRoutingPlan(srcCluster, srcStoreDefMap.get(store));
            // submit work on every partition that is to be forklifted
            for (Integer partitionId : partitionList) {
                if (this.mode == ForkLiftTaskMode.global_resolution) {
                    // do thorough global resolution across replicas
                    SinglePartitionGloballyResolvingForkLiftTask work = new SinglePartitionGloballyResolvingForkLiftTask(storeInstance, partitionId, latch);
                    workerPool.submit(work);
                } else if (this.mode == ForkLiftTaskMode.primary_resolution) {
                    // do the less cleaner, but much faster route
                    SinglePartitionPrimaryResolvingForkLiftTask work = new SinglePartitionPrimaryResolvingForkLiftTask(storeInstance, partitionId, latch);
                    workerPool.submit(work);
                } else if (this.mode == ForkLiftTaskMode.no_resolution) {
                    // do the less cleaner, but much faster route
                    SinglePartitionNoResolutionForkLiftTask work = new SinglePartitionNoResolutionForkLiftTask(storeInstance, partitionId, latch);
                    workerPool.submit(work);
                }
            }
            // wait till all the partitions are processed
            latch.await();
            dstStreamingClient.closeStreamingSession();
            logger.info("Finished processing store " + store);
        }
    } catch (Exception e) {
        logger.error("Exception running forklift tool", e);
    } finally {
        workerPool.shutdown();
        try {
            workerPool.awaitTermination(DEFAULT_WORKER_POOL_SHUTDOWN_WAIT_MINS, TimeUnit.MINUTES);
        } catch (InterruptedException ie) {
            logger.error("InterruptedException while waiting for worker pool to shutdown", ie);
        }
        srcAdminClient.close();
        dstStreamingClient.getAdminClient().close();
    }
}
Also used : StoreRoutingPlan(voldemort.routing.StoreRoutingPlan) Cluster(voldemort.cluster.Cluster) CountDownLatch(java.util.concurrent.CountDownLatch) ObsoleteVersionException(voldemort.versioning.ObsoleteVersionException) VoldemortException(voldemort.VoldemortException) VoldemortApplicationException(voldemort.VoldemortApplicationException)

Example 4 with StoreRoutingPlan

use of voldemort.routing.StoreRoutingPlan in project voldemort by voldemort.

the class ZoneCLipperTest method testDropZoneIdWorks.

@Test
public void testDropZoneIdWorks() {
    // Create a list of current partition ids. We will use this set to
    // compare partitions ids with the interim cluster
    Set<Integer> originalPartitions = new HashSet<Integer>();
    for (Integer zoneId : initialCluster.getZoneIds()) {
        originalPartitions.addAll(initialCluster.getPartitionIdsInZone(zoneId));
    }
    // Get an intermediate cluster where partitions that belong to the zone
    // that is being dropped have been moved to the existing zones
    Cluster interimCluster = RebalanceUtils.vacateZone(initialCluster, dropZoneId);
    // Make sure that the intermediate cluster should have same number of
    // partitions
    RebalanceUtils.validateClusterPartitionCounts(initialCluster, interimCluster);
    // Make sure that the intermediate cluster should have same number of
    // nodes
    RebalanceUtils.validateClusterNodeCounts(initialCluster, interimCluster);
    // Make sure that the intermediate cluster doesn't have any partitions in
    // the dropped zone
    assertTrue("Zone being dropped has partitions. ZoneClipper didn't work properly", interimCluster.getPartitionIdsInZone(dropZoneId).isEmpty());
    // Make sure that the nodes being dropped don't host any partitions
    for (Integer nodeId : interimCluster.getNodeIdsInZone(dropZoneId)) {
        assertTrue("Nodes in the zone being dropped don't have empty partitions list", interimCluster.getNodeById(nodeId).getPartitionIds().isEmpty());
    }
    Set<Integer> finalPartitions = new HashSet<Integer>();
    for (Integer zoneId : interimCluster.getZoneIds()) {
        finalPartitions.addAll(interimCluster.getPartitionIdsInZone(zoneId));
    }
    // Compare to original partition ids list
    assertTrue("Original and interm partition ids don't match", originalPartitions.equals(finalPartitions));
    // Make sure that there is no data movement
    RebalancePlan rebalancePlan = ClusterTestUtils.makePlan(initialCluster, storeDefs, interimCluster, storeDefs);
    // Make sure we have a plan
    assertEquals(rebalancePlan.getPlan().size(), 1);
    // Make sure there is no cross zones between zones in the plan
    assertEquals(rebalancePlan.getPartitionStoresMovedXZone(), 0);
    // Make sure there is no data movement between nodes
    assertEquals(rebalancePlan.getPartitionStoresMoved(), 0);
    for (Integer nodeId : interimCluster.getNodeIds()) {
        Set<Integer> remainingNodes = Sets.symmetricDifference(interimCluster.getNodeIds(), Sets.newHashSet(nodeId));
        for (Integer otherNodeId : remainingNodes) {
            assertTrue("Something went wrong as there is data movement between nodes", rebalancePlan.getNodeMoveMap().get(nodeId, otherNodeId) == 0);
        }
    }
    // Also get the adjusted store definitions, with the zone dropped
    Cluster finalCluster = RebalanceUtils.dropZone(interimCluster, dropZoneId);
    List<StoreDefinition> clippedStoreDefs = RebalanceUtils.dropZone(storeDefs, dropZoneId);
    for (StoreDefinition storeDef : clippedStoreDefs) {
        StoreDefinition orgStoreDef = StoreDefinitionUtils.getStoreDefinitionWithName(storeDefs, storeDef.getName());
        assertFalse("Clipped storedef has replication for dropped zone", storeDef.getZoneReplicationFactor().containsKey(dropZoneId));
        assertEquals("Clipped storedef has incorrect number of zones", initialCluster.getZones().size() - 1, storeDef.getZoneReplicationFactor().size());
        assertEquals("Clipped storedef has incorrect total repfactor", orgStoreDef.getReplicationFactor() - orgStoreDef.getZoneReplicationFactor().get(dropZoneId), storeDef.getReplicationFactor());
    }
    // Confirm that we would not route to any of the dropped nodes for any
    // store.
    Set<Integer> dropNodes = interimCluster.getNodeIdsInZone(dropZoneId);
    for (StoreDefinition storeDef : clippedStoreDefs) {
        StoreRoutingPlan routingPlan = new StoreRoutingPlan(finalCluster, storeDef);
        Node[] partitionToNode = finalCluster.getPartitionIdToNodeArray();
        for (int p = 0; p < partitionToNode.length; p++) {
            List<Integer> replicaNodes = routingPlan.getReplicationNodeList(p);
            assertFalse("Should not be routing to any dropped nodes", replicaNodes.removeAll(dropNodes));
        }
    }
}
Also used : RebalancePlan(voldemort.client.rebalance.RebalancePlan) StoreRoutingPlan(voldemort.routing.StoreRoutingPlan) StoreDefinition(voldemort.store.StoreDefinition) Node(voldemort.cluster.Node) Cluster(voldemort.cluster.Cluster) HashSet(java.util.HashSet) Test(org.junit.Test)

Example 5 with StoreRoutingPlan

use of voldemort.routing.StoreRoutingPlan in project voldemort by voldemort.

the class ClusterForkLiftToolTest method testForkLiftOverWrite.

@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, // OverWrite
    true, // ignore
    false, // mismatch
    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());
            }
        }
    }
}
Also used : StoreRoutingPlan(voldemort.routing.StoreRoutingPlan) Versioned(voldemort.versioning.Versioned) VectorClock(voldemort.versioning.VectorClock) HashMap(java.util.HashMap) Map(java.util.Map) ClockEntry(voldemort.versioning.ClockEntry) Test(org.junit.Test)

Aggregations

StoreRoutingPlan (voldemort.routing.StoreRoutingPlan)14 StoreDefinition (voldemort.store.StoreDefinition)8 Test (org.junit.Test)6 Versioned (voldemort.versioning.Versioned)5 HashMap (java.util.HashMap)4 VoldemortException (voldemort.VoldemortException)4 ClockEntry (voldemort.versioning.ClockEntry)4 VectorClock (voldemort.versioning.VectorClock)4 Map (java.util.Map)3 Cluster (voldemort.cluster.Cluster)3 Node (voldemort.cluster.Node)3 ByteArray (voldemort.utils.ByteArray)2 File (java.io.File)1 IOException (java.io.IOException)1 StringReader (java.io.StringReader)1 ArrayList (java.util.ArrayList)1 HashSet (java.util.HashSet)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 MutableBoolean (org.apache.commons.lang.mutable.MutableBoolean)1 Before (org.junit.Before)1