Merge branch 'master' into CURATOR-3.0
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/ChildData.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/ChildData.java
index 21e0bc4..e3c60cf 100644
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/ChildData.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/ChildData.java
@@ -20,20 +20,19 @@
 
 import org.apache.zookeeper.data.Stat;
 import java.util.Arrays;
-import java.util.concurrent.atomic.AtomicReference;
 import org.apache.curator.utils.PathUtils;
 
 public class ChildData implements Comparable<ChildData>
 {
-    private final String    path;
-    private final Stat      stat;
-    private final AtomicReference<byte[]>    data;
+    private final String path;
+    private final Stat stat;
+    private final byte[] data;
 
     public ChildData(String path, Stat stat, byte[] data)
     {
         this.path = PathUtils.validatePath(path);
         this.stat = stat;
-        this.data = new AtomicReference<byte[]>(data);
+        this.data = data;
     }
 
     /**
@@ -71,7 +70,7 @@
 
         ChildData childData = (ChildData)o;
 
-        if ( !Arrays.equals(data.get(), childData.data.get()) )
+        if ( !Arrays.equals(data, childData.data) )
         {
             return false;
         }
@@ -92,7 +91,7 @@
     {
         int result = path != null ? path.hashCode() : 0;
         result = 31 * result + (stat != null ? stat.hashCode() : 0);
-        result = 31 * result + (data != null ? Arrays.hashCode(data.get()) : 0);
+        result = 31 * result + Arrays.hashCode(data);
         return result;
     }
 
@@ -126,12 +125,7 @@
      */
     public byte[] getData()
     {
-        return data.get();
-    }
-
-    void clearData()
-    {
-        data.set(null);
+        return data;
     }
 
     @Override
@@ -140,7 +134,7 @@
         return "ChildData{" +
             "path='" + path + '\'' +
             ", stat=" + stat +
-            ", data=" + Arrays.toString(data.get()) +
+            ", data=" + Arrays.toString(data) +
             '}';
     }
 }
diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
index 858f94a..1ff3f38 100644
--- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
+++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/PathChildrenCache.java
@@ -445,7 +445,10 @@
         {
             if ( (ifVersion < 0) || (ifVersion == data.getStat().getVersion()) )
             {
-                data.clearData();
+                if ( data.getData() != null )
+                {
+                    currentData.replace(fullPath, data, new ChildData(data.getPath(), data.getStat(), null));
+                }
                 return true;
             }
         }
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 a2f0e86..0ee1832 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
@@ -221,8 +221,7 @@
         final AtomicReference<NodeState> nodeState = new AtomicReference<NodeState>(NodeState.PENDING);
         final TreeNode parent;
         final String path;
-        final AtomicReference<Stat> stat = new AtomicReference<Stat>();
-        final AtomicReference<byte[]> data = new AtomicReference<byte[]>();
+        final AtomicReference<ChildData> childData = new AtomicReference<ChildData>();
         final AtomicReference<ConcurrentMap<String, TreeNode>> children = new AtomicReference<ConcurrentMap<String, TreeNode>>();
         final int depth;
 
@@ -303,10 +302,8 @@
 
         void wasDeleted() throws Exception
         {
-            Stat oldStat = stat.getAndSet(null);
-            byte[] oldData = data.getAndSet(null);
+            ChildData oldChildData = childData.getAndSet(null);
             client.watches().remove(this).ofType(WatcherType.Any).locally().inBackground().forPath(path);
-
             ConcurrentMap<String, TreeNode> childMap = children.getAndSet(null);
             if ( childMap != null )
             {
@@ -326,7 +323,7 @@
             NodeState oldState = nodeState.getAndSet(NodeState.DEAD);
             if ( oldState == NodeState.LIVE )
             {
-                publishEvent(TreeCacheEvent.Type.NODE_REMOVED, new ChildData(path, oldStat, oldData));
+                publishEvent(TreeCacheEvent.Type.NODE_REMOVED, oldChildData);
             }
 
             if ( parent == null )
@@ -391,12 +388,12 @@
             case CHILDREN:
                 if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
                 {
-                    Stat oldStat = stat.get();
-                    if ( oldStat != null && oldStat.getMzxid() == newStat.getMzxid() )
+                    ChildData oldChildData = childData.get();
+                    if ( oldChildData != null && oldChildData.getStat().getMzxid() == newStat.getMzxid() )
                     {
-                        // Only update stat if mzxid is different, otherwise we might obscure
+                        // Only update stat if mzxid is same, otherwise we might obscure
                         // GET_DATA event updates.
-                        stat.set(newStat);
+                        childData.compareAndSet(oldChildData, new ChildData(oldChildData.getPath(), newStat, oldChildData.getData()));
                     }
 
                     if ( event.getChildren().isEmpty() )
@@ -443,22 +440,27 @@
             case GET_DATA:
                 if ( event.getResultCode() == KeeperException.Code.OK.intValue() )
                 {
+                    ChildData toPublish = new ChildData(event.getPath(), newStat, event.getData());
+                    ChildData oldChildData;
                     if ( cacheData )
                     {
-                        data.set(event.getData());
-                    }
-
-                    Stat oldStat = stat.getAndSet(newStat);
-                    NodeState oldState = nodeState.getAndSet(NodeState.LIVE);
-                    if ( oldState != NodeState.LIVE )
-                    {
-                        publishEvent(TreeCacheEvent.Type.NODE_ADDED, new ChildData(event.getPath(), newStat, event.getData()));
+                        oldChildData = childData.getAndSet(toPublish);
                     }
                     else
                     {
-                        if ( oldStat == null || oldStat.getMzxid() != newStat.getMzxid() )
+                        oldChildData = childData.getAndSet(new ChildData(event.getPath(), newStat, null));
+                    }
+
+                    NodeState oldState = nodeState.getAndSet(NodeState.LIVE);
+                    if ( oldState != NodeState.LIVE )
+                    {
+                        publishEvent(TreeCacheEvent.Type.NODE_ADDED, toPublish);
+                    }
+                    else
+                    {
+                        if ( oldChildData == null || oldChildData.getStat().getMzxid() != newStat.getMzxid() )
                         {
-                            publishEvent(TreeCacheEvent.Type.NODE_UPDATED, new ChildData(event.getPath(), newStat, event.getData()));
+                            publishEvent(TreeCacheEvent.Type.NODE_UPDATED, toPublish);
                         }
                     }
                 }
@@ -691,9 +693,9 @@
             for ( Map.Entry<String, TreeNode> entry : map.entrySet() )
             {
                 TreeNode childNode = entry.getValue();
-                ChildData childData = new ChildData(childNode.path, childNode.stat.get(), childNode.data.get());
+                ChildData childData = childNode.childData.get();
                 // Double-check liveness after retreiving data.
-                if ( childNode.nodeState.get() == NodeState.LIVE )
+                if ( childData != null && childNode.nodeState.get() == NodeState.LIVE )
                 {
                     builder.put(entry.getKey(), childData);
                 }
@@ -720,7 +722,7 @@
         {
             return null;
         }
-        ChildData result = new ChildData(node.path, node.stat.get(), node.data.get());
+        ChildData result = node.childData.get();
         // Double-check liveness after retreiving data.
         return node.nodeState.get() == NodeState.LIVE ? result : null;
     }