You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2017/11/17 21:20:37 UTC

[05/13] hbase git commit: HBASE-19114 Split out o.a.h.h.zookeeper from hbase-server and hbase-client

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperNodeTracker.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperNodeTracker.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperNodeTracker.java
deleted file mode 100644
index 951c6ba..0000000
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZooKeeperNodeTracker.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/**
- *
- * 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.zookeeper;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import java.io.IOException;
-import java.util.Random;
-import java.util.concurrent.Semaphore;
-
-import junit.framework.Assert;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.apache.hadoop.hbase.*;
-import org.apache.hadoop.hbase.master.TestActiveMasterManager.NodeDeletionListener;
-import org.apache.hadoop.hbase.testclassification.MediumTests;
-import org.apache.hadoop.hbase.testclassification.MiscTests;
-import org.apache.hadoop.hbase.util.Bytes;
-import org.apache.hadoop.hbase.util.Threads;
-import org.apache.zookeeper.CreateMode;
-import org.apache.zookeeper.WatchedEvent;
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooDefs.Ids;
-import org.apache.zookeeper.ZooKeeper;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category({MiscTests.class, MediumTests.class})
-public class TestZooKeeperNodeTracker {
-  private static final Log LOG = LogFactory.getLog(TestZooKeeperNodeTracker.class);
-  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
-
-  private final static Random rand = new Random();
-
-  @BeforeClass
-  public static void setUpBeforeClass() throws Exception {
-    TEST_UTIL.startMiniZKCluster();
-  }
-
-  @AfterClass
-  public static void tearDownAfterClass() throws Exception {
-    TEST_UTIL.shutdownMiniZKCluster();
-  }
-
-  /**
-   * Test that we can interrupt a node that is blocked on a wait.
-   * @throws IOException
-   * @throws InterruptedException
-   */
-  @Test public void testInterruptible() throws IOException, InterruptedException {
-    Abortable abortable = new StubAbortable();
-    ZooKeeperWatcher zk = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
-      "testInterruptible", abortable);
-    final TestTracker tracker = new TestTracker(zk, "/xyz", abortable);
-    tracker.start();
-    Thread t = new Thread() {
-      @Override
-      public void run() {
-        try {
-          tracker.blockUntilAvailable();
-        } catch (InterruptedException e) {
-          throw new RuntimeException("Interrupted", e);
-        }
-      }
-    };
-    t.start();
-    while (!t.isAlive()) Threads.sleep(1);
-    tracker.stop();
-    t.join();
-    // If it wasn't interruptible, we'd never get to here.
-  }
-
-  @Test
-  public void testNodeTracker() throws Exception {
-    Abortable abortable = new StubAbortable();
-    ZooKeeperWatcher zk = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
-        "testNodeTracker", abortable);
-    ZKUtil.createAndFailSilent(zk, zk.znodePaths.baseZNode);
-
-    final String node =
-      ZNodePaths.joinZNode(zk.znodePaths.baseZNode, new Long(rand.nextLong()).toString());
-
-    final byte [] dataOne = Bytes.toBytes("dataOne");
-    final byte [] dataTwo = Bytes.toBytes("dataTwo");
-
-    // Start a ZKNT with no node currently available
-    TestTracker localTracker = new TestTracker(zk, node, abortable);
-    localTracker.start();
-    zk.registerListener(localTracker);
-
-    // Make sure we don't have a node
-    assertNull(localTracker.getData(false));
-
-    // Spin up a thread with another ZKNT and have it block
-    WaitToGetDataThread thread = new WaitToGetDataThread(zk, node);
-    thread.start();
-
-    // Verify the thread doesn't have a node
-    assertFalse(thread.hasData);
-
-    // Now, start a new ZKNT with the node already available
-    TestTracker secondTracker = new TestTracker(zk, node, null);
-    secondTracker.start();
-    zk.registerListener(secondTracker);
-
-    // Put up an additional zk listener so we know when zk event is done
-    TestingZKListener zkListener = new TestingZKListener(zk, node);
-    zk.registerListener(zkListener);
-    assertEquals(0, zkListener.createdLock.availablePermits());
-
-    // Create a completely separate zk connection for test triggers and avoid
-    // any weird watcher interactions from the test
-    final ZooKeeper zkconn = new ZooKeeper(
-        ZKConfig.getZKQuorumServersString(TEST_UTIL.getConfiguration()), 60000,
-        new StubWatcher());
-
-    // Add the node with data one
-    zkconn.create(node, dataOne, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
-
-    // Wait for the zk event to be processed
-    zkListener.waitForCreation();
-    thread.join();
-
-    // Both trackers should have the node available with data one
-    assertNotNull(localTracker.getData(false));
-    assertNotNull(localTracker.blockUntilAvailable());
-    assertTrue(Bytes.equals(localTracker.getData(false), dataOne));
-    assertTrue(thread.hasData);
-    assertTrue(Bytes.equals(thread.tracker.getData(false), dataOne));
-    LOG.info("Successfully got data one");
-
-    // Make sure it's available and with the expected data
-    assertNotNull(secondTracker.getData(false));
-    assertNotNull(secondTracker.blockUntilAvailable());
-    assertTrue(Bytes.equals(secondTracker.getData(false), dataOne));
-    LOG.info("Successfully got data one with the second tracker");
-
-    // Drop the node
-    zkconn.delete(node, -1);
-    zkListener.waitForDeletion();
-
-    // Create a new thread but with the existing thread's tracker to wait
-    TestTracker threadTracker = thread.tracker;
-    thread = new WaitToGetDataThread(zk, node, threadTracker);
-    thread.start();
-
-    // Verify other guys don't have data
-    assertFalse(thread.hasData);
-    assertNull(secondTracker.getData(false));
-    assertNull(localTracker.getData(false));
-    LOG.info("Successfully made unavailable");
-
-    // Create with second data
-    zkconn.create(node, dataTwo, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
-
-    // Wait for the zk event to be processed
-    zkListener.waitForCreation();
-    thread.join();
-
-    // All trackers should have the node available with data two
-    assertNotNull(localTracker.getData(false));
-    assertNotNull(localTracker.blockUntilAvailable());
-    assertTrue(Bytes.equals(localTracker.getData(false), dataTwo));
-    assertNotNull(secondTracker.getData(false));
-    assertNotNull(secondTracker.blockUntilAvailable());
-    assertTrue(Bytes.equals(secondTracker.getData(false), dataTwo));
-    assertTrue(thread.hasData);
-    assertTrue(Bytes.equals(thread.tracker.getData(false), dataTwo));
-    LOG.info("Successfully got data two on all trackers and threads");
-
-    // Change the data back to data one
-    zkconn.setData(node, dataOne, -1);
-
-    // Wait for zk event to be processed
-    zkListener.waitForDataChange();
-
-    // All trackers should have the node available with data one
-    assertNotNull(localTracker.getData(false));
-    assertNotNull(localTracker.blockUntilAvailable());
-    assertTrue(Bytes.equals(localTracker.getData(false), dataOne));
-    assertNotNull(secondTracker.getData(false));
-    assertNotNull(secondTracker.blockUntilAvailable());
-    assertTrue(Bytes.equals(secondTracker.getData(false), dataOne));
-    assertTrue(thread.hasData);
-    assertTrue(Bytes.equals(thread.tracker.getData(false), dataOne));
-    LOG.info("Successfully got data one following a data change on all trackers and threads");
-  }
-
-  public static class WaitToGetDataThread extends Thread {
-
-    TestTracker tracker;
-    boolean hasData;
-
-    public WaitToGetDataThread(ZooKeeperWatcher zk, String node) {
-      tracker = new TestTracker(zk, node, null);
-      tracker.start();
-      zk.registerListener(tracker);
-      hasData = false;
-    }
-
-    public WaitToGetDataThread(ZooKeeperWatcher zk, String node,
-        TestTracker tracker) {
-      this.tracker = tracker;
-      hasData = false;
-    }
-
-    @Override
-    public void run() {
-      LOG.info("Waiting for data to be available in WaitToGetDataThread");
-      try {
-        tracker.blockUntilAvailable();
-      } catch (InterruptedException e) {
-        e.printStackTrace();
-      }
-      LOG.info("Data now available in tracker from WaitToGetDataThread");
-      hasData = true;
-    }
-  }
-
-  public static class TestTracker extends ZooKeeperNodeTracker {
-    public TestTracker(ZooKeeperWatcher watcher, String node,
-        Abortable abortable) {
-      super(watcher, node, abortable);
-    }
-  }
-
-  public static class TestingZKListener extends ZooKeeperListener {
-    private static final Log LOG = LogFactory.getLog(NodeDeletionListener.class);
-
-    private Semaphore deletedLock;
-    private Semaphore createdLock;
-    private Semaphore changedLock;
-    private String node;
-
-    public TestingZKListener(ZooKeeperWatcher watcher, String node) {
-      super(watcher);
-      deletedLock = new Semaphore(0);
-      createdLock = new Semaphore(0);
-      changedLock = new Semaphore(0);
-      this.node = node;
-    }
-
-    @Override
-    public void nodeDeleted(String path) {
-      if(path.equals(node)) {
-        LOG.debug("nodeDeleted(" + path + ")");
-        deletedLock.release();
-      }
-    }
-
-    @Override
-    public void nodeCreated(String path) {
-      if(path.equals(node)) {
-        LOG.debug("nodeCreated(" + path + ")");
-        createdLock.release();
-      }
-    }
-
-    @Override
-    public void nodeDataChanged(String path) {
-      if(path.equals(node)) {
-        LOG.debug("nodeDataChanged(" + path + ")");
-        changedLock.release();
-      }
-    }
-
-    public void waitForDeletion() throws InterruptedException {
-      deletedLock.acquire();
-    }
-
-    public void waitForCreation() throws InterruptedException {
-      createdLock.acquire();
-    }
-
-    public void waitForDataChange() throws InterruptedException {
-      changedLock.acquire();
-    }
-  }
-
-  public static class StubAbortable implements Abortable {
-    @Override
-    public void abort(final String msg, final Throwable t) {}
-    
-    @Override
-    public boolean isAborted() {
-      return false;
-    }
-    
-  }
-
-  public static class StubWatcher implements Watcher {
-    @Override
-    public void process(WatchedEvent event) {}
-  }
-
-  @Test
-  public void testCleanZNode() throws Exception {
-    ZooKeeperWatcher zkw = new ZooKeeperWatcher(TEST_UTIL.getConfiguration(),
-        "testNodeTracker", new TestZooKeeperNodeTracker.StubAbortable());
-
-    final ServerName sn = ServerName.valueOf("127.0.0.1:52", 45L);
-
-    ZKUtil.createAndFailSilent(zkw,
-        TEST_UTIL.getConfiguration().get(HConstants.ZOOKEEPER_ZNODE_PARENT,
-            HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT));
-
-    final String nodeName =  zkw.znodePaths.masterAddressZNode;
-
-    // Check that we manage the case when there is no data
-    ZKUtil.createAndFailSilent(zkw, nodeName);
-    MasterAddressTracker.deleteIfEquals(zkw, sn.toString());
-    Assert.assertFalse(ZKUtil.getData(zkw, nodeName) == null);
-
-    // Check that we don't delete if we're not supposed to
-    ZKUtil.setData(zkw, nodeName, MasterAddressTracker.toByteArray(sn, 0));
-    MasterAddressTracker.deleteIfEquals(zkw, ServerName.valueOf("127.0.0.2:52", 45L).toString());
-    Assert.assertFalse(ZKUtil.getData(zkw, nodeName) == null);
-
-    // Check that we delete when we're supposed to
-    ZKUtil.setData(zkw, nodeName,MasterAddressTracker.toByteArray(sn, 0));
-    MasterAddressTracker.deleteIfEquals(zkw, sn.toString());
-    Assert.assertTrue( ZKUtil.getData(zkw, nodeName)== null );
-
-    // Check that we support the case when the znode does not exist
-    MasterAddressTracker.deleteIfEquals(zkw, sn.toString()); // must not throw an exception
-  }
-
-}
-

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-shell/src/main/ruby/hbase/admin.rb
----------------------------------------------------------------------
diff --git a/hbase-shell/src/main/ruby/hbase/admin.rb b/hbase-shell/src/main/ruby/hbase/admin.rb
index 0ce38cc..9f8551c 100644
--- a/hbase-shell/src/main/ruby/hbase/admin.rb
+++ b/hbase-shell/src/main/ruby/hbase/admin.rb
@@ -328,7 +328,7 @@ module Hbase
     #----------------------------------------------------------------------------------------------
     # Returns ZooKeeper status dump
     def zk_dump
-      @zk_wrapper = org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher.new(
+      @zk_wrapper = org.apache.hadoop.hbase.zookeeper.ZKWatcher.new(
         @admin.getConfiguration,
         'admin',
         nil

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/pom.xml
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/pom.xml b/hbase-zookeeper/pom.xml
new file mode 100644
index 0000000..06b7dff
--- /dev/null
+++ b/hbase-zookeeper/pom.xml
@@ -0,0 +1,412 @@
+<?xml version="1.0"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<!--
+/*
+ * 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.
+ */
+-->
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <artifactId>hbase-build-configuration</artifactId>
+    <groupId>org.apache.hbase</groupId>
+    <version>3.0.0-SNAPSHOT</version>
+    <relativePath>../hbase-build-configuration</relativePath>
+  </parent>
+  <artifactId>hbase-zookeeper</artifactId>
+  <name>Apache HBase - Zookeeper</name>
+  <description>Zookeeper Helpers for HBase</description>
+
+  <build>
+    <!-- Makes sure the resources get added before they are processed
+      by placing this first -->
+    <testResources>
+      <!-- Our test artifact has different license info than our source/bin ones -->
+      <testResource>
+        <directory>src/test/resources/META-INF/</directory>
+        <targetPath>META-INF/</targetPath>
+        <includes>
+          <include>NOTICE</include>
+        </includes>
+        <filtering>true</filtering>
+      </testResource>
+    </testResources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-site-plugin</artifactId>
+        <configuration>
+          <skip>true</skip>
+        </configuration>
+      </plugin>
+      <!-- Run with -Dmaven.test.skip.exec=true to build -tests.jar without running
+        tests (this is needed for upstream projects whose tests need this jar simply for
+        compilation) -->
+      <plugin>
+        <!--Make it so assembly:single does nothing in here-->
+        <artifactId>maven-assembly-plugin</artifactId>
+        <configuration>
+          <skipAssembly>true</skipAssembly>
+        </configuration>
+      </plugin>
+      <!-- Make a jar and put the sources in the jar -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-source-plugin</artifactId>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>jar</goal>
+              <goal>test-jar</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <!-- General plugins -->
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-eclipse-plugin</artifactId>
+        <configuration>
+          <additionalProjectnatures>
+            <projectnature>org.jamon.project.jamonnature</projectnature>
+          </additionalProjectnatures>
+          <buildcommands>
+            <buildcommand>org.jamon.project.templateBuilder</buildcommand>
+            <buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
+            <buildcommand>org.jamon.project.markerUpdater</buildcommand>
+          </buildcommands>
+          <additionalConfig>
+            <file>
+              <name>.settings/org.jamon.prefs</name>
+              <content># now
+                eclipse.preferences.version=1
+                templateSourceDir=src/main/jamon
+                templateOutputDir=target/generated-jamon
+              </content>
+            </file>
+          </additionalConfig>
+        </configuration>
+      </plugin>
+      <!-- Run findbugs -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>findbugs-maven-plugin</artifactId>
+      </plugin>
+      <!-- Testing plugins -->
+      <plugin>
+        <artifactId>maven-surefire-plugin</artifactId>
+        <configuration>
+          <properties>
+            <property>
+              <name>listener</name>
+              <value>org.apache.hadoop.hbase.ResourceCheckerJUnitListener</value>
+            </property>
+          </properties>
+        </configuration>
+      </plugin>
+    </plugins>
+    <!-- General Resources -->
+    <pluginManagement>
+       <plugins>
+         <!--This plugin's configuration is used to store Eclipse m2e settings
+             only. It has no influence on the Maven build itself and needs to
+             be kept in plugin management, not in the actual plugins. -->
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-antrun-plugin</artifactId>
+                    <versionRange>[1.6,)</versionRange>
+                    <goals>
+                      <goal>run</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <execute>
+                      <runOnIncremental>false</runOnIncremental>
+                      <runOnConfiguration>true</runOnConfiguration>
+                    </execute>
+                  </action>
+                </pluginExecution>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-dependency-plugin</artifactId>
+                    <versionRange>[2.8,)</versionRange>
+                    <goals>
+                      <goal>build-classpath</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore></ignore>
+                  </action>
+                </pluginExecution>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.apache.maven.plugins</groupId>
+                    <artifactId>maven-compiler-plugin</artifactId>
+                    <versionRange>[3.2,)</versionRange>
+                    <goals>
+                      <goal>compile</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore></ignore>
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.hbase.thirdparty</groupId>
+      <artifactId>hbase-shaded-protobuf</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase.thirdparty</groupId>
+      <artifactId>hbase-shaded-miscellaneous</artifactId>
+    </dependency>
+    <!-- Intra-project dependencies -->
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-common</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-annotations</artifactId>
+      <type>test-jar</type>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-protocol-shaded</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-hadoop-compat</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.hbase</groupId>
+      <artifactId>hbase-hadoop2-compat</artifactId>
+      <exclusions>
+        <!-- We don't need MR support classes here. -->
+        <exclusion>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-mapreduce-client-core</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <!-- General dependencies -->
+    <dependency>
+       <groupId>com.github.stephenc.findbugs</groupId>
+       <artifactId>findbugs-annotations</artifactId>
+       <optional>true</optional>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-logging</groupId>
+      <artifactId>commons-logging</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.zookeeper</groupId>
+      <artifactId>zookeeper</artifactId>
+    </dependency>
+    <!-- Test dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+  <profiles>
+    <!-- Needs to make the profile in apache parent pom -->
+    <profile>
+      <id>apache-release</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.apache.maven.plugins</groupId>
+            <artifactId>maven-resources-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>license-javadocs</id>
+                <phase>prepare-package</phase>
+                <goals>
+                  <goal>copy-resources</goal>
+                </goals>
+                <configuration>
+                  <outputDirectory>${project.build.directory}/apidocs</outputDirectory>
+                  <resources>
+                    <resource>
+                      <directory>src/main/javadoc/META-INF/</directory>
+                      <targetPath>META-INF/</targetPath>
+                      <includes>
+                        <include>LICENSE</include>
+                        <include>NOTICE</include>
+                      </includes>
+                      <filtering>true</filtering>
+                    </resource>
+                  </resources>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <!-- Skip the tests in this module -->
+    <profile>
+      <id>skipZooKeeperTests</id>
+      <activation>
+        <property>
+          <name>skipZooKeeperTests</name>
+        </property>
+      </activation>
+      <properties>
+        <surefire.skipFirstPart>true</surefire.skipFirstPart>
+        <surefire.skipSecondPart>true</surefire.skipSecondPart>
+      </properties>
+    </profile>
+    <!-- Profiles for building against different hadoop versions -->
+    <!-- There are a lot of common dependencies used here, should investigate
+    if we can combine these profiles somehow -->
+
+    <!-- profile for building against Hadoop 2.x.  This is the default.  -->
+    <profile>
+      <id>hadoop-2.0</id>
+      <activation>
+        <property>
+            <!--Below formatting for dev-support/generate-hadoopX-poms.sh-->
+            <!--h2--><name>!hadoop.profile</name>
+        </property>
+      </activation>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-common</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-auth</artifactId>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-dependency-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>create-mrapp-generated-classpath</id>
+                <phase>generate-test-resources</phase>
+                <goals>
+                  <goal>build-classpath</goal>
+                </goals>
+                <configuration>
+                  <!-- needed to run the unit test for DS to generate
+                  the required classpath that is required in the env
+                  of the launch container in the mini mr/yarn cluster
+                  -->
+                  <outputFile>${project.build.directory}/test-classes/mrapp-generated-classpath</outputFile>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+    <!--
+      profile for building against Hadoop 3.0.x. Activate using:
+       mvn -Dhadoop.profile=3.0
+    -->
+    <profile>
+      <id>hadoop-3.0</id>
+      <activation>
+        <property>
+          <name>hadoop.profile</name>
+          <value>3.0</value>
+        </property>
+      </activation>
+      <properties>
+        <hadoop.version>${hadoop-three.version}</hadoop.version>
+      </properties>
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-common</artifactId>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.hadoop</groupId>
+          <artifactId>hadoop-auth</artifactId>
+        </dependency>
+      </dependencies>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-dependency-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>create-mrapp-generated-classpath</id>
+                <phase>generate-test-resources</phase>
+                <goals>
+                  <goal>build-classpath</goal>
+                </goals>
+                <configuration>
+                  <!-- needed to run the unit test for DS to generate
+                  the required classpath that is required in the env
+                  of the launch container in the mini mr/yarn cluster
+                  -->
+                  <outputFile>${project.build.directory}/test-classes/mrapp-generated-classpath</outputFile>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
+</project>

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ClusterStatusTracker.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ClusterStatusTracker.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ClusterStatusTracker.java
new file mode 100644
index 0000000..d145d08
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ClusterStatusTracker.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.zookeeper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.hadoop.hbase.Abortable;
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Tracker on cluster settings up in zookeeper.
+ * This is not related to {@link org.apache.hadoop.hbase.ClusterStatus}. That class
+ * is a data structure that holds snapshot of current view on cluster. This class
+ * is about tracking cluster attributes up in zookeeper.
+ *
+ */
+@InterfaceAudience.Private
+public class ClusterStatusTracker extends ZKNodeTracker {
+  private static final Log LOG = LogFactory.getLog(ClusterStatusTracker.class);
+
+  /**
+   * Creates a cluster status tracker.
+   *
+   * <p>After construction, use {@link #start} to kick off tracking.
+   *
+   * @param watcher
+   * @param abortable
+   */
+  public ClusterStatusTracker(ZKWatcher watcher, Abortable abortable) {
+    super(watcher, watcher.znodePaths.clusterStateZNode, abortable);
+  }
+
+  /**
+   * Checks if cluster is up.
+   * @return true if the cluster up ('shutdown' is its name up in zk) znode
+   * exists with data, false if not
+   */
+  public boolean isClusterUp() {
+    return super.getData(false) != null;
+  }
+
+  /**
+   * Sets the cluster as up.
+   * @throws KeeperException unexpected zk exception
+   */
+  public void setClusterUp()
+  throws KeeperException {
+    byte [] upData = toByteArray();
+    try {
+      ZKUtil.createAndWatch(watcher, watcher.znodePaths.clusterStateZNode, upData);
+    } catch(KeeperException.NodeExistsException nee) {
+      ZKUtil.setData(watcher, watcher.znodePaths.clusterStateZNode, upData);
+    }
+  }
+
+  /**
+   * Sets the cluster as down by deleting the znode.
+   * @throws KeeperException unexpected zk exception
+   */
+  public void setClusterDown()
+  throws KeeperException {
+    try {
+      ZKUtil.deleteNode(watcher, watcher.znodePaths.clusterStateZNode);
+    } catch(KeeperException.NoNodeException nne) {
+      LOG.warn("Attempted to set cluster as down but already down, cluster " +
+          "state node (" + watcher.znodePaths.clusterStateZNode + ") not found");
+    }
+  }
+
+  /**
+   * @return Content of the clusterup znode as a serialized pb with the pb
+   * magic as prefix.
+   */
+  static byte [] toByteArray() {
+    ZooKeeperProtos.ClusterUp.Builder builder =
+      ZooKeeperProtos.ClusterUp.newBuilder();
+    builder.setStartDate(new java.util.Date().toString());
+    return ProtobufUtil.prependPBMagic(builder.build().toByteArray());
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/DeletionListener.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/DeletionListener.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/DeletionListener.java
new file mode 100644
index 0000000..7c02891
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/DeletionListener.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright The Apache Software Foundation
+ *
+ * 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.zookeeper;
+
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * A ZooKeeper watcher meant to detect deletions of ZNodes.
+ */
+@InterfaceAudience.Private
+public class DeletionListener extends ZKListener {
+
+  private static final Log LOG = LogFactory.getLog(DeletionListener.class);
+
+  private final String pathToWatch;
+  private final CountDownLatch deletedLatch;
+
+  private volatile Throwable exception;
+
+  /**
+   * Create a new instance of the deletion watcher.
+   * @param zkWatcher ZookeeperWatcher instance
+   * @param pathToWatch (Fully qualified) ZNode path that we are waiting to
+   *                    be deleted.
+   * @param deletedLatch Count down on this latch when deletion has occurred.
+   */
+  public DeletionListener(ZKWatcher zkWatcher, String pathToWatch,
+                          CountDownLatch deletedLatch) {
+    super(zkWatcher);
+    this.pathToWatch = pathToWatch;
+    this.deletedLatch = deletedLatch;
+    exception = null;
+  }
+
+  /**
+   * Check if an exception has occurred when re-setting the watch.
+   * @return True if we were unable to re-set a watch on a ZNode due to
+   *         an exception.
+   */
+  public boolean hasException() {
+    return exception != null;
+  }
+
+  /**
+   * Get the last exception which has occurred when re-setting the watch.
+   * Use hasException() to check whether or not an exception has occurred.
+   * @return The last exception observed when re-setting the watch.
+   */
+  public Throwable getException() {
+    return exception;
+  }
+
+  @Override
+  public void nodeDataChanged(String path) {
+    if (!path.equals(pathToWatch)) {
+      return;
+    }
+    try {
+      if (!(ZKUtil.setWatchIfNodeExists(watcher, pathToWatch))) {
+        deletedLatch.countDown();
+      }
+    } catch (KeeperException ex) {
+      exception = ex;
+      deletedLatch.countDown();
+      LOG.error("Error when re-setting the watch on " + pathToWatch, ex);
+    }
+  }
+
+  @Override
+  public void nodeDeleted(String path) {
+    if (!path.equals(pathToWatch)) {
+      return;
+    }
+    if (LOG.isDebugEnabled()) {
+      LOG.debug("Processing delete on " + pathToWatch);
+    }
+    deletedLatch.countDown();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/EmptyWatcher.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/EmptyWatcher.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/EmptyWatcher.java
new file mode 100644
index 0000000..6470faa
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/EmptyWatcher.java
@@ -0,0 +1,34 @@
+/*
+ * 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.zookeeper;
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+
+/**
+ * An empty ZooKeeper watcher
+ */
+@InterfaceAudience.Private
+public class EmptyWatcher implements Watcher {
+  // Used in this package but also by tests so needs to be public
+  public static final EmptyWatcher instance = new EmptyWatcher();
+  private EmptyWatcher() {}
+
+  public void process(WatchedEvent event) {}
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/HQuorumPeer.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/HQuorumPeer.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/HQuorumPeer.java
new file mode 100644
index 0000000..f07b841
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/HQuorumPeer.java
@@ -0,0 +1,165 @@
+/*
+ *
+ * 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.zookeeper;
+
+import static org.apache.hadoop.hbase.HConstants.DEFAULT_ZK_SESSION_TIMEOUT;
+import static org.apache.hadoop.hbase.HConstants.ZK_SESSION_TIMEOUT;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.HBaseConfiguration;
+import org.apache.hadoop.hbase.HBaseInterfaceAudience;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.yetus.audience.InterfaceStability;
+import org.apache.hadoop.hbase.util.DNS;
+import org.apache.hadoop.hbase.util.Strings;
+import org.apache.hadoop.util.StringUtils;
+import org.apache.zookeeper.server.ServerConfig;
+import org.apache.zookeeper.server.ZooKeeperServerMain;
+import org.apache.zookeeper.server.quorum.QuorumPeerConfig;
+import org.apache.zookeeper.server.quorum.QuorumPeerMain;
+
+/**
+ * HBase's version of ZooKeeper's QuorumPeer. When HBase is set to manage
+ * ZooKeeper, this class is used to start up QuorumPeer instances. By doing
+ * things in here rather than directly calling to ZooKeeper, we have more
+ * control over the process. This class uses {@link ZKConfig} to get settings
+ * from the hbase-site.xml file.
+ */
+@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
+@InterfaceStability.Evolving
+public class HQuorumPeer {
+
+  /**
+   * Parse ZooKeeper configuration from HBase XML config and run a QuorumPeer.
+   * @param args String[] of command line arguments. Not used.
+   */
+  public static void main(String[] args) {
+    Configuration conf = HBaseConfiguration.create();
+    try {
+      Properties zkProperties = ZKConfig.makeZKProps(conf);
+      writeMyID(zkProperties);
+      QuorumPeerConfig zkConfig = new QuorumPeerConfig();
+      zkConfig.parseProperties(zkProperties);
+
+      // login the zookeeper server principal (if using security)
+      ZKUtil.loginServer(conf, HConstants.ZK_SERVER_KEYTAB_FILE,
+        HConstants.ZK_SERVER_KERBEROS_PRINCIPAL,
+        zkConfig.getClientPortAddress().getHostName());
+
+      runZKServer(zkConfig);
+    } catch (Exception e) {
+      e.printStackTrace();
+      System.exit(-1);
+    }
+  }
+
+  private static void runZKServer(QuorumPeerConfig zkConfig) throws UnknownHostException, IOException {
+    if (zkConfig.isDistributed()) {
+      QuorumPeerMain qp = new QuorumPeerMain();
+      qp.runFromConfig(zkConfig);
+    } else {
+      ZooKeeperServerMain zk = new ZooKeeperServerMain();
+      ServerConfig serverConfig = new ServerConfig();
+      serverConfig.readFrom(zkConfig);
+      zk.runFromConfig(serverConfig);
+    }
+  }
+
+  private static boolean addressIsLocalHost(String address) {
+    return address.equals("localhost") || address.equals("127.0.0.1");
+  }
+
+  static void writeMyID(Properties properties) throws IOException {
+    long myId = -1;
+
+    Configuration conf = HBaseConfiguration.create();
+    String myAddress = Strings.domainNamePointerToHostName(DNS.getDefaultHost(
+        conf.get("hbase.zookeeper.dns.interface","default"),
+        conf.get("hbase.zookeeper.dns.nameserver","default")));
+
+    List<String> ips = new ArrayList<>();
+
+    // Add what could be the best (configured) match
+    ips.add(myAddress.contains(".") ?
+        myAddress :
+        StringUtils.simpleHostname(myAddress));
+
+    // For all nics get all hostnames and IPs
+    Enumeration<?> nics = NetworkInterface.getNetworkInterfaces();
+    while(nics.hasMoreElements()) {
+      Enumeration<?> rawAdrs =
+          ((NetworkInterface)nics.nextElement()).getInetAddresses();
+      while(rawAdrs.hasMoreElements()) {
+        InetAddress inet = (InetAddress) rawAdrs.nextElement();
+        ips.add(StringUtils.simpleHostname(inet.getHostName()));
+        ips.add(inet.getHostAddress());
+      }
+    }
+
+    for (Entry<Object, Object> entry : properties.entrySet()) {
+      String key = entry.getKey().toString().trim();
+      String value = entry.getValue().toString().trim();
+      if (key.startsWith("server.")) {
+        int dot = key.indexOf('.');
+        long id = Long.parseLong(key.substring(dot + 1));
+        String[] parts = value.split(":");
+        String address = parts[0];
+        if (addressIsLocalHost(address) || ips.contains(address)) {
+          myId = id;
+          break;
+        }
+      }
+    }
+
+    // Set the max session timeout from the provided client-side timeout
+    properties.setProperty("maxSessionTimeout",
+      conf.get(HConstants.ZK_SESSION_TIMEOUT, Integer.toString(HConstants.DEFAULT_ZK_SESSION_TIMEOUT)));
+
+    if (myId == -1) {
+      throw new IOException("Could not find my address: " + myAddress +
+                            " in list of ZooKeeper quorum servers");
+    }
+
+    String dataDirStr = properties.get("dataDir").toString().trim();
+    File dataDir = new File(dataDirStr);
+    if (!dataDir.isDirectory()) {
+      if (!dataDir.mkdirs()) {
+        throw new IOException("Unable to create data dir " + dataDir);
+      }
+    }
+
+    File myIdFile = new File(dataDir, "myid");
+    PrintWriter w = new PrintWriter(myIdFile);
+    w.println(myId);
+    w.close();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/InstancePending.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/InstancePending.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/InstancePending.java
new file mode 100644
index 0000000..e63bfc5
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/InstancePending.java
@@ -0,0 +1,80 @@
+/*
+ * 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.zookeeper;
+
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * Placeholder of an instance which will be accessed by other threads
+ * but is not yet created. Thread safe.
+ */
+class InstancePending<T> {
+  // Based on a subtle part of the Java Language Specification,
+  // in order to avoid a slight overhead of synchronization for each access.
+
+  private final CountDownLatch pendingLatch = new CountDownLatch(1);
+
+  /** Piggybacking on {@code pendingLatch}. */
+  private InstanceHolder<T> instanceHolder;
+
+  private static class InstanceHolder<T> {
+    // The JLS ensures the visibility of a final field and its contents
+    // unless they are exposed to another thread while the construction.
+    final T instance;
+
+    InstanceHolder(T instance) {
+      this.instance = instance;
+    }
+  }
+
+  /**
+   * Returns the instance given by the method {@link #prepare}.
+   * This is an uninterruptible blocking method
+   * and the interruption flag will be set just before returning if any.
+   */
+  T get() {
+    InstanceHolder<T> instanceHolder;
+    boolean interrupted = false;
+
+    while ((instanceHolder = this.instanceHolder) == null) {
+      try {
+        pendingLatch.await();
+      } catch (InterruptedException e) {
+        interrupted = true;
+      }
+    }
+
+    if (interrupted) {
+      Thread.currentThread().interrupt();
+    }
+    return instanceHolder.instance;
+  }
+
+  /**
+   * Associates the given instance for the method {@link #get}.
+   * This method should be called once, and {@code instance} should be non-null.
+   * This method is expected to call as soon as possible
+   * because the method {@code get} is uninterruptibly blocked until this method is called.
+   */
+  void prepare(T instance) {
+    assert instance != null;
+    instanceHolder = new InstanceHolder<>(instance);
+    pendingLatch.countDown();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/LoadBalancerTracker.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/LoadBalancerTracker.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/LoadBalancerTracker.java
new file mode 100644
index 0000000..55dafcb
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/LoadBalancerTracker.java
@@ -0,0 +1,94 @@
+/*
+ * 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.zookeeper;
+
+import java.io.IOException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.hadoop.hbase.Abortable;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.LoadBalancerProtos;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Tracks the load balancer state up in ZK
+ */
+@InterfaceAudience.Private
+public class LoadBalancerTracker extends ZKNodeTracker {
+  private static final Log LOG = LogFactory.getLog(LoadBalancerTracker.class);
+
+  public LoadBalancerTracker(ZKWatcher watcher,
+      Abortable abortable) {
+    super(watcher, watcher.znodePaths.balancerZNode, abortable);
+  }
+
+  /**
+   * Return true if the balance switch is on, false otherwise
+   */
+  public boolean isBalancerOn() {
+    byte [] upData = super.getData(false);
+    try {
+      // if data in ZK is null, use default of on.
+      return upData == null || parseFrom(upData).getBalancerOn();
+    } catch (DeserializationException dex) {
+      LOG.error("ZK state for LoadBalancer could not be parsed " + Bytes.toStringBinary(upData));
+      // return false to be safe.
+      return false;
+    }
+  }
+
+  /**
+   * Set the balancer on/off
+   * @param balancerOn
+   * @throws KeeperException
+   */
+  public void setBalancerOn(boolean balancerOn) throws KeeperException {
+  byte [] upData = toByteArray(balancerOn);
+    try {
+      ZKUtil.setData(watcher, watcher.znodePaths.balancerZNode, upData);
+    } catch(KeeperException.NoNodeException nne) {
+      ZKUtil.createAndWatch(watcher, watcher.znodePaths.balancerZNode, upData);
+    }
+    super.nodeDataChanged(watcher.znodePaths.balancerZNode);
+  }
+
+  private byte [] toByteArray(boolean isBalancerOn) {
+    LoadBalancerProtos.LoadBalancerState.Builder builder =
+      LoadBalancerProtos.LoadBalancerState.newBuilder();
+    builder.setBalancerOn(isBalancerOn);
+    return ProtobufUtil.prependPBMagic(builder.build().toByteArray());
+  }
+
+  private LoadBalancerProtos.LoadBalancerState parseFrom(byte [] pbBytes)
+  throws DeserializationException {
+    ProtobufUtil.expectPBMagicPrefix(pbBytes);
+    LoadBalancerProtos.LoadBalancerState.Builder builder =
+      LoadBalancerProtos.LoadBalancerState.newBuilder();
+    try {
+      int magicLen = ProtobufUtil.lengthOfPBMagic();
+      ProtobufUtil.mergeFrom(builder, pbBytes, magicLen, pbBytes.length - magicLen);
+    } catch (IOException e) {
+      throw new DeserializationException(e);
+    }
+    return builder.build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterAddressTracker.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterAddressTracker.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterAddressTracker.java
new file mode 100644
index 0000000..85668ad
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterAddressTracker.java
@@ -0,0 +1,281 @@
+/*
+ * 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.zookeeper;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+
+import org.apache.hadoop.hbase.Abortable;
+import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.ServerName;
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.hadoop.hbase.exceptions.DeserializationException;
+import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos;
+import org.apache.hadoop.hbase.shaded.protobuf.generated.ZooKeeperProtos;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.data.Stat;
+import org.apache.hadoop.hbase.shaded.com.google.protobuf.InvalidProtocolBufferException;
+
+/**
+ * Manages the location of the current active Master for the RegionServer.
+ * <p>
+ * Listens for ZooKeeper events related to the master address. The node
+ * <code>/master</code> will contain the address of the current master.
+ * This listener is interested in
+ * <code>NodeDeleted</code> and <code>NodeCreated</code> events on
+ * <code>/master</code>.
+ * <p>
+ * Utilizes {@link ZKNodeTracker} for zk interactions.
+ * <p>
+ * You can get the current master via {@link #getMasterAddress()} or via
+ * {@link #getMasterAddress(ZKWatcher)} if you do not have a running
+ * instance of this Tracker in your context.
+ * <p>
+ * This class also includes utility for interacting with the master znode, for
+ * writing and reading the znode content.
+ */
+@InterfaceAudience.Private
+public class MasterAddressTracker extends ZKNodeTracker {
+  /**
+   * Construct a master address listener with the specified
+   * <code>zookeeper</code> reference.
+   * <p>
+   * This constructor does not trigger any actions, you must call methods
+   * explicitly.  Normally you will just want to execute {@link #start()} to
+   * begin tracking of the master address.
+   *
+   * @param watcher zk reference and watcher
+   * @param abortable abortable in case of fatal error
+   */
+  public MasterAddressTracker(ZKWatcher watcher, Abortable abortable) {
+    super(watcher, watcher.znodePaths.masterAddressZNode, abortable);
+  }
+
+  /**
+   * Get the address of the current master if one is available.  Returns null
+   * if no current master.
+   * @return Server name or null if timed out.
+   */
+  public ServerName getMasterAddress() {
+    return getMasterAddress(false);
+  }
+
+  /**
+   * Get the info port of the current master of one is available.
+   * Return 0 if no current master or zookeeper is unavailable
+   * @return info port or 0 if timed out
+   */
+  public int getMasterInfoPort() {
+    try {
+      final ZooKeeperProtos.Master master = parse(this.getData(false));
+      if (master == null) {
+        return 0;
+      }
+      return master.getInfoPort();
+    } catch (DeserializationException e) {
+      LOG.warn("Failed parse master zk node data", e);
+      return 0;
+    }
+  }
+  /**
+   * Get the info port of the backup master if it is available.
+   * Return 0 if no backup master or zookeeper is unavailable
+   * @param sn server name of backup master
+   * @return info port or 0 if timed out or exceptions
+   */
+  public int getBackupMasterInfoPort(final ServerName sn) {
+    String backupZNode = ZNodePaths.joinZNode(watcher.znodePaths.backupMasterAddressesZNode,
+      sn.toString());
+    try {
+      byte[] data = ZKUtil.getData(watcher, backupZNode);
+      final ZooKeeperProtos.Master backup = parse(data);
+      if (backup == null) {
+        return 0;
+      }
+      return backup.getInfoPort();
+    } catch (Exception e) {
+      LOG.warn("Failed to get backup master: " + sn + "'s info port.", e);
+      return 0;
+    }
+  }
+
+  /**
+   * Get the address of the current master if one is available.  Returns null
+   * if no current master. If refresh is set, try to load the data from ZK again,
+   * otherwise, cached data will be used.
+   *
+   * @param refresh whether to refresh the data by calling ZK directly.
+   * @return Server name or null if timed out.
+   */
+  public ServerName getMasterAddress(final boolean refresh) {
+    try {
+      return ProtobufUtil.parseServerNameFrom(super.getData(refresh));
+    } catch (DeserializationException e) {
+      LOG.warn("Failed parse", e);
+      return null;
+    }
+  }
+
+  /**
+   * Get master address.
+   * Use this instead of {@link #getMasterAddress()} if you do not have an
+   * instance of this tracker in your context.
+   * @param zkw ZKWatcher to use
+   * @return ServerName stored in the the master address znode or null if no
+   * znode present.
+   * @throws KeeperException
+   * @throws IOException
+   */
+  public static ServerName getMasterAddress(final ZKWatcher zkw)
+  throws KeeperException, IOException {
+    byte [] data;
+    try {
+      data = ZKUtil.getData(zkw, zkw.znodePaths.masterAddressZNode);
+    } catch (InterruptedException e) {
+      throw new InterruptedIOException();
+    }
+    // TODO javadoc claims we return null in this case. :/
+    if (data == null){
+      throw new IOException("Can't get master address from ZooKeeper; znode data == null");
+    }
+    try {
+      return ProtobufUtil.parseServerNameFrom(data);
+    } catch (DeserializationException e) {
+      KeeperException ke = new KeeperException.DataInconsistencyException();
+      ke.initCause(e);
+      throw ke;
+    }
+  }
+
+  /**
+   * Get master info port.
+   * Use this instead of {@link #getMasterInfoPort()} if you do not have an
+   * instance of this tracker in your context.
+   * @param zkw ZKWatcher to use
+   * @return master info port in the the master address znode or null if no
+   * znode present.
+   * // TODO can't return null for 'int' return type. non-static verison returns 0
+   * @throws KeeperException
+   * @throws IOException
+   */
+  public static int getMasterInfoPort(final ZKWatcher zkw) throws KeeperException,
+      IOException {
+    byte[] data;
+    try {
+      data = ZKUtil.getData(zkw, zkw.znodePaths.masterAddressZNode);
+    } catch (InterruptedException e) {
+      throw new InterruptedIOException();
+    }
+    // TODO javadoc claims we return null in this case. :/
+    if (data == null) {
+      throw new IOException("Can't get master address from ZooKeeper; znode data == null");
+    }
+    try {
+      return parse(data).getInfoPort();
+    } catch (DeserializationException e) {
+      KeeperException ke = new KeeperException.DataInconsistencyException();
+      ke.initCause(e);
+      throw ke;
+    }
+  }
+
+  /**
+   * Set master address into the <code>master</code> znode or into the backup
+   * subdirectory of backup masters; switch off the passed in <code>znode</code>
+   * path.
+   * @param zkw The ZKWatcher to use.
+   * @param znode Where to create the znode; could be at the top level or it
+   * could be under backup masters
+   * @param master ServerName of the current master must not be null.
+   * @return true if node created, false if not; a watch is set in both cases
+   * @throws KeeperException
+   */
+  public static boolean setMasterAddress(final ZKWatcher zkw,
+      final String znode, final ServerName master, int infoPort)
+  throws KeeperException {
+    return ZKUtil.createEphemeralNodeAndWatch(zkw, znode, toByteArray(master, infoPort));
+  }
+
+  /**
+   * Check if there is a master available.
+   * @return true if there is a master set, false if not.
+   */
+  public boolean hasMaster() {
+    return super.getData(false) != null;
+  }
+
+  /**
+   * @param sn must not be null
+   * @return Content of the master znode as a serialized pb with the pb
+   * magic as prefix.
+   */
+  static byte[] toByteArray(final ServerName sn, int infoPort) {
+    ZooKeeperProtos.Master.Builder mbuilder = ZooKeeperProtos.Master.newBuilder();
+    HBaseProtos.ServerName.Builder snbuilder = HBaseProtos.ServerName.newBuilder();
+    snbuilder.setHostName(sn.getHostname());
+    snbuilder.setPort(sn.getPort());
+    snbuilder.setStartCode(sn.getStartcode());
+    mbuilder.setMaster(snbuilder.build());
+    mbuilder.setRpcVersion(HConstants.RPC_CURRENT_VERSION);
+    mbuilder.setInfoPort(infoPort);
+    return ProtobufUtil.prependPBMagic(mbuilder.build().toByteArray());
+  }
+
+  /**
+   * @param data zookeeper data. may be null
+   * @return pb object of master, null if no active master
+   * @throws DeserializationException
+   */
+  public static ZooKeeperProtos.Master parse(byte[] data) throws DeserializationException {
+    if (data == null) {
+      return null;
+    }
+    int prefixLen = ProtobufUtil.lengthOfPBMagic();
+    try {
+      return ZooKeeperProtos.Master.PARSER.parseFrom(data, prefixLen, data.length - prefixLen);
+    } catch (InvalidProtocolBufferException e) {
+      throw new DeserializationException(e);
+    }
+  }
+  /**
+   * delete the master znode if its content is same as the parameter
+   * @param zkw must not be null
+   * @param content must not be null
+   */
+  public static boolean deleteIfEquals(ZKWatcher zkw, final String content) {
+    if (content == null){
+      throw new IllegalArgumentException("Content must not be null");
+    }
+
+    try {
+      Stat stat = new Stat();
+      byte[] data = ZKUtil.getDataNoWatch(zkw, zkw.znodePaths.masterAddressZNode, stat);
+      ServerName sn = ProtobufUtil.parseServerNameFrom(data);
+      if (sn != null && content.equals(sn.toString())) {
+        return (ZKUtil.deleteNode(zkw, zkw.znodePaths.masterAddressZNode, stat.getVersion()));
+      }
+    } catch (KeeperException e) {
+      LOG.warn("Can't get or delete the master znode", e);
+    } catch (DeserializationException e) {
+      LOG.warn("Can't get or delete the master znode", e);
+    }
+
+    return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/hbase/blob/330b0d05/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterMaintenanceModeTracker.java
----------------------------------------------------------------------
diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterMaintenanceModeTracker.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterMaintenanceModeTracker.java
new file mode 100644
index 0000000..952da6f
--- /dev/null
+++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/MasterMaintenanceModeTracker.java
@@ -0,0 +1,81 @@
+/*
+ *
+ * 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.zookeeper;
+
+import java.util.List;
+
+import org.apache.yetus.audience.InterfaceAudience;
+import org.apache.zookeeper.KeeperException;
+
+/**
+ * Tracks the master Maintenance Mode via ZK.
+ */
+@InterfaceAudience.Private
+public class MasterMaintenanceModeTracker extends ZKListener {
+  private boolean hasChildren;
+
+  public MasterMaintenanceModeTracker(ZKWatcher watcher) {
+    super(watcher);
+    hasChildren = false;
+  }
+
+  public boolean isInMaintenanceMode() {
+    return hasChildren;
+  }
+
+  private void update(String path) {
+    if (path.startsWith(watcher.znodePaths.masterMaintZNode)) {
+      update();
+    }
+  }
+
+  private void update() {
+    try {
+      List<String> children =
+          ZKUtil.listChildrenAndWatchForNewChildren(watcher, watcher.znodePaths.masterMaintZNode);
+      hasChildren = (children != null && children.size() > 0);
+    } catch (KeeperException e) {
+      // Ignore the ZK keeper exception
+      hasChildren = false;
+    }
+  }
+
+  /**
+   * Starts the tracking of whether master is in Maintenance Mode.
+   */
+  public void start() {
+    watcher.registerListener(this);
+    update();
+  }
+
+  @Override
+  public void nodeCreated(String path) {
+    update(path);
+  }
+
+  @Override
+  public void nodeDeleted(String path) {
+    update(path);
+  }
+
+  @Override
+  public void nodeChildrenChanged(String path) {
+    update(path);
+  }
+}