You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by ha...@apache.org on 2017/02/05 06:22:56 UTC

zookeeper git commit: ZOOKEEPER-2680: Correct DataNode.getChildren() inconsistent behaviour.

Repository: zookeeper
Updated Branches:
  refs/heads/master edf75b5e3 -> 26aee2228


ZOOKEEPER-2680: Correct DataNode.getChildren() inconsistent behaviour.

DataNode.getChildren() API behavior should be changed and it should always return empty set if the node does not have any child. Currently this API returns some times null some times empty set.

Author: Mohammad Arshad <ar...@apache.org>

Reviewers: Edward Ribeiro <ed...@gmail.com>, Abraham Fine <af...@apache.org>, Michael Han <ha...@apache.org>

Closes #160 from arshadmohammad/ZOOKEEPER-2680-DataNode-getChildren and squashes the following commits:

ff9f105 [Mohammad Arshad] Revert back few changes form DataTree
f2691ca [Mohammad Arshad] Removed Null check from all references of getChildren
7c4592d [Mohammad Arshad] Review comment fix
0dbf350 [Mohammad Arshad] separated test cases
01459c8 [Mohammad Arshad] ZOOKEEPER-2680:Correct DataNode.getChildren() inconsistent behaviour.


Project: http://git-wip-us.apache.org/repos/asf/zookeeper/repo
Commit: http://git-wip-us.apache.org/repos/asf/zookeeper/commit/26aee222
Tree: http://git-wip-us.apache.org/repos/asf/zookeeper/tree/26aee222
Diff: http://git-wip-us.apache.org/repos/asf/zookeeper/diff/26aee222

Branch: refs/heads/master
Commit: 26aee2228451257f3b0b5093bc0c101822e06bc8
Parents: edf75b5
Author: Mohammad Arshad <ar...@apache.org>
Authored: Sat Feb 4 22:22:51 2017 -0800
Committer: Michael Han <ha...@apache.org>
Committed: Sat Feb 4 22:22:51 2017 -0800

----------------------------------------------------------------------
 .../zookeeper/server/ContainerManager.java      |  4 +-
 .../org/apache/zookeeper/server/DataNode.java   |  7 ++-
 .../org/apache/zookeeper/server/DataTree.java   | 43 ++++---------
 .../zookeeper/server/PrepRequestProcessor.java  |  3 +-
 .../zookeeper/server/SnapshotFormatter.java     |  6 +-
 .../apache/zookeeper/server/DataNodeTest.java   | 65 ++++++++++++++++++++
 6 files changed, 88 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/zookeeper/blob/26aee222/src/java/main/org/apache/zookeeper/server/ContainerManager.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/ContainerManager.java b/src/java/main/org/apache/zookeeper/server/ContainerManager.java
index 8834f29..fb1cb66 100644
--- a/src/java/main/org/apache/zookeeper/server/ContainerManager.java
+++ b/src/java/main/org/apache/zookeeper/server/ContainerManager.java
@@ -149,7 +149,7 @@ public class ContainerManager {
                 would be immediately be deleted.
              */
             if ((node != null) && (node.stat.getCversion() > 0) &&
-                    (node.getChildren().size() == 0)) {
+                    (node.getChildren().isEmpty())) {
                 candidates.add(containerPath);
             }
         }
@@ -157,7 +157,7 @@ public class ContainerManager {
             DataNode node = zkDb.getDataTree().getNode(ttlPath);
             if (node != null) {
                 Set<String> children = node.getChildren();
-                if ((children == null) || (children.size() == 0)) {
+                if (children.isEmpty()) {
                     long elapsed = getElapsed(node);
                     long ttl = EphemeralType.getTTL(node.stat.getEphemeralOwner());
                     if ((ttl != 0) && (elapsed > ttl)) {

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/26aee222/src/java/main/org/apache/zookeeper/server/DataNode.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/DataNode.java b/src/java/main/org/apache/zookeeper/server/DataNode.java
index ce359cd..0859aab 100644
--- a/src/java/main/org/apache/zookeeper/server/DataNode.java
+++ b/src/java/main/org/apache/zookeeper/server/DataNode.java
@@ -57,6 +57,8 @@ public class DataNode implements Record {
      */
     private Set<String> children = null;
 
+    private static final Set<String> EMPTY_SET = Collections.emptySet();
+
     /**
      * default constructor for the datanode
      */
@@ -122,11 +124,12 @@ public class DataNode implements Record {
     /**
      * convenience methods to get the children
      * 
-     * @return the children of this datanode
+     * @return the children of this datanode. If the datanode has no children, empty
+     *         set is returned
      */
     public synchronized Set<String> getChildren() {
         if (children == null) {
-            return children;
+            return EMPTY_SET;
         }
 
         return Collections.unmodifiableSet(children);

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/26aee222/src/java/main/org/apache/zookeeper/server/DataTree.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/DataTree.java b/src/java/main/org/apache/zookeeper/server/DataTree.java
index 65c30ef..f0ab2b3 100644
--- a/src/java/main/org/apache/zookeeper/server/DataTree.java
+++ b/src/java/main/org/apache/zookeeper/server/DataTree.java
@@ -458,7 +458,7 @@ public class DataTree {
         }
         synchronized (parent) {
             Set<String> children = parent.getChildren();
-            if (children != null && children.contains(childName)) {
+            if (children.contains(childName)) {
                 throw new KeeperException.NodeExistsException();
             }
 
@@ -677,13 +677,7 @@ public class DataTree {
             if (stat != null) {
                 n.copyStat(stat);
             }
-            ArrayList<String> children;
-            Set<String> childs = n.getChildren();
-            if (childs == null) {
-                children = new ArrayList<String>(0);
-            } else {
-                children = new ArrayList<String>(childs);
-            }
+            List<String> children=new ArrayList<String>(n.getChildren());
 
             if (watcher != null) {
                 childWatches.addWatch(path, watcher);
@@ -1056,17 +1050,12 @@ public class DataTree {
         int len = 0;
         synchronized (node) {
             Set<String> childs = node.getChildren();
-            if (childs != null) {
-                children = childs.toArray(new String[childs.size()]);
-            }
+            children = childs.toArray(new String[childs.size()]);
             len = (node.data == null ? 0 : node.data.length);
         }
         // add itself
         counts.count += 1;
         counts.bytes += len;
-        if (children == null || children.length == 0) {
-            return;
-        }
         for (String child : children) {
             getCounts(path + "/" + child, counts);
         }
@@ -1106,11 +1095,9 @@ public class DataTree {
         String children[] = null;
         synchronized (node) {
             Set<String> childs = node.getChildren();
-            if (childs != null) {
-                children = childs.toArray(new String[childs.size()]);
-            }
+            children = childs.toArray(new String[childs.size()]);
         }
-        if (children == null || children.length == 0) {
+        if (children.length == 0) {
             // this node does not have a child
             // is the leaf node
             // check if its the leaf node
@@ -1169,23 +1156,19 @@ public class DataTree {
             //are never changed
             nodeCopy = new DataNode(node.data, node.acl, statCopy);
             Set<String> childs = node.getChildren();
-            if (childs != null) {
-                children = childs.toArray(new String[childs.size()]);
-            }
+            children = childs.toArray(new String[childs.size()]);
         }
         oa.writeString(pathString, "path");
         oa.writeRecord(nodeCopy, "node");
         path.append('/');
         int off = path.length();
-        if (children != null) {
-            for (String child : children) {
-                // since this is single buffer being resused
-                // we need
-                // to truncate the previous bytes of string.
-                path.delete(off, Integer.MAX_VALUE);
-                path.append(child);
-                serializeNode(oa, path);
-            }
+        for (String child : children) {
+            // since this is single buffer being resused
+            // we need
+            // to truncate the previous bytes of string.
+            path.delete(off, Integer.MAX_VALUE);
+            path.append(child);
+            serializeNode(oa, path);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/26aee222/src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java b/src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java
index 007b066..9ad4eea 100644
--- a/src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java
+++ b/src/java/main/org/apache/zookeeper/server/PrepRequestProcessor.java
@@ -168,8 +168,7 @@ public class PrepRequestProcessor extends ZooKeeperCriticalThread implements
                     synchronized(n) {
                         children = n.getChildren();
                     }
-                    lastChange = new ChangeRecord(-1, path, n.stat,
-                        children != null ? children.size() : 0,
+                    lastChange = new ChangeRecord(-1, path, n.stat, children.size(),
                             zks.getZKDatabase().aclForNode(n));
                 }
             }

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/26aee222/src/java/main/org/apache/zookeeper/server/SnapshotFormatter.java
----------------------------------------------------------------------
diff --git a/src/java/main/org/apache/zookeeper/server/SnapshotFormatter.java b/src/java/main/org/apache/zookeeper/server/SnapshotFormatter.java
index f94c54d..bc43402 100644
--- a/src/java/main/org/apache/zookeeper/server/SnapshotFormatter.java
+++ b/src/java/main/org/apache/zookeeper/server/SnapshotFormatter.java
@@ -94,10 +94,8 @@ public class SnapshotFormatter {
             }
             children = n.getChildren();
         }
-        if (children != null) {
-            for (String child : children) {
-                printZnode(dataTree, name + (name.equals("/") ? "" : "/") + child);
-            }
+        for (String child : children) {
+            printZnode(dataTree, name + (name.equals("/") ? "" : "/") + child);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/zookeeper/blob/26aee222/src/java/test/org/apache/zookeeper/server/DataNodeTest.java
----------------------------------------------------------------------
diff --git a/src/java/test/org/apache/zookeeper/server/DataNodeTest.java b/src/java/test/org/apache/zookeeper/server/DataNodeTest.java
new file mode 100644
index 0000000..6289766
--- /dev/null
+++ b/src/java/test/org/apache/zookeeper/server/DataNodeTest.java
@@ -0,0 +1,65 @@
+/**
+ * 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.*;
+
+import java.util.Set;
+
+import org.junit.Test;
+
+public class DataNodeTest {
+
+    @Test
+    public void testGetChildrenShouldReturnEmptySetWhenThereAreNoChidren() {
+        // create DataNode and call getChildren
+        DataNode dataNode = new DataNode();
+        Set<String> children = dataNode.getChildren();
+        assertNotNull(children);
+        assertEquals(0, children.size());
+
+        // add child,remove child and then call getChildren
+        String child = "child";
+        dataNode.addChild(child);
+        dataNode.removeChild(child);
+        children = dataNode.getChildren();
+        assertNotNull(children);
+        assertEquals(0, children.size());
+
+        // Returned empty set must not be modifiable
+        children = dataNode.getChildren();
+        try {
+            children.add("new child");
+            fail("UnsupportedOperationException is expected");
+        } catch (UnsupportedOperationException e) {
+            // do nothing
+        }
+    }
+
+    @Test
+    public void testGetChildrenReturnsImmutableEmptySet() {
+        DataNode dataNode = new DataNode();
+        Set<String> children = dataNode.getChildren();
+        try {
+            children.add("new child");
+            fail("UnsupportedOperationException is expected");
+        } catch (UnsupportedOperationException e) {
+            // do nothing
+        }
+    }
+}