From df267929322c5e83bb8d57bbed65978b0159ec8b Mon Sep 17 00:00:00 2001 From: Sujith Simon Date: Thu, 14 Nov 2019 08:24:09 +0530 Subject: [PATCH 1/4] ZOOKEEPER-2238: Support limiting the maximum number of connections/clients to a zookeeper server Support limiting the maximum number of connections/clients to a zookeeper server Author: sujithsimon22 Reviewers: Justin Mao Ling , Brian Nixon , Edward Ribeiro , Enrico Olivelli , Mohammad Arshad Closes #1108 from sujithsimon22/ZOOKEEPER-2238 --- .../main/resources/markdown/zookeeperAdmin.md | 9 + .../server/NIOServerCnxnFactory.java | 4 + .../server/NettyServerCnxnFactory.java | 6 + .../zookeeper/server/ServerCnxnFactory.java | 41 ++++ .../zookeeper/server/ServerCnxnHelper.java | 35 ++++ .../zookeeper/server/ZooKeeperServerBean.java | 4 + .../server/ZooKeeperServerMXBean.java | 5 + .../server/quorum/LocalPeerBean.java | 5 + .../server/quorum/LocalPeerMXBean.java | 4 + .../server/ZooKeeperServerMaxCnxnsTest.java | 177 ++++++++++++++++++ 10 files changed, 290 insertions(+) create mode 100644 zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnHelper.java create mode 100644 zookeeper-server/src/test/java/org/apache/zookeeper/server/ZooKeeperServerMaxCnxnsTest.java diff --git a/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md b/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md index da9cb2c7f52..662355d51d6 100644 --- a/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md +++ b/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md @@ -667,6 +667,15 @@ property, when available, is noted below. recommended to set the value to N * **preAllocSize** where N >= 2. +* *maxCnxns* : + (Java system property: **zookeeper.maxCnxns**) + Limits the total number of concurrent connections that can be made to a + zookeeper server (per client Port of each server ). This is used to prevent certain + classes of DoS attacks. The default is 0 and setting it to 0 entirely removes + the limit on total number of concurrent connections. Accounting for the + number of connections for serverCnxnFactory and a secureServerCnxnFactory is done + separately, so a peer is allowed to host up to 2*maxCnxns provided they are of appropriate types. + * *maxClientCnxns* : (No Java system property) Limits the number of concurrent connections (at the socket diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/NIOServerCnxnFactory.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/NIOServerCnxnFactory.java index b42d97a920c..de29fa2424d 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/NIOServerCnxnFactory.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/NIOServerCnxnFactory.java @@ -273,6 +273,9 @@ private boolean doAccept() { try { sc = acceptSocket.accept(); accepted = true; + if (limitTotalNumberOfCnxns()) { + throw new IOException("Too many connections max allowed is " + maxCnxns); + } InetAddress ia = sc.socket().getInetAddress(); int cnxncount = getClientCnxnCount(ia); @@ -634,6 +637,7 @@ public void configure(InetSocketAddress addr, int maxcc, int backlog, boolean se configureSaslLogin(); maxClientCnxns = maxcc; + initMaxCnxns(); sessionlessCnxnTimeout = Integer.getInteger(ZOOKEEPER_NIO_SESSIONLESS_CNXN_TIMEOUT, 10000); // We also use the sessionlessCnxnTimeout as expiring interval for // cnxnExpiryQueue. These don't need to be the same, but the expiring diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java index 81ad271d3df..ef35837c460 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java @@ -186,6 +186,11 @@ public void channelActive(ChannelHandlerContext ctx) throws Exception { } final Channel channel = ctx.channel(); + if (limitTotalNumberOfCnxns()) { + ServerMetrics.getMetrics().CONNECTION_REJECTED.add(1); + channel.close(); + return; + } InetAddress addr = ((InetSocketAddress) channel.remoteAddress()).getAddress(); if (maxClientCnxns > 0 && getClientCnxnCount(addr) >= maxClientCnxns) { ServerMetrics.getMetrics().CONNECTION_REJECTED.add(1); @@ -524,6 +529,7 @@ public void closeAll(ServerCnxn.DisconnectReason reason) { @Override public void configure(InetSocketAddress addr, int maxClientCnxns, int backlog, boolean secure) throws IOException { configureSaslLogin(); + initMaxCnxns(); localAddress = addr; this.maxClientCnxns = maxClientCnxns; this.secure = secure; diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnFactory.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnFactory.java index 996fb32573d..3db1ca12ddb 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnFactory.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnFactory.java @@ -40,6 +40,8 @@ public abstract class ServerCnxnFactory { public static final String ZOOKEEPER_SERVER_CNXN_FACTORY = "zookeeper.serverCnxnFactory"; + private static final String ZOOKEEPER_MAX_CONNECTION = "zookeeper.maxCnxns"; + public static final int ZOOKEEPER_MAX_CONNECTION_DEFAULT = 0; private static final Logger LOG = LoggerFactory.getLogger(ServerCnxnFactory.class); @@ -51,6 +53,9 @@ public abstract class ServerCnxnFactory { */ static final ByteBuffer closeConn = ByteBuffer.allocate(0); + // total number of connections accepted by the ZooKeeper server + protected int maxCnxns; + // sessionMap is used by closeSession() final ConcurrentHashMap sessionMap = new ConcurrentHashMap(); @@ -287,4 +292,40 @@ public static String getUserName() { return loginUser; } + /** + * Maximum number of connections allowed in the ZooKeeper system + */ + public int getMaxCnxns() { + return maxCnxns; + } + + protected void initMaxCnxns() { + maxCnxns = Integer.getInteger(ZOOKEEPER_MAX_CONNECTION, ZOOKEEPER_MAX_CONNECTION_DEFAULT); + if (maxCnxns < 0) { + maxCnxns = ZOOKEEPER_MAX_CONNECTION_DEFAULT; + LOG.warn("maxCnxns should be greater than or equal to 0, using default vlaue {}.", + ZOOKEEPER_MAX_CONNECTION_DEFAULT); + } else if (maxCnxns == ZOOKEEPER_MAX_CONNECTION_DEFAULT) { + LOG.warn("maxCnxns is not configured, using default value {}.", + ZOOKEEPER_MAX_CONNECTION_DEFAULT); + } else { + LOG.info("maxCnxns configured value is {}.", maxCnxns); + } + } + + /** + * Ensure total number of connections are less than the maxCnxns + */ + protected boolean limitTotalNumberOfCnxns() { + if (maxCnxns <= 0) { + // maxCnxns limit is disabled + return false; + } + int cnxns = getNumAliveConnections(); + if (cnxns >= maxCnxns) { + LOG.error("Too many connections " + cnxns + " - max is " + maxCnxns); + return true; + } + return false; + } } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnHelper.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnHelper.java new file mode 100644 index 00000000000..8f78c7c4459 --- /dev/null +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ServerCnxnHelper.java @@ -0,0 +1,35 @@ +/* + * 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; + +public class ServerCnxnHelper { + + /** gets maximum number of connections in ZooKeeper */ + public static int getMaxCnxns(ServerCnxnFactory secureServerCnxnFactory, ServerCnxnFactory serverCnxnFactory) { + if (serverCnxnFactory != null) { + return serverCnxnFactory.getMaxCnxns(); + } + if (secureServerCnxnFactory != null) { + return secureServerCnxnFactory.getMaxCnxns(); + } + // default + return ServerCnxnFactory.ZOOKEEPER_MAX_CONNECTION_DEFAULT; + } + +} diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerBean.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerBean.java index 1783197a9ca..bd9b6432440 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerBean.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerBean.java @@ -403,4 +403,8 @@ public int getLargeRequestThreshold() { public void setLargeRequestThreshold(int threshold) { zks.setLargeRequestThreshold(threshold); } + + public int getMaxCnxns() { + return ServerCnxnHelper.getMaxCnxns(zks.secureServerCnxnFactory, zks.serverCnxnFactory); + } } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMXBean.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMXBean.java index cf4667522c3..71a9d987e04 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMXBean.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMXBean.java @@ -221,4 +221,9 @@ public interface ZooKeeperServerMXBean { int getMaxBatchSize(); void setMaxBatchSize(int size); + /** + * @return Current maxCnxns allowed to a single ZooKeeper server + */ + int getMaxCnxns(); + } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerBean.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerBean.java index e576b454a3c..b89bb4971c3 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerBean.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerBean.java @@ -19,6 +19,7 @@ package org.apache.zookeeper.server.quorum; import static org.apache.zookeeper.common.NetUtils.formatInetAddr; +import org.apache.zookeeper.server.ServerCnxnHelper; /** * Implementation of the local peer MBean interface. @@ -122,4 +123,8 @@ public boolean isLeader() { return peer.isLeader(peer.getId()); } + @Override + public int getMaxCnxns() { + return ServerCnxnHelper.getMaxCnxns(peer.secureCnxnFactory, peer.cnxnFactory); + } } diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java index 84f141ec65a..ca8edff800c 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/LocalPeerMXBean.java @@ -120,4 +120,8 @@ public interface LocalPeerMXBean extends ServerMXBean { */ boolean isLeader(); + /** + * @return Current maxCnxns allowed to a single ZooKeeper server + */ + int getMaxCnxns(); } diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZooKeeperServerMaxCnxnsTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZooKeeperServerMaxCnxnsTest.java new file mode 100644 index 00000000000..48f5b998387 --- /dev/null +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/ZooKeeperServerMaxCnxnsTest.java @@ -0,0 +1,177 @@ +/** + * 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.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeoutException; +import org.apache.zookeeper.CreateMode; +import org.apache.zookeeper.PortAssignment; +import org.apache.zookeeper.WatchedEvent; +import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZooDefs; +import org.apache.zookeeper.ZooKeeper; +import org.apache.zookeeper.server.quorum.QuorumPeerTestBase; +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; + +public class ZooKeeperServerMaxCnxnsTest extends QuorumPeerTestBase { + + protected static final Logger LOG = LoggerFactory.getLogger(ZooKeeperServerMaxCnxnsTest.class); + private static int SERVER_COUNT = 3; + private MainThread[] mt; + private ZooKeeper[] clients; + + /** + *
+     * Test case for https://issues.apache.org/jira/browse/ZOOKEEPER-2238.
+     * Support limiting the maximum number of connections/clients to a ZooKeeper server.
+     * 
+ */ + + @Test(timeout = 120000) + public void testMaxZooKeeperClientsWithNIOServerCnxnFactory() throws Exception { + String serverCnxnFactory = "org.apache.zookeeper.server.NIOServerCnxnFactory"; + testMaxZooKeeperClients(serverCnxnFactory); + } + + @Test(timeout = 120000) + public void testMaxZooKeeperClientsWithNettyServerCnxnFactory() throws Exception { + String serverCnxnFactory = "org.apache.zookeeper.server.NettyServerCnxnFactory"; + testMaxZooKeeperClients(serverCnxnFactory); + } + + private void testMaxZooKeeperClients(String serverCnxnFactory) throws Exception { + final int clientPorts[] = new int[SERVER_COUNT]; + int maxCnxns = 2; + StringBuilder sb = new StringBuilder(); + sb.append("maxCnxns=" + maxCnxns + "\n"); + sb.append("serverCnxnFactory=" + serverCnxnFactory + "\n"); + String server; + + for (int i = 0; i < SERVER_COUNT; i++) { + clientPorts[i] = PortAssignment.unique(); + server = "server." + i + "=127.0.0.1:" + PortAssignment.unique() + ":" + + PortAssignment.unique() + ":participant;127.0.0.1:" + clientPorts[i]; + sb.append(server + "\n"); + } + String currentQuorumCfgSection = sb.toString(); + MainThread mt[] = new MainThread[SERVER_COUNT]; + + // start 3 servers + for (int i = 0; i < SERVER_COUNT; i++) { + mt[i] = new MainThread(i, clientPorts[i], currentQuorumCfgSection, false); + mt[i].start(); + } + + // ensure all servers started + for (int i = 0; i < SERVER_COUNT; i++) { + Assert.assertTrue("waiting for server " + i + " being up", ClientBase + .waitForServerUp("127.0.0.1:" + clientPorts[i], ClientBase.CONNECTION_TIMEOUT)); + } + + int maxAllowedConnection = maxCnxns * SERVER_COUNT; + String cxnString = getCxnString(clientPorts); + + final CountDownLatch countDownLatch = new CountDownLatch(maxAllowedConnection); + ZooKeeper[] clients = new ZooKeeper[maxAllowedConnection]; + Watcher watcher = new Watcher() { + + @Override + public void process(WatchedEvent event) { + if (event.getState() == Event.KeeperState.SyncConnected) { + countDownLatch.countDown(); + } + } + }; + for (int i = 0; i < maxAllowedConnection; i++) { + clients[i] = new ZooKeeper(cxnString, ClientBase.CONNECTION_TIMEOUT, watcher); + Thread.sleep(100); + } + countDownLatch.await(); + // reaching this point indicates that all maxAllowedConnection connected + + // No more client to be allowed to connect now as we have reached the + // max connections + CountdownWatcher cdw = new CountdownWatcher(); + ZooKeeper extraClient = new ZooKeeper(cxnString, ClientBase.CONNECTION_TIMEOUT, cdw); + try { + cdw.waitForConnected(ClientBase.CONNECTION_TIMEOUT / 2); + fail("Client is not supposed to get connected as max connection already reached."); + } catch (TimeoutException e) { + extraClient.close(); + } + + // lets close one already connected client + clients[0].close(); + + // Now extra client must automatically get connected + cdw = new CountdownWatcher(); + extraClient = new ZooKeeper(cxnString, ClientBase.CONNECTION_TIMEOUT, cdw); + cdw.waitForConnected(ClientBase.CONNECTION_TIMEOUT); + + // verify some basic operation + String create = extraClient.create("/test", "".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, + CreateMode.PERSISTENT); + assertEquals("/test", create); + + // cleanup + extraClient.close(); + } + + private String getCxnString(int[] clientPorts) { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < clientPorts.length; i++) { + builder.append("127.0.0.1:" + clientPorts[i]); + if (i != clientPorts.length - 1) { + builder.append(","); + } + } + return builder.toString(); + } + + @After + public void tearDown() { + // stop all clients + if (clients != null) { + for (ZooKeeper zooKeeper : clients) { + try { + zooKeeper.close(); + } catch (InterruptedException e) { + LOG.warn("ZooKeeper interrupted while closing it.", e); + } + } + } + // stop all severs + if (mt != null) { + for (int i = 0; i < SERVER_COUNT; i++) { + try { + mt[i].shutdown(); + } catch (InterruptedException e) { + LOG.warn("Quorum Peer interrupted while shutting it down", e); + } + } + } + } +} \ No newline at end of file From aeb9f78c454c59d5d258f0a99bb5e57ed2cbaebe Mon Sep 17 00:00:00 2001 From: tison Date: Thu, 14 Nov 2019 16:44:36 +0100 Subject: [PATCH 2/4] ZOOKEEPER-3571: Ensure test base directory before tests Ensure `build.test.dir` is present as a directory. Otherwise many times it suffers from ``` java.io.IOException: No such file or directory at java.io.UnixFileSystem.createFileExclusively(Native Method) at java.io.File.createTempFile(File.java:2024) at org.apache.zookeeper.test.ClientBase.createTmpDir(ClientBase.java:371) at org.apache.zookeeper.test.ClientBase.setUpWithServerId(ClientBase.java:514) at org.apache.zookeeper.test.ClientBase.setUp(ClientBase.java:491) ``` Author: tison Reviewers: eolivelli@apache.org, andor@apache.org Closes #1112 from TisonKun/ZOOKEEPER-3571 --- .../java/org/apache/zookeeper/ZKTestCase.java | 21 ++++++++++++++++++- .../org/apache/zookeeper/test/ClientBase.java | 7 +++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/ZKTestCase.java b/zookeeper-server/src/test/java/org/apache/zookeeper/ZKTestCase.java index b256a7a37a4..d9d481aa24d 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/ZKTestCase.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/ZKTestCase.java @@ -18,8 +18,11 @@ package org.apache.zookeeper; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.File; import java.time.LocalDateTime; +import org.junit.BeforeClass; import org.junit.Rule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; @@ -33,10 +36,10 @@ * Basic utilities shared by all tests. Also logging of various events during * the test execution (start/stop/success/failure/etc...) */ -@SuppressWarnings("deprecation") @RunWith(JUnit4ZKTestRunner.class) public class ZKTestCase { + protected static final File testBaseDir = new File(System.getProperty("build.test.dir", "build")); private static final Logger LOG = LoggerFactory.getLogger(ZKTestCase.class); private String testName; @@ -45,6 +48,22 @@ protected String getTestName() { return testName; } + @BeforeClass + public static void before() { + if (!testBaseDir.exists()) { + assertTrue( + "Cannot properly create test base directory " + testBaseDir.getAbsolutePath(), + testBaseDir.mkdirs()); + } else if (!testBaseDir.isDirectory()) { + assertTrue( + "Cannot properly delete file with duplicate name of test base directory " + testBaseDir.getAbsolutePath(), + testBaseDir.delete()); + assertTrue( + "Cannot properly create test base directory " + testBaseDir.getAbsolutePath(), + testBaseDir.mkdirs()); + } + } + @Rule public TestWatcher watchman = new TestWatcher() { diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ClientBase.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ClientBase.java index ef3291fbc8e..4235b6b6349 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/ClientBase.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/ClientBase.java @@ -70,7 +70,6 @@ public abstract class ClientBase extends ZKTestCase { protected static final Logger LOG = LoggerFactory.getLogger(ClientBase.class); public static int CONNECTION_TIMEOUT = 30000; - static final File BASETEST = new File(System.getProperty("build.test.dir", "build")); protected String hostPort = "127.0.0.1:" + PortAssignment.unique(); protected int maxCnxns = 0; @@ -344,11 +343,11 @@ static void verifyThreadTerminated(Thread thread, long millis) throws Interrupte } public static File createEmptyTestDir() throws IOException { - return createTmpDir(BASETEST, false); + return createTmpDir(testBaseDir, false); } public static File createTmpDir() throws IOException { - return createTmpDir(BASETEST, true); + return createTmpDir(testBaseDir, true); } static File createTmpDir(File parentDir, boolean createInitFile) throws IOException { @@ -495,7 +494,7 @@ protected void setUpWithServerId(int serverId) throws Exception { setUpAll(); - tmpDir = createTmpDir(BASETEST, true); + tmpDir = createTmpDir(testBaseDir, true); startServer(serverId); From 9f13268567dfcc26a5f59a7449aeec21fb5e16b3 Mon Sep 17 00:00:00 2001 From: Andor Molnar Date: Fri, 15 Nov 2019 10:56:42 +0100 Subject: [PATCH 3/4] Revert "ZOOKEEPER-3598: Fix potential data inconsistency issue due to CommitProcessor not gracefully shutdown" This reverts commit 79f99af81842f415b97e1c3c18c953df5bd129b2. --- .../org/apache/zookeeper/server/ExitCode.java | 5 +- .../server/quorum/CommitProcessor.java | 15 ---- .../server/quorum/CommitProcessorTest.java | 80 +------------------ 3 files changed, 3 insertions(+), 97 deletions(-) diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ExitCode.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ExitCode.java index 810be278b83..67af2c8df8f 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ExitCode.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ExitCode.java @@ -48,10 +48,7 @@ public enum ExitCode { QUORUM_PACKET_ERROR(13), /** Unable to bind to the quorum (election) port after multiple retry */ - UNABLE_TO_BIND_QUORUM_PORT(14), - - /** Failed to shutdown the request processor pipeline gracefully **/ - SHUTDOWN_UNGRACEFULLY(16); + UNABLE_TO_BIND_QUORUM_PORT(14); private final int value; diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/CommitProcessor.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/CommitProcessor.java index 8044e657ea7..4e521874b6e 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/CommitProcessor.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/CommitProcessor.java @@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicInteger; import org.apache.zookeeper.ZooDefs.OpCode; import org.apache.zookeeper.common.Time; -import org.apache.zookeeper.server.ExitCode; import org.apache.zookeeper.server.Request; import org.apache.zookeeper.server.RequestProcessor; import org.apache.zookeeper.server.ServerMetrics; @@ -622,20 +621,6 @@ public void shutdown() { workerPool.join(workerShutdownTimeoutMS); } - try { - this.join(workerShutdownTimeoutMS); - } catch (InterruptedException e) { - LOG.warn("Interrupted while waiting for CommitProcessor to finish"); - Thread.currentThread().interrupt(); - } - - if (this.isAlive()) { - LOG.warn("CommitProcessor does not shutdown gracefully after " - + "waiting for {} ms, exit to avoid potential " - + "inconsistency issue", workerShutdownTimeoutMS); - System.exit(ExitCode.SHUTDOWN_UNGRACEFULLY.getValue()); - } - if (nextProcessor != null) { nextProcessor.shutdown(); } diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/CommitProcessorTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/CommitProcessorTest.java index e83ed73bad4..d939dc0eb86 100644 --- a/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/CommitProcessorTest.java +++ b/zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/CommitProcessorTest.java @@ -28,9 +28,7 @@ import java.util.ArrayList; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import org.apache.jute.BinaryOutputArchive; @@ -84,18 +82,13 @@ public class CommitProcessorTest extends ZKTestCase { File tmpDir; ArrayList testClients = new ArrayList(); CommitProcessor commitProcessor; - DelayRequestProcessor delayProcessor; public void setUp(int numCommitThreads, int numClientThreads, int writePercent) throws Exception { - setUp(numCommitThreads, numClientThreads, writePercent, false); - } - - public void setUp(int numCommitThreads, int numClientThreads, int writePercent, boolean withDelayProcessor) throws Exception { stopped = false; System.setProperty(CommitProcessor.ZOOKEEPER_COMMIT_PROC_NUM_WORKER_THREADS, Integer.toString(numCommitThreads)); tmpDir = ClientBase.createTmpDir(); ClientBase.setupTestEnv(); - zks = new TestZooKeeperServer(tmpDir, tmpDir, 4000, withDelayProcessor); + zks = new TestZooKeeperServer(tmpDir, tmpDir, 4000); zks.startup(); for (int i = 0; i < numClientThreads; ++i) { TestClientThread client = new TestClientThread(writePercent); @@ -218,23 +211,6 @@ public void testNoCommitWorkersReadOnlyWorkload() throws Exception { assertTrue("Write requests processed", processedWriteRequests.get() == numClients); } - @Test - public void testWaitingForWriteToFinishBeforeShutdown() throws Exception { - setUp(1, 0, 0, true); - - // send a single write request - TestClientThread client = new TestClientThread(0); - client.sendWriteRequest(); - - // wait for request being committed - delayProcessor.waitRequestProcessing(); - - zks.shutdown(); - - // Make sure we've finished the in-flight request before shutdown returns - assertFalse(commitProcessor.isAlive()); - } - @Test public void testNoCommitWorkersMixedWorkload() throws Exception { int numClients = 10; @@ -311,15 +287,8 @@ private synchronized void failTest(String reason) { private class TestZooKeeperServer extends ZooKeeperServer { - final boolean withDelayProcessor; - public TestZooKeeperServer(File snapDir, File logDir, int tickTime) throws IOException { - this(snapDir, logDir, tickTime, false); - } - - public TestZooKeeperServer(File snapDir, File logDir, int tickTime, boolean withDelayProcessor) throws IOException { super(snapDir, logDir, tickTime); - this.withDelayProcessor = withDelayProcessor; } public PrepRequestProcessor getFirstProcessor() { @@ -334,12 +303,7 @@ protected void setupRequestProcessors() { // ValidateProcessor is set up in a similar fashion to ToBeApplied // processor, so it can do pre/post validating of requests ValidateProcessor validateProcessor = new ValidateProcessor(finalProcessor); - if (withDelayProcessor) { - delayProcessor = new DelayRequestProcessor(validateProcessor); - commitProcessor = new CommitProcessor(delayProcessor, "1", true, null); - } else { - commitProcessor = new CommitProcessor(validateProcessor, "1", true, null); - } + commitProcessor = new CommitProcessor(validateProcessor, "1", true, null); validateProcessor.setCommitProcessor(commitProcessor); commitProcessor.start(); MockProposalRequestProcessor proposalProcessor = new MockProposalRequestProcessor(commitProcessor); @@ -350,46 +314,6 @@ protected void setupRequestProcessors() { } - private class DelayRequestProcessor implements RequestProcessor { - // delay 1s for each request - static final int DEFAULT_DELAY = 1000; - RequestProcessor nextProcessor; - CountDownLatch waitingProcessRequestBeingCalled; - - public DelayRequestProcessor(RequestProcessor nextProcessor) { - this.nextProcessor = nextProcessor; - this.waitingProcessRequestBeingCalled = new CountDownLatch(1); - } - - @Override - public void processRequest(Request request) throws RequestProcessorException { - try { - this.waitingProcessRequestBeingCalled.countDown(); - LOG.info("Sleeping {} ms for request {}", DEFAULT_DELAY, request); - Thread.sleep(DEFAULT_DELAY); - } catch (InterruptedException e) { /* ignore */ } - nextProcessor.processRequest(request); - } - - public void waitRequestProcessing() { - try { - if (!waitingProcessRequestBeingCalled.await(3000, TimeUnit.MILLISECONDS)) { - LOG.info("Did not see request processing in 3s"); - } - } catch (InterruptedException e) { - LOG.info("Interrupted when waiting for processRequest being called"); - } - } - - @Override - public void shutdown() { - LOG.info("shutdown DelayRequestProcessor"); - if (nextProcessor != null) { - nextProcessor.shutdown(); - } - } - } - private class MockProposalRequestProcessor extends Thread implements RequestProcessor { private final CommitProcessor commitProcessor; From d2bec6b097c64b7c6e5ead4335bbd8d0afaa6d12 Mon Sep 17 00:00:00 2001 From: Enrico Olivelli Date: Fri, 15 Nov 2019 14:34:05 +0100 Subject: [PATCH 4/4] ZOOKEEPER-3363: Drop ANT build.xml - drop Ant and Ivy files - drop old Cobertura README file - drop old jdiff file Author: Enrico Olivelli Author: Enrico Olivelli Reviewers: Norbert Kalmar Closes #1139 from eolivelli/fix/drop-ant --- README_packaging.md | 23 - build.xml | 2003 ------------ ivy.xml | 164 - ivysettings.xml | 41 - .../src/main/assembly/source-package.xml | 3 - .../main/resources/lib/cobertura/README.txt | 3 - .../resources/lib/jdiff/zookeeper_3.1.1.xml | 2717 ----------------- 7 files changed, 4954 deletions(-) delete mode 100644 build.xml delete mode 100644 ivy.xml delete mode 100644 ivysettings.xml delete mode 100644 zookeeper-server/src/main/resources/lib/cobertura/README.txt delete mode 100644 zookeeper-server/src/main/resources/lib/jdiff/zookeeper_3.1.1.xml diff --git a/README_packaging.md b/README_packaging.md index ea54e963567..2ccbba6bdf0 100644 --- a/README_packaging.md +++ b/README_packaging.md @@ -65,26 +65,3 @@ The compiled C client can be found here: - `zookeeper-client/zookeeper-client-c/target/c/include/zookeeper` - Native library headers The same folders gets archived to the `zookeeper-assembly/target/apache-zookeeper--lib.tar.gz` file, assuming you activated the `full-build` maven profile. - -## Package build command (using ant) - -**Command to build tarball package:** `ant tar` - -`zookeeper-.tar.gz` tarball file structure layout: - -- `/bin` - User executable -- `/sbin` - System executable -- `/libexec` - Configuration boot trap script -- `/lib` - Library dependencies -- `/docs` - Documents -- `/share/zookeeper` - Project files - - -**Command to build tarball package with native components:** `ant package-native tar` - -`zookeeper--lib.tar.gz` tarball file structure layout: - -- `/bin` - User executable -- `/lib` - Native libraries -- `/include/zookeeper` - Native library headers - diff --git a/build.xml b/build.xml deleted file mode 100644 index da4ab2e0c9a..00000000000 --- a/build.xml +++ /dev/null @@ -1,2003 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The version is ${zookeeper-pom.version} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Running ${test.junit.threads} concurrent JUnit processes. - - - - - - - - - - - - - - - - - - - - - - Tests failed! - - - - Running single JUnit process. Upgrade to Ant 1.9.4 or later to run multiple JUnit processes. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Clover not found. - Please make sure clover-${clover.version}.jar is in ${clover.home}/lib, or made available - to Ant using other mechanisms like -lib or CLASSPATH. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ivy.xml b/ivy.xml deleted file mode 100644 index 3797845f12a..00000000000 --- a/ivy.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - - - - - - ZooKeeper - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/ivysettings.xml b/ivysettings.xml deleted file mode 100644 index 1d06c403cee..00000000000 --- a/ivysettings.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/zookeeper-assembly/src/main/assembly/source-package.xml b/zookeeper-assembly/src/main/assembly/source-package.xml index 8135e623244..15a5c68df79 100644 --- a/zookeeper-assembly/src/main/assembly/source-package.xml +++ b/zookeeper-assembly/src/main/assembly/source-package.xml @@ -107,9 +107,6 @@ . pom.xml - build.xml - ivy.xml - ivysettings.xml excludeFindBugsFilter.xml owaspSuppressions.xml checktyle.xml diff --git a/zookeeper-server/src/main/resources/lib/cobertura/README.txt b/zookeeper-server/src/main/resources/lib/cobertura/README.txt deleted file mode 100644 index f5ba88f1feb..00000000000 --- a/zookeeper-server/src/main/resources/lib/cobertura/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -Download the cobertura binary from the following location and unpack it into this directory. Run "cobertura-report" target from build.xml to generate coverage report. - -http://cobertura.sourceforge.net/download.html diff --git a/zookeeper-server/src/main/resources/lib/jdiff/zookeeper_3.1.1.xml b/zookeeper-server/src/main/resources/lib/jdiff/zookeeper_3.1.1.xml deleted file mode 100644 index c28b238b86a..00000000000 --- a/zookeeper-server/src/main/resources/lib/jdiff/zookeeper_3.1.1.xml +++ /dev/null @@ -1,2717 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  • --short - prints a short version string "1.2.3" -
  • --revision - prints a short version string with the SVN - repository revision "1.2.3-94" -
  • --full - prints the revision and the build date - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The client object will pick an arbitrary server and try to connect to it. - If failed, it will try the next one in the list, until a connection is - established, or all the servers have been tried. - - @param host - comma separated host:port pairs, each corresponding to a zk - server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" - @param sessionTimeout - session timeout in milliseconds - @param watcher - a watcher object which will be notified of state changes, may - also be notified for node events - - @throws IOException in cases of network failure]]> - - - - - - - The client object will pick an arbitrary server and try to connect to it. - If failed, it will try the next one in the list, until a connection is - established, or all the servers have been tried. -

    - Use {@link #getSessionId} and {@link #getSessionPasswd} on an established - client connection, these values must be passed as sessionId and - sessionPasswd respectively if reconnecting. Otherwise, if not - reconnecting, use the other constructor which does not require these - parameters. - - @param host - comma separated host:port pairs, each corresponding to a zk - server. e.g. "127.0.0.1:3000,127.0.0.1:3001,127.0.0.1:3002" - @param sessionTimeout - session timeout in milliseconds - @param watcher - a watcher object which will be notified of state changes, may - also be notified for node events - @param sessionId - specific session id to use if reconnecting - @param sessionPasswd - password for this session - - @throws IOException in cases of network failure]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The flags argument specifies whether the created node will be ephemeral - or not. -

    - An ephemeral node will be removed by the ZooKeeper automatically when the - session associated with the creation of the node expires. -

    - The flags argument can also specify to create a sequential node. The - actual path name of a sequential node will be the given path plus a - suffix "_i" where i is the current sequential number of the node. Once - such a node is created, the sequential number will be incremented by one. -

    - If a node with the same actual path already exists in the ZooKeeper, a - KeeperException with error code KeeperException.NodeExists will be - thrown. Note that since a different actual path is used for each - invocation of creating sequential node with the same path argument, the - call will never throw "file exists" KeeperException. -

    - If the parent node does not exist in the ZooKeeper, a KeeperException - with error code KeeperException.NoNode will be thrown. -

    - An ephemeral node cannot have children. If the parent node of the given - path is ephemeral, a KeeperException with error code - KeeperException.NoChildrenForEphemerals will be thrown. -

    - This operation, if successful, will trigger all the watches left on the - node of the given path by exists and getData API calls, and the watches - left on the parent node by getChildren API calls. -

    - If a node is created successfully, the ZooKeeper server will trigger the - watches on the path left by exists calls, and the watches on the parent - of the node by getChildren calls. -

    - The maximum allowable size of the data array is 1 MB (1,048,576 bytes). - Arrays larger than this will cause a KeeperExecption to be thrown. - - @param path - the path for the node - @param data - the initial data for the node - @param acl - the acl for the node - @param flags - specifying whether the node to be created is ephemeral - and/or sequential - @return the actual path of the created node - @throws KeeperException if the server returns a non-zero error code - @throws org.apache.zookeeper.KeeperException.InvalidACLException if the ACL is invalid - @throws InterruptedException if the transaction is interrupted - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - - - - - - - - - , CreateMode)]]> - - - - - - - - - - A KeeperException with error code KeeperException.NoNode will be thrown - if the nodes does not exist. -

    - A KeeperException with error code KeeperException.BadVersion will be - thrown if the given version does not match the node's version. -

    - A KeeperException with error code KeeperException.NotEmpty will be thrown - if the node has children. -

    - This operation, if successful, will trigger all the watches on the node - of the given path left by exists API calls, and the watches on the parent - node left by getChildren API calls. - - @param path - the path of the node to be deleted. - @param version - the expected node version. - @throws InterruptedException IF the server transaction is interrupted - @throws KeeperException If the server signals an error with a non-zero return code. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - - - - - - - - - - If the watch is non-null and the call is successful (no exception is thrown), - a watch will be left on the node with the given path. The watch will be - triggered by a successful operation that creates/delete the node or sets - the data on the node. - - @param path the node path - @param watcher explicit watcher - @return the stat of the node of the given path; return null if no such a - node exists. - @throws KeeperException If the server signals an error - @throws InterruptedException If the server transaction is interrupted. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - If the watch is true and the call is successful (no exception is thrown), - a watch will be left on the node with the given path. The watch will be - triggered by a successful operation that creates/delete the node or sets - the data on the node. - - @param path - the node path - @param watch - whether need to watch this node - @return the stat of the node of the given path; return null if no such a - node exists. - @throws KeeperException If the server signals an error - @throws InterruptedException If the server transaction is interrupted.]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - If the watch is non-null and the call is successful (no exception is - thrown), a watch will be left on the node with the given path. The watch - will be triggered by a successful operation that sets data on the node, or - deletes the node. -

    - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. - - @param path the given path - @param watcher explicit watcher - @param stat the stat of the node - @return the data of the node - @throws KeeperException If the server signals an error with a non-zero error code - @throws InterruptedException If the server transaction is interrupted. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - - If the watch is true and the call is successful (no exception is - thrown), a watch will be left on the node with the given path. The watch - will be triggered by a successful operation that sets data on the node, or - deletes the node. -

    - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. - - @param path the given path - @param watch whether need to watch this node - @param stat the stat of the node - @return the data of the node - @throws KeeperException If the server signals an error with a non-zero error code - @throws InterruptedException If the server transaction is interrupted.]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This operation, if successful, will trigger all the watches on the node - of the given path left by getData calls. -

    - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. -

    - A KeeperException with error code KeeperException.BadVersion will be - thrown if the given version does not match the node's version. -

    - The maximum allowable size of the data array is 1 MB (1,048,576 bytes). - Arrays larger than this will cause a KeeperExecption to be thrown. - - @param path - the path of the node - @param data - the data to set - @param version - the expected matching version - @return the state of the node - @throws InterruptedException If the server transaction is interrupted. - @throws KeeperException If the server signals an error with a non-zero error code. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - - - - - - - - - - - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. - - @param path - the given path for the node - @param stat - the stat of the node will be copied to this parameter. - @return the ACL array of the given node. - @throws InterruptedException If the server transaction is interrupted. - @throws KeeperException If the server signals an error with a non-zero error code. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - - - - - - - - - - - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. -

    - A KeeperException with error code KeeperException.BadVersion will be - thrown if the given version does not match the node's version. - - @param path - @param acl - @param version - @return the stat of the node. - @throws InterruptedException If the server transaction is interrupted. - @throws KeeperException If the server signals an error with a non-zero error code. - @throws org.apache.zookeeper.KeeperException.InvalidACLException If the acl is invalide. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - - - - - - - - - - - If the watch is non-null and the call is successful (no exception is thrown), - a watch will be left on the node with the given path. The watch willbe - triggered by a successful operation that deletes the node of the given - path or creates/delete a child under the node. -

    - The list of children returned is not sorted and no guarantee is provided - as to its natural or lexical order. -

    - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. - - @param path - @param watcher explicit watcher - @return an unordered array of children of the node with the given path - @throws InterruptedException If the server transaction is interrupted. - @throws KeeperException If the server signals an error with a non-zero error code. - @throws IllegalArgumentException if an invalid path is specified]]> - - - - - - - - - - If the watch is true and the call is successful (no exception is thrown), - a watch will be left on the node with the given path. The watch willbe - triggered by a successful operation that deletes the node of the given - path or creates/delete a child under the node. -

    - The list of children returned is not sorted and no guarantee is provided - as to its natural or lexical order. -

    - A KeeperException with error code KeeperException.NoNode will be thrown - if no node with the given path exists. - - @param path - @param watch - @return an unordered array of children of the node with the given path - @throws InterruptedException If the server transaction is interrupted. - @throws KeeperException If the server signals an error with a non-zero error code.]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Once a connection to a server is established, a session ID is assigned to the - client. The client will send heart beats to the server periodically to keep - the session valid. -

    - The application can call ZooKeeper APIs through a client as long as the - session ID of the client remains valid. -

    - If for some reason, the client fails to send heart beats to the server for a - prolonged period of time (exceeding the sessionTimeout value, for instance), - the server will expire the session, and the session ID will become invalid. - The client object will no longer be usable. To make ZooKeeper API calls, the - application must create a new client object. -

    - If the ZooKeeper server the client currently connects to fails or otherwise - does not respond, the client will automatically try to connect to another - server before its session ID expires. If successful, the application can - continue to use the client. -

    - Some successful ZooKeeper API calls can leave watches on the "data nodes" in - the ZooKeeper server. Other successful ZooKeeper API calls can trigger those - watches. Once a watch is triggered, an event will be delivered to the client - which left the watch at the first place. Each watch can be triggered only - once. Thus, up to one event will be delivered to a client for every watch it - leaves. -

    - A client needs an object of a class implementing Watcher interface for - processing the events delivered to the client. - - When a client drops current connection and re-connects to a server, all the - existing watches are considered as being triggered but the undelivered events - are lost. To emulate this, the client will generate a special event to tell - the event handler a connection has been dropped. This special event has type - EventNone and state sKeeperStateDisconnected.]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -