You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by fp...@apache.org on 2016/12/21 22:32:12 UTC
zookeeper git commit: ZOOKEEPER-2383: Startup race in ZooKeeperServer
Repository: zookeeper
Updated Branches:
refs/heads/master 8616a9ec8 -> eac693cc7
ZOOKEEPER-2383: Startup race in ZooKeeperServer
Author: Rakesh Radhakrishnan <ra...@apache.org>
Reviewers: fpj <fp...@apache.org>, rgs <rg...@apache.org>, hanm <ha...@apache.org>
Closes #101 from rakeshadr/ZK-2383 and squashes the following commits:
4faa761 [Rakesh Radhakrishnan] ZOOKEEPER-2383: Startup race in ZooKeeperServer
d2078d0 [Rakesh Radhakrishnan] ZOOKEEPER-2383
Project: http://git-wip-us.apache.org/repos/asf/zookeeper/repo
Commit: http://git-wip-us.apache.org/repos/asf/zookeeper/commit/eac693cc
Tree: http://git-wip-us.apache.org/repos/asf/zookeeper/tree/eac693cc
Diff: http://git-wip-us.apache.org/repos/asf/zookeeper/diff/eac693cc
Branch: refs/heads/master
Commit: eac693cc76a34f96b9116ef33d1e92af7129416d
Parents: 8616a9e
Author: Rakesh Radhakrishnan <ra...@apache.org>
Authored: Wed Dec 21 22:32:01 2016 +0000
Committer: fpj <fp...@apache.org>
Committed: Wed Dec 21 22:32:01 2016 +0000
----------------------------------------------------------------------
.../apache/zookeeper/server/NIOServerCnxn.java | 8 +-
.../zookeeper/server/NettyServerCnxn.java | 2 +-
.../apache/zookeeper/server/admin/Commands.java | 2 +-
.../command/AbstractFourLetterCommand.java | 4 +
.../server/command/CnxnStatResetCommand.java | 2 +-
.../zookeeper/server/command/ConfCommand.java | 2 +-
.../zookeeper/server/command/ConsCommand.java | 2 +-
.../zookeeper/server/command/DirsCommand.java | 2 +-
.../zookeeper/server/command/DumpCommand.java | 2 +-
.../zookeeper/server/command/IsroCommand.java | 2 +-
.../server/command/MonitorCommand.java | 2 +-
.../zookeeper/server/command/StatCommand.java | 2 +-
.../server/command/StatResetCommand.java | 2 +-
.../zookeeper/server/command/WatchCommand.java | 2 +-
.../server/ZooKeeperServerStartupTest.java | 270 +++++++++++++++++++
15 files changed, 292 insertions(+), 14 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java b/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
index f2f225c..c944889 100644
--- a/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
+++ b/src/java/main/org/apache/zookeeper/server/NIOServerCnxn.java
@@ -426,7 +426,7 @@ public class NIOServerCnxn extends ServerCnxn {
}
private void readConnectRequest() throws IOException, InterruptedException {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
throw new IOException("ZooKeeperServer not running");
}
zkServer.processConnectRequest(this, incomingBuffer);
@@ -539,13 +539,17 @@ public class NIOServerCnxn extends ServerCnxn {
if (len < 0 || len > BinaryInputArchive.maxBuffer) {
throw new IOException("Len error " + len);
}
- if (zkServer == null) {
+ if (isZKServerRunning()) {
throw new IOException("ZooKeeperServer not running");
}
incomingBuffer = ByteBuffer.allocate(len);
return true;
}
+ boolean isZKServerRunning() {
+ return zkServer == null || !zkServer.isRunning();
+ }
+
public long getOutstandingRequests() {
return outstandingRequests.get();
}
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java b/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
index c48f6b1..9b6f28e 100644
--- a/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
+++ b/src/java/main/org/apache/zookeeper/server/NettyServerCnxn.java
@@ -332,7 +332,7 @@ public class NettyServerCnxn extends ServerCnxn {
bb.flip();
ZooKeeperServer zks = this.zkServer;
- if (zks == null) {
+ if (zks == null || !zks.isRunning()) {
throw new IOException("ZK down");
}
if (initialized) {
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/admin/Commands.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/admin/Commands.java b/src/java/main/org/apache/zookeeper/server/admin/Commands.java
index 21893f1..4f96de3 100644
--- a/src/java/main/org/apache/zookeeper/server/admin/Commands.java
+++ b/src/java/main/org/apache/zookeeper/server/admin/Commands.java
@@ -86,7 +86,7 @@ public class Commands {
if (!commands.containsKey(cmdName)) {
return new CommandResponse(cmdName, "Unknown command: " + cmdName);
}
- if (zkServer == null) {
+ if (zkServer == null || !zkServer.isRunning()) {
return new CommandResponse(cmdName, "This ZooKeeper instance is not currently serving requests");
}
return commands.get(cmdName).run(zkServer, kwargs);
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java b/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java
index 451ae67..a075a91 100644
--- a/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/AbstractFourLetterCommand.java
@@ -64,6 +64,10 @@ public abstract class AbstractFourLetterCommand {
this.zkServer = zkServer;
}
+ boolean isZKServerRunning() {
+ return zkServer == null || !zkServer.isRunning();
+ }
+
public void setFactory(ServerCnxnFactory factory) {
this.factory = factory;
}
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/CnxnStatResetCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/CnxnStatResetCommand.java b/src/java/main/org/apache/zookeeper/server/command/CnxnStatResetCommand.java
index cfdf0ba..c44c840 100644
--- a/src/java/main/org/apache/zookeeper/server/command/CnxnStatResetCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/CnxnStatResetCommand.java
@@ -29,7 +29,7 @@ public class CnxnStatResetCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
factory.resetAllConnectionStats();
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/ConfCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/ConfCommand.java b/src/java/main/org/apache/zookeeper/server/command/ConfCommand.java
index f48e453..a06666d 100644
--- a/src/java/main/org/apache/zookeeper/server/command/ConfCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/ConfCommand.java
@@ -29,7 +29,7 @@ public class ConfCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
zkServer.dumpConf(pw);
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/ConsCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/ConsCommand.java b/src/java/main/org/apache/zookeeper/server/command/ConsCommand.java
index 61593de..0c8e3dd 100644
--- a/src/java/main/org/apache/zookeeper/server/command/ConsCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/ConsCommand.java
@@ -29,7 +29,7 @@ public class ConsCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
for (ServerCnxn c : factory.getConnections()) {
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/DirsCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/DirsCommand.java b/src/java/main/org/apache/zookeeper/server/command/DirsCommand.java
index 5a442e8..09623d7 100644
--- a/src/java/main/org/apache/zookeeper/server/command/DirsCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/DirsCommand.java
@@ -31,7 +31,7 @@ public class DirsCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() throws IOException {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
return;
}
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/DumpCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/DumpCommand.java b/src/java/main/org/apache/zookeeper/server/command/DumpCommand.java
index f22e3af..903bfd6 100644
--- a/src/java/main/org/apache/zookeeper/server/command/DumpCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/DumpCommand.java
@@ -30,7 +30,7 @@ public class DumpCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
pw.println("SessionTracker dump:");
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/IsroCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/IsroCommand.java b/src/java/main/org/apache/zookeeper/server/command/IsroCommand.java
index 0615a63..542831e 100644
--- a/src/java/main/org/apache/zookeeper/server/command/IsroCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/IsroCommand.java
@@ -31,7 +31,7 @@ public class IsroCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.print("null");
} else if (zkServer instanceof ReadOnlyZooKeeperServer) {
pw.print("ro");
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java b/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java
index c048541..b3e75f3 100644
--- a/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/MonitorCommand.java
@@ -36,7 +36,7 @@ public class MonitorCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
return;
}
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/StatCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/StatCommand.java b/src/java/main/org/apache/zookeeper/server/command/StatCommand.java
index 0b5f911..021b296 100644
--- a/src/java/main/org/apache/zookeeper/server/command/StatCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/StatCommand.java
@@ -37,7 +37,7 @@ public class StatCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
pw.print("Zookeeper version: ");
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java b/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java
index 9538ce2..c7d5ad7 100644
--- a/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/StatResetCommand.java
@@ -29,7 +29,7 @@ public class StatResetCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
zkServer.serverStats().reset();
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/main/org/apache/zookeeper/server/command/WatchCommand.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/command/WatchCommand.java b/src/java/main/org/apache/zookeeper/server/command/WatchCommand.java
index ca97ab9..dd6c247 100644
--- a/src/java/main/org/apache/zookeeper/server/command/WatchCommand.java
+++ b/src/java/main/org/apache/zookeeper/server/command/WatchCommand.java
@@ -32,7 +32,7 @@ public class WatchCommand extends AbstractFourLetterCommand {
@Override
public void commandRun() {
- if (zkServer == null) {
+ if (isZKServerRunning()) {
pw.println(ZK_NOT_SERVING);
} else {
DataTree dt = zkServer.getZKDatabase().getDataTree();
http://git-wip-us.apache.org/repos/asf/zookeeper/blob/eac693cc/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java b/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java
new file mode 100644
index 0000000..da4b829
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/ZooKeeperServerStartupTest.java
@@ -0,0 +1,270 @@
+/**
+ * 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.zookeeper.server;
+
+import static org.apache.zookeeper.client.FourLetterWordMain.send4LetterWord;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.zookeeper.PortAssignment;
+import org.apache.zookeeper.ZKTestCase;
+import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.common.X509Exception.SSLContextException;
+import org.apache.zookeeper.test.ClientBase;
+import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class tests the startup behavior of ZooKeeper server.
+ */
+public class ZooKeeperServerStartupTest extends ZKTestCase {
+ private static final Logger LOG = LoggerFactory
+ .getLogger(ZooKeeperServerStartupTest.class);
+ private static int PORT = PortAssignment.unique();
+ private static String HOST = "127.0.0.1";
+ private static String HOSTPORT = HOST + ":" + PORT;
+ private static final String ZK_NOT_SERVING = "This ZooKeeper instance is not currently serving requests";
+
+ private ServerCnxnFactory servcnxnf;
+ private ZooKeeperServer zks;
+ private File tmpDir;
+ private CountDownLatch startupDelayLatch = new CountDownLatch(1);
+
+ @After
+ public void teardown() throws Exception {
+ // count down to avoid infinite blocking call due to this latch, if
+ // any.
+ startupDelayLatch.countDown();
+
+ if (servcnxnf != null) {
+ servcnxnf.shutdown();
+ }
+ if (zks != null) {
+ zks.shutdown();
+ }
+ if (zks.getZKDatabase() != null) {
+ zks.getZKDatabase().close();
+ }
+ ClientBase.recursiveDelete(tmpDir);
+ }
+
+ /**
+ * Test case for
+ * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.
+ */
+ @Test(timeout = 30000)
+ public void testClientConnectionRequestDuringStartupWithNIOServerCnxn()
+ throws Exception {
+ tmpDir = ClientBase.createTmpDir();
+ ClientBase.setupTestEnv();
+
+ startSimpleZKServer(startupDelayLatch);
+ SimpleZooKeeperServer simplezks = (SimpleZooKeeperServer) zks;
+ Assert.assertTrue(
+ "Failed to invoke zks#startup() method during server startup",
+ simplezks.waitForStartupInvocation(10));
+
+ CountdownWatcher watcher = new CountdownWatcher();
+ ZooKeeper zkClient = new ZooKeeper(HOSTPORT,
+ ClientBase.CONNECTION_TIMEOUT, watcher);
+
+ Assert.assertFalse(
+ "Since server is not fully started, zks#createSession() shouldn't be invoked",
+ simplezks.waitForSessionCreation(5));
+
+ LOG.info(
+ "Decrements the count of the latch, so that server will proceed with startup");
+ startupDelayLatch.countDown();
+
+ Assert.assertTrue("waiting for server being up ", ClientBase
+ .waitForServerUp(HOSTPORT, ClientBase.CONNECTION_TIMEOUT));
+
+ Assert.assertTrue(
+ "Failed to invoke zks#createSession() method during client session creation",
+ simplezks.waitForSessionCreation(5));
+ watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+ zkClient.close();
+ }
+
+ /**
+ * Test case for
+ * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.
+ */
+ @Test(timeout = 30000)
+ public void testClientConnectionRequestDuringStartupWithNettyServerCnxn()
+ throws Exception {
+ tmpDir = ClientBase.createTmpDir();
+ ClientBase.setupTestEnv();
+
+ String originalServerCnxnFactory = System
+ .getProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);
+ try {
+ System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,
+ NettyServerCnxnFactory.class.getName());
+ startSimpleZKServer(startupDelayLatch);
+ SimpleZooKeeperServer simplezks = (SimpleZooKeeperServer) zks;
+ Assert.assertTrue(
+ "Failed to invoke zks#startup() method during server startup",
+ simplezks.waitForStartupInvocation(10));
+
+ CountdownWatcher watcher = new CountdownWatcher();
+ ZooKeeper zkClient = new ZooKeeper(HOSTPORT,
+ ClientBase.CONNECTION_TIMEOUT, watcher);
+
+ Assert.assertFalse(
+ "Since server is not fully started, zks#createSession() shouldn't be invoked",
+ simplezks.waitForSessionCreation(5));
+
+ LOG.info(
+ "Decrements the count of the latch, so that server will proceed with startup");
+ startupDelayLatch.countDown();
+
+ Assert.assertTrue("waiting for server being up ", ClientBase
+ .waitForServerUp(HOSTPORT, ClientBase.CONNECTION_TIMEOUT));
+
+ Assert.assertTrue(
+ "Failed to invoke zks#createSession() method during client session creation",
+ simplezks.waitForSessionCreation(5));
+ watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
+ zkClient.close();
+ } finally {
+ // reset cnxn factory
+ if (originalServerCnxnFactory == null) {
+ System.clearProperty(
+ ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY);
+ return;
+ }
+ System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY,
+ originalServerCnxnFactory);
+ }
+ }
+
+ /**
+ * Test case for
+ * {@link https://issues.apache.org/jira/browse/ZOOKEEPER-2383}.
+ */
+ @Test(timeout = 30000)
+ public void testFourLetterWords() throws Exception {
+ startSimpleZKServer(startupDelayLatch);
+ verify("conf", ZK_NOT_SERVING);
+ verify("crst", ZK_NOT_SERVING);
+ verify("cons", ZK_NOT_SERVING);
+ verify("dirs", ZK_NOT_SERVING);
+ verify("dump", ZK_NOT_SERVING);
+ verify("mntr", ZK_NOT_SERVING);
+ verify("stat", ZK_NOT_SERVING);
+ verify("srst", ZK_NOT_SERVING);
+ verify("wchp", ZK_NOT_SERVING);
+ verify("wchc", ZK_NOT_SERVING);
+ verify("wchs", ZK_NOT_SERVING);
+ verify("isro", "null");
+ }
+
+ private void verify(String cmd, String expected)
+ throws IOException, SSLContextException {
+ String resp = sendRequest(cmd);
+ LOG.info("cmd " + cmd + " expected " + expected + " got " + resp);
+ Assert.assertTrue("Unexpected response", resp.contains(expected));
+ }
+
+ private String sendRequest(String cmd)
+ throws IOException, SSLContextException {
+ return send4LetterWord(HOST, PORT, cmd);
+ }
+
+ private void startSimpleZKServer(CountDownLatch startupDelayLatch)
+ throws IOException {
+ zks = new SimpleZooKeeperServer(tmpDir, tmpDir, 3000,
+ startupDelayLatch);
+ SyncRequestProcessor.setSnapCount(100);
+ final int PORT = Integer.parseInt(HOSTPORT.split(":")[1]);
+
+ servcnxnf = ServerCnxnFactory.createFactory(PORT, -1);
+ Thread startupThread = new Thread() {
+ public void run() {
+ try {
+ servcnxnf.startup(zks);
+ } catch (IOException e) {
+ LOG.error("Unexcepted exception during server startup", e);
+ // Ignoring exception. If there is an ioexception
+ // then one of the following assertion will fail
+ } catch (InterruptedException e) {
+ LOG.error("Unexcepted exception during server startup", e);
+ // Ignoring exception. If there is an interrupted exception
+ // then one of the following assertion will fail
+ }
+ };
+ };
+ LOG.info("Starting zk server {}", HOSTPORT);
+ startupThread.start();
+ }
+
+ private static class SimpleZooKeeperServer extends ZooKeeperServer {
+ private CountDownLatch startupDelayLatch;
+ private CountDownLatch startupInvokedLatch = new CountDownLatch(1);
+ private CountDownLatch createSessionInvokedLatch = new CountDownLatch(
+ 1);
+
+ public SimpleZooKeeperServer(File snapDir, File logDir, int tickTime,
+ CountDownLatch startupDelayLatch) throws IOException {
+ super(snapDir, logDir, tickTime);
+ this.startupDelayLatch = startupDelayLatch;
+ }
+
+ @Override
+ public synchronized void startup() {
+ try {
+ startupInvokedLatch.countDown();
+ // Delaying the zk server startup so that
+ // ZooKeeperServer#sessionTracker reference won't be
+ // initialized. In the defect scenario, while processing the
+ // connection request zkServer needs sessionTracker reference,
+ // but this is not yet initialized and the server is still in
+ // the startup phase, resulting in NPE.
+ startupDelayLatch.await();
+ } catch (InterruptedException e) {
+ Assert.fail(
+ "Unexpected InterruptedException while startinng up!");
+ }
+ super.startup();
+ }
+
+ @Override
+ long createSession(ServerCnxn cnxn, byte[] passwd, int timeout) {
+ createSessionInvokedLatch.countDown();
+ return super.createSession(cnxn, passwd, timeout);
+ }
+
+ boolean waitForStartupInvocation(long timeout)
+ throws InterruptedException {
+ return startupInvokedLatch.await(timeout, TimeUnit.SECONDS);
+ }
+
+ boolean waitForSessionCreation(long timeout)
+ throws InterruptedException {
+ return createSessionInvokedLatch.await(timeout, TimeUnit.SECONDS);
+ }
+ }
+}