You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@curator.apache.org by ra...@apache.org on 2016/01/18 22:04:05 UTC

[02/11] curator git commit: Added TreeCacheSelector to allow for controling which nodes a TreeCache processes

Added TreeCacheSelector to allow for controling which nodes a TreeCache processes


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

Branch: refs/heads/CURATOR-3.0
Commit: a01f2a00dcbf608f5e297683e51a5244ffd679bf
Parents: 45332f3
Author: randgalt <ra...@apache.org>
Authored: Tue Jan 12 14:13:54 2016 -0500
Committer: randgalt <ra...@apache.org>
Committed: Tue Jan 12 14:13:54 2016 -0500

----------------------------------------------------------------------
 .../recipes/cache/DefaultTreeCacheSelector.java | 37 +++++++++++
 .../framework/recipes/cache/TreeCache.java      | 32 +++++++---
 .../recipes/cache/TreeCacheSelector.java        | 66 ++++++++++++++++++++
 .../framework/recipes/cache/TestTreeCache.java  | 48 ++++++++++++++
 4 files changed, 175 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/a01f2a00/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/DefaultTreeCacheSelector.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/DefaultTreeCacheSelector.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/DefaultTreeCacheSelector.java
new file mode 100644
index 0000000..822f098
--- /dev/null
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/DefaultTreeCacheSelector.java
@@ -0,0 +1,37 @@
+/**
+ * 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.curator.framework.recipes.cache;
+
+/**
+ * Default TreeCache selector - returns true for all methods
+ */
+public class DefaultTreeCacheSelector implements TreeCacheSelector
+{
+    @Override
+    public boolean traverseChildren(String fullPath)
+    {
+        return true;
+    }
+
+    @Override
+    public boolean acceptChild(String fullPath)
+    {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/a01f2a00/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
index 4f3ffb6..eeb54a5 100644
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCache.java
@@ -72,6 +72,7 @@ public class TreeCache implements Closeable
 {
     private static final Logger LOG = LoggerFactory.getLogger(TreeCache.class);
     private final boolean createParentNodes;
+    private final TreeCacheSelector selector;
 
     public static final class Builder
     {
@@ -82,6 +83,7 @@ public class TreeCache implements Closeable
         private CloseableExecutorService executorService = null;
         private int maxDepth = Integer.MAX_VALUE;
         private boolean createParentNodes = false;
+        private TreeCacheSelector selector = new DefaultTreeCacheSelector();
 
         private Builder(CuratorFramework client, String path)
         {
@@ -99,7 +101,7 @@ public class TreeCache implements Closeable
             {
                 executor = new CloseableExecutorService(Executors.newSingleThreadExecutor(defaultThreadFactory));
             }
-            return new TreeCache(client, path, cacheData, dataIsCompressed, maxDepth, executor, createParentNodes);
+            return new TreeCache(client, path, cacheData, dataIsCompressed, maxDepth, executor, createParentNodes, selector);
         }
 
         /**
@@ -176,6 +178,18 @@ public class TreeCache implements Closeable
             this.createParentNodes = createParentNodes;
             return this;
         }
+
+        /**
+         * By default, {@link DefaultTreeCacheSelector} is used. Change the selector here.
+         *
+         * @param selector new selector
+         * @return this for chaining
+         */
+        public Builder setSelector(TreeCacheSelector selector)
+        {
+            this.selector = selector;
+            return this;
+        }
     }
 
     /**
@@ -220,7 +234,7 @@ public class TreeCache implements Closeable
 
         private void refresh() throws Exception
         {
-            if (depth < maxDepth)
+            if ((depth < maxDepth) && selector.traverseChildren(path))
             {
                 outstandingOps.addAndGet(2);
                 doRefreshData();
@@ -232,7 +246,7 @@ public class TreeCache implements Closeable
 
         private void refreshChildren() throws Exception
         {
-            if (depth < maxDepth)
+            if ((depth < maxDepth) && selector.traverseChildren(path))
             {
                 outstandingOps.incrementAndGet();
                 doRefreshChildren();
@@ -395,7 +409,7 @@ public class TreeCache implements Closeable
                     List<String> newChildren = new ArrayList<String>();
                     for ( String child : event.getChildren() )
                     {
-                        if ( !childMap.containsKey(child) )
+                        if ( !childMap.containsKey(child) && selector.acceptChild(ZKPaths.makePath(path, child)) )
                         {
                             newChildren.add(child);
                         }
@@ -515,7 +529,7 @@ public class TreeCache implements Closeable
      */
     public TreeCache(CuratorFramework client, String path)
     {
-        this(client, path, true, false, Integer.MAX_VALUE, new CloseableExecutorService(Executors.newSingleThreadExecutor(defaultThreadFactory), true), false);
+        this(client, path, true, false, Integer.MAX_VALUE, new CloseableExecutorService(Executors.newSingleThreadExecutor(defaultThreadFactory), true), false, new DefaultTreeCacheSelector());
     }
 
     /**
@@ -525,16 +539,18 @@ public class TreeCache implements Closeable
      * @param dataIsCompressed if true, data in the path is compressed
      * @param executorService  Closeable ExecutorService to use for the TreeCache's background thread
      * @param createParentNodes true to create parent nodes as containers
+     * @param selector         the selector to use
      */
-    TreeCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, int maxDepth, final CloseableExecutorService executorService, boolean createParentNodes)
+    TreeCache(CuratorFramework client, String path, boolean cacheData, boolean dataIsCompressed, int maxDepth, final CloseableExecutorService executorService, boolean createParentNodes, TreeCacheSelector selector)
     {
         this.createParentNodes = createParentNodes;
+        this.selector = Preconditions.checkNotNull(selector, "selector cannot be null");
         this.root = new TreeNode(validatePath(path), null);
-        this.client = client;
+        this.client = Preconditions.checkNotNull(client, "client cannot be null");
         this.cacheData = cacheData;
         this.dataIsCompressed = dataIsCompressed;
         this.maxDepth = maxDepth;
-        this.executorService = executorService;
+        this.executorService = Preconditions.checkNotNull(executorService, "executorService cannot be null");
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/curator/blob/a01f2a00/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCacheSelector.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCacheSelector.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCacheSelector.java
new file mode 100644
index 0000000..5d98ad9
--- /dev/null
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/TreeCacheSelector.java
@@ -0,0 +1,66 @@
+/**
+ * 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.curator.framework.recipes.cache;
+
+/**
+ * <p>
+ *     Controls which nodes a TreeCache processes. When iterating
+ *     over the children of a parent node, a given node's children are
+ *     queried only if {@link #traverseChildren(String)} returns true.
+ *     When caching the list of nodes for a parent node, a given node is
+ *     stored only if {@link #acceptChild(String)} returns true.
+ * </p>
+ *
+ * <p>
+ *     E.g. Given:
+ * <pre>
+ * root
+ *     n1-a
+ *     n1-b
+ *         n2-a
+ *         n2-b
+ *             n3-a
+ *     n1-c
+ *     n1-d
+ * </pre>
+ *     You could have a TreeCache only work with the nodes: n1-a, n1-b, n2-a, n2-b, n1-d
+ *     by returning false from traverseChildren() for "/root/n1-b/n2-b" and returning
+ *     false from acceptChild("/root/n1-c").
+ * </p>
+ */
+public interface TreeCacheSelector
+{
+    /**
+     * Return true if children of this path should be cached.
+     * i.e. if false is returned, this node is not queried to
+     * determine if it has children or not
+     *
+     * @param fullPath full path of the ZNode
+     * @return true/false
+     */
+    boolean traverseChildren(String fullPath);
+
+    /**
+     * Return true if this node should be returned from the cache
+     *
+     * @param fullPath full path of the ZNode
+     * @return true/false
+     */
+    boolean acceptChild(String fullPath);
+}

http://git-wip-us.apache.org/repos/asf/curator/blob/a01f2a00/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
index 0bccb54..767b3ae 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestTreeCache.java
@@ -22,6 +22,7 @@ package org.apache.curator.framework.recipes.cache;
 import com.google.common.collect.ImmutableSet;
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.test.KillSession;
+import org.apache.curator.utils.CloseableExecutorService;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.zookeeper.CreateMode;
 import org.testng.Assert;
@@ -31,6 +32,53 @@ import java.util.concurrent.Semaphore;
 public class TestTreeCache extends BaseTestTreeCache
 {
     @Test
+    public void testSelector() throws Exception
+    {
+        client.create().forPath("/root");
+        client.create().forPath("/root/n1-a");
+        client.create().forPath("/root/n1-b");
+        client.create().forPath("/root/n1-b/n2-a");
+        client.create().forPath("/root/n1-b/n2-b");
+        client.create().forPath("/root/n1-b/n2-b/n3-a");
+        client.create().forPath("/root/n1-c");
+        client.create().forPath("/root/n1-d");
+
+        TreeCacheSelector selector = new TreeCacheSelector()
+        {
+            @Override
+            public boolean traverseChildren(String fullPath)
+            {
+                return !fullPath.equals("/root/n1-b/n2-b");
+            }
+
+            @Override
+            public boolean acceptChild(String fullPath)
+            {
+                return !fullPath.equals("/root/n1-c");
+            }
+        };
+        TreeCache treeCache = TreeCache.newBuilder(client, "/root").setSelector(selector).build();
+        try
+        {
+            treeCache.getListenable().addListener(eventListener);
+            treeCache.start();
+
+            assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/root");
+            assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/root/n1-a");
+            assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/root/n1-b");
+            assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/root/n1-d");
+            assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/root/n1-b/n2-a");
+            assertEvent(TreeCacheEvent.Type.NODE_ADDED, "/root/n1-b/n2-b");
+            assertEvent(TreeCacheEvent.Type.INITIALIZED);
+            assertNoMoreEvents();
+        }
+        finally
+        {
+            CloseableUtils.closeQuietly(treeCache);
+        }
+    }
+
+    @Test
     public void testStartup() throws Exception
     {
         client.create().forPath("/test");