TargetExternalView implementation To make router quickly update, we will have a target external view implementation that make router listen on newly calculated change of master instead of waiting for M->S and S->M complete.
Project: http://git-wip-us.apache.org/repos/asf/helix/repo Commit: http://git-wip-us.apache.org/repos/asf/helix/commit/d89fbb93 Tree: http://git-wip-us.apache.org/repos/asf/helix/tree/d89fbb93 Diff: http://git-wip-us.apache.org/repos/asf/helix/diff/d89fbb93 Branch: refs/heads/master Commit: d89fbb93de273f1101e94d2c4c06bd6ad1256f23 Parents: a83e8d6 Author: Junkai Xue <j...@linkedin.com> Authored: Tue Sep 26 11:07:48 2017 -0700 Committer: Junkai Xue <j...@linkedin.com> Committed: Mon Nov 6 17:08:59 2017 -0800 ---------------------------------------------------------------------- .../java/org/apache/helix/HelixConstants.java | 1 + .../java/org/apache/helix/HelixManager.java | 6 +- .../main/java/org/apache/helix/PropertyKey.java | 17 +++ .../org/apache/helix/PropertyPathBuilder.java | 10 ++ .../java/org/apache/helix/PropertyType.java | 1 + .../controller/GenericHelixController.java | 2 + .../controller/stages/ClusterDataCache.java | 10 ++ .../stages/TargetExteralViewCalcStage.java | 116 +++++++++++++++++++ .../helix/manager/zk/CallbackHandler.java | 6 +- .../apache/helix/manager/zk/ZKHelixManager.java | 6 + .../org/apache/helix/model/ClusterConfig.java | 18 ++- .../controller/stages/DummyClusterManager.java | 5 + .../controller/TestTargetExternalView.java | 85 ++++++++++++++ .../java/org/apache/helix/mock/MockManager.java | 5 + .../helix/participant/MockZKHelixManager.java | 5 + 15 files changed, 289 insertions(+), 4 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/HelixConstants.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/HelixConstants.java b/helix-core/src/main/java/org/apache/helix/HelixConstants.java index 119ad5a..6935a23 100644 --- a/helix-core/src/main/java/org/apache/helix/HelixConstants.java +++ b/helix-core/src/main/java/org/apache/helix/HelixConstants.java @@ -35,6 +35,7 @@ public interface HelixConstants { CURRENT_STATE, MESSAGE, EXTERNAL_VIEW, + TARGET_EXTERNAL_VIEW, CONTROLLER, MESSAGES_CONTROLLER, HEALTH http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/HelixManager.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/HelixManager.java b/helix-core/src/main/java/org/apache/helix/HelixManager.java index bc67a1a..ff61a04 100644 --- a/helix-core/src/main/java/org/apache/helix/HelixManager.java +++ b/helix-core/src/main/java/org/apache/helix/HelixManager.java @@ -215,7 +215,11 @@ public interface HelixManager { */ void addExternalViewChangeListener(ExternalViewChangeListener listener) throws Exception; - + /** + * @see ExternalViewChangeListener#onExternalViewChange(List, NotificationContext) + * @param listener + */ + void addTargetExternalViewChangeListener(ExternalViewChangeListener listener) throws Exception; /** * @see ExternalViewChangeListener#onExternalViewChange(List, NotificationContext) * @param listener http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/PropertyKey.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/PropertyKey.java b/helix-core/src/main/java/org/apache/helix/PropertyKey.java index b198ac2..20cb833 100644 --- a/helix-core/src/main/java/org/apache/helix/PropertyKey.java +++ b/helix-core/src/main/java/org/apache/helix/PropertyKey.java @@ -554,6 +554,23 @@ public class PropertyKey { } /** + * Get a property key associated with all target external view + * @return {@link PropertyKey} + */ + public PropertyKey targetExternalViews() { + return new PropertyKey(TARGETEXTERNALVIEW, ExternalView.class, _clusterName); + } + + /** + * Get a property key associated with an target external view of a resource + * @param resourceName + * @return {@link PropertyKey} + */ + public PropertyKey targetExternalView(String resourceName) { + return new PropertyKey(TARGETEXTERNALVIEW, ExternalView.class, _clusterName, resourceName); + } + + /** * Get a property key associated with a controller * @return {@link PropertyKey} */ http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/PropertyPathBuilder.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/PropertyPathBuilder.java b/helix-core/src/main/java/org/apache/helix/PropertyPathBuilder.java index 756b716..61aeebb 100644 --- a/helix-core/src/main/java/org/apache/helix/PropertyPathBuilder.java +++ b/helix-core/src/main/java/org/apache/helix/PropertyPathBuilder.java @@ -83,6 +83,8 @@ public class PropertyPathBuilder { addEntry(PropertyType.IDEALSTATES, 2, "/{clusterName}/IDEALSTATES/{resourceName}"); addEntry(PropertyType.EXTERNALVIEW, 1, "/{clusterName}/EXTERNALVIEW"); addEntry(PropertyType.EXTERNALVIEW, 2, "/{clusterName}/EXTERNALVIEW/{resourceName}"); + addEntry(PropertyType.TARGETEXTERNALVIEW, 1, "/{clusterName}/TARGETEXTERNALVIEW"); + addEntry(PropertyType.TARGETEXTERNALVIEW, 2, "/{clusterName}/TARGETEXTERNALVIEW/{resourceName}"); addEntry(PropertyType.STATEMODELDEFS, 1, "/{clusterName}/STATEMODELDEFS"); addEntry(PropertyType.STATEMODELDEFS, 2, "/{clusterName}/STATEMODELDEFS/{stateModelName}"); addEntry(PropertyType.CONTROLLER, 1, "/{clusterName}/CONTROLLER"); @@ -228,6 +230,14 @@ public class PropertyPathBuilder { return String.format("/%s/EXTERNALVIEW/%s", clusterName, resourceName); } + public static String targetExternalView(String clusterName) { + return String.format("/%s/TARGETEXTERNALVIEW", clusterName); + } + + public static String targetExternalView(String clusterName, String resourceName) { + return String.format("/%s/TARGETEXTERNALVIEW/%s", clusterName, resourceName); + } + public static String liveInstance(String clusterName) { return String.format("/%s/LIVEINSTANCES", clusterName); } http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/PropertyType.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/PropertyType.java b/helix-core/src/main/java/org/apache/helix/PropertyType.java index 75bdc22..b522014 100644 --- a/helix-core/src/main/java/org/apache/helix/PropertyType.java +++ b/helix-core/src/main/java/org/apache/helix/PropertyType.java @@ -41,6 +41,7 @@ public enum PropertyType { INSTANCES(Type.CLUSTER, true, false), IDEALSTATES(Type.CLUSTER, true, false, false, false, true), EXTERNALVIEW(Type.CLUSTER, true, false), + TARGETEXTERNALVIEW(Type.CLUSTER, true, false), STATEMODELDEFS(Type.CLUSTER, true, false, false, false, true), CONTROLLER(Type.CLUSTER, true, false), PROPERTYSTORE(Type.CLUSTER, true, false), http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/controller/GenericHelixController.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/controller/GenericHelixController.java b/helix-core/src/main/java/org/apache/helix/controller/GenericHelixController.java index 9496aec..b101049 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/GenericHelixController.java +++ b/helix-core/src/main/java/org/apache/helix/controller/GenericHelixController.java @@ -65,6 +65,7 @@ import org.apache.helix.controller.stages.PersistAssignmentStage; import org.apache.helix.controller.stages.ReadClusterDataStage; import org.apache.helix.controller.stages.ResourceComputationStage; import org.apache.helix.controller.stages.ResourceValidationStage; +import org.apache.helix.controller.stages.TargetExteralViewCalcStage; import org.apache.helix.controller.stages.TaskAssignmentStage; import org.apache.helix.model.ClusterConfig; import org.apache.helix.model.CurrentState; @@ -248,6 +249,7 @@ public class GenericHelixController implements IdealStateChangeListener, rebalancePipeline.addStage(new MessageThrottleStage()); rebalancePipeline.addStage(new TaskAssignmentStage()); rebalancePipeline.addStage(new PersistAssignmentStage()); + rebalancePipeline.addStage(new TargetExteralViewCalcStage()); // external view generation Pipeline externalViewPipeline = new Pipeline(pipelineName); http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/controller/stages/ClusterDataCache.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/controller/stages/ClusterDataCache.java b/helix-core/src/main/java/org/apache/helix/controller/stages/ClusterDataCache.java index 8ce614c..f9fc514 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/stages/ClusterDataCache.java +++ b/helix-core/src/main/java/org/apache/helix/controller/stages/ClusterDataCache.java @@ -41,6 +41,7 @@ import org.apache.helix.model.ClusterConfig; import org.apache.helix.model.ClusterConstraints; import org.apache.helix.model.ClusterConstraints.ConstraintType; import org.apache.helix.model.CurrentState; +import org.apache.helix.model.ExternalView; import org.apache.helix.model.IdealState; import org.apache.helix.model.InstanceConfig; import org.apache.helix.model.LiveInstance; @@ -91,6 +92,7 @@ public class ClusterDataCache { private Map<String, JobConfig> _jobConfigMap = new HashMap<>(); private Map<String, WorkflowConfig> _workflowConfigMap = new HashMap<>(); private Map<String, ZNRecord> _contextMap = new HashMap<>(); + private Map<String, ExternalView> _targetExternalViewMap = Maps.newHashMap(); // maintain a cache of participant messages across pipeline runs private Map<String, Map<String, Message>> _messageCache = Maps.newHashMap(); @@ -859,6 +861,14 @@ public class ClusterDataCache { return _contextMap; } + public ExternalView getTargetExternalView(String resourceName) { + return _targetExternalViewMap.get(resourceName); + } + + public void updateTargetExternalView(String resourceName, ExternalView targetExternalView) { + _targetExternalViewMap.put(resourceName, targetExternalView); + } + /** * Indicate that a full read should be done on the next refresh */ http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/controller/stages/TargetExteralViewCalcStage.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/controller/stages/TargetExteralViewCalcStage.java b/helix-core/src/main/java/org/apache/helix/controller/stages/TargetExteralViewCalcStage.java new file mode 100644 index 0000000..46fc64e --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/stages/TargetExteralViewCalcStage.java @@ -0,0 +1,116 @@ +package org.apache.helix.controller.stages; + +/* + * 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 java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.helix.AccessOption; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.HelixManager; +import org.apache.helix.HelixProperty; +import org.apache.helix.PropertyKey; +import org.apache.helix.controller.common.PartitionStateMap; +import org.apache.helix.controller.pipeline.AbstractBaseStage; +import org.apache.helix.model.ClusterConfig; +import org.apache.helix.model.ExternalView; +import org.apache.helix.model.IdealState; +import org.apache.helix.model.Partition; +import org.apache.helix.model.Resource; +import org.apache.log4j.Logger; + +import com.google.common.collect.Maps; + +public class TargetExteralViewCalcStage extends AbstractBaseStage { + private static final Logger LOG = Logger.getLogger(TargetExteralViewCalcStage.class); + + @Override + public void process(ClusterEvent event) throws Exception { + LOG.info("START TargetExteralViewCalcStage.process()"); + long startTime = System.currentTimeMillis(); + ClusterDataCache cache = event.getAttribute(AttributeName.ClusterDataCache.name()); + ClusterConfig clusterConfig = cache.getClusterConfig(); + + if (cache.isTaskCache() || !clusterConfig.isTargetExternalViewEnabled()) { + return; + } + + HelixManager helixManager = event.getAttribute(AttributeName.helixmanager.name()); + HelixDataAccessor accessor = helixManager.getHelixDataAccessor(); + + if (!accessor.getBaseDataAccessor() + .exists(accessor.keyBuilder().targetExternalViews().getPath(), AccessOption.PERSISTENT)) { + accessor.getBaseDataAccessor() + .create(accessor.keyBuilder().targetExternalViews().getPath(), null, + AccessOption.PERSISTENT); + } + + IntermediateStateOutput intermediateAssignment = + event.getAttribute(AttributeName.INTERMEDIATE_STATE.name()); + Map<String, Resource> resourceMap = event.getAttribute(AttributeName.RESOURCES.name()); + + List<PropertyKey> keys = new ArrayList<>(); + List<HelixProperty> targetExternalViews = new ArrayList<>(); + + for (String resourceName : intermediateAssignment.resourceSet()) { + if (cache.getIdealState(resourceName) == null || cache.getIdealState(resourceName).isExternalViewDisabled()) { + continue; + } + Resource resource = resourceMap.get(resourceName); + if (resource != null) { + PartitionStateMap partitionStateMap = + intermediateAssignment.getPartitionStateMap(resourceName); + Map<String, Map<String, String>> assignmentToPersist = convertToMapFields(partitionStateMap.getStateMap()); + + ExternalView targetExternalView = cache.getTargetExternalView(resourceName); + if (targetExternalView == null) { + targetExternalView = new ExternalView(resourceName); + targetExternalView.getRecord() + .getSimpleFields() + .putAll(cache.getIdealState(resourceName).getRecord().getSimpleFields()); + } + if (assignmentToPersist != null && !targetExternalView.getRecord().getMapFields() + .equals(assignmentToPersist)) { + targetExternalView.getRecord().setMapFields(assignmentToPersist); + keys.add(accessor.keyBuilder().targetExternalView(resourceName)); + targetExternalViews.add(targetExternalView); + cache.updateTargetExternalView(resourceName, targetExternalView); + } + } + } + accessor.setChildren(keys, targetExternalViews); + + long endTime = System.currentTimeMillis(); + LOG.info( + "END TargetExteralViewCalcStage.process() for cluster " + cache.getClusterName() + " took " + ( + endTime - startTime) + " ms"); + } + + private Map<String, Map<String, String>> convertToMapFields( + Map<Partition, Map<String, String>> partitionMapMap) { + Map<String, Map<String, String>> mapFields = Maps.newHashMap(); + for (Partition p : partitionMapMap.keySet()) { + mapFields.put(p.getPartitionName(), new HashMap<>(partitionMapMap.get(p))); + } + return mapFields; + } +} http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/manager/zk/CallbackHandler.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/manager/zk/CallbackHandler.java b/helix-core/src/main/java/org/apache/helix/manager/zk/CallbackHandler.java index 41fae3e..aa0cbbc 100644 --- a/helix-core/src/main/java/org/apache/helix/manager/zk/CallbackHandler.java +++ b/helix-core/src/main/java/org/apache/helix/manager/zk/CallbackHandler.java @@ -191,6 +191,7 @@ public class CallbackHandler implements IZkChildListener, IZkDataListener { listenerClass = MessageListener.class; break; case EXTERNAL_VIEW: + case TARGET_EXTERNAL_VIEW: listenerClass = ExternalViewChangeListener.class; break; case CONTROLLER: @@ -362,7 +363,7 @@ public class CallbackHandler implements IZkChildListener, IZkDataListener { List<Message> messages = preFetch(_propertyKey); messageListener.onMessage(_manager.getInstanceName(), messages, changeContext); - } else if (_changeType == EXTERNAL_VIEW) { + } else if (_changeType == EXTERNAL_VIEW || _changeType == TARGET_EXTERNAL_VIEW) { ExternalViewChangeListener externalViewListener = (ExternalViewChangeListener) _listener; subscribeForChanges(changeContext, _path, true); List<ExternalView> externalViewList = preFetch(_propertyKey); @@ -447,7 +448,8 @@ public class CallbackHandler implements IZkChildListener, IZkDataListener { switch (_changeType) { case CURRENT_STATE: case IDEAL_STATE: - case EXTERNAL_VIEW: { + case EXTERNAL_VIEW: + case TARGET_EXTERNAL_VIEW:{ // check if bucketized BaseDataAccessor<ZNRecord> baseAccessor = new ZkBaseDataAccessor<ZNRecord>(_zkClient); List<ZNRecord> records = baseAccessor.getChildren(path, null, 0); http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixManager.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixManager.java b/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixManager.java index db660bd..c32ce64 100644 --- a/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixManager.java +++ b/helix-core/src/main/java/org/apache/helix/manager/zk/ZKHelixManager.java @@ -539,6 +539,12 @@ public class ZKHelixManager implements HelixManager, IZkStateListener { new EventType[] { EventType.NodeChildrenChanged }); } + @Override + public void addTargetExternalViewChangeListener(ExternalViewChangeListener listener) throws Exception { + addListener(listener, new Builder(_clusterName).externalViews(), ChangeType.TARGET_EXTERNAL_VIEW, + new EventType[] { EventType.NodeChildrenChanged }); + } + @Deprecated @Override public void addExternalViewChangeListener(org.apache.helix.ExternalViewChangeListener listener) throws Exception { http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java b/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java index 542ac65..9ca106f 100644 --- a/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java +++ b/helix-core/src/main/java/org/apache/helix/model/ClusterConfig.java @@ -58,7 +58,8 @@ public class ClusterConfig extends HelixProperty { REBALANCE_TIMER_PERIOD, MAX_CONCURRENT_TASK_PER_INSTANCE, MAX_PARTITIONS_PER_INSTANCE, - MAX_OFFLINE_INSTANCES_ALLOWED + MAX_OFFLINE_INSTANCES_ALLOWED, + TARGET_EXTERNALVIEW_ENABLED } private final static int DEFAULT_MAX_CONCURRENT_TASK_PER_INSTANCE = 40; private static final String IDEAL_STATE_RULE_PREFIX = "IdealStateRule!"; @@ -418,6 +419,21 @@ public class ClusterConfig extends HelixProperty { } /** + * Enable/disable target externalview persist + * @param enabled + */ + public void enableTargetExternalView(boolean enabled) { + _record.setBooleanField(ClusterConfigProperty.TARGET_EXTERNALVIEW_ENABLED.name(), enabled); + } + + /** + * Determine whether target externalview is enabled or disabled + * @return + */ + public boolean isTargetExternalViewEnabled() { + return _record.getBooleanField(ClusterConfigProperty.TARGET_EXTERNALVIEW_ENABLED.name(), false); + } + /** * Get maximum allowed running task count on all instances in this cluster. * Instance level configuration will override cluster configuration. * @return the maximum task count http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/test/java/org/apache/helix/controller/stages/DummyClusterManager.java ---------------------------------------------------------------------- diff --git a/helix-core/src/test/java/org/apache/helix/controller/stages/DummyClusterManager.java b/helix-core/src/test/java/org/apache/helix/controller/stages/DummyClusterManager.java index 2055c61..87ea7f3 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/stages/DummyClusterManager.java +++ b/helix-core/src/test/java/org/apache/helix/controller/stages/DummyClusterManager.java @@ -135,6 +135,11 @@ public class DummyClusterManager implements HelixManager { } @Override + public void addTargetExternalViewChangeListener(ExternalViewChangeListener listener) throws Exception { + // TODO Auto-generated method stub + } + + @Override public void addExternalViewChangeListener(org.apache.helix.ExternalViewChangeListener listener) throws Exception { } http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/test/java/org/apache/helix/integration/controller/TestTargetExternalView.java ---------------------------------------------------------------------- diff --git a/helix-core/src/test/java/org/apache/helix/integration/controller/TestTargetExternalView.java b/helix-core/src/test/java/org/apache/helix/integration/controller/TestTargetExternalView.java new file mode 100644 index 0000000..d6fdb10 --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/integration/controller/TestTargetExternalView.java @@ -0,0 +1,85 @@ +package org.apache.helix.integration.controller; + +/* + * 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 java.util.List; + +import org.apache.helix.ConfigAccessor; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.integration.task.TaskTestBase; +import org.apache.helix.model.ClusterConfig; +import org.apache.helix.model.ExternalView; +import org.apache.helix.model.IdealState; +import org.testng.Assert; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +public class TestTargetExternalView extends TaskTestBase{ + + private ConfigAccessor _configAccessor; + private HelixDataAccessor _accessor; + @BeforeClass + public void beforeClass() throws Exception { + _numDbs = 3; + _numParitions = 8; + _numNodes = 4; + _numReplicas = 2; + super.beforeClass(); + _configAccessor = new ConfigAccessor(_gZkClient); + _accessor = _manager.getHelixDataAccessor(); + } + + @Test + public void testTargetExternalViewEnable() throws InterruptedException { + // Before enable target external view + Assert + .assertFalse(_gZkClient.exists(_accessor.keyBuilder().targetExternalViews().getPath())); + + ClusterConfig clusterConfig = _configAccessor.getClusterConfig(CLUSTER_NAME); + clusterConfig.enableTargetExternalView(true); + clusterConfig.setPersistIntermediateAssignment(true); + _configAccessor.setClusterConfig(CLUSTER_NAME, clusterConfig); + Thread.sleep(2000L); + + Assert + .assertEquals(_accessor.getChildNames(_accessor.keyBuilder().targetExternalViews()).size(), + 3); + + List<ExternalView> targetExternalViews = + _accessor.getChildValues(_accessor.keyBuilder().externalViews()); + List<IdealState> idealStates = _accessor.getChildValues(_accessor.keyBuilder().idealStates()); + + for (int i = 0; i < idealStates.size(); i++) { + Assert.assertTrue(targetExternalViews.get(i).getRecord().getMapFields() + .equals(idealStates.get(i).getRecord().getMapFields())); + } + + // Disable one instance to see whether the target external views changes. + _gSetupTool.getClusterManagementTool().enableInstance(CLUSTER_NAME, _participants[0].getInstanceName(), false); + + targetExternalViews = _accessor.getChildValues(_accessor.keyBuilder().externalViews()); + idealStates = _accessor.getChildValues(_accessor.keyBuilder().idealStates()); + + for (int i = 0; i < idealStates.size(); i++) { + Assert.assertTrue( + targetExternalViews.get(i).getRecord().getMapFields().equals(idealStates.get(i).getRecord().getMapFields())); + } + } +} http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/test/java/org/apache/helix/mock/MockManager.java ---------------------------------------------------------------------- diff --git a/helix-core/src/test/java/org/apache/helix/mock/MockManager.java b/helix-core/src/test/java/org/apache/helix/mock/MockManager.java index 778a4f5..109b016 100644 --- a/helix-core/src/test/java/org/apache/helix/mock/MockManager.java +++ b/helix-core/src/test/java/org/apache/helix/mock/MockManager.java @@ -136,6 +136,11 @@ public class MockManager implements HelixManager { } @Override + public void addTargetExternalViewChangeListener(ExternalViewChangeListener listener) throws Exception { + // TODO Auto-generated method stub + } + + @Override public void addExternalViewChangeListener(org.apache.helix.ExternalViewChangeListener listener) throws Exception { } http://git-wip-us.apache.org/repos/asf/helix/blob/d89fbb93/helix-core/src/test/java/org/apache/helix/participant/MockZKHelixManager.java ---------------------------------------------------------------------- diff --git a/helix-core/src/test/java/org/apache/helix/participant/MockZKHelixManager.java b/helix-core/src/test/java/org/apache/helix/participant/MockZKHelixManager.java index 6d768a7..049d4c6 100644 --- a/helix-core/src/test/java/org/apache/helix/participant/MockZKHelixManager.java +++ b/helix-core/src/test/java/org/apache/helix/participant/MockZKHelixManager.java @@ -157,6 +157,11 @@ public class MockZKHelixManager implements HelixManager { } @Override + public void addTargetExternalViewChangeListener(ExternalViewChangeListener listener) throws Exception { + // TODO Auto-generated method stub + } + + @Override public void addExternalViewChangeListener(org.apache.helix.ExternalViewChangeListener listener) throws Exception { }