Updated Branches: refs/heads/master 181073db7 -> b67c3d3b2
[HELIX-285] add integration test util's, rb=15160 Project: http://git-wip-us.apache.org/repos/asf/incubator-helix/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-helix/commit/b67c3d3b Tree: http://git-wip-us.apache.org/repos/asf/incubator-helix/tree/b67c3d3b Diff: http://git-wip-us.apache.org/repos/asf/incubator-helix/diff/b67c3d3b Branch: refs/heads/master Commit: b67c3d3b2decc562650737d17a9e38a10801c93b Parents: 181073d Author: zzhang <[email protected]> Authored: Thu Oct 31 16:48:16 2013 -0700 Committer: zzhang <[email protected]> Committed: Thu Oct 31 17:04:24 2013 -0700 ---------------------------------------------------------------------- helix-core/pom.xml | 4 + .../helix/controller/HelixControllerMain.java | 4 + .../manager/zk/HelixManagerShutdownHook.java | 26 +++ .../tools/ClusterExternalViewVerifier.java | 151 +++++++++++++++ .../helix/tools/ClusterLiveNodesVerifier.java | 26 +++ .../org/apache/helix/tools/ClusterVerifier.java | 128 +++++++++++++ .../apache/helix/tools/IntegrationTestUtil.java | 185 +++++++++++++++++++ .../apache/helix/examples/ExampleProcess.java | 13 +- 8 files changed, 535 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/pom.xml ---------------------------------------------------------------------- diff --git a/helix-core/pom.xml b/helix-core/pom.xml index 3a8e02b..b6ddd23 100644 --- a/helix-core/pom.xml +++ b/helix-core/pom.xml @@ -218,6 +218,10 @@ under the License. <mainClass>org.apache.helix.tools.YAMLClusterSetup</mainClass> <name>yaml-cluster-setup</name> </program> + <program> + <mainClass>org.apache.helix.tools.IntegrationTestUtil</mainClass> + <name>test-util</name> + </program> </programs> </configuration> </plugin> http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java b/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java index 4aae39b..62f3b23 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java +++ b/helix-core/src/main/java/org/apache/helix/controller/HelixControllerMain.java @@ -48,6 +48,7 @@ import org.apache.helix.HelixManager; import org.apache.helix.HelixManagerFactory; import org.apache.helix.InstanceType; import org.apache.helix.controller.restlet.ZKPropertyTransferServer; +import org.apache.helix.manager.zk.HelixManagerShutdownHook; import org.apache.helix.participant.DistClusterControllerStateModelFactory; import org.apache.helix.participant.StateMachineEngine; import org.apache.log4j.Logger; @@ -233,6 +234,9 @@ public class HelixControllerMain { HelixManager manager = startHelixController(zkConnectString, clusterName, controllerName, controllerMode); + + Runtime.getRuntime().addShutdownHook(new HelixManagerShutdownHook(manager)); + try { Thread.currentThread().join(); } catch (InterruptedException e) { http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java b/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java new file mode 100644 index 0000000..f91bf71 --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/manager/zk/HelixManagerShutdownHook.java @@ -0,0 +1,26 @@ +package org.apache.helix.manager.zk; + +import org.apache.helix.HelixManager; +import org.apache.log4j.Logger; + +/** + * Shutdown hook for helix manager + * Working for kill -2/-15 + * NOT working for kill -9 + */ +public class HelixManagerShutdownHook extends Thread { + private static Logger LOG = Logger.getLogger(HelixManagerShutdownHook.class); + + final HelixManager _manager; + + public HelixManagerShutdownHook(HelixManager manager) { + _manager = manager; + } + + @Override + public void run() { + LOG.info("HelixControllerMainShutdownHook invoked on manager: " + _manager.getClusterName() + + ", " + _manager.getInstanceName()); + _manager.disconnect(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java b/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java new file mode 100644 index 0000000..b72170f --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/tools/ClusterExternalViewVerifier.java @@ -0,0 +1,151 @@ +package org.apache.helix.tools; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.helix.controller.pipeline.Stage; +import org.apache.helix.controller.pipeline.StageContext; +import org.apache.helix.controller.stages.AttributeName; +import org.apache.helix.controller.stages.BestPossibleStateCalcStage; +import org.apache.helix.controller.stages.BestPossibleStateOutput; +import org.apache.helix.controller.stages.ClusterDataCache; +import org.apache.helix.controller.stages.ClusterEvent; +import org.apache.helix.controller.stages.CurrentStateComputationStage; +import org.apache.helix.controller.stages.ResourceComputationStage; +import org.apache.helix.manager.zk.ZkClient; +import org.apache.helix.model.ExternalView; +import org.apache.helix.model.Partition; +import org.apache.log4j.Logger; + +/** + * given zk, cluster, and a list of expected live-instances + * check whether cluster's external-view reaches best-possible states + */ +public class ClusterExternalViewVerifier extends ClusterVerifier { + private static Logger LOG = Logger.getLogger(ClusterExternalViewVerifier.class); + + final List<String> _expectSortedLiveNodes; // always sorted + + public ClusterExternalViewVerifier(ZkClient zkclient, String clusterName, + List<String> expectLiveNodes) { + super(zkclient, clusterName); + _expectSortedLiveNodes = expectLiveNodes; + Collections.sort(_expectSortedLiveNodes); + } + + boolean verifyLiveNodes(List<String> actualLiveNodes) { + Collections.sort(actualLiveNodes); + return _expectSortedLiveNodes.equals(actualLiveNodes); + } + + /** + * @param externalView + * @param bestPossibleState map of partition to map of instance to state + * @return + */ + boolean verifyExternalView(ExternalView externalView, + Map<Partition, Map<String, String>> bestPossibleState) { + Map<String, Map<String, String>> bestPossibleStateMap = + convertBestPossibleState(bestPossibleState); + // trimBestPossibleState(bestPossibleStateMap); + + Map<String, Map<String, String>> externalViewMap = externalView.getRecord().getMapFields(); + return externalViewMap.equals(bestPossibleStateMap); + } + + static void runStage(ClusterEvent event, Stage stage) throws Exception { + StageContext context = new StageContext(); + stage.init(context); + stage.preProcess(); + stage.process(event); + stage.postProcess(); + } + + BestPossibleStateOutput calculateBestPossibleState(ClusterDataCache cache) throws Exception { + ClusterEvent event = new ClusterEvent("event"); + event.addAttribute("ClusterDataCache", cache); + + List<Stage> stages = new ArrayList<Stage>(); + stages.add(new ResourceComputationStage()); + stages.add(new CurrentStateComputationStage()); + stages.add(new BestPossibleStateCalcStage()); + + for (Stage stage : stages) { + runStage(event, stage); + } + + return event.getAttribute(AttributeName.BEST_POSSIBLE_STATE.toString()); + } + + /** + * remove empty map and DROPPED state from best possible state + * @param bestPossibleState + */ + // static void trimBestPossibleState(Map<String, Map<String, String>> bestPossibleState) { + // Iterator<Entry<String, Map<String, String>>> iter = bestPossibleState.entrySet().iterator(); + // while (iter.hasNext()) { + // Map.Entry<String, Map<String, String>> entry = iter.next(); + // Map<String, String> instanceStateMap = entry.getValue(); + // if (instanceStateMap.isEmpty()) { + // iter.remove(); + // } else { + // // remove instances with DROPPED state + // Iterator<Map.Entry<String, String>> insIter = instanceStateMap.entrySet().iterator(); + // while (insIter.hasNext()) { + // Map.Entry<String, String> insEntry = insIter.next(); + // String state = insEntry.getValue(); + // if (state.equalsIgnoreCase(HelixDefinedState.DROPPED.toString())) { + // insIter.remove(); + // } + // } + // } + // } + // } + + static Map<String, Map<String, String>> convertBestPossibleState( + Map<Partition, Map<String, String>> bestPossibleState) { + Map<String, Map<String, String>> result = new HashMap<String, Map<String, String>>(); + for (Partition partition : bestPossibleState.keySet()) { + result.put(partition.getPartitionName(), bestPossibleState.get(partition)); + } + return result; + } + + @Override + public boolean verify() throws Exception { + ClusterDataCache cache = new ClusterDataCache(); + cache.refresh(_accessor); + + List<String> liveInstances = new ArrayList<String>(); + liveInstances.addAll(cache.getLiveInstances().keySet()); + boolean success = verifyLiveNodes(liveInstances); + if (!success) { + LOG.info("liveNodes not match, expect: " + _expectSortedLiveNodes + ", actual: " + + liveInstances); + return false; + } + + BestPossibleStateOutput bestPossbileStates = calculateBestPossibleState(cache); + Map<String, ExternalView> externalViews = + _accessor.getChildValuesMap(_keyBuilder.externalViews()); + + // TODO all ideal-states should be included in external-views + + for (String resourceName : externalViews.keySet()) { + ExternalView externalView = externalViews.get(resourceName); + Map<Partition, Map<String, String>> bestPossbileState = + bestPossbileStates.getResourceMap(resourceName); + success = verifyExternalView(externalView, bestPossbileState); + if (!success) { + LOG.info("external-view for resource: " + resourceName + " not match"); + return false; + } + } + + return true; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java b/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java new file mode 100644 index 0000000..2912247 --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/tools/ClusterLiveNodesVerifier.java @@ -0,0 +1,26 @@ +package org.apache.helix.tools; + +import java.util.Collections; +import java.util.List; + +import org.apache.helix.manager.zk.ZkClient; + +public class ClusterLiveNodesVerifier extends ClusterVerifier { + + final List<String> _expectSortedLiveNodes; // always sorted + + public ClusterLiveNodesVerifier(ZkClient zkclient, String clusterName, + List<String> expectLiveNodes) { + super(zkclient, clusterName); + _expectSortedLiveNodes = expectLiveNodes; + Collections.sort(_expectSortedLiveNodes); + } + + @Override + public boolean verify() throws Exception { + List<String> actualLiveNodes = _accessor.getChildNames(_keyBuilder.liveInstances()); + Collections.sort(actualLiveNodes); + return _expectSortedLiveNodes.equals(actualLiveNodes); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java new file mode 100644 index 0000000..ca8eea7 --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/tools/ClusterVerifier.java @@ -0,0 +1,128 @@ +package org.apache.helix.tools; + +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.I0Itec.zkclient.IZkChildListener; +import org.I0Itec.zkclient.IZkDataListener; +import org.apache.helix.HelixDataAccessor; +import org.apache.helix.PropertyKey; +import org.apache.helix.ZNRecord; +import org.apache.helix.manager.zk.ZKHelixDataAccessor; +import org.apache.helix.manager.zk.ZkBaseDataAccessor; +import org.apache.helix.manager.zk.ZkClient; +import org.apache.log4j.Logger; + +public abstract class ClusterVerifier implements IZkChildListener, IZkDataListener { + private static Logger LOG = Logger.getLogger(ClusterVerifier.class); + + protected final ZkClient _zkclient; + protected final String _clusterName; + protected final HelixDataAccessor _accessor; + protected final PropertyKey.Builder _keyBuilder; + private CountDownLatch _countdown; + + static class ClusterVerifyTrigger { + final PropertyKey _triggerKey; + final boolean _triggerOnChildDataChange; + + public ClusterVerifyTrigger(PropertyKey triggerKey, boolean triggerOnChildDataChange) { + _triggerKey = triggerKey; + _triggerOnChildDataChange = triggerOnChildDataChange; + } + } + + public ClusterVerifier(ZkClient zkclient, String clusterName) { + _zkclient = zkclient; + _clusterName = clusterName; + _accessor = new ZKHelixDataAccessor(clusterName, new ZkBaseDataAccessor<ZNRecord>(zkclient)); + _keyBuilder = _accessor.keyBuilder(); + } + + public boolean verifyByCallback(long timeout, List<ClusterVerifyTrigger> triggers) { + _countdown = new CountDownLatch(1); + + for (ClusterVerifyTrigger trigger : triggers) { + String path = trigger._triggerKey.getPath(); + _zkclient.subscribeChildChanges(path, this); + if (trigger._triggerOnChildDataChange) { + List<String> childs = _zkclient.getChildren(path); + for (String child : childs) { + String childPath = String.format("%s/%s", path, child); + _zkclient.subscribeDataChanges(childPath, this); + } + } + } + + boolean success = false; + try { + success = verify(); + if (!success) { + + success = _countdown.await(timeout, TimeUnit.MILLISECONDS); + if (!success) { + // make a final try if timeout + success = verify(); + } + } + } catch (Exception e) { + LOG.error("Exception in verifier", e); + } + + // clean up + _zkclient.unsubscribeAll(); + + return success; + } + + @Override + public void handleDataChange(String dataPath, Object data) throws Exception { + boolean success = verify(); + if (success) { + _countdown.countDown(); + } + } + + @Override + public void handleDataDeleted(String dataPath) throws Exception { + _zkclient.unsubscribeDataChanges(dataPath, this); + } + + @Override + public void handleChildChange(String parentPath, List<String> currentChilds) throws Exception { + for (String child : currentChilds) { + String childPath = String.format("%s/%s", parentPath, child); + _zkclient.subscribeDataChanges(childPath, this); + } + + boolean success = verify(); + if (success) { + _countdown.countDown(); + } + } + + public boolean verifyByPolling(long timeout) { + try { + long start = System.currentTimeMillis(); + boolean success; + do { + success = verify(); + if (success) { + return true; + } + TimeUnit.MILLISECONDS.sleep(500); + } while ((System.currentTimeMillis() - start) <= timeout); + } catch (Exception e) { + LOG.error("Exception in verifier", e); + } + return false; + } + + /** + * verify + * @return + * @throws Exception + */ + public abstract boolean verify() throws Exception; +} http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java ---------------------------------------------------------------------- diff --git a/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java b/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java new file mode 100644 index 0000000..8c70bbc --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/tools/IntegrationTestUtil.java @@ -0,0 +1,185 @@ +package org.apache.helix.tools; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.GnuParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionBuilder; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; +import org.apache.helix.PropertyKey; +import org.apache.helix.ZNRecord; +import org.apache.helix.manager.zk.ZNRecordSerializer; +import org.apache.helix.manager.zk.ZkClient; +import org.apache.log4j.Logger; + +/** + * collection of test utilities for integration tests + */ +public class IntegrationTestUtil { + private static Logger LOG = Logger.getLogger(IntegrationTestUtil.class); + + public static final long defaultTimeout = 30 * 1000; // in milliseconds + public static final String help = "help"; + public static final String zkSvr = "zkSvr"; + + public static final String verifyExternalView = "verifyExternalView"; + public static final String verifyLiveNodes = "verifyLiveNodes"; + public static final String readZNode = "readZNode"; + public static final String readLeader = "readLeader"; + + final ZkClient _zkclient; + final ZNRecordSerializer _serializer; + + public IntegrationTestUtil(ZkClient zkclient) { + _zkclient = zkclient; + _serializer = new ZNRecordSerializer(); + } + + public void verifyExternalView(String[] args) { + if (args == null || args.length == 0) { + System.err.println("Illegal arguments for " + verifyExternalView); + return; + } + + long timeoutValue = defaultTimeout; + + String clusterName = args[0]; + List<String> liveNodes = new ArrayList<String>(); + for (int i = 1; i < args.length; i++) { + liveNodes.add(args[i]); + } + + ClusterExternalViewVerifier verifier = + new ClusterExternalViewVerifier(_zkclient, clusterName, liveNodes); + boolean success = verifier.verifyByPolling(timeoutValue); + System.out.println(success ? "Successful" : "Failed"); + + } + + public void verifyLiveNodes(String[] args) { + if (args == null || args.length == 0) { + System.err.println("Illegal arguments for " + verifyLiveNodes); + return; + } + + long timeoutValue = defaultTimeout; + + String clusterName = args[0]; + List<String> liveNodes = new ArrayList<String>(); + for (int i = 1; i < args.length; i++) { + liveNodes.add(args[i]); + } + + ClusterLiveNodesVerifier verifier = + new ClusterLiveNodesVerifier(_zkclient, clusterName, liveNodes); + boolean success = verifier.verifyByPolling(timeoutValue); + System.out.println(success ? "Successful" : "Failed"); + } + + public void readZNode(String path) { + ZNRecord record = _zkclient.readData(path, true); + if (record == null) { + System.out.println("null"); + } else { + System.out.println(new String(_serializer.serialize(record))); + } + } + + @SuppressWarnings("static-access") + static Options constructCommandLineOptions() { + Option helpOption = + OptionBuilder.withLongOpt(help).withDescription("Prints command-line options information") + .create(); + + Option zkSvrOption = + OptionBuilder.hasArgs(1).isRequired(true).withArgName("zookeeperAddress") + .withLongOpt(zkSvr).withDescription("Provide zookeeper-address").create(); + + Option verifyExternalViewOption = + OptionBuilder.hasArgs().isRequired(false).withArgName("clusterName node1 node2..") + .withLongOpt(verifyExternalView).withDescription("Verify external-view").create(); + + Option verifyLiveNodesOption = + OptionBuilder.hasArg().isRequired(false).withArgName("clusterName node1, node2..") + .withLongOpt(verifyLiveNodes).withDescription("Verify live-nodes").create(); + + Option readZNodeOption = + OptionBuilder.hasArgs(1).isRequired(false).withArgName("zkPath").withLongOpt(readZNode) + .withDescription("Read znode").create(); + + Option readLeaderOption = + OptionBuilder.hasArgs(1).isRequired(false).withArgName("clusterName") + .withLongOpt(readLeader).withDescription("Read cluster controller").create(); + + OptionGroup optGroup = new OptionGroup(); + optGroup.setRequired(true); + optGroup.addOption(verifyExternalViewOption); + optGroup.addOption(verifyLiveNodesOption); + optGroup.addOption(readZNodeOption); + optGroup.addOption(readLeaderOption); + + Options options = new Options(); + options.addOption(helpOption); + options.addOption(zkSvrOption); + options.addOptionGroup(optGroup); + + return options; + } + + static void printUsage(Options cliOptions) { + HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.setWidth(1000); + helpFormatter.printHelp("java " + ClusterExternalViewVerifier.class.getName(), cliOptions); + } + + static void processCommandLineArgs(String[] cliArgs) { + CommandLineParser cliParser = new GnuParser(); + Options cliOptions = constructCommandLineOptions(); + CommandLine cmd = null; + try { + cmd = cliParser.parse(cliOptions, cliArgs); + } catch (ParseException pe) { + System.err.println("failed to parse command-line args: " + Arrays.asList(cliArgs) + + ", exception: " + pe.toString()); + printUsage(cliOptions); + System.exit(1); + } + + String zkServer = cmd.getOptionValue(zkSvr); + + ZkClient zkclient = + new ZkClient(zkServer, ZkClient.DEFAULT_SESSION_TIMEOUT, + ZkClient.DEFAULT_CONNECTION_TIMEOUT, new ZNRecordSerializer()); + IntegrationTestUtil util = new IntegrationTestUtil(zkclient); + + if (cmd != null) { + if (cmd.hasOption(verifyExternalView)) { + String[] args = cmd.getOptionValues(verifyExternalView); + util.verifyExternalView(args); + } else if (cmd.hasOption(verifyLiveNodes)) { + String[] args = cmd.getOptionValues(verifyLiveNodes); + util.verifyLiveNodes(args); + } else if (cmd.hasOption(readZNode)) { + String path = cmd.getOptionValue(readZNode); + util.readZNode(path); + } else if (cmd.hasOption(readLeader)) { + String clusterName = cmd.getOptionValue(readLeader); + PropertyKey.Builder keyBuilder = new PropertyKey.Builder(clusterName); + util.readZNode(keyBuilder.controllerLeader().getPath()); + } else { + printUsage(cliOptions); + } + } + } + + public static void main(String[] args) { + processCommandLineArgs(args); + } +} http://git-wip-us.apache.org/repos/asf/incubator-helix/blob/b67c3d3b/helix-examples/src/main/java/org/apache/helix/examples/ExampleProcess.java ---------------------------------------------------------------------- diff --git a/helix-examples/src/main/java/org/apache/helix/examples/ExampleProcess.java b/helix-examples/src/main/java/org/apache/helix/examples/ExampleProcess.java index 34a13e5..e023cf9 100644 --- a/helix-examples/src/main/java/org/apache/helix/examples/ExampleProcess.java +++ b/helix-examples/src/main/java/org/apache/helix/examples/ExampleProcess.java @@ -33,13 +33,16 @@ import org.apache.commons.cli.ParseException; import org.apache.helix.HelixManager; import org.apache.helix.HelixManagerFactory; import org.apache.helix.InstanceType; +import org.apache.helix.manager.zk.HelixManagerShutdownHook; import org.apache.helix.model.Message.MessageType; import org.apache.helix.participant.StateMachineEngine; import org.apache.helix.participant.statemachine.StateModel; import org.apache.helix.participant.statemachine.StateModelFactory; import org.apache.helix.tools.ClusterStateVerifier; +import org.apache.log4j.Logger; public class ExampleProcess { + private static final Logger LOG = Logger.getLogger(ExampleProcess.class); public static final String zkServer = "zkSvr"; public static final String cluster = "cluster"; @@ -57,8 +60,6 @@ public class ExampleProcess { private final String stateModelType; private HelixManager manager; - // private StateMachineEngine genericStateMachineHandler; - private StateModelFactory<StateModel> stateModelFactory; private final int delay; @@ -98,6 +99,10 @@ public class ExampleProcess { manager.disconnect(); } + public HelixManager getManager() { + return manager; + } + @SuppressWarnings("static-access") private static Options constructCommandLineOptions() { Option helpOption = @@ -168,6 +173,7 @@ public class ExampleProcess { public static void printUsage(Options cliOptions) { HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.setWidth(1000); helpFormatter.printHelp("java " + ExampleProcess.class.getName(), cliOptions); } @@ -232,6 +238,9 @@ public class ExampleProcess { new ExampleProcess(zkConnectString, clusterName, instanceName, file, stateModelValue, delay); process.start(); + + Runtime.getRuntime().addShutdownHook(new HelixManagerShutdownHook(process.getManager())); + Thread.currentThread().join(); } }
