Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id E7F99200C20 for ; Sun, 5 Feb 2017 07:23:00 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id E674A160B66; Sun, 5 Feb 2017 06:23:00 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id E1307160B63 for ; Sun, 5 Feb 2017 07:22:59 +0100 (CET) Received: (qmail 37431 invoked by uid 500); 5 Feb 2017 06:22:57 -0000 Mailing-List: contact commits-help@zookeeper.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@zookeeper.apache.org Delivered-To: mailing list commits@zookeeper.apache.org Received: (qmail 37419 invoked by uid 99); 5 Feb 2017 06:22:56 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Sun, 05 Feb 2017 06:22:56 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 86266DFC31; Sun, 5 Feb 2017 06:22:56 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: hanm@apache.org To: commits@zookeeper.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: zookeeper git commit: ZOOKEEPER-2680: Correct DataNode.getChildren() inconsistent behaviour. Date: Sun, 5 Feb 2017 06:22:56 +0000 (UTC) archived-at: Sun, 05 Feb 2017 06:23:01 -0000 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 Reviewers: Edward Ribeiro , Abraham Fine , Michael Han 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 Authored: Sat Feb 4 22:22:51 2017 -0800 Committer: Michael Han 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 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 children = null; + private static final Set 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 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 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 children; - Set childs = n.getChildren(); - if (childs == null) { - children = new ArrayList(0); - } else { - children = new ArrayList(childs); - } + List children=new ArrayList(n.getChildren()); if (watcher != null) { childWatches.addWatch(path, watcher); @@ -1056,17 +1050,12 @@ public class DataTree { int len = 0; synchronized (node) { Set 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 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 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 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 children = dataNode.getChildren(); + try { + children.add("new child"); + fail("UnsupportedOperationException is expected"); + } catch (UnsupportedOperationException e) { + // do nothing + } + } +}