diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/CuratorCacheImpl.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/CuratorCacheImpl.java index 23268f5e6..3f4e81b5f 100644 --- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/CuratorCacheImpl.java +++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/cache/CuratorCacheImpl.java @@ -178,6 +178,11 @@ private void checkChildrenChanged(String fromPath, Stat oldStat, Stat newStat) { return; // children haven't changed } + if (newStat.getNumChildren() == 0) { + // The persistent recursive watcher reports children created after this stat was read. + return; + } + try { BackgroundCallback callback = (__, event) -> { if (event.getResultCode() == OK.intValue()) { diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestCuratorCache.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestCuratorCache.java index fe37d674a..7f5909475 100644 --- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestCuratorCache.java +++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/cache/TestCuratorCache.java @@ -108,6 +108,41 @@ public void initialized() { } } + @Test + public void testEmptyNodesAreCachedAndNewChildrenAreObserved() throws Exception { + try (CuratorFramework client = CuratorFrameworkFactory.newClient( + server.getConnectString(), timing.session(), timing.connection(), new RetryOneTime(1))) { + client.start(); + client.create().creatingParentsIfNeeded().forPath("/test/empty-one"); + client.create().forPath("/test/empty-two"); + + CountDownLatch initializedLatch = new CountDownLatch(1); + CountDownLatch childCreatedLatch = new CountDownLatch(1); + try (CuratorCache cache = CuratorCache.build(client, "/test")) { + cache.listenable() + .addListener(builder() + .forInitialized(initializedLatch::countDown) + .forCreates(data -> { + if ("/test/empty-one/child".equals(data.getPath())) { + childCreatedLatch.countDown(); + } + }) + .build()); + cache.start(); + + assertTrue(timing.awaitLatch(initializedLatch)); + assertEquals(3, cache.size()); + assertTrue(cache.get("/test/empty-one").isPresent()); + assertTrue(cache.get("/test/empty-two").isPresent()); + + client.create().forPath("/test/empty-one/child"); + assertTrue(timing.awaitLatch(childCreatedLatch)); + assertTrue(cache.get("/test/empty-one/child").isPresent()); + assertEquals(4, cache.size()); + } + } + } + @Test public void testListenerBuilder() throws Exception { try (CuratorFramework client = CuratorFrameworkFactory.newClient(