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(