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);
+ }
+}