You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by sy...@apache.org on 2020/07/29 16:59:15 UTC
[zookeeper] branch master updated: ZOOKEEPER-3895: Client side
NullPointerException in case of empty Multi operation
This is an automated email from the ASF dual-hosted git repository.
symat pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git
The following commit(s) were added to refs/heads/master by this push:
new ce523e0 ZOOKEEPER-3895: Client side NullPointerException in case of empty Multi operation
ce523e0 is described below
commit ce523e01938e26ad92d613bd28b59501e9a853df
Author: Enrico Olivelli <eo...@apache.org>
AuthorDate: Wed Jul 29 16:55:45 2020 +0000
ZOOKEEPER-3895: Client side NullPointerException in case of empty Multi operation
https://issues.apache.org/jira/browse/ZOOKEEPER-3895
Author: Enrico Olivelli <eo...@apache.org>
Reviewers: tison <wa...@gmail.com>, Mate Szalay-Beko <sy...@apache.org>
Closes #1407 from eolivelli/fix/ZOOKEEPER-3895
---
.../src/main/java/org/apache/zookeeper/ClientCnxn.java | 13 +++++++++++++
.../src/main/java/org/apache/zookeeper/ZooKeeper.java | 10 ++++++++++
.../java/org/apache/zookeeper/test/MultiOperationTest.java | 9 +++++++++
3 files changed, 32 insertions(+)
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java
index 87094b8..4dc6fde 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxn.java
@@ -30,6 +30,7 @@ import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -469,6 +470,16 @@ public class ClientCnxn {
return name + suffix;
}
+ /**
+ * Tests that current thread is the main event loop.
+ * This method is useful only for tests inside ZooKeeper project
+ * it is not a public API intended for use by external applications.
+ * @return true if Thread.currentThread() is an EventThread.
+ */
+ public static boolean isInEventThread() {
+ return Thread.currentThread() instanceof EventThread;
+ }
+
class EventThread extends ZooKeeperThread {
private final LinkedBlockingQueue<Object> waitingEvents = new LinkedBlockingQueue<Object>();
@@ -589,6 +600,8 @@ public class ClientCnxn {
((AsyncCallback.EphemeralsCallback) lcb.cb).processResult(lcb.rc, lcb.ctx, null);
} else if (lcb.cb instanceof AsyncCallback.AllChildrenNumberCallback) {
((AsyncCallback.AllChildrenNumberCallback) lcb.cb).processResult(lcb.rc, lcb.path, lcb.ctx, -1);
+ } else if (lcb.cb instanceof AsyncCallback.MultiCallback) {
+ ((AsyncCallback.MultiCallback) lcb.cb).processResult(lcb.rc, lcb.path, lcb.ctx, Collections.emptyList());
} else {
((VoidCallback) lcb.cb).processResult(lcb.rc, lcb.path, lcb.ctx);
}
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java
index 201cf20..6b723af 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/ZooKeeper.java
@@ -24,6 +24,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -1711,6 +1712,11 @@ public class ZooKeeper implements AutoCloseable {
MultiOperationRecord request,
MultiCallback cb,
Object ctx) throws IllegalArgumentException {
+ if (request.size() == 0) {
+ // nothing to do, early exit
+ cnxn.queueCallback(cb, KeeperException.Code.OK.intValue(), null, ctx);
+ return;
+ }
RequestHeader h = new RequestHeader();
switch (request.getOpKind()) {
case TRANSACTION:
@@ -1729,6 +1735,10 @@ public class ZooKeeper implements AutoCloseable {
protected List<OpResult> multiInternal(
MultiOperationRecord request) throws InterruptedException, KeeperException, IllegalArgumentException {
RequestHeader h = new RequestHeader();
+ if (request.size() == 0) {
+ // nothing to do, early exit
+ return Collections.emptyList();
+ }
switch (request.getOpKind()) {
case TRANSACTION:
h.setType(ZooDefs.OpCode.multi);
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/MultiOperationTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/MultiOperationTest.java
index 6e23bd6..5dfd73e 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/MultiOperationTest.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/MultiOperationTest.java
@@ -39,6 +39,7 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.zookeeper.AsyncCallback;
import org.apache.zookeeper.AsyncCallback.MultiCallback;
+import org.apache.zookeeper.ClientCnxn;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.Op;
@@ -107,6 +108,9 @@ public class MultiOperationTest extends ClientBase {
zk.multi(ops, new MultiCallback() {
@Override
public void processResult(int rc, String path, Object ctx, List<OpResult> opResults) {
+ if (!ClientCnxn.isInEventThread()) {
+ throw new RuntimeException("not in event thread");
+ }
synchronized (res) {
res.rc = rc;
res.results = opResults;
@@ -443,6 +447,11 @@ public class MultiOperationTest extends ClientBase {
}
@Test
+ public void testEmpty() throws Exception {
+ multi(zk, Arrays.asList());
+ }
+
+ @Test
public void testCreateDelete() throws Exception {
multi(zk, Arrays.asList(