diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java index eeae94b58028..38158e5fe563 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/ZKPermissionWatcher.java @@ -185,25 +185,28 @@ public void run() { public void nodeChildrenChanged(final String path) { waitUntilStarted(); if (path.equals(aclZNode)) { - try { - final List nodeList = - ZKUtil.getChildDataAndWatchForNewChildren(watcher, aclZNode); - // preempt any existing nodeChildrenChanged event processing - if (childrenChangedFuture != null && !childrenChangedFuture.isDone()) { - boolean cancelled = childrenChangedFuture.cancel(true); - if (!cancelled) { - // task may have finished between our check and attempted cancel, this is fine. - if (! childrenChangedFuture.isDone()) { - LOG.warn("Could not cancel processing node children changed event, " + - "please file a JIRA and attach logs if possible."); - } + // preempt any existing nodeChildrenChanged event processing + if (childrenChangedFuture != null && !childrenChangedFuture.isDone()) { + boolean cancelled = childrenChangedFuture.cancel(true); + if (!cancelled) { + // task may have finished between our check and attempted cancel, this is fine. + if (!childrenChangedFuture.isDone()) { + LOG.warn("Could not cancel processing node children changed event, " + + "please file a JIRA and attach logs if possible."); } } - childrenChangedFuture = asyncProcessNodeUpdate(() -> refreshNodes(nodeList)); - } catch (KeeperException ke) { - LOG.error("Error reading data from zookeeper for path "+path, ke); - watcher.abort("ZooKeeper error get node children for path "+path, ke); } + childrenChangedFuture = asyncProcessNodeUpdate(() -> { + try { + final List nodeList = + ZKUtil.getChildDataAndWatchForNewChildren(watcher, aclZNode, false); + refreshNodes(nodeList); + } catch (KeeperException ke) { + String msg = "ZooKeeper error while reading node children data for path " + path; + LOG.error(msg, ke); + watcher.abort(msg, ke); + } + }); } } diff --git a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java index 3f0f93f63213..19d11d0704fc 100644 --- a/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java +++ b/hbase-zookeeper/src/main/java/org/apache/hadoop/hbase/zookeeper/ZKUtil.java @@ -634,9 +634,24 @@ public static int getNumberOfChildren(ZKWatcher zkw, String znode) * @return data of the specified znode, or null * @throws KeeperException if unexpected zookeeper exception */ - public static byte [] getDataAndWatch(ZKWatcher zkw, String znode) + public static byte[] getDataAndWatch(ZKWatcher zkw, String znode) throws KeeperException { + return getDataInternal(zkw, znode, null, true, true); + } + + /** + * Get the data at the specified znode and set a watch. + * Returns the data and sets a watch if the node exists. Returns null and no + * watch is set if the node does not exist or there is an exception. + * + * @param zkw zk reference + * @param znode path of node + * @param throwOnInterrupt if false then just interrupt the thread, do not throw exception + * @return data of the specified znode, or null + * @throws KeeperException if unexpected zookeeper exception + */ + public static byte[] getDataAndWatch(ZKWatcher zkw, String znode, boolean throwOnInterrupt) throws KeeperException { - return getDataInternal(zkw, znode, null, true); + return getDataInternal(zkw, znode, null, true, throwOnInterrupt); } /** @@ -653,11 +668,11 @@ public static int getNumberOfChildren(ZKWatcher zkw, String znode) */ public static byte[] getDataAndWatch(ZKWatcher zkw, String znode, Stat stat) throws KeeperException { - return getDataInternal(zkw, znode, stat, true); + return getDataInternal(zkw, znode, stat, true, true); } - private static byte[] getDataInternal(ZKWatcher zkw, String znode, Stat stat, - boolean watcherSet) + private static byte[] getDataInternal(ZKWatcher zkw, String znode, Stat stat, boolean watcherSet, + boolean throwOnInterrupt) throws KeeperException { try { byte [] data = zkw.getRecoverableZooKeeper().getData(znode, zkw, stat); @@ -675,7 +690,11 @@ private static byte[] getDataInternal(ZKWatcher zkw, String znode, Stat stat, return null; } catch (InterruptedException e) { LOG.warn(zkw.prefix("Unable to get data of znode " + znode), e); - zkw.interruptedException(e); + if (throwOnInterrupt) { + zkw.interruptedException(e); + } else { + zkw.interruptedExceptionNoThrow(e, true); + } return null; } } @@ -735,15 +754,43 @@ private static byte[] getDataInternal(ZKWatcher zkw, String znode, Stat stat, * @deprecated Unused */ @Deprecated + public static List getChildDataAndWatchForNewChildren(ZKWatcher zkw, String baseNode) + throws KeeperException { + return getChildDataAndWatchForNewChildren(zkw, baseNode, true); + } + + /** + * Returns the date of child znodes of the specified znode. Also sets a watch on + * the specified znode which will capture a NodeDeleted event on the specified + * znode as well as NodeChildrenChanged if any children of the specified znode + * are created or deleted. + * + * Returns null if the specified node does not exist. Otherwise returns a + * list of children of the specified node. If the node exists but it has no + * children, an empty list will be returned. + * + * @param zkw zk reference + * @param baseNode path of node to list and watch children of + * @param throwOnInterrupt if true then just interrupt the thread, do not throw exception + * @return list of data of children of the specified node, an empty list if the node + * exists but has no children, and null if the node does not exist + * @throws KeeperException if unexpected zookeeper exception + * @deprecated Unused + */ + @Deprecated public static List getChildDataAndWatchForNewChildren( - ZKWatcher zkw, String baseNode) throws KeeperException { + ZKWatcher zkw, String baseNode, boolean throwOnInterrupt) throws KeeperException { List nodes = ZKUtil.listChildrenAndWatchForNewChildren(zkw, baseNode); if (nodes != null) { List newNodes = new ArrayList<>(); for (String node : nodes) { + if (Thread.interrupted()) { + // Partial data should not be processed. Cancel processing by sending empty list. + return Collections.emptyList(); + } String nodePath = ZNodePaths.joinZNode(baseNode, node); - byte[] data = ZKUtil.getDataAndWatch(zkw, nodePath); + byte[] data = ZKUtil.getDataAndWatch(zkw, nodePath, throwOnInterrupt); newNodes.add(new NodeAndData(nodePath, data)); } return newNodes;