blob: e1223cef00ea49bf2faaf9dfd745a7ae0fe45f68 [file] [log] [blame]
/**
* 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.
*/
package org.apache.hadoop.hbase;
import java.io.File;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.zookeeper.MiniZooKeeperCluster;
import org.apache.hadoop.hbase.zookeeper.ZKWatcher;
import org.apache.yetus.audience.InterfaceAudience;
import org.apache.yetus.audience.InterfaceStability;
/**
* Helpers for testing HBase that do not depend on specific server/etc. things. The main difference
* from {@link HBaseCommonTestingUtil} is that we can start a zookeeper cluster.
*/
@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.PHOENIX)
@InterfaceStability.Evolving
public class HBaseZKTestingUtil extends HBaseCommonTestingUtil {
private MiniZooKeeperCluster zkCluster;
/**
* Set if we were passed a zkCluster. If so, we won't shutdown zk as part of general shutdown.
*/
private boolean passedZkCluster;
protected ZKWatcher zooKeeperWatcher;
/** Directory (a subdirectory of dataTestDir) used by the dfs cluster if any */
protected File clusterTestDir;
public HBaseZKTestingUtil() {
this(HBaseConfiguration.create());
}
public HBaseZKTestingUtil(Configuration conf) {
super(conf);
}
/**
* Returns Where the cluster will write data on the local subsystem. Creates it if it does not
* exist already. A subdir of {@code HBaseCommonTestingUtility#getBaseTestDir()}
*/
Path getClusterTestDir() {
if (clusterTestDir == null) {
setupClusterTestDir();
}
return new Path(clusterTestDir.getAbsolutePath());
}
/**
* Creates a directory for the cluster, under the test data
*/
protected void setupClusterTestDir() {
if (clusterTestDir != null) {
return;
}
// Using randomUUID ensures that multiple clusters can be launched by
// a same test, if it stops & starts them
Path testDir = getDataTestDir("cluster_" + getRandomUUID().toString());
clusterTestDir = new File(testDir.toString()).getAbsoluteFile();
// Have it cleaned up on exit
boolean b = deleteOnExit();
if (b) {
clusterTestDir.deleteOnExit();
}
LOG.info("Created new mini-cluster data directory: " + clusterTestDir + ", deleteOnExit=" + b);
}
/**
* Call this if you only want a zk cluster.
* @see #shutdownMiniZKCluster()
* @return zk cluster started.
*/
public MiniZooKeeperCluster startMiniZKCluster() throws Exception {
return startMiniZKCluster(1);
}
/**
* Call this if you only want a zk cluster.
* @see #shutdownMiniZKCluster()
* @return zk cluster started.
*/
public MiniZooKeeperCluster startMiniZKCluster(int zooKeeperServerNum, int... clientPortList)
throws Exception {
setupClusterTestDir();
return startMiniZKCluster(clusterTestDir, zooKeeperServerNum, clientPortList);
}
/**
* Start a mini ZK cluster. If the property "test.hbase.zookeeper.property.clientPort" is set the
* port mentioned is used as the default port for ZooKeeper.
*/
private MiniZooKeeperCluster startMiniZKCluster(File dir, int zooKeeperServerNum,
int[] clientPortList) throws Exception {
if (this.zkCluster != null) {
throw new IOException("Cluster already running at " + dir);
}
this.passedZkCluster = false;
this.zkCluster = new MiniZooKeeperCluster(this.getConfiguration());
int defPort = this.conf.getInt("test.hbase.zookeeper.property.clientPort", 0);
if (defPort > 0) {
// If there is a port in the config file, we use it.
this.zkCluster.setDefaultClientPort(defPort);
}
if (clientPortList != null) {
// Ignore extra client ports
int clientPortListSize = Math.min(clientPortList.length, zooKeeperServerNum);
for (int i = 0; i < clientPortListSize; i++) {
this.zkCluster.addClientPort(clientPortList[i]);
}
}
int clientPort = this.zkCluster.startup(dir, zooKeeperServerNum);
this.conf.set(HConstants.ZOOKEEPER_CLIENT_PORT, Integer.toString(clientPort));
return this.zkCluster;
}
public MiniZooKeeperCluster getZkCluster() {
return zkCluster;
}
public void setZkCluster(MiniZooKeeperCluster zkCluster) {
this.passedZkCluster = true;
this.zkCluster = zkCluster;
conf.setInt(HConstants.ZOOKEEPER_CLIENT_PORT, zkCluster.getClientPort());
}
/**
* Shuts down zk cluster created by call to {@link #startMiniZKCluster()} or does nothing.
* @see #startMiniZKCluster()
*/
public void shutdownMiniZKCluster() throws IOException {
if (!passedZkCluster && this.zkCluster != null) {
this.zkCluster.shutdown();
this.zkCluster = null;
}
}
/**
* Returns a ZKWatcher instance. This instance is shared between HBaseTestingUtility instance
* users. Don't close it, it will be closed automatically when the cluster shutdowns
* @return The ZKWatcher instance.
*/
public ZKWatcher getZooKeeperWatcher() throws IOException {
if (zooKeeperWatcher == null) {
zooKeeperWatcher = new ZKWatcher(conf, "testing utility", new Abortable() {
@Override
public void abort(String why, Throwable e) {
throw new RuntimeException("Unexpected abort in HBaseZKTestingUtility:" + why, e);
}
@Override
public boolean isAborted() {
return false;
}
});
}
return zooKeeperWatcher;
}
/**
* Returns true if we removed the test dirs
*/
@Override
public boolean cleanupTestDir() {
boolean ret = super.cleanupTestDir();
if (deleteDir(this.clusterTestDir)) {
this.clusterTestDir = null;
return ret;
}
return false;
}
}