/**
* Copyright (C) 2014-2016 LinkedIn Corp. (pinot-core@linkedin.com)
*
* Licensed 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.
*/
package com.linkedin.pinot.common.utils;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import org.I0Itec.zkclient.ZkClient;
import org.apache.zookeeper.server.ServerConfig;
import org.apache.zookeeper.server.ZooKeeperServerMain;
import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ZkStarter {
private static final Logger LOGGER = LoggerFactory.getLogger(ZkStarter.class);
public static final int DEFAULT_ZK_TEST_PORT = 2191;
public static final String DEFAULT_ZK_STR = "localhost:" + DEFAULT_ZK_TEST_PORT;
public static class ZookeeperInstance {
private PublicZooKeeperServerMain _serverMain;
private String _dataDirPath;
private ZookeeperInstance(PublicZooKeeperServerMain serverMain, String dataDirPath) {
_serverMain = serverMain;
_dataDirPath = dataDirPath;
}
}
/**
* Silly class to make protected methods public.
*/
static class PublicZooKeeperServerMain extends ZooKeeperServerMain {
@Override
public void initializeAndRun(String[] args) throws QuorumPeerConfig.ConfigException, IOException {
super.initializeAndRun(args);
}
@Override
public void runFromConfig(final ServerConfig config) throws IOException {
ServerConfig newServerConfig = new ServerConfig() {
public void parse(String[] args) {
config.parse(args);
}
public void parse(String path)
throws QuorumPeerConfig.ConfigException {
config.parse(path);
}
public void readFrom(QuorumPeerConfig otherConfig) {
config.readFrom(otherConfig);
}
public InetSocketAddress getClientPortAddress() {
return config.getClientPortAddress();
}
public String getDataDir() {
return config.getDataDir();
}
public String getDataLogDir() {
return config.getDataLogDir();
}
public int getTickTime() {
return config.getTickTime();
}
public int getMaxClientCnxns() {
dataDir = getDataDir();
dataLogDir = getDataLogDir();
tickTime = getTickTime();
minSessionTimeout = getMinSessionTimeout();
maxSessionTimeout = getMaxSessionTimeout();
maxClientCnxns = 0;
return 0;
}
public int getMinSessionTimeout() {
return config.getMinSessionTimeout();
}
public int getMaxSessionTimeout() {
return config.getMaxSessionTimeout();
}
};
newServerConfig.getMaxClientCnxns();
super.runFromConfig(newServerConfig);
}
@Override
public void shutdown() {
super.shutdown();
}
}
/**
* Starts an empty local Zk instance on the default port
*/
public static ZookeeperInstance startLocalZkServer() {
return startLocalZkServer(DEFAULT_ZK_TEST_PORT);
}
/**
* Starts a local Zk instance with a generated empty data directory
* @param port The port to listen on
*/
public static ZookeeperInstance startLocalZkServer(final int port) {
return startLocalZkServer(port,
org.apache.commons.io.FileUtils.getTempDirectoryPath() + File.separator + "test-" + System.currentTimeMillis());
}
/**
* Starts a local Zk instance
* @param port The port to listen on
* @param dataDirPath The path for the Zk data directory
*/
public synchronized static ZookeeperInstance startLocalZkServer(final int port, final String dataDirPath) {
// Start the local ZK server
try {
final PublicZooKeeperServerMain zookeeperServerMain = new PublicZooKeeperServerMain();
final String[] args = new String[] { Integer.toString(port), dataDirPath };
new Thread() {
@Override
public void run() {
try {
zookeeperServerMain.initializeAndRun(args);
} catch (QuorumPeerConfig.ConfigException e) {
LOGGER.warn("Caught exception while starting ZK", e);
} catch (IOException e) {
LOGGER.warn("Caught exception while starting ZK", e);
}
}
}.start();
// Wait until the ZK server is started
ZkClient client = new ZkClient("localhost:" + port, 10000);
client.waitUntilConnected(10L, TimeUnit.SECONDS);
client.close();
return new ZookeeperInstance(zookeeperServerMain, dataDirPath);
} catch (Exception e) {
LOGGER.warn("Caught exception while starting ZK", e);
throw new RuntimeException(e);
}
}
/**
* Stops a local Zk instance, deleting its data directory
*/
public static void stopLocalZkServer(final ZookeeperInstance instance) {
stopLocalZkServer(instance, true);
}
/**
* Stops a local Zk instance.
* @param deleteDataDir Whether or not to delete the data directory
*/
public synchronized static void stopLocalZkServer(final ZookeeperInstance instance, final boolean deleteDataDir) {
if (instance._serverMain != null) {
try {
// Shut down ZK
instance._serverMain.shutdown();
instance._serverMain = null;
// Delete the data dir
if (deleteDataDir) {
org.apache.commons.io.FileUtils.deleteDirectory(new File(instance._dataDirPath));
}
} catch (Exception e) {
LOGGER.warn("Caught exception while stopping ZK server", e);
throw new RuntimeException(e);
}
}
}
}