zookeeper source code analysis - event monitoring Watcher

Posted by RyanSF07 on Tue, 10 Dec 2019 13:50:09 +0100

Next, I went on to analyze the source code of the Watcher related classes.

ClientWatchManager

public Set<Watcher> materialize(Watcher.Event.KeeperState state,
        Watcher.Event.EventType type, String path);

This interface has only one method and needs to be implemented. This method represents the Watcher collection to be notified when an event occurs, which may be an empty collection.

ZKWatchManager

1. ZKWatchManager is the internal class of ZooKeeper, which implements ClientWatchManager.
2. ZKWatchManager defines three Map key value pairs. The key is the node path and the value is Watcher. It respectively corresponds to the Watcher of data change, whether the node has a Watcher or not, and the Watcher of child node change.

static class ZKWatchManager implements ClientWatchManager {
        //watchers of data change
        private final Map<String, Set<Watcher>> dataWatches =
            new HashMap<String, Set<Watcher>>();
        //watchers whether nodes exist or not
        private final Map<String, Set<Watcher>> existWatches =
            new HashMap<String, Set<Watcher>>();
        //watchers with children changing
        private final Map<String, Set<Watcher>> childWatches =
            new HashMap<String, Set<Watcher>>();

3. Material method

This method returns the Watcher collection to be notified after the event. In this method, the corresponding event type will be determined first according to the EventType type, and then the corresponding operation will be made according to the different event types. For example, for the None type, i.e. there is no event, the Watcher corresponding to the clientPath will be deleted from the three key value pairs, and then the remaining Watcher set will be added to the result set; for the NodeDataChanged and nodechreated events , which removes the Watcher corresponding to the clientPath from dataWatches and existWatches, and then adds the remaining Watcher collection to the result collection.

@Override
        public Set<Watcher> materialize(Watcher.Event.KeeperState state,
                                        Watcher.Event.EventType type,
                                        String clientPath)
        {
            //Return result set
            Set<Watcher> result = new HashSet<Watcher>();

            switch (type) {//Event type
            case None://No type
                //Add default watcher
                result.add(defaultWatcher);
                //Determine whether to clear according to whether the status of disableAutoWatchReset and Zookeeper is synchronous connection
                boolean clear = disableAutoWatchReset && state != Watcher.Event.KeeperState.SyncConnected;
                //Operate on three different watchermaps
                synchronized(dataWatches) {
                    for(Set<Watcher> ws: dataWatches.values()) {
                        // Add to result set
                        result.addAll(ws);
                    }
                    if (clear) { // Need to clear
                        dataWatches.clear();
                    }
                }

                synchronized(existWatches) {
                    for(Set<Watcher> ws: existWatches.values()) {
                        result.addAll(ws);
                    }
                    if (clear) {
                        existWatches.clear();
                    }
                }

                synchronized(childWatches) {
                    for(Set<Watcher> ws: childWatches.values()) {
                        result.addAll(ws);
                    }
                    if (clear) {
                        childWatches.clear();
                    }
                }

                return result;
            case NodeDataChanged:// Node data changes
            case NodeCreated:// Create node
                synchronized (dataWatches) {
                    //Remove the Watcher corresponding to the clientPath and add all to the result collection
                    addTo(dataWatches.remove(clientPath), result);
                }
                synchronized (existWatches) {
                    //Remove the Watcher corresponding to the clientPath and add all to the result collection
                    addTo(existWatches.remove(clientPath), result);
                }
                break;
            case NodeChildrenChanged: // Node child changes
                synchronized (childWatches) {
                    // Remove the Watcher corresponding to the clientPath and add all to the result collection
                    addTo(childWatches.remove(clientPath), result);
                }
                break;
            case NodeDeleted:// Delete node
                synchronized (dataWatches) {
                    // Remove the Watcher corresponding to the clientPath and add all to the result collection
                    addTo(dataWatches.remove(clientPath), result);
                }
                // XXX This shouldn't be needed, but just in case
                synchronized (existWatches) {
                    Set<Watcher> list = existWatches.remove(clientPath);
                    if (list != null) {
                        addTo(list, result);
                        LOG.warn("We are triggering an exists watch for delete! Shouldn't happen!");
                    }
                }
                synchronized (childWatches) {
                    //Remove the Watcher corresponding to the clientPath and add all to the result collection
                    addTo(childWatches.remove(clientPath), result);
                }
                break;
            default:
                String msg = "Unhandled watch event type " + type
                    + " with state " + state + " on path " + clientPath;
                LOG.error(msg);
                throw new RuntimeException(msg);
            }

            return result;
        }
    }

Topics: Java Zookeeper