diff --git src/main/java/org/apache/hadoop/hbase/master/HMaster.java src/main/java/org/apache/hadoop/hbase/master/HMaster.java
index 9d21903..2048991 100644
--- src/main/java/org/apache/hadoop/hbase/master/HMaster.java
+++ src/main/java/org/apache/hadoop/hbase/master/HMaster.java
@@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.Abortable;
import org.apache.hadoop.hbase.Chore;
import org.apache.hadoop.hbase.ClusterStatus;
import org.apache.hadoop.hbase.HColumnDescriptor;
@@ -405,8 +406,9 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server {
this.balancer = LoadBalancerFactory.getLoadBalancer(conf);
zooKeeper.registerListenerFirst(assignmentManager);
- this.regionServerTracker = new RegionServerTracker(zooKeeper, this,
- this.serverManager);
+ this.regionServerTracker =
+ createRegionServerTracker(this.zooKeeper, this, this.serverManager);
+
this.regionServerTracker.start();
this.drainingServerTracker = new DrainingServerTracker(zooKeeper, this,
@@ -432,6 +434,18 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server {
", cluster-up flag was=" + wasUp);
}
+ /**
+ * Used testing
+ * @param zkw
+ * @param a
+ * @param sm
+ * @return Instance of RegionServerTracker
+ */
+ public RegionServerTracker createRegionServerTracker(final ZooKeeperWatcher zkw,
+ final Abortable a, final ServerManager sm) {
+ return new RegionServerTracker(zkw, a, sm);
+ }
+
// Check if we should stop every second.
private Sleeper stopSleeper = new Sleeper(1000, this);
private void loop() {
@@ -512,8 +526,7 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server {
// TODO: Should do this in background rather than block master startup
status.setStatus("Splitting logs after master startup");
- this.fileSystemManager.
- splitLogAfterStartup(this.serverManager.getOnlineServers().keySet());
+ splitLogAfterStartup(this.fileSystemManager, this.serverManager);
// Make sure root and meta assigned before proceeding.
assignRootAndMeta(status);
@@ -560,6 +573,16 @@ implements HMasterInterface, HMasterRegionInterface, MasterServices, Server {
}
/**
+ * Used in tests
+ * @param mfs
+ * @param sm
+ */
+ public void splitLogAfterStartup(final MasterFileSystem mfs,
+ final ServerManager sm) {
+ mfs. splitLogAfterStartup(sm.getOnlineServers().keySet());
+ }
+
+ /**
* Check -ROOT- and .META. are assigned. If not,
* assign them.
* @throws InterruptedException
diff --git src/test/java/org/apache/hadoop/hbase/TestTest.java src/test/java/org/apache/hadoop/hbase/TestTest.java
new file mode 100644
index 0000000..5da456e
--- /dev/null
+++ src/test/java/org/apache/hadoop/hbase/TestTest.java
@@ -0,0 +1,94 @@
+package org.apache.hadoop.hbase;
+
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.master.HMaster;
+import org.apache.hadoop.hbase.master.MasterFileSystem;
+import org.apache.hadoop.hbase.master.ServerManager;
+import org.apache.hadoop.hbase.util.Threads;
+import org.apache.hadoop.hbase.zookeeper.RegionServerTracker;
+import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
+import org.apache.zookeeper.KeeperException;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestTest {
+ private static final HBaseTestingUtility TESTUTIL =
+ new HBaseTestingUtility();
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ // Set it so that this test runs with my custom master
+ TESTUTIL.getConfiguration().setClass(HConstants.MASTER_IMPL,
+ TestingMaster.class, HMaster.class);
+ // Start up the cluster.
+ TESTUTIL.startMiniCluster();
+ }
+
+ @Test
+ public void testtest() {
+ // This test does nothing currently.
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ TESTUTIL.shutdownMiniCluster();
+ }
+
+ /**
+ * An HMaster instance used in this test. If 'TestingMaster.sleep' is set
+ * in the Configuration, then we'll sleep after log is split and we'll also
+ * return a custom RegionServerTracker.
+ */
+ public static class TestingMaster extends HMaster {
+ public TestingMaster(Configuration conf) throws IOException,
+ KeeperException, InterruptedException {
+ super(conf);
+ }
+
+ @Override
+ public void splitLogAfterStartup(MasterFileSystem mfs, ServerManager sm) {
+ super.splitLogAfterStartup(mfs, sm);
+ // If "TestingMaster.sleep" is set, sleep after log split.
+ if (getConfiguration().getBoolean("TestingMaster.sleep", false)) {
+ int duration =
+ getConfiguration().getInt("TestingMaster.sleep.duration", 0);
+ Threads.sleep(duration);
+ }
+ }
+
+ @Override
+ public RegionServerTracker createRegionServerTracker(final ZooKeeperWatcher zkw,
+ final Abortable a, final ServerManager sm) {
+ // If "TestingMaster.sleep", then return our custom RegionServerTracker
+ return getConfiguration().getBoolean("TestingMaster.sleep", false)?
+ new GatedNodeDeleteRegionServerTracker(zkw, a, sm):
+ super.createRegionServerTracker(zkw, a, sm);
+ }
+ }
+
+ /**
+ * A RegionServerTracker whose delete we can stall.
+ * On nodeDeleted, it will block until the data member gate is cleared.
+ */
+ static class GatedNodeDeleteRegionServerTracker extends RegionServerTracker {
+ final AtomicBoolean gate = new AtomicBoolean(true);
+
+ public GatedNodeDeleteRegionServerTracker(ZooKeeperWatcher watcher,
+ Abortable abortable, ServerManager serverManager) {
+ super(watcher, abortable, serverManager);
+ }
+
+ @Override
+ public void nodeDeleted(String path) {
+ if (path.startsWith(watcher.rsZNode)) {
+ while(this.gate.get()) Threads.sleep(1);
+ }
+ super.nodeDeleted(path);
+ }
+ }
+}
\ No newline at end of file