This is an automated email from the ASF dual-hosted git repository. ctubbsii pushed a commit to branch single-node-props in repository https://gitbox.apache.org/repos/asf/accumulo.git
commit 292453bf49eb4053c300aa634d6bf061726f30de Author: Christopher Tubbs <ctubb...@apache.org> AuthorDate: Wed Apr 27 15:51:56 2022 -0400 Minor enhancements to ZK utilities --- .../apache/accumulo/fate/zookeeper/ZooReader.java | 15 ++++++ .../accumulo/fate/zookeeper/ZooReaderWriter.java | 56 ++++++++++++++++++---- .../apache/accumulo/fate/zookeeper/ZooUtil.java | 38 +++++++++++++++ 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java b/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java index 4165d3faa7..2aa996b613 100644 --- a/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java +++ b/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReader.java @@ -66,6 +66,16 @@ public class ZooReader { return RETRY_FACTORY; } + /** + * Returns the requested ZooKeeper client session timeout. The client may negotiate a different + * value and the actual negotiated value may change after a re-connect. + * + * @return the timeout in milliseconds + */ + public int getSessionTimeout() { + return timeout; + } + public byte[] getData(String zPath) throws KeeperException, InterruptedException { return retryLoop(zk -> zk.getData(zPath, null, null)); } @@ -79,6 +89,11 @@ public class ZooReader { return retryLoop(zk -> zk.getData(zPath, requireNonNull(watcher), null)); } + public byte[] getData(String zPath, Watcher watcher, Stat stat) + throws KeeperException, InterruptedException { + return retryLoop(zk -> zk.getData(zPath, requireNonNull(watcher), requireNonNull(stat))); + } + public Stat getStatus(String zPath) throws KeeperException, InterruptedException { return retryLoop(zk -> zk.exists(zPath, null)); } diff --git a/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java b/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java index 8e79007cc1..58c5671f50 100644 --- a/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java +++ b/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooReaderWriter.java @@ -134,6 +134,33 @@ public class ZooReaderWriter extends ZooReader { e -> e.code() == Code.NONODE && policy == NodeExistsPolicy.OVERWRITE); } + /** + * Overwrite a persistent node if the data version matches. + * + * @param zPath + * the zookeeper path + * @param data + * the byte array data + * @param expectedVersion + * the expected data version of the zookeeper node. + * @return true if the data was set, false if the version does not match expected. + * @throws KeeperException + * if a KeeperException occurs (no node most likely) + * @throws InterruptedException + * if the zookeeper write is interrupted. + */ + public boolean overwritePersistentData(String zPath, byte[] data, final int expectedVersion) + throws KeeperException, InterruptedException { + return retryLoop(zk -> { + try { + zk.setData(zPath, data, expectedVersion); + return true; + } catch (KeeperException.BadVersionException ex) { + return false; + } + }); + } + /** * Create a persistent sequential node with the default ACL * @@ -242,15 +269,28 @@ public class ZooReaderWriter extends ZooReader { * Delete the specified node, and ignore NONODE exceptions. */ public void delete(String path) throws KeeperException, InterruptedException { - retryLoop(zk -> { - try { - zk.delete(path, -1); - } catch (KeeperException e) { - // ignore the case where the node doesn't exist - if (e.code() != Code.NONODE) { - throw e; - } + try { + deleteStrict(path, -1); + } catch (KeeperException e) { + if (e.code() != Code.NONODE) { + throw e; } + } + } + + /** + * Delete the specified node if the version matches the provided version. All underlying + * exceptions are thrown back to the caller. + * + * @param path + * the path of the ZooKeeper node. + * @param version + * the expected version of the ZooKeeper node. + */ + public void deleteStrict(final String path, final int version) + throws KeeperException, InterruptedException { + retryLoop(zk -> { + zk.delete(path, version); return null; }); } diff --git a/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java b/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java index 82c3a1658b..6f6431ede1 100644 --- a/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java +++ b/core/src/main/java/org/apache/accumulo/fate/zookeeper/ZooUtil.java @@ -21,6 +21,10 @@ package org.apache.accumulo.fate.zookeeper; import static java.nio.charset.StandardCharsets.UTF_8; import java.math.BigInteger; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; @@ -32,6 +36,7 @@ import org.apache.zookeeper.ZooDefs.Ids; import org.apache.zookeeper.ZooDefs.Perms; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; +import org.apache.zookeeper.data.Stat; public class ZooUtil { @@ -43,6 +48,10 @@ public class ZooUtil { SKIP, CREATE, FAIL } + // used for zookeeper stat print formatting + private static final DateTimeFormatter fmt = + DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss 'UTC' yyyy"); + public static class LockID { public long eid; public String path; @@ -124,6 +133,35 @@ public class ZooUtil { } } + /** + * For debug: print the ZooKeeper Stat with value labels for a more user friendly string. The + * format matches the zookeeper cli stat command. + * + * @param stat + * Zookeeper Stat structure + * @return a formatted string. + */ + public static String printStat(final Stat stat) { + + if (stat == null) { + return "null"; + } + + return "\ncZxid = " + String.format("0x%x", stat.getCzxid()) + "\nctime = " + + getFmtTime(stat.getCtime()) + "\nmZxid = " + String.format("0x%x", stat.getMzxid()) + + "\nmtime = " + getFmtTime(stat.getMtime()) + "\npZxid = " + + String.format("0x%x", stat.getPzxid()) + "\ncversion = " + stat.getCversion() + + "\ndataVersion = " + stat.getVersion() + "\naclVersion = " + stat.getAversion() + + "\nephemeralOwner = " + String.format("0x%x", stat.getEphemeralOwner()) + + "\ndataLength = " + stat.getDataLength() + "\nnumChildren = " + stat.getNumChildren(); + } + + private static String getFmtTime(final long epoch) { + OffsetDateTime timestamp = + OffsetDateTime.ofInstant(Instant.ofEpochMilli(epoch), ZoneOffset.UTC); + return fmt.format(timestamp); + } + public static void digestAuth(ZooKeeper zoo, String secret) { auth(zoo, "digest", ("accumulo:" + secret).getBytes(UTF_8)); }