narendly commented on a change in pull request #369: Add the workaround fix for 
assigning partitions when instance weight …
URL: https://github.com/apache/helix/pull/369#discussion_r310239705
 
 

 ##########
 File path: 
helix-core/src/test/java/org/apache/helix/controller/rebalancer/strategy/crushMapping/TestCardDealingAdjustmentAlgorithmV2.java
 ##########
 @@ -0,0 +1,328 @@
+package org.apache.helix.controller.rebalancer.strategy.crushMapping;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.helix.controller.rebalancer.topology.InstanceNode;
+import org.apache.helix.controller.rebalancer.topology.Node;
+import org.apache.helix.controller.rebalancer.topology.Topology;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.mockito.Mockito.*;
+
+
+public class TestCardDealingAdjustmentAlgorithmV2 {
+  private Topology _topology;
+  private int[][] _defaultFaultZones = new int[][]{{1, 2, 3}, // zone0: i1, 
i2, i3
+      {4, 5, 6}, // zone1: i4, i5, i6
+      {7, 8, 9}  // zone0: i7, i8, i9
+  };
+
+  @BeforeClass
+  public void setUpTopology() {
+    _topology = mock(Topology.class);
+    
when(_topology.getFaultZones()).thenReturn(createFaultZones(_defaultFaultZones));
+  }
+
+  @Test(description = "Verify a few properties after algorithm instance is 
created")
+  public void testAlgorithmConstructor() {
+    CardDealingAdjustmentAlgorithmV2 algorithm =
+        new CardDealingAdjustmentAlgorithmV2(_topology, 3, 
CardDealingAdjustmentAlgorithmV2.Mode.EVENNESS);
+    Map<Node, Long> instanceWeights = algorithm.getInstanceWeight();
+    // verify weight is set correctly
+    for (Map.Entry<Node, Long> entry : instanceWeights.entrySet()) {
+      if (entry.getKey().getId() != entry.getValue()) {
+        Assert.fail(String.format("%s %s should have weight of %s", 
entry.getKey().getName(), entry.getKey().getId(),
+            entry.getValue()));
+      }
+    }
+    Map<Node, Long> faultZoneWeights = algorithm.getFaultZoneWeight();
+    Map<Node, Set<String>> faultZonePartationMap = 
algorithm.getFaultZonePartitionMap();
+    Set<Node> faultZones = faultZoneWeights.keySet();
+
+    Assert.assertEquals(faultZoneWeights.size(), 3);
+    Assert.assertEquals(faultZonePartationMap.keySet(), faultZones);
+
+    long sum = 0;
+    for (long weight : faultZoneWeights.values()) {
+      sum += weight;
+    }
+    // verify total weight is computed correct
+    if (sum != algorithm.getTotalWeight()) {
+      Assert.fail(String.format("total weight %s != total weight of zones %s", 
algorithm.getTotalWeight(), sum));
+    }
+    Map<Node, Node> instanceFaultZone = algorithm.getInstanceFaultZone();
+    Assert.assertEquals(instanceFaultZone.size(), 9);
+
+    // verify zone mapping is correct
+    for (Node zone : faultZones) {
+      long zoneId = zone.getId();
+      Set<Long> instanceIds = ImmutableSet.of(3 * zoneId + 1L, 3 * zoneId + 
2L, 3 * zoneId + 3L);
+      List<Node> instanceNodes = zone.getChildren();
+      Assert.assertEquals(instanceNodes.size(), 3);
+      Set<Long> actualInstanceIds = new HashSet<>();
+      for (Node node : instanceNodes) {
+        actualInstanceIds.add(node.getId());
+      }
+      Assert.assertEquals(actualInstanceIds, instanceIds);
+    }
+  }
+
+  @DataProvider
+  public static Object[][] stableComputingVerification() {
+    return new Object[][]{
+        // replica, repeatTimes, seed, true: evenness false: less movement
+        {1, 10, 0, true}, {2, 10, 10, true}, {3, 10, 100, true}, {1, 10, 0, 
true}, {2, 10, 10, true},
+        {3, 10, 100, true}, {1, 10, 0, true}, {2, 10, 10, true}, {3, 10, 100, 
true}, {1, 10, 0, false},
+        {2, 10, 10, false}, {3, 10, 100, false}, {1, 10, 0, false}, {2, 10, 
10, false}, {3, 10, 100, false},
+        {1, 10, 0, false}, {2, 10, 10, false}, {3, 10, 100, false}};
+  }
+
+  @Test(description = "Compute mapping multiple times, the mapping of each 
time should be same", dataProvider = "stableComputingVerification")
+  public void testStableComputeMappingForMultipleTimes(int replica, int 
repeatTimes, int seed,
+      boolean isEvennessPreferred) {
+    CardDealingAdjustmentAlgorithmV2.Mode preference =
+        isEvennessPreferred ? CardDealingAdjustmentAlgorithmV2.Mode.EVENNESS
+            : CardDealingAdjustmentAlgorithmV2.Mode.MINIMIZE_MOVEMENT;
+    CardDealingAdjustmentAlgorithmV2 algorithm = new 
CardDealingAdjustmentAlgorithmV2(_topology, replica, preference);
+    Set<Node> instanceNodes = algorithm.getInstanceFaultZone().keySet();
+    Map<Node, List<String>> nodeToPartitions = new HashMap<>();
+    for (Node instanceNode : instanceNodes) {
+      int start = (int) instanceNode.getId();
+      int end = start + (int) instanceNode.getWeight();
+      nodeToPartitions.put(instanceNode, createDummyPartitions(start, end));
+    }
+
+    Map<Long, Set<String>> oldSimpleMapping = 
getSimpleMapping(nodeToPartitions);
+    Map<Long, Set<String>> lastCalculatedDifference = new HashMap<>();
+    while (repeatTimes > 0) {
+      System.out.println(
+          String.format("Round %s replica %s algorithm seed: %s preference: %s 
", repeatTimes, replica, seed,
+              preference));
+      // deep clone the original mapping
+      Map<Node, List<String>> newMapping = new HashMap<>();
+      for (Map.Entry<Node, List<String>> entry : nodeToPartitions.entrySet()) {
+        newMapping.put(entry.getKey(), new ArrayList<>(entry.getValue()));
+      }
+      new CardDealingAdjustmentAlgorithmV2(_topology, replica, 
preference).computeMapping(newMapping, seed);
+
+      Map<Long, Set<String>> newDifference = getDifference(oldSimpleMapping, 
getSimpleMapping(newMapping));
+
+      if (!lastCalculatedDifference.isEmpty() && 
!newDifference.equals(lastCalculatedDifference)) {
+        Assert.fail("Different mapping of the same input");
+      }
+
+      lastCalculatedDifference = newDifference;
+      repeatTimes -= 1;
+    }
+  }
+
+  @DataProvider
+  public static Object[][] replicas() {
+    return new Object[][]{{1}, {2}, {3}, {4}, {5}};
+  }
+
+  @Test(description = "Test performance given different replica count", 
dataProvider = "replicas")
+  public void testComputeMappingForDifferentReplicas(int replica) {
+    CardDealingAdjustmentAlgorithmV2 algorithm =
+        new CardDealingAdjustmentAlgorithmV2(_topology, replica, 
CardDealingAdjustmentAlgorithmV2.Mode.EVENNESS);
+    Set<Node> instanceNodes = algorithm.getInstanceFaultZone().keySet();
+    Map<Node, List<String>> nodeToPartitions = new HashMap<>();
+    for (Node instanceNode : instanceNodes) {
+      int start = (int) instanceNode.getId();
+      int end = start + (int) instanceNode.getWeight();
+      nodeToPartitions.put(instanceNode, createDummyPartitions(start, end));
+    }
+    Map<Long, Set<String>> oldSimpleMapping = 
getSimpleMapping(nodeToPartitions);
+    boolean isAllAssigned = algorithm.computeMapping(nodeToPartitions, 100);
+    Map<Long, Set<String>> difference = getDifference(oldSimpleMapping, 
getSimpleMapping(nodeToPartitions));
+    int totalMovements = 0;
+    for (Set<String> value : difference.values()) {
+      totalMovements += value.size();
+    }
+
+    // store the pre-computed result
+    Map<Integer, Integer> expected = ImmutableMap.of(1, 8, 2, 8, 3, 19, 4, 0, 
5, 0);
+
+    if (totalMovements != expected.get(replica)) {
+      Assert.fail(
+          String.format("Total movements: %s != expected %s, replica: %s", 
totalMovements, expected.get(replica),
+              replica));
+    }
+  }
+
+  @Test(description = "Test performance given different preference (evenness 
or less movements)")
+  public void testComputeMappingForDifferentPreference() {
+    CardDealingAdjustmentAlgorithmV2 algorithm1 =
+        new CardDealingAdjustmentAlgorithmV2(_topology, 3, 
CardDealingAdjustmentAlgorithmV2.Mode.EVENNESS);
+    CardDealingAdjustmentAlgorithmV2 algorithm2 =
+        new CardDealingAdjustmentAlgorithmV2(_topology, 3, 
CardDealingAdjustmentAlgorithmV2.Mode.MINIMIZE_MOVEMENT);
 
 Review comment:
   Magic number -> constant

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
[email protected]


With regards,
Apache Git Services

Reply via email to