You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@helix.apache.org by jx...@apache.org on 2017/05/23 21:28:48 UTC
[2/2] helix git commit: Allow user to enable persisting preference
list and best possible state map into IdealState in full-auto mode.
Allow user to enable persisting preference list and best possible state map into IdealState in full-auto mode.
Project: http://git-wip-us.apache.org/repos/asf/helix/repo
Commit: http://git-wip-us.apache.org/repos/asf/helix/commit/8ba068e7
Tree: http://git-wip-us.apache.org/repos/asf/helix/tree/8ba068e7
Diff: http://git-wip-us.apache.org/repos/asf/helix/diff/8ba068e7
Branch: refs/heads/helix-0.6.x
Commit: 8ba068e7b78aedf4743f2da57670384534d1d4f8
Parents: 7c92bf5
Author: Lei Xia <lx...@linkedin.com>
Authored: Tue May 23 13:58:24 2017 -0700
Committer: Lei Xia <lx...@linkedin.com>
Committed: Tue May 23 13:58:24 2017 -0700
----------------------------------------------------------------------
.../stages/BestPossibleStateCalcStage.java | 3 +
.../stages/BestPossibleStateOutput.java | 42 +++++
.../stages/PersistAssignmentStage.java | 172 ++++++++++---------
.../java/org/apache/helix/model/IdealState.java | 65 +++++--
.../TestRebalancerPersistAssignments.java | 126 +++++---------
5 files changed, 227 insertions(+), 181 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/helix/blob/8ba068e7/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateCalcStage.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateCalcStage.java b/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateCalcStage.java
index cba0659..526f532 100644
--- a/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateCalcStage.java
+++ b/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateCalcStage.java
@@ -127,6 +127,7 @@ public class BestPossibleStateCalcStage extends AbstractBaseStage {
rebalancer.init(manager);
idealState =
rebalancer.computeNewIdealState(resourceName, idealState, currentStateOutput, cache);
+ output.setPreferenceLists(resourceName, idealState.getPreferenceLists());
// Use the internal MappingCalculator interface to compute the final assignment
// The next release will support rebalancers that compute the mapping from start to finish
@@ -180,6 +181,8 @@ public class BestPossibleStateCalcStage extends AbstractBaseStage {
rebalancer = customizedRebalancer;
break;
default:
+ logger.error(
+ "Fail to find the rebalancer, invalid rebalance mode " + idealState.getRebalanceMode());
break;
}
http://git-wip-us.apache.org/repos/asf/helix/blob/8ba068e7/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateOutput.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateOutput.java b/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateOutput.java
index 168a3b0..a3ad56d 100644
--- a/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateOutput.java
+++ b/helix-core/src/main/java/org/apache/helix/controller/stages/BestPossibleStateOutput.java
@@ -21,6 +21,7 @@ package org.apache.helix.controller.stages;
import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -29,6 +30,8 @@ import org.apache.helix.model.Partition;
public class BestPossibleStateOutput {
// Map of resource->partition->instance->state
Map<String, Map<Partition, Map<String, String>>> _stateMap;
+ /* resource -> partition -> preference list */
+ private Map<String, Map<String, List<String>>> _preferenceLists;
public BestPossibleStateOutput() {
_stateMap = new HashMap<String, Map<Partition, Map<String, String>>>();
@@ -77,6 +80,45 @@ public class BestPossibleStateOutput {
return _stateMap;
}
+ public Map<String, Map<String, List<String>>> getPreferenceLists() {
+ return _preferenceLists;
+ }
+
+ public Map<String, List<String>> getPreferenceLists(String resource) {
+ if (_preferenceLists != null && _preferenceLists.containsKey(resource)) {
+ return _preferenceLists.get(resource);
+ }
+
+ return null;
+ }
+
+ public List<String> getPreferenceList(String resource, String partition) {
+ if (_preferenceLists != null && _preferenceLists.containsKey(resource) && _preferenceLists
+ .get(resource).containsKey(partition)) {
+ return _preferenceLists.get(resource).get(partition);
+ }
+
+ return null;
+ }
+
+ public void setPreferenceList(String resource, String partition, List<String> list) {
+ if (_preferenceLists == null) {
+ _preferenceLists = new HashMap<String, Map<String, List<String>>>();
+ }
+ if (!_preferenceLists.containsKey(resource)) {
+ _preferenceLists.put(resource, new HashMap<String, List<String>>());
+ }
+ _preferenceLists.get(resource).put(partition, list);
+ }
+
+ public void setPreferenceLists(String resource,
+ Map<String, List<String>> resourcePreferenceLists) {
+ if (_preferenceLists == null) {
+ _preferenceLists = new HashMap<String, Map<String, List<String>>>();
+ }
+ _preferenceLists.put(resource, resourcePreferenceLists);
+ }
+
@Override
public String toString() {
return _stateMap.toString();
http://git-wip-us.apache.org/repos/asf/helix/blob/8ba068e7/helix-core/src/main/java/org/apache/helix/controller/stages/PersistAssignmentStage.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/controller/stages/PersistAssignmentStage.java b/helix-core/src/main/java/org/apache/helix/controller/stages/PersistAssignmentStage.java
index 9c297f8..425b38b 100644
--- a/helix-core/src/main/java/org/apache/helix/controller/stages/PersistAssignmentStage.java
+++ b/helix-core/src/main/java/org/apache/helix/controller/stages/PersistAssignmentStage.java
@@ -19,19 +19,16 @@ package org.apache.helix.controller.stages;
* under the License.
*/
-import java.util.Collections;
-import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
-
+import java.util.Set;
import org.apache.helix.HelixDataAccessor;
import org.apache.helix.HelixManager;
import org.apache.helix.PropertyKey;
import org.apache.helix.controller.pipeline.AbstractBaseStage;
-import org.apache.helix.model.BuiltInStateModelDefinitions;
import org.apache.helix.model.ClusterConfig;
import org.apache.helix.model.IdealState;
-import org.apache.helix.model.MasterSlaveSMD;
import org.apache.helix.model.Partition;
import org.apache.helix.model.Resource;
import org.apache.log4j.Logger;
@@ -49,56 +46,58 @@ public class PersistAssignmentStage extends AbstractBaseStage {
ClusterDataCache cache = event.getAttribute("ClusterDataCache");
ClusterConfig clusterConfig = cache.getClusterConfig();
- if (clusterConfig.isPersistBestPossibleAssignment()) {
- HelixManager helixManager = event.getAttribute("helixmanager");
- HelixDataAccessor accessor = helixManager.getHelixDataAccessor();
- PropertyKey.Builder keyBuilder = accessor.keyBuilder();
- BestPossibleStateOutput bestPossibleAssignments =
- event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.toString());
- Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.toString());
-
- for (String resourceId : bestPossibleAssignments.resourceSet()) {
- Resource resource = resourceMap.get(resourceId);
- if (resource != null) {
- boolean changed = false;
- Map<Partition, Map<String, String>> bestPossibleAssignment =
- bestPossibleAssignments.getResourceMap(resourceId);
- IdealState idealState = cache.getIdealState(resourceId);
- if (idealState == null) {
- LOG.warn("IdealState not found for resource " + resourceId);
- continue;
- }
- IdealState.RebalanceMode mode = idealState.getRebalanceMode();
- if (!mode.equals(IdealState.RebalanceMode.SEMI_AUTO) && !mode
- .equals(IdealState.RebalanceMode.FULL_AUTO)) {
- // do not persist assignment for resource in neither semi or full auto.
- continue;
- }
+ if (!clusterConfig.isPersistBestPossibleAssignment()) {
+ return;
+ }
- //TODO: temporary solution for Espresso/Dbus backcompatible, should remove this.
- Map<Partition, Map<String, String>> assignmentToPersist =
- convertAssignmentPersisted(resource, idealState, bestPossibleAssignment);
-
- for (Partition partition : resource.getPartitions()) {
- Map<String, String> instanceMap = assignmentToPersist.get(partition);
- Map<String, String> existInstanceMap =
- idealState.getInstanceStateMap(partition.getPartitionName());
- if (instanceMap == null && existInstanceMap == null) {
- continue;
- }
- if (instanceMap == null || existInstanceMap == null || !instanceMap
- .equals(existInstanceMap)) {
- changed = true;
- break;
- }
+ BestPossibleStateOutput bestPossibleAssignment =
+ event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.name());
+
+ HelixManager helixManager = event.getAttribute("helixmanager");
+ HelixDataAccessor accessor = helixManager.getHelixDataAccessor();
+ PropertyKey.Builder keyBuilder = accessor.keyBuilder();
+ Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name());
+
+ for (String resourceId : bestPossibleAssignment.resourceSet()) {
+ Resource resource = resourceMap.get(resourceId);
+ if (resource != null) {
+ final IdealState idealState = cache.getIdealState(resourceId);
+ if (idealState == null) {
+ LOG.warn("IdealState not found for resource " + resourceId);
+ continue;
+ }
+ IdealState.RebalanceMode mode = idealState.getRebalanceMode();
+ if (!mode.equals(IdealState.RebalanceMode.SEMI_AUTO) && !mode
+ .equals(IdealState.RebalanceMode.FULL_AUTO)) {
+ // do not persist assignment for resource in neither semi or full auto.
+ continue;
+ }
+
+ boolean needPersist = false;
+ if (mode.equals(IdealState.RebalanceMode.FULL_AUTO)) {
+ // persist preference list in ful-auto mode.
+ Map<String, List<String>> newLists =
+ bestPossibleAssignment.getPreferenceLists(resourceId);
+ if (newLists != null && hasPreferenceListChanged(newLists, idealState)) {
+ idealState.setPreferenceLists(newLists);
+ needPersist = true;
}
- if (changed) {
- for (Partition partition : assignmentToPersist.keySet()) {
- Map<String, String> instanceMap = assignmentToPersist.get(partition);
- idealState.setInstanceStateMap(partition.getPartitionName(), instanceMap);
- }
- accessor.setProperty(keyBuilder.idealStates(resourceId), idealState);
+ }
+
+ Map<Partition, Map<String, String>> bestPossibleAssignements =
+ bestPossibleAssignment.getResourceMap(resourceId);
+
+ if (bestPossibleAssignements != null && hasInstanceMapChanged(bestPossibleAssignements,
+ idealState)) {
+ for (Partition partition : bestPossibleAssignements.keySet()) {
+ Map<String, String> instanceMap = bestPossibleAssignements.get(partition);
+ idealState.setInstanceStateMap(partition.getPartitionName(), instanceMap);
}
+ needPersist = true;
+ }
+
+ if (needPersist) {
+ accessor.setProperty(keyBuilder.idealStates(resourceId), idealState);
}
}
}
@@ -108,47 +107,50 @@ public class PersistAssignmentStage extends AbstractBaseStage {
}
/**
- * TODO: This is a temporary hacky for back-compatible support of Espresso and Databus,
- * we should get rid of this conversion as soon as possible.
- * --- Lei, 2016/9/9.
+ * has the preference list changed from the one persisted in current IdealState
*/
- private Map<Partition, Map<String, String>> convertAssignmentPersisted(Resource resource,
- IdealState idealState, Map<Partition, Map<String, String>> bestPossibleAssignment) {
- String stateModelDef = idealState.getStateModelDefRef();
- /** Only convert for MasterSlave resources */
- if (!stateModelDef.equals(BuiltInStateModelDefinitions.MasterSlave.name())) {
- return bestPossibleAssignment;
+ private boolean hasPreferenceListChanged(Map<String, List<String>> newLists,
+ IdealState idealState) {
+ Map<String, List<String>> existLists = idealState.getPreferenceLists();
+
+ Set<String> partitions = new HashSet<String>(newLists.keySet());
+ partitions.addAll(existLists.keySet());
+
+ for (String partition : partitions) {
+ List<String> assignedInstances = newLists.get(partition);
+ List<String> existingInstances = existLists.get(partition);
+ if (assignedInstances == null && existingInstances == null) {
+ continue;
+ }
+ if (assignedInstances == null || existingInstances == null || !assignedInstances
+ .equals(existingInstances)) {
+ return true;
+ }
}
- Map<Partition, Map<String, String>> assignmentToPersist =
- new HashMap<Partition, Map<String, String>>();
-
- for (Partition partition : resource.getPartitions()) {
- Map<String, String> instanceMap = new HashMap<String, String>();
- instanceMap.putAll(bestPossibleAssignment.get(partition));
+ return false;
+ }
- List<String> preferenceList = idealState.getPreferenceList(partition.getPartitionName());
- boolean hasMaster = false;
- for (String ins : preferenceList) {
- String state = instanceMap.get(ins);
- if (state == null || (!state.equals(MasterSlaveSMD.States.SLAVE.name()) && !state
- .equals(MasterSlaveSMD.States.MASTER.name()))) {
- instanceMap.put(ins, MasterSlaveSMD.States.SLAVE.name());
- }
+ private boolean hasInstanceMapChanged(Map<Partition, Map<String, String>> newAssiments,
+ IdealState idealState) {
+ Set<Partition> partitions = new HashSet<Partition>(newAssiments.keySet());
+ for (String p : idealState.getPartitionSet()) {
+ partitions.add(new Partition(p));
+ }
- if (state != null && state.equals(MasterSlaveSMD.States.MASTER.name())) {
- hasMaster = true;
- }
+ for (Partition partition : partitions) {
+ Map<String, String> instanceMap = newAssiments.get(partition);
+ Map<String, String> existInstanceMap =
+ idealState.getInstanceStateMap(partition.getPartitionName());
+ if (instanceMap == null && existInstanceMap == null) {
+ continue;
}
-
- // if no master, just pick the first node in the preference list as the master.
- if (!hasMaster && preferenceList.size() > 0) {
- instanceMap.put(preferenceList.get(0), MasterSlaveSMD.States.MASTER.name());
+ if (instanceMap == null || existInstanceMap == null || !instanceMap
+ .equals(existInstanceMap)) {
+ return true;
}
-
- assignmentToPersist.put(partition, instanceMap);
}
- return assignmentToPersist;
+ return false;
}
}
http://git-wip-us.apache.org/repos/asf/helix/blob/8ba068e7/helix-core/src/main/java/org/apache/helix/model/IdealState.java
----------------------------------------------------------------------
diff --git a/helix-core/src/main/java/org/apache/helix/model/IdealState.java b/helix-core/src/main/java/org/apache/helix/model/IdealState.java
index 907bd27..48e43d6 100644
--- a/helix-core/src/main/java/org/apache/helix/model/IdealState.java
+++ b/helix-core/src/main/java/org/apache/helix/model/IdealState.java
@@ -352,6 +352,9 @@ public class IdealState extends HelixProperty {
/**
* Get the current mapping of a partition
+ * CAUTION: In FULL-AUTO mode, this method could return empty map if
+ * {@link ClusterConfig#setPersistBestPossibleAssignment(Boolean)} is set to true.
+ *
* @param partitionName the name of the partition
* @return the instances where the replicas live and the state of each
*/
@@ -371,37 +374,75 @@ public class IdealState extends HelixProperty {
}
/**
- * Get the instances who host replicas of a partition
+ * Get the instances who host replicas of a partition.
+ * CAUTION: In FULL-AUTO mode, this method could return empty map if
+ * {@link ClusterConfig#setPersistBestPossibleAssignment(Boolean)} is set to true.
+ +
* @param partitionName the partition to look up
* @return set of instance names
*/
public Set<String> getInstanceSet(String partitionName) {
- if (getRebalanceMode() == RebalanceMode.SEMI_AUTO
- || getRebalanceMode() == RebalanceMode.FULL_AUTO
- || getRebalanceMode() == RebalanceMode.USER_DEFINED
- || getRebalanceMode() == RebalanceMode.TASK) {
+ switch (getRebalanceMode()) {
+ case FULL_AUTO:
+ case SEMI_AUTO:
+ case USER_DEFINED:
+ case TASK:
List<String> prefList = _record.getListField(partitionName);
- if (prefList != null) {
+ if (prefList != null && !prefList.isEmpty()) {
return new TreeSet<String>(prefList);
} else {
- logger.warn(partitionName + " does NOT exist");
- return Collections.emptySet();
+ Map<String, String> stateMap = _record.getMapField(partitionName);
+ if (stateMap != null && !stateMap.isEmpty()) {
+ return new TreeSet<String>(stateMap.keySet());
+ } else {
+ logger.warn(partitionName + " does NOT exist");
+ }
}
- } else if (getRebalanceMode() == RebalanceMode.CUSTOMIZED) {
+ break;
+ case CUSTOMIZED:
Map<String, String> stateMap = _record.getMapField(partitionName);
if (stateMap != null) {
return new TreeSet<String>(stateMap.keySet());
} else {
logger.warn(partitionName + " does NOT exist");
- return Collections.emptySet();
}
- } else {
+ break;
+ case NONE:
+ default:
logger.error("Invalid ideal state mode: " + getResourceName());
- return Collections.emptySet();
+ break;
}
+ return Collections.emptySet();
+ }
+
+ /** Set the preference list of a partition
+ * @param partitionName the name of the partition
+ * @param instanceList the instance preference list
+ */
+ public void setPreferenceList(String partitionName, List<String> instanceList) {
+ _record.setListField(partitionName, instanceList);
+ }
+
+ /**
+ * Set the preference lists for all partitions in this resource.
+ *
+ * @param instanceLists the map of instance preference lists.
+ */
+ public void setPreferenceLists(Map<String, List<String>> instanceLists) {
+ _record.setListFields(instanceLists);
+ }
+
+ /**
+ * Get the preference lists for all partitions
+ *
+ * @return map of lists of instances for all partitions in this resource.
+ */
+ public Map<String, List<String>> getPreferenceLists() {
+ return _record.getListFields();
}
+
/**
* Get the preference list of a partition
* @param partitionName the name of the partition
http://git-wip-us.apache.org/repos/asf/helix/blob/8ba068e7/helix-core/src/test/java/org/apache/helix/integration/TestRebalancerPersistAssignments.java
----------------------------------------------------------------------
diff --git a/helix-core/src/test/java/org/apache/helix/integration/TestRebalancerPersistAssignments.java b/helix-core/src/test/java/org/apache/helix/integration/TestRebalancerPersistAssignments.java
index 3aec847..2a9dc69 100644
--- a/helix-core/src/test/java/org/apache/helix/integration/TestRebalancerPersistAssignments.java
+++ b/helix-core/src/test/java/org/apache/helix/integration/TestRebalancerPersistAssignments.java
@@ -24,11 +24,8 @@ import org.apache.helix.integration.manager.MockParticipantManager;
import org.apache.helix.model.BuiltInStateModelDefinitions;
import org.apache.helix.model.IdealState;
import org.apache.helix.model.IdealState.RebalanceMode;
-import org.apache.helix.model.MasterSlaveSMD;
import org.apache.helix.tools.ClusterSetup;
import org.apache.helix.tools.ClusterVerifiers.BestPossibleExternalViewVerifier;
-import org.apache.helix.tools.ClusterVerifiers.ClusterStateVerifier;
-import org.apache.helix.tools.ClusterVerifiers.HelixClusterVerifier;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
@@ -42,6 +39,8 @@ import java.util.Map;
import java.util.Set;
public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
+ Set<String> _instanceNames = new HashSet<String>();
+
@Override
@BeforeClass
public void beforeClass() throws Exception {
@@ -69,13 +68,14 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
// start dummy participants
for (int i = 0; i < NODE_NR; i++) {
String instanceName = PARTICIPANT_PREFIX + "_" + (START_PORT + i);
+ _instanceNames.add(instanceName);
_participants[i] = new MockParticipantManager(ZK_ADDR, CLUSTER_NAME, instanceName);
_participants[i].syncStart();
}
}
@DataProvider(name = "rebalanceModes")
- public static RebalanceMode [][] rebalanceModes() {
+ public static Object [][] rebalanceModes() {
return new RebalanceMode[][] { {RebalanceMode.SEMI_AUTO}, {RebalanceMode.FULL_AUTO}};
}
@@ -88,23 +88,25 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
BuiltInStateModelDefinitions.LeaderStandby.name(), rebalanceMode.name());
_setupTool.rebalanceStorageCluster(CLUSTER_NAME, testDb, 3);
- HelixClusterVerifier verifier =
+ BestPossibleExternalViewVerifier.Builder verifierBuilder =
new BestPossibleExternalViewVerifier.Builder(CLUSTER_NAME).setZkAddr(ZK_ADDR)
- .setResources(new HashSet<String>(Collections.singleton(testDb))).build();
- Thread.sleep(500);
- Assert.assertTrue(verifier.verify());
+ .setResources(new HashSet<String>(Collections.singleton(testDb)));
+
+ Assert.assertTrue(verifierBuilder.build().verify());
// kill 1 node
_participants[0].syncStop();
- Assert.assertTrue(verifier.verify());
+ Set<String> liveInstances = new HashSet<String>(_instanceNames);
+ liveInstances.remove(_participants[0].getInstanceName());
+ verifierBuilder.setExpectLiveInstances(liveInstances);
+ Assert.assertTrue(verifierBuilder.build().verify());
IdealState idealState =
_setupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, testDb);
Set<String> excludedInstances = new HashSet<String>();
excludedInstances.add(_participants[0].getInstanceName());
- Thread.sleep(2000);
verifyAssignmentInIdealStateWithPersistDisabled(idealState, excludedInstances);
// clean up
@@ -124,10 +126,11 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
BuiltInStateModelDefinitions.LeaderStandby.name(), rebalanceMode.name());
_setupTool.rebalanceStorageCluster(CLUSTER_NAME, testDb, 3);
- HelixClusterVerifier verifier =
+ BestPossibleExternalViewVerifier.Builder verifierBuilder =
new BestPossibleExternalViewVerifier.Builder(CLUSTER_NAME).setZkAddr(ZK_ADDR)
- .setResources(new HashSet<String>(Collections.singleton(testDb))).build();
- Assert.assertTrue(verifier.verify());
+ .setResources(new HashSet<String>(Collections.singleton(testDb)));
+
+ Assert.assertTrue(verifierBuilder.build().verify());
IdealState idealState =
_setupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, testDb);
@@ -136,9 +139,10 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
// kill 1 node
_participants[0].syncStop();
- Boolean result = ClusterStateVerifier.verifyByZkCallback(
- new ClusterStateVerifier.BestPossAndExtViewZkVerifier(ZK_ADDR, CLUSTER_NAME));
- Assert.assertTrue(result);
+ Set<String> liveInstances = new HashSet<String>(_instanceNames);
+ liveInstances.remove(_participants[0].getInstanceName());
+ verifierBuilder.setExpectLiveInstances(liveInstances);
+ Assert.assertTrue(verifierBuilder.build().verify());
idealState = _setupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, testDb);
// verify that IdealState contains updated assignment in it map fields.
@@ -154,72 +158,8 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
_participants[0].syncStart();
}
- /**
- * This test is to test the temporary solution for solving Espresso/Databus back-compatible map format issue.
- *
- * @throws Exception
- */
- @Test(dependsOnMethods = { "testDisablePersist" })
- public void testSemiAutoEnablePersistMasterSlave() throws Exception {
- String testDb = "TestDB1-MasterSlave";
- enablePersistBestPossibleAssignment(_gZkClient, CLUSTER_NAME, true);
-
- _setupTool.addResourceToCluster(CLUSTER_NAME, testDb, 5, BuiltInStateModelDefinitions.MasterSlave.name(),
- RebalanceMode.SEMI_AUTO.name());
- _setupTool.rebalanceStorageCluster(CLUSTER_NAME, testDb, 3);
-
- HelixClusterVerifier verifier =
- new BestPossibleExternalViewVerifier.Builder(CLUSTER_NAME).setZkAddr(ZK_ADDR)
- .setResources(new HashSet<String>(Collections.singleton(testDb))).build();
- Assert.assertTrue(verifier.verify());
-
- IdealState idealState =
- _setupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, testDb);
- verifySemiAutoMasterSlaveAssignment(idealState);
-
- // kill 1 node
- _participants[0].syncStop();
-
- Assert.assertTrue(verifier.verify());
-
- idealState = _setupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, testDb);
- verifySemiAutoMasterSlaveAssignment(idealState);
-
- // disable an instance
- _setupTool.getClusterManagementTool()
- .enableInstance(CLUSTER_NAME, _participants[1].getInstanceName(), false);
- idealState = _setupTool.getClusterManagementTool().getResourceIdealState(CLUSTER_NAME, testDb);
- verifySemiAutoMasterSlaveAssignment(idealState);
-
- // clean up
- _setupTool.getClusterManagementTool().dropResource(CLUSTER_NAME, testDb);
- _setupTool.getClusterManagementTool()
- .enableInstance(CLUSTER_NAME, _participants[1].getInstanceName(), true);
- _participants[0].reset();
- _participants[0].syncStart();
- }
-
- private void verifySemiAutoMasterSlaveAssignment(IdealState idealState) {
- for (String partition : idealState.getPartitionSet()) {
- Map<String, String> instanceStateMap = idealState.getInstanceStateMap(partition);
- List<String> preferenceList = idealState.getPreferenceList(partition);
- int numMaster = 0;
-
- for (String ins : preferenceList) {
- Assert.assertTrue(instanceStateMap.containsKey(ins));
- String state = instanceStateMap.get(ins);
- Assert.assertTrue(state.equals(MasterSlaveSMD.States.MASTER.name()) || state
- .equals(MasterSlaveSMD.States.SLAVE.name()));
- if (state.equals(MasterSlaveSMD.States.MASTER.name())) {
- numMaster++;
- }
- }
-
- Assert.assertEquals(numMaster, 1);
- }
- }
-
- // verify that the disabled or failed instance should not be included in bestPossible assignment.
+ // verify that both list field and map field should be persisted in IS,
+ // And the disabled or failed instance should not be included in bestPossible assignment.
private void verifyAssignmentInIdealStateWithPersistEnabled(IdealState idealState,
Set<String> excludedInstances) {
for (String partition : idealState.getPartitionSet()) {
@@ -228,8 +168,20 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
Assert.assertFalse(instanceStateMap.isEmpty());
Set<String> instancesInMap = instanceStateMap.keySet();
- Set<String> instanceInList = idealState.getInstanceSet(partition);
- Assert.assertTrue(instanceInList.containsAll(instancesInMap));
+ if (idealState.getRebalanceMode() == RebalanceMode.SEMI_AUTO) {
+ Set<String> instanceInList = idealState.getInstanceSet(partition);
+ Assert.assertTrue(instanceInList.containsAll(instancesInMap));
+ }
+
+ if(idealState.getRebalanceMode() == RebalanceMode.FULL_AUTO) {
+ // preference list should be persisted in IS.
+ List<String> instanceList = idealState.getPreferenceList(partition);
+ Assert.assertNotNull(instanceList);
+ Assert.assertFalse(instanceList.isEmpty());
+ for (String ins : excludedInstances) {
+ Assert.assertFalse(instanceList.contains(ins));
+ }
+ }
for (String ins : excludedInstances) {
Assert.assertFalse(instancesInMap.contains(ins));
@@ -254,6 +206,12 @@ public class TestRebalancerPersistAssignments extends ZkStandAloneCMTestBase {
// if at least one excluded instance is included, it means assignment was not updated.
assignmentNotChanged = true;
}
+ if(idealState.getRebalanceMode() == RebalanceMode.FULL_AUTO) {
+ List<String> instanceList = idealState.getPreferenceList(partition);
+ if (instanceList.contains(ins)) {
+ assignmentNotChanged = true;
+ }
+ }
}
}