Uploaded image for project: 'ZooKeeper'
  1. ZooKeeper
  2. ZOOKEEPER-4466

Support different watch modes on same path

    XMLWordPrintableJSON

Details

    • Hide
      Previously, there is only one watch mode per path and session. Later watch will ruin existing watch. For example, getData after AddWatchMode::Persistent will result in one-time data watch and persistent children watch. This is not our intend and it fears clients from arbitrary watch. So we decide to support multiple different watch modes on one path in one session. This way, users of client can watch whatever paths in whatever modes. They will not ruin each other.
      Show
      Previously, there is only one watch mode per path and session. Later watch will ruin existing watch. For example, getData after AddWatchMode::Persistent will result in one-time data watch and persistent children watch. This is not our intend and it fears clients from arbitrary watch. So we decide to support multiple different watch modes on one path in one session. This way, users of client can watch whatever paths in whatever modes. They will not ruin each other.

    Description

      I used to think watchers of different modes are orthogonal. I found there are not, when I wrote tests for unfinished rust client. And I wrote test cases in java and confirmed.

      I copied test case here for evaluation. You also clone from my fork.

          // zookeeper-server/src/test/java/org/apache/zookeeper/test/PersistentRecursiveWatcherTest.java
      
          @Test
          public void testPathOverlapWithStandardWatcher() throws Exception {
              try (ZooKeeper zk = createClient(new CountdownWatcher(), hostPort)) {
                  CountDownLatch nodeCreated = new CountDownLatch(1);
                  zk.addWatch("/a", persistentWatcher, PERSISTENT_RECURSIVE);
                  zk.exists("/a", event -> nodeCreated.countDown());
      
                  zk.create("/a", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                  zk.create("/a/b", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                  zk.delete("/a/b", -1);
                  zk.delete("/a", -1);
      
                  assertEvent(events, Watcher.Event.EventType.NodeCreated, "/a");
                  assertEvent(events, Watcher.Event.EventType.NodeCreated, "/a/b");
                  assertEvent(events, Watcher.Event.EventType.NodeDeleted, "/a/b");
                  assertEvent(events, Watcher.Event.EventType.NodeDeleted, "/a");
      
                  assertTrue(nodeCreated.await(5, TimeUnit.SECONDS));
              }
          }
      
          @Test
          public void testPathOverlapWithPersistentWatcher() throws Exception {
              try (ZooKeeper zk = createClient(new CountdownWatcher(), hostPort)) {
                  zk.addWatch("/a", persistentWatcher, PERSISTENT_RECURSIVE);
                  zk.addWatch("/a/b", event -> {}, PERSISTENT);
                  zk.create("/a", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                  zk.create("/a/b", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                  zk.create("/a/b/c", new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
                  zk.delete("/a/b/c", -1);
                  zk.delete("/a/b", -1);
                  zk.delete("/a", -1);
                  assertEvent(events, Watcher.Event.EventType.NodeCreated, "/a");
                  assertEvent(events, Watcher.Event.EventType.NodeCreated, "/a/b");
                  assertEvent(events, Watcher.Event.EventType.NodeCreated, "/a/b/c");
                  assertEvent(events, Watcher.Event.EventType.NodeDeleted, "/a/b/c");
                  assertEvent(events, Watcher.Event.EventType.NodeDeleted, "/a/b");
                  assertEvent(events, Watcher.Event.EventType.NodeDeleted, "/a");
              }
          }
      

      I skimmed the code and found two possible causes:

      1. ZKWatchManager.materialize materializes all persistent watchers(include recursive ones) for NodeChildrenChanged event.
      2. WatcherModeManager trackes only one watcher mode.

      Attachments

        Issue Links

          Activity

            People

              kezhuw Kezhu Wang
              kezhuw Kezhu Wang
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 3h 10m
                  3h 10m