@SuppressWarnings("unchecked") private static void visitSubTreeDFSHelper(ZooKeeper zk, final String path, boolean watch, StringCallback cb) throws KeeperException, InterruptedException { // we've already validated, therefore if the path is of length 1 it's the root final boolean isRoot = path.length() == 1; try { List<String> children = zk.getChildren(path, watch, null); Collections.sort(children); for (String child : children) { String childPath = (isRoot ? path : path + "/") + child; cb.processResult(Code.OK.intValue(), childPath, null, child); } for (String child : children) { String childPath = (isRoot ? path : path + "/") + child; visitSubTreeDFSHelper(zk, childPath, watch, cb); } } catch (KeeperException.NoNodeException e) { // Handle race condition where a node is listed // but gets deleted before it can be queried return; // ignore } } }
/** * Visits the subtree with root as given path and calls the passed callback with each znode * found during the search. It performs a depth-first, pre-order traversal of the tree. * <p> * <b>Important:</b> This is <i>not an atomic snapshot</i> of the tree ever, but the * state as it exists across multiple RPCs from zkClient to the ensemble. * For practical purposes, it is suggested to bring the clients to the ensemble * down (i.e. prevent writes to pathRoot) to 'simulate' a snapshot behavior. */ public static void visitSubTreeDFS(ZooKeeper zk, final String path, boolean watch, StringCallback cb) throws KeeperException, InterruptedException { PathUtils.validatePath(path); zk.getData(path, watch, null); cb.processResult(Code.OK.intValue(), path, null, path); visitSubTreeDFSHelper(zk, path, watch, cb); }