kaisun2000 commented on a change in pull request #1035:
URL: https://github.com/apache/helix/pull/1035#discussion_r435079661



##########
File path: 
zookeeper-api/src/main/java/org/apache/helix/zookeeper/zkclient/ZkClient.java
##########
@@ -1865,17 +1934,24 @@ public Object call() throws Exception {
    *         exist.
    */
   public List<String> watchForChilds(final String path) {
+    return watchForChilds(path, false);
+  }
+
+  private List<String> watchForChilds(final String path, boolean 
skipWatchingNodeNotExist) {
     if (_zookeeperEventThread != null && Thread.currentThread() == 
_zookeeperEventThread) {
       throw new IllegalArgumentException("Must not be done in the zookeeper 
event thread.");
     }
     return retryUntilConnected(new Callable<List<String>>() {
       @Override
       public List<String> call() throws Exception {
-        exists(path, true);
+        if (!skipWatchingNodeNotExist) {

Review comment:
       @dasahcc, this part is kind of complicated. Seems you are concerned that 
there are some insistent state. But fortunately, we can reason this way, which 
covers all the cases.
   
   "if node does not exist and skipWatchingNodeNotExist is true", in some case, 
we do need to install data watch if we expect the parent node is to be created. 
   
   Let us look at the life cycle of CallbackHandler (CB) to see all the cases.
   
   - INIT of CallbackHandler when parent node note existing. CB first installs 
data(exists) watch to this parent node. Then when the node is created, CB got 
notification of creation. Then CB will read all of the children (installing 
child watch at this time) and install data watch for each children. 
   
   - INIT of CallbackHandler when parent node exists. CB still first installs 
data watch to this parent node. And the use getData() to get the list of 
children and install data watch for each children. 
   
   Not the above two code paths are the same. They are started from CB's 
subscribeForChanges() --> subscribeChildChange(INIT) --> 
_zkClient.subscribeChildChanges( skipWatchingNodeNotExist as false) --> 
watchForChild(skipWatchingNodeNotExist as false)
   
   This would trigger both exists() and getData(). This is exactly what we 
want, because in the first case, you need exists() if the parent path does not 
exists as explained before. 
   
   Then your next question can be why for the second case I need exists() if 
the path does exist? The is because later, if the paren path is removed, you 
want to remove the CB from ZkHelixManager too. With data watch, you are 
guaranteed a notification of handleChildChange(). Here the 
`_manager.removeListener(_propertyKey, _listener);` code path would be trigger. 
This is exactly what happens when current state parent node moves due to new 
session established in participant code. 
   
   So above discussion addressed the basic life cycle of CallbackHandler. 
   
   The left case is about what happens when normal notification of CALLBACK 
type.
   This is triggered by adding or deleting a current state node under the 
parent path. At this time, the code path is: 
   
   subscribeForChanges() --> subscribeChildChange(CALLBACK) --> 
_zkClient.subscribeChildChanges( skipWatchingNodeNotExist as true) --> 
watchForChild(skipWatchingNodeNotExist as true)
   
   Here, watchForChild will not install data watch for parent node, only use 
getData to install child watch and return list of children. Then 
CallbackHandler would install data watch for each children. 
   
   So here, if you think about it, there is no in-consistant case of installing 
part of the parent child watch, but not child data watch. 
   
   Note, we should not install data watch to parent node here at CALLBACK stage 
for the reason that the removing of parent node is async to this whole process. 
That can be the source of leaking once the INIT phase passed, as I explained in 
the doc.
   
   The above discussion exhausts all the cases of CallbackHandler life cycle. 
Hope this would give people a clear idea of how we reason it. 
   




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
[email protected]



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to