You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ap...@apache.org on 2015/07/03 23:52:25 UTC
[6/8] hbase git commit: HBASE-13925 Use zookeeper multi to clear
znodes in ZKProcedureUtil
HBASE-13925 Use zookeeper multi to clear znodes in ZKProcedureUtil
Signed-off-by: Andrew Purtell <ap...@apache.org>
Conflicts:
hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/003ca96e
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/003ca96e
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/003ca96e
Branch: refs/heads/branch-1.1
Commit: 003ca96eea7ad6410e13c11df04b54a46fb3cd02
Parents: db667e0
Author: Ashish Singhi <as...@huawei.com>
Authored: Thu Jun 18 18:50:21 2015 +0530
Committer: Andrew Purtell <ap...@apache.org>
Committed: Fri Jul 3 12:30:10 2015 -0700
----------------------------------------------------------------------
.../apache/hadoop/hbase/zookeeper/ZKUtil.java | 119 ++++++++++++++++---
.../hadoop/hbase/procedure/ZKProcedureUtil.java | 20 ++--
.../hadoop/hbase/zookeeper/TestZKMulti.java | 74 ++++++++++++
3 files changed, 184 insertions(+), 29 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/003ca96e/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
index 37bc822..d1e278d 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java
@@ -1386,25 +1386,7 @@ public class ZKUtil {
*/
public static void deleteNodeRecursively(ZooKeeperWatcher zkw, String node)
throws KeeperException {
- try {
- List<String> children = ZKUtil.listChildrenNoWatch(zkw, node);
- // the node is already deleted, so we just finish
- if (children == null) return;
-
- if(!children.isEmpty()) {
- for(String child : children) {
- deleteNodeRecursively(zkw, joinZNode(node, child));
- }
- }
-
- //Zookeeper Watches are one time triggers; When children of parent nodes are deleted
- //recursively, must set another watch, get notified of delete node
- if (zkw.getRecoverableZooKeeper().exists(node, zkw) != null){
- zkw.getRecoverableZooKeeper().delete(node, -1);
- }
- } catch(InterruptedException ie) {
- zkw.interruptedException(ie);
- }
+ deleteNodeRecursivelyMultiOrSequential(zkw, true, node);
}
/**
@@ -1479,6 +1461,69 @@ public class ZKUtil {
}
/**
+ * Delete the specified node and its children. This traverse the
+ * znode tree for listing the children and then delete
+ * these znodes including the parent using multi-update api or
+ * sequential based on the specified configurations.
+ * <p>
+ * Sets no watches. Throws all exceptions besides dealing with deletion of
+ * children.
+ * <p>
+ * If hbase.zookeeper.useMulti is true, use ZooKeeper's multi-update
+ * functionality. Otherwise, run the list of operations sequentially.
+ * <p>
+ * If all of the following are true:
+ * <ul>
+ * <li>runSequentialOnMultiFailure is true
+ * <li>hbase.zookeeper.useMulti is true
+ * </ul>
+ * on calling multi, we get a ZooKeeper exception that can be handled by a
+ * sequential call(*), we retry the operations one-by-one (sequentially).
+ *
+ * @param zkw
+ * - zk reference
+ * @param runSequentialOnMultiFailure
+ * - if true when we get a ZooKeeper exception that could retry the
+ * operations one-by-one (sequentially)
+ * @param pathRoots
+ * - path of the parent node(s)
+ * @throws KeeperException.NotEmptyException
+ * if node has children while deleting
+ * @throws KeeperException
+ * if unexpected ZooKeeper exception
+ * @throws IllegalArgumentException
+ * if an invalid path is specified
+ */
+ public static void deleteNodeRecursivelyMultiOrSequential(ZooKeeperWatcher zkw,
+ boolean runSequentialOnMultiFailure, String... pathRoots) throws KeeperException {
+ if (pathRoots == null || pathRoots.length <= 0) {
+ LOG.warn("Given path is not valid!");
+ return;
+ }
+ List<ZKUtilOp> ops = new ArrayList<ZKUtil.ZKUtilOp>();
+ for (String eachRoot : pathRoots) {
+ // Zookeeper Watches are one time triggers; When children of parent nodes are deleted
+ // recursively, must set another watch, get notified of delete node
+ List<String> children = listChildrenBFSAndWatchThem(zkw, eachRoot);
+ // Delete the leaves first and eventually get rid of the root
+ for (int i = children.size() - 1; i >= 0; --i) {
+ ops.add(ZKUtilOp.deleteNodeFailSilent(children.get(i)));
+ }
+ try {
+ if (zkw.getRecoverableZooKeeper().exists(eachRoot, zkw) != null) {
+ ops.add(ZKUtilOp.deleteNodeFailSilent(eachRoot));
+ }
+ } catch (InterruptedException e) {
+ zkw.interruptedException(e);
+ }
+ }
+ // atleast one element should exist
+ if (ops.size() > 0) {
+ multiOrSequential(zkw, ops, runSequentialOnMultiFailure);
+ }
+ }
+
+ /**
* BFS Traversal of all the children under path, with the entries in the list,
* in the same order as that of the traversal. Lists all the children without
* setting any watches.
@@ -1515,6 +1560,42 @@ public class ZKUtil {
}
/**
+ * BFS Traversal of all the children under path, with the entries in the list,
+ * in the same order as that of the traversal.
+ * Lists all the children and set watches on to them.
+ *
+ * @param zkw
+ * - zk reference
+ * @param znode
+ * - path of node
+ * @return list of children znodes under the path
+ * @throws KeeperException
+ * if unexpected ZooKeeper exception
+ */
+ private static List<String> listChildrenBFSAndWatchThem(ZooKeeperWatcher zkw, final String znode)
+ throws KeeperException {
+ Deque<String> queue = new LinkedList<String>();
+ List<String> tree = new ArrayList<String>();
+ queue.add(znode);
+ while (true) {
+ String node = queue.pollFirst();
+ if (node == null) {
+ break;
+ }
+ List<String> children = listChildrenAndWatchThem(zkw, node);
+ if (children == null) {
+ continue;
+ }
+ for (final String child : children) {
+ final String childPath = node + "/" + child;
+ queue.add(childPath);
+ tree.add(childPath);
+ }
+ }
+ return tree;
+ }
+
+ /**
* Represents an action taken by ZKUtil, e.g. createAndFailSilent.
* These actions are higher-level than ZKOp actions, which represent
* individual actions in the ZooKeeper API, like create.
http://git-wip-us.apache.org/repos/asf/hbase/blob/003ca96e/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/ZKProcedureUtil.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/ZKProcedureUtil.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/ZKProcedureUtil.java
index 9e0ef7f..8171218 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/ZKProcedureUtil.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/procedure/ZKProcedureUtil.java
@@ -267,29 +267,29 @@ public abstract class ZKProcedureUtil
}
public void clearChildZNodes() throws KeeperException {
- // TODO This is potentially racy since not atomic. update when we support zk that has multi
LOG.info("Clearing all procedure znodes: " + acquiredZnode + " " + reachedZnode + " "
+ abortZnode);
// If the coordinator was shutdown mid-procedure, then we are going to lose
// an procedure that was previously started by cleaning out all the previous state. Its much
// harder to figure out how to keep an procedure going and the subject of HBASE-5487.
- ZKUtil.deleteChildrenRecursively(watcher, acquiredZnode);
- ZKUtil.deleteChildrenRecursively(watcher, reachedZnode);
- ZKUtil.deleteChildrenRecursively(watcher, abortZnode);
+ ZKUtil.deleteChildrenRecursivelyMultiOrSequential(watcher, true, acquiredZnode, reachedZnode,
+ abortZnode);
}
public void clearZNodes(String procedureName) throws KeeperException {
- // TODO This is potentially racy since not atomic. update when we support zk that has multi
LOG.info("Clearing all znodes for procedure " + procedureName + "including nodes "
+ acquiredZnode + " " + reachedZnode + " " + abortZnode);
// Make sure we trigger the watches on these nodes by creating them. (HBASE-13885)
- ZKUtil.createAndFailSilent(watcher, getAcquiredBarrierNode(procedureName));
- ZKUtil.createAndFailSilent(watcher, getAbortZNode(procedureName));
+ String acquiredBarrierNode = getAcquiredBarrierNode(procedureName);
+ String reachedBarrierNode = getReachedBarrierNode(procedureName);
+ String abortZNode = getAbortZNode(procedureName);
- ZKUtil.deleteNodeRecursively(watcher, getAcquiredBarrierNode(procedureName));
- ZKUtil.deleteNodeRecursively(watcher, getReachedBarrierNode(procedureName));
- ZKUtil.deleteNodeRecursively(watcher, getAbortZNode(procedureName));
+ ZKUtil.createAndFailSilent(watcher, acquiredBarrierNode);
+ ZKUtil.createAndFailSilent(watcher, abortZNode);
+
+ ZKUtil.deleteNodeRecursivelyMultiOrSequential(watcher, true, acquiredBarrierNode,
+ reachedBarrierNode, abortZNode);
}
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/003ca96e/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKMulti.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKMulti.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKMulti.java
index cbf8f9e..9926e47 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKMulti.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/zookeeper/TestZKMulti.java
@@ -338,6 +338,80 @@ public class TestZKMulti {
}
}
+ /**
+ * Verifies that for the given root node, it should delete all the nodes recursively using
+ * multi-update api.
+ */
+ @Test(timeout = 60000)
+ public void testDeleteNodeRecursivelyMulti() throws Exception {
+ String parentZNode = "/testdeleteNodeRecursivelyMulti";
+ createZNodeTree(parentZNode);
+
+ ZKUtil.deleteNodeRecursively(zkw, parentZNode);
+ assertTrue("Parent znode should be deleted.", ZKUtil.checkExists(zkw, parentZNode) == -1);
+ }
+
+ /**
+ * Verifies that for the given root node, it should delete all the nodes recursively using
+ * normal sequential way.
+ */
+ @Test(timeout = 60000)
+ public void testDeleteNodeRecursivelySequential() throws Exception {
+ String parentZNode = "/testdeleteNodeRecursivelySequential";
+ createZNodeTree(parentZNode);
+ boolean useMulti = zkw.getConfiguration().getBoolean("hbase.zookeeper.useMulti", false);
+ zkw.getConfiguration().setBoolean("hbase.zookeeper.useMulti", false);
+ try {
+ // disables the multi-update api execution
+ ZKUtil.deleteNodeRecursively(zkw, parentZNode);
+ assertTrue("Parent znode should be deleted.", ZKUtil.checkExists(zkw, parentZNode) == -1);
+ } finally {
+ // sets back the multi-update api execution
+ zkw.getConfiguration().setBoolean("hbase.zookeeper.useMulti", useMulti);
+ }
+ }
+
+ @Test(timeout = 60000)
+ public void testDeleteNodeRecursivelyMultiOrSequential() throws Exception {
+ String parentZNode1 = "/testdeleteNode1";
+ String parentZNode2 = "/testdeleteNode2";
+ String parentZNode3 = "/testdeleteNode3";
+ createZNodeTree(parentZNode1);
+ createZNodeTree(parentZNode2);
+ createZNodeTree(parentZNode3);
+
+ ZKUtil.deleteNodeRecursivelyMultiOrSequential(zkw, false, parentZNode1, parentZNode2,
+ parentZNode3);
+ assertTrue("Parent znode 1 should be deleted.", ZKUtil.checkExists(zkw, parentZNode1) == -1);
+ assertTrue("Parent znode 2 should be deleted.", ZKUtil.checkExists(zkw, parentZNode2) == -1);
+ assertTrue("Parent znode 3 should be deleted.", ZKUtil.checkExists(zkw, parentZNode3) == -1);
+ }
+
+ @Test(timeout = 60000)
+ public void testDeleteChildrenRecursivelyMultiOrSequential() throws Exception {
+ String parentZNode1 = "/testdeleteChildren1";
+ String parentZNode2 = "/testdeleteChildren2";
+ String parentZNode3 = "/testdeleteChildren3";
+ createZNodeTree(parentZNode1);
+ createZNodeTree(parentZNode2);
+ createZNodeTree(parentZNode3);
+
+ ZKUtil.deleteChildrenRecursivelyMultiOrSequential(zkw, true, parentZNode1, parentZNode2,
+ parentZNode3);
+
+ assertTrue("Wrongly deleted parent znode 1!", ZKUtil.checkExists(zkw, parentZNode1) > -1);
+ List<String> children = zkw.getRecoverableZooKeeper().getChildren(parentZNode1, false);
+ assertTrue("Failed to delete child znodes of parent znode 1!", 0 == children.size());
+
+ assertTrue("Wrongly deleted parent znode 2!", ZKUtil.checkExists(zkw, parentZNode2) > -1);
+ children = zkw.getRecoverableZooKeeper().getChildren(parentZNode2, false);
+ assertTrue("Failed to delete child znodes of parent znode 1!", 0 == children.size());
+
+ assertTrue("Wrongly deleted parent znode 3!", ZKUtil.checkExists(zkw, parentZNode3) > -1);
+ children = zkw.getRecoverableZooKeeper().getChildren(parentZNode3, false);
+ assertTrue("Failed to delete child znodes of parent znode 1!", 0 == children.size());
+ }
+
private void createZNodeTree(String rootZNode) throws KeeperException,
InterruptedException {
List<Op> opList = new ArrayList<Op>();