You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by ct...@apache.org on 2022/04/27 19:52:14 UTC

[accumulo] 02/02: Minor enhancements to ZK utilities

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 <ct...@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));
   }