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

[1/2] curator git commit: CURATOR-154 - Modified the handling for creating the ephemeral node so that if it already exists, an attempt will be made to set its data to match the data that the PersistentEphemeralNode has cached.

Repository: curator
Updated Branches:
  refs/heads/master c65e09141 -> 6e16d0d5c


CURATOR-154 - Modified the handling for creating the ephemeral node so
that if it already exists, an attempt will be made to set its data to
match the data that the PersistentEphemeralNode has cached.


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

Branch: refs/heads/master
Commit: 64973b0d91c0625b00d400227e6b1971233df595
Parents: 1c194b4
Author: Cameron McKenzie <ca...@unico.com.au>
Authored: Wed Oct 29 16:32:35 2014 +1100
Committer: Cameron McKenzie <ca...@unico.com.au>
Committed: Wed Oct 29 16:32:35 2014 +1100

----------------------------------------------------------------------
 .../recipes/nodes/PersistentEphemeralNode.java  | 52 ++++++++++--
 .../nodes/TestPersistentEphemeralNode.java      | 84 +++++++++++++++++++-
 2 files changed, 124 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/64973b0d/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
index d78573c..41c04f6 100644
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
@@ -20,6 +20,7 @@
 package org.apache.curator.framework.recipes.nodes;
 
 import com.google.common.base.Preconditions;
+
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.api.ACLBackgroundPathAndBytesable;
 import org.apache.curator.framework.api.BackgroundCallback;
@@ -31,14 +32,17 @@ import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.Watcher.Event.EventType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+
 import java.io.Closeable;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicReference;
+
 import org.apache.curator.utils.PathUtils;
 
 /**
@@ -67,7 +71,10 @@ public class PersistentEphemeralNode implements Closeable
         @Override
         public void process(WatchedEvent event)
         {
-            createNode();
+        	if ( event.getType() == EventType.NodeDeleted)
+        	{
+        		createNode();
+        	}
         }
     };
     private final BackgroundCallback checkExistsCallback = new BackgroundCallback()
@@ -81,6 +88,21 @@ public class PersistentEphemeralNode implements Closeable
             }
         }
     };
+    private final BackgroundCallback setDataCallback = new BackgroundCallback() {
+		
+		@Override
+		public void processResult(CuratorFramework client, CuratorEvent event)
+				throws Exception {
+			//If the result is ok then initialisation is complete (if we're still initialising)
+			//Don't retry on other errors as the only recoverable cases will be connection loss
+			//and the node not existing, both of which are already handled by other watches.
+			if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
+			{
+				//Update is ok, mark initialisation as complete if required.
+				initialisationComplete();
+			}
+		}
+	};	
     private final ConnectionStateListener connectionStateListener = new ConnectionStateListener()
     {
         @Override
@@ -188,12 +210,12 @@ public class PersistentEphemeralNode implements Closeable
      * @param basePath the base path for the node
      * @param data     data for the node
      */
-    public PersistentEphemeralNode(CuratorFramework client, Mode mode, String basePath, byte[] data)
+    public PersistentEphemeralNode(CuratorFramework client, Mode mode, String basePath, byte[] initData)
     {
         this.client = Preconditions.checkNotNull(client, "client cannot be null");
         this.basePath = PathUtils.validatePath(basePath);
         this.mode = Preconditions.checkNotNull(mode, "mode cannot be null");
-        data = Preconditions.checkNotNull(data, "data cannot be null");
+        final byte[] data = Preconditions.checkNotNull(initData, "data cannot be null");
 
         backgroundCallback = new BackgroundCallback()
         {
@@ -201,9 +223,11 @@ public class PersistentEphemeralNode implements Closeable
             public void processResult(CuratorFramework client, CuratorEvent event) throws Exception
             {
                 String path = null;
+                boolean nodeExists = false;
                 if ( event.getResultCode() == KeeperException.Code.NODEEXISTS.intValue() )
-                {
-                    path = event.getPath();
+                {                	
+                	path = event.getPath();
+                	nodeExists = true;
                 }
                 else if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
                 {
@@ -214,10 +238,13 @@ public class PersistentEphemeralNode implements Closeable
                     nodePath.set(path);
                     watchNode();
 
-                    CountDownLatch localLatch = initialCreateLatch.getAndSet(null);
-                    if ( localLatch != null )
+                    if(nodeExists)
                     {
-                        localLatch.countDown();
+                    	client.setData().inBackground(setDataCallback).forPath(getActualPath(), data);
+                    }
+                    else
+                    {
+                    	initialisationComplete();
                     }
                 }
                 else
@@ -230,6 +257,15 @@ public class PersistentEphemeralNode implements Closeable
         createMethod = mode.isProtected() ? client.create().creatingParentsIfNeeded().withProtection() : client.create().creatingParentsIfNeeded();
         this.data.set(Arrays.copyOf(data, data.length));
     }
+    
+    private void initialisationComplete()
+    {
+        CountDownLatch localLatch = initialCreateLatch.getAndSet(null);
+        if ( localLatch != null )
+        {
+            localLatch.countDown();
+        }
+    }
 
     /**
      * You must call start() to initiate the persistent ephemeral node. An attempt to create the node

http://git-wip-us.apache.org/repos/asf/curator/blob/64973b0d/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
----------------------------------------------------------------------
diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
index 47ae757..31e7ef2 100644
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
@@ -20,6 +20,7 @@ package org.apache.curator.framework.recipes.nodes;
 
 import com.google.common.base.Throwables;
 import com.google.common.collect.Lists;
+
 import org.apache.curator.framework.CuratorFramework;
 import org.apache.curator.framework.CuratorFrameworkFactory;
 import org.apache.curator.framework.state.ConnectionState;
@@ -31,12 +32,15 @@ import org.apache.curator.test.TestingServer;
 import org.apache.curator.test.Timing;
 import org.apache.curator.utils.CloseableUtils;
 import org.apache.curator.utils.ZKPaths;
+import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.WatchedEvent;
 import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.Watcher.Event.EventType;
 import org.apache.zookeeper.data.Stat;
 import org.testng.Assert;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
+
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
@@ -75,7 +79,7 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
     @Test
     public void testListenersReconnectedIsFast() throws Exception
     {
-        server.close();
+        server.stop();
 
         CuratorFramework client = CuratorFrameworkFactory.newClient(server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1));
         try
@@ -103,13 +107,13 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
             };
             client.getConnectionStateListenable().addListener(listener);
             timing.sleepABit();
-            server = new TestingServer(server.getPort());
+            server.restart();
             Assert.assertTrue(timing.awaitLatch(connectedLatch));
             timing.sleepABit();
             Assert.assertTrue(node.waitForInitialCreate(timing.forWaiting().milliseconds(), TimeUnit.MILLISECONDS));
-            server.close();
+            server.stop();
             timing.sleepABit();
-            server = new TestingServer(server.getPort());
+            server.restart();
             timing.sleepABit();
             Assert.assertTrue(timing.awaitLatch(reconnectedLatch));
         }
@@ -459,6 +463,78 @@ public class TestPersistentEphemeralNode extends BaseClassForTests
             node.close();
         }
     }
+    
+    /**
+     * Test that if a persistent ephemeral node is created and the node already exists
+     * that if data is present in the PersistentEphermalNode that it is still set. 
+     * @throws Exception
+     */
+    @Test
+    public void testSetDataWhenNodeExists() throws Exception
+    {
+        CuratorFramework curator = newCurator();
+        curator.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(PATH, "InitialData".getBytes());
+        
+        byte[] data = "Hello World".getBytes();
+             
+        PersistentEphemeralNode node = new PersistentEphemeralNode(curator, PersistentEphemeralNode.Mode.EPHEMERAL, PATH, data);
+        node.start();
+        try
+        {
+            node.waitForInitialCreate(timing.forWaiting().seconds(), TimeUnit.SECONDS);
+            assertTrue(Arrays.equals(curator.getData().forPath(node.getActualPath()), data));
+        }
+        finally
+        {
+            node.close();
+        }
+    }
+    
+    @Test
+    public void testSetDataWhenDisconnected() throws Exception
+    {
+        CuratorFramework curator = newCurator();
+        
+        byte[] initialData = "Hello World".getBytes();
+        byte[] updatedData = "Updated".getBytes();
+             
+        PersistentEphemeralNode node = new PersistentEphemeralNode(curator, PersistentEphemeralNode.Mode.EPHEMERAL, PATH, initialData);
+        node.start();
+        try
+        {
+            node.waitForInitialCreate(timing.forWaiting().seconds(), TimeUnit.SECONDS);
+            assertTrue(Arrays.equals(curator.getData().forPath(node.getActualPath()), initialData));
+            
+            server.stop();
+            
+            final CountDownLatch dataUpdateLatch = new CountDownLatch(1);
+            
+            Watcher watcher = new Watcher()
+            {
+				@Override
+				public void process(WatchedEvent event)
+				{
+					if ( event.getType() == EventType.NodeDataChanged )
+					{
+						dataUpdateLatch.countDown();
+					}
+				}            	
+            };
+            
+            curator.getData().usingWatcher(watcher).inBackground().forPath(node.getActualPath());
+            
+            node.setData(updatedData);
+            server.restart();
+
+            assertTrue(timing.awaitLatch(dataUpdateLatch));
+                       
+            assertTrue(Arrays.equals(curator.getData().forPath(node.getActualPath()), updatedData));
+        }
+        finally
+        {
+            node.close();
+        }    	
+    }
 
     private void assertNodeExists(CuratorFramework curator, String path) throws Exception
     {


[2/2] curator git commit: Merge branch 'master' into CURATOR-154

Posted by ca...@apache.org.
Merge branch 'master' into CURATOR-154

Conflicts:
	curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java


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

Branch: refs/heads/master
Commit: 6e16d0d5c35fa02b6976037d230a0e25e25d7572
Parents: 64973b0 c65e091
Author: Cameron McKenzie <ca...@unico.com.au>
Authored: Wed Apr 22 09:06:29 2015 +1000
Committer: Cameron McKenzie <ca...@unico.com.au>
Committed: Wed Apr 22 09:06:29 2015 +1000

----------------------------------------------------------------------
 curator-client/pom.xml                          |   4 +-
 .../org/apache/curator/utils/ThreadUtils.java   |   5 +
 .../java/org/apache/curator/utils/ZKPaths.java  | 103 ++++--
 .../org/apache/curator/utils/TestZKPaths.java   |  11 +
 curator-examples/pom.xml                        |   2 +-
 .../main/java/discovery/InstanceDetails.java    |   2 +-
 curator-framework/pom.xml                       |   4 +-
 .../org/apache/curator/framework/AuthInfo.java  |  51 +++
 .../framework/CuratorFrameworkFactory.java      | 127 +++++--
 .../framework/imps/CreateBuilderImpl.java       |  16 +-
 .../framework/imps/CuratorFrameworkImpl.java    | 116 +++---
 .../imps/CuratorTempFrameworkImpl.java          |  10 +-
 .../framework/imps/DeleteBuilderImpl.java       | 103 +++---
 .../curator/framework/imps/NamespaceFacade.java |   8 +-
 .../curator/framework/imps/NamespaceImpl.java   |   6 +-
 .../curator/framework/imps/TestFramework.java   | 349 ++++++++++++-------
 .../framework/imps/TestFrameworkEdges.java      |  81 ++++-
 curator-recipes/pom.xml                         |   4 +-
 .../recipes/cache/PathChildrenCache.java        |  16 +-
 .../framework/recipes/cache/TreeCache.java      |   2 +-
 .../framework/recipes/locks/ChildReaper.java    | 157 ++++++++-
 .../locks/InterProcessReadWriteLock.java        |  34 +-
 .../recipes/locks/InterProcessSemaphoreV2.java  |   7 +
 .../curator/framework/recipes/locks/Reaper.java |  65 +++-
 .../recipes/nodes/PersistentEphemeralNode.java  |   2 +-
 .../src/site/confluence/Tree-cache.confluence   |  39 ---
 .../src/site/confluence/tree-cache.confluence   |  39 +++
 .../framework/recipes/cache/TestTreeCache.java  |  43 +++
 .../recipes/leader/TestLeaderSelector.java      |  67 ++++
 .../recipes/locks/TestChildReaper.java          | 248 ++++++++++++-
 .../locks/TestInterProcessReadWriteLock.java    |  33 ++
 .../locks/TestInterProcessSemaphore.java        |  40 +++
 .../framework/recipes/locks/TestReaper.java     |  90 ++++-
 .../nodes/TestPersistentEphemeralNode.java      |  37 ++
 curator-test/pom.xml                            |   4 +-
 curator-x-discovery-server/pom.xml              |   4 +-
 .../contexts/GenericDiscoveryContext.java       |   8 +-
 .../contexts/IntegerDiscoveryContext.java       |   4 +-
 .../server/contexts/StringDiscoveryContext.java |   4 +-
 .../entity/JsonServiceInstanceMarshaller.java   |   6 +-
 .../entity/JsonServiceInstancesMarshaller.java  |   8 +-
 .../entity/JsonServiceNamesMarshaller.java      |   8 +-
 .../discovery/server/rest/DiscoveryContext.java |   4 +-
 .../server/jetty_jersey/ServiceDetails.java     |   4 +-
 curator-x-discovery/pom.xml                     |  18 +-
 .../x/discovery/ServiceDiscoveryBuilder.java    |  45 ++-
 .../curator/x/discovery/ServiceInstance.java    |   6 +-
 .../details/JsonInstanceSerializer.java         |   4 +-
 .../discovery/details/ServiceDiscoveryImpl.java |  81 ++++-
 .../x/discovery/TestServiceDiscovery.java       | 106 ++++--
 .../discovery/details/TestWatchedInstances.java |  94 +++++
 curator-x-rpc/pom.xml                           |  23 +-
 .../java/org/apache/curator/x/rpc/RpcTests.java |   6 +-
 pom.xml                                         |  84 +----
 54 files changed, 1854 insertions(+), 588 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/curator/blob/6e16d0d5/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/curator/blob/6e16d0d5/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
----------------------------------------------------------------------
diff --cc curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
index 31e7ef2,8bc8d3d..1c66271
--- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
+++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java
@@@ -465,76 -464,40 +466,112 @@@ public class TestPersistentEphemeralNod
      }
      
      /**
 +     * Test that if a persistent ephemeral node is created and the node already exists
 +     * that if data is present in the PersistentEphermalNode that it is still set. 
 +     * @throws Exception
 +     */
 +    @Test
 +    public void testSetDataWhenNodeExists() throws Exception
 +    {
 +        CuratorFramework curator = newCurator();
 +        curator.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL).forPath(PATH, "InitialData".getBytes());
 +        
 +        byte[] data = "Hello World".getBytes();
 +             
 +        PersistentEphemeralNode node = new PersistentEphemeralNode(curator, PersistentEphemeralNode.Mode.EPHEMERAL, PATH, data);
 +        node.start();
 +        try
 +        {
 +            node.waitForInitialCreate(timing.forWaiting().seconds(), TimeUnit.SECONDS);
 +            assertTrue(Arrays.equals(curator.getData().forPath(node.getActualPath()), data));
 +        }
 +        finally
 +        {
 +            node.close();
 +        }
 +    }
 +    
 +    @Test
 +    public void testSetDataWhenDisconnected() throws Exception
 +    {
 +        CuratorFramework curator = newCurator();
 +        
 +        byte[] initialData = "Hello World".getBytes();
 +        byte[] updatedData = "Updated".getBytes();
 +             
 +        PersistentEphemeralNode node = new PersistentEphemeralNode(curator, PersistentEphemeralNode.Mode.EPHEMERAL, PATH, initialData);
 +        node.start();
 +        try
 +        {
 +            node.waitForInitialCreate(timing.forWaiting().seconds(), TimeUnit.SECONDS);
 +            assertTrue(Arrays.equals(curator.getData().forPath(node.getActualPath()), initialData));
 +            
 +            server.stop();
 +            
 +            final CountDownLatch dataUpdateLatch = new CountDownLatch(1);
 +            
 +            Watcher watcher = new Watcher()
 +            {
 +				@Override
 +				public void process(WatchedEvent event)
 +				{
 +					if ( event.getType() == EventType.NodeDataChanged )
 +					{
 +						dataUpdateLatch.countDown();
 +					}
 +				}            	
 +            };
 +            
 +            curator.getData().usingWatcher(watcher).inBackground().forPath(node.getActualPath());
 +            
 +            node.setData(updatedData);
 +            server.restart();
 +
 +            assertTrue(timing.awaitLatch(dataUpdateLatch));
 +                       
 +            assertTrue(Arrays.equals(curator.getData().forPath(node.getActualPath()), updatedData));
 +        }
 +        finally
 +        {
 +            node.close();
 +        }    	
 +    }
++    
++    /**
+      * See CURATOR-190
+      * For protected nodes on reconnect the current protected name was passed to the create builder meaning that it got
+      * appended to the new protected node name. This meant that a new node got created on each reconnect.
+      * @throws Exception
+      */
+     @Test
+     public void testProtected() throws Exception
+     {
+         CuratorFramework curator = newCurator();
+ 
+         PersistentEphemeralNode node = new PersistentEphemeralNode(curator, PersistentEphemeralNode.Mode.PROTECTED_EPHEMERAL, PATH,
+                                                                    new byte[0]);
+         node.start();
+         try
+         {
+             node.waitForInitialCreate(timing.forWaiting().seconds(), TimeUnit.SECONDS);
+             assertNodeExists(curator, node.getActualPath());
+ 
+             server.restart();            
+             
+             curator.blockUntilConnected(5, TimeUnit.SECONDS);
+ 
+             assertNodeExists(curator, node.getActualPath());
+             
+             //There should only be a single child, the persisted ephemeral node
+             List<String> children = curator.getChildren().forPath(DIR);
+             assertFalse(children == null);
+             assertEquals(children.size(), 1);
+         }
+         finally
+         {
+             node.close();
+         }
+     }
  
      private void assertNodeExists(CuratorFramework curator, String path) throws Exception
      {