Index: hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java =================================================================== --- hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java (revision 1574791) +++ hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/RecoverableZooKeeper.java (working copy) @@ -720,4 +720,36 @@ public String getIdentifier() { return identifier; } + + /** + * BFS Traversal of all the children under path, with the entries in the list, in the same order as + * that of the traversal. This is an idempotent operation. Retry before throwing exception + * @return List of children znodes under the path + */ + public List getAllChildrenBFS(String path) throws KeeperException, InterruptedException { + TraceScope traceScope = null; + try { + traceScope = Trace.startSpan("RecoverableZookeeper.getAllChildrenBFS"); + RetryCounter retryCounter = retryCounterFactory.create(); + while (true) { + try { + return org.apache.zookeeper.ZKUtil.listSubTreeBFS(zk, path); + } catch (KeeperException e) { + switch (e.code()) { + case CONNECTIONLOSS: + case SESSIONEXPIRED: + case OPERATIONTIMEOUT: + retryOrThrow(retryCounter, e, "getAllChildrenBFS"); + break; + + default: + throw e; + } + } + retryCounter.sleepUntilNextRetry(); + } + } finally { + if (traceScope != null) traceScope.close(); + } + } } Index: hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java =================================================================== --- hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java (revision 1574791) +++ hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java (working copy) @@ -60,10 +60,12 @@ import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.KeeperException.NoNodeException; import org.apache.zookeeper.Op; +import org.apache.zookeeper.OpResult; import org.apache.zookeeper.Watcher; import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.client.ZooKeeperSaslClient; +import org.apache.zookeeper.common.PathUtils; import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; import org.apache.zookeeper.proto.CreateRequest; @@ -1328,20 +1330,45 @@ } /** - * Delete all the children of the specified node but not the node itself. - * - * Sets no watches. Throws all exceptions besides dealing with deletion of - * children. + * Delete all the children of the specified node but not the node itself. Sets no watches. Throws + * all exceptions besides dealing with deletion of children. + * @throws InterruptedException */ public static void deleteChildrenRecursively(ZooKeeperWatcher zkw, String node) - throws KeeperException { - List children = ZKUtil.listChildrenNoWatch(zkw, node); - if (children == null || children.isEmpty()) return; - for(String child : children) { - deleteNodeRecursively(zkw, joinZNode(node, child)); + throws KeeperException, InterruptedException { + List opList = prepareOpList(zkw, node); + zkw.getRecoverableZooKeeper().multi(opList); + } + + /** + * Delete all the children of the specified nodes but not the nodes itself. Sets no watches. Throws + * all exceptions besides dealing with deletion of children. + * @throws InterruptedException + */ + public static List multiDeleteRecursive(ZooKeeperWatcher zkw, String... pathRoots) + throws InterruptedException, KeeperException { + if (pathRoots == null || pathRoots.length <= 0) { + return new ArrayList(); } + List opList = new ArrayList(); + for (String eachPath : pathRoots) { + List eachRoot = prepareOpList(zkw, eachPath); + opList.addAll(eachRoot); + } + return zkw.getRecoverableZooKeeper().multi(opList); } + private static List prepareOpList(ZooKeeperWatcher zkw, final String path) + throws InterruptedException, KeeperException { + PathUtils.validatePath(path); + List tree = zkw.getRecoverableZooKeeper().getAllChildrenBFS(path); + List opList = new ArrayList(tree.size()); + for (int i = tree.size() - 1; i > 0; --i) { + // Delete the leaves first and eventually get rid of the root + opList.add(Op.delete(tree.get(i), -1)); + } + return opList; + } /** * Represents an action taken by ZKUtil, e.g. createAndFailSilent. * These actions are higher-level than ZKOp actions, which represent