diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ReadOnlyZKClient.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ReadOnlyZKClient.java index 9873e831a6..b2bc47c800 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ReadOnlyZKClient.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ReadOnlyZKClient.java @@ -66,6 +66,8 @@ public final class ReadOnlyZKClient implements Closeable { private static final EnumSet FAIL_FAST_CODES = EnumSet.of(Code.NOAUTH, Code.AUTHFAILED); + private final Configuration conf; + private final String connectString; private final int sessionTimeoutMs; @@ -133,6 +135,7 @@ public final class ReadOnlyZKClient implements Closeable { } else { this.connectString = ZKConfig.getZKQuorumServersString(conf); } + this.conf = conf; this.sessionTimeoutMs = conf.getInt(ZK_SESSION_TIMEOUT, DEFAULT_ZK_SESSION_TIMEOUT); this.maxRetries = conf.getInt(RECOVERY_RETRY, DEFAULT_RECOVERY_RETRY); this.retryIntervalMs = @@ -297,7 +300,8 @@ public final class ReadOnlyZKClient implements Closeable { private ZooKeeper getZk() throws IOException { // may be closed when session expired if (zookeeper == null || !zookeeper.getState().isAlive()) { - zookeeper = new ZooKeeper(connectString, sessionTimeoutMs, e -> {}); + zookeeper = ZooKeeperHelper.createZkWithZkEnv(conf, + connectString, sessionTimeoutMs, e -> {}); } return zookeeper; } diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperHelper.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperHelper.java index dd26ed5f20..8507195d02 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperHelper.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZooKeeperHelper.java @@ -18,29 +18,69 @@ package org.apache.hadoop.hbase.zookeeper; import java.io.IOException; + +import java.util.Iterator; +import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.ZooKeeperConnectionException; import org.apache.hadoop.hbase.util.Threads; import org.apache.hbase.thirdparty.com.google.common.base.Stopwatch; import org.apache.yetus.audience.InterfaceAudience; +import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooKeeper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; /** * Methods that help working with ZooKeeper */ @InterfaceAudience.Private public final class ZooKeeperHelper { + private static final Logger LOG = LoggerFactory.getLogger(ZooKeeperHelper.class); + // This class cannot be instantiated private ZooKeeperHelper() { } + + private static final String ZK_ENV_CONF_PREFIX = "zkenv."; + /** Configures system properties for ZK based on zkenv.* config settings. */ + public static void configureZkEnv(Configuration conf) { + Iterator> iter = conf.iterator(); + while (iter.hasNext()) { + Map.Entry e = iter.next(); + if (e.getKey().startsWith(ZK_ENV_CONF_PREFIX)) { + String key = e.getKey().substring(ZK_ENV_CONF_PREFIX.length()); + LOG.info("Setting ZK system property {}={}", key, e.getValue()); + System.setProperty(key, e.getValue()); + } + } + } + + private static final AtomicBoolean zkEnvConfigured = new AtomicBoolean(false); + /** Calls configureZkEnv if not already done, and creates new zookeeper client. */ + public static ZooKeeper createZkWithZkEnv(Configuration conf, + String connectString, int sessionTimeout, Watcher watcher) throws IOException { + // This doesn't account for different conf objects from different callers having different + // properties. System properties are JVM-wide, so we don't support such a scenario. + if (conf != null && zkEnvConfigured.compareAndSet(false, true)) { + configureZkEnv(conf); + } + return new ZooKeeper(connectString, sessionTimeout, watcher); + } + /** * Get a ZooKeeper instance and wait until it connected before returning. * @param sessionTimeoutMs Used as session timeout passed to the created ZooKeeper AND as the * timeout to wait on connection establishment. */ + @VisibleForTesting public static ZooKeeper getConnectedZooKeeper(String connectString, int sessionTimeoutMs) throws IOException { ZooKeeper zookeeper = new ZooKeeper(connectString, sessionTimeoutMs, e -> {}); diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java index 40f4aa6654..7982a0d416 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/tool/Canary.java @@ -87,6 +87,7 @@ import org.apache.hadoop.hbase.util.ReflectionUtils; import org.apache.hadoop.hbase.util.RegionSplitter; import org.apache.hadoop.hbase.zookeeper.EmptyWatcher; import org.apache.hadoop.hbase.zookeeper.ZKConfig; +import org.apache.hadoop.hbase.zookeeper.ZKUtil; import org.apache.hadoop.util.GenericOptionsParser; import org.apache.hadoop.util.Tool; import org.apache.hadoop.util.ToolRunner; @@ -297,7 +298,8 @@ public final class Canary implements Tool { @Override public Void call() throws Exception { ZooKeeper zooKeeper = null; try { - zooKeeper = new ZooKeeper(host, timeout, EmptyWatcher.instance); + zooKeeper = ZKUtil.createZkWithZkEnv(connection.getConfiguration(), + host, timeout, EmptyWatcher.instance); Stat exists = zooKeeper.exists(znode, false); StopWatch stopwatch = new StopWatch(); stopwatch.start(); diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java index c23e3d2254..451e8b4792 100644 --- a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java +++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.trace.TraceUtil; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.EnvironmentEdgeManager; @@ -76,6 +77,7 @@ public class RecoverableZooKeeper { // the actual ZooKeeper client instance private ZooKeeper zk; private final RetryCounterFactory retryCounterFactory; + private final Configuration conf; // An identifier of this process in the cluster private final String identifier; private final byte[] id; @@ -83,16 +85,10 @@ public class RecoverableZooKeeper { private int sessionTimeout; private String quorumServers; - public RecoverableZooKeeper(String quorumServers, int sessionTimeout, - Watcher watcher, int maxRetries, int retryIntervalMillis, int maxSleepTime) - throws IOException { - this(quorumServers, sessionTimeout, watcher, maxRetries, retryIntervalMillis, maxSleepTime, - null); - } @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="DE_MIGHT_IGNORE", justification="None. Its always been this way.") - public RecoverableZooKeeper(String quorumServers, int sessionTimeout, + public RecoverableZooKeeper(Configuration conf, String quorumServers, int sessionTimeout, Watcher watcher, int maxRetries, int retryIntervalMillis, int maxSleepTime, String identifier) throws IOException { // TODO: Add support for zk 'chroot'; we don't add it to the quorumServers String as we should. @@ -111,6 +107,7 @@ public class RecoverableZooKeeper { this.watcher = watcher; this.sessionTimeout = sessionTimeout; this.quorumServers = quorumServers; + this.conf = conf; try { checkZk(); @@ -128,7 +125,7 @@ public class RecoverableZooKeeper { protected synchronized ZooKeeper checkZk() throws KeeperException { if (this.zk == null) { try { - this.zk = new ZooKeeper(quorumServers, sessionTimeout, watcher); + this.zk = ZKUtil.createZkWithZkEnv(conf, quorumServers, sessionTimeout, watcher); } catch (IOException ex) { LOG.warn("Unable to create ZooKeeper Connection", ex); throw new KeeperException.OperationTimeoutException(); diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java index 57c847c0fe..acf7a1ca97 100644 --- a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java +++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java @@ -135,7 +135,7 @@ public final class ZKUtil { int maxSleepTime = conf.getInt("zookeeper.recovery.retry.maxsleeptime", 60000); zkDumpConnectionTimeOut = conf.getInt("zookeeper.dump.connection.timeout", 1000); - return new RecoverableZooKeeper(ensemble, timeout, watcher, + return new RecoverableZooKeeper(conf, ensemble, timeout, watcher, retry, retryIntervalMillis, maxSleepTime, identifier); } @@ -2004,6 +2004,11 @@ public final class ZKUtil { } } + public static ZooKeeper createZkWithZkEnv(Configuration conf, + String connectString, int sessionTimeout, Watcher watcher) throws IOException { + return ZooKeeperHelper.createZkWithZkEnv(conf, connectString, sessionTimeout, watcher); + } + /** * Waits for HBase installation's base (parent) znode to become available. * @throws IOException on ZK errors @@ -2012,7 +2017,7 @@ public final class ZKUtil { LOG.info("Waiting until the base znode is available"); String parentZNode = conf.get(HConstants.ZOOKEEPER_ZNODE_PARENT, HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT); - ZooKeeper zk = new ZooKeeper(ZKConfig.getZKQuorumServersString(conf), + ZooKeeper zk = ZKUtil.createZkWithZkEnv(conf, ZKConfig.getZKQuorumServersString(conf), conf.getInt(HConstants.ZK_SESSION_TIMEOUT, HConstants.DEFAULT_ZK_SESSION_TIMEOUT), EmptyWatcher.instance);