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