This is an automated email from the ASF dual-hosted git repository.

dlmarion pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git

commit e46bee565340d99c33efac4cb3c0341e30c96df7
Merge: af4955d592 249fac277d
Author: Dave Marion <[email protected]>
AuthorDate: Tue Mar 10 12:37:08 2026 +0000

    Merge branch '2.1'

 .../org/apache/accumulo/core/lock/ServiceLock.java | 152 ++++++++++++++-------
 .../apache/accumulo/test/lock/ServiceLockIT.java   |   2 +-
 2 files changed, 103 insertions(+), 51 deletions(-)

diff --cc core/src/main/java/org/apache/accumulo/core/lock/ServiceLock.java
index e841582fad,e52de4a036..4a007f1b32
--- a/core/src/main/java/org/apache/accumulo/core/lock/ServiceLock.java
+++ b/core/src/main/java/org/apache/accumulo/core/lock/ServiceLock.java
@@@ -47,10 -45,25 +47,29 @@@ import org.apache.zookeeper.data.Stat
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
+ import com.google.common.base.Preconditions;
+ 
 +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 +
+ /**
+  * This class uses Sequential Ephemeral ZooKeeper Nodes
+  * 
(https://zookeeper.apache.org/doc/r3.9.5/zookeeperProgrammers.html#Sequence+Nodes+--+Unique+Naming)
+  * to implement locks for Accumulo server processes. This class will create 
an ephemeral sequential
+  * node under a base path using the prefix "zlock#" + UUID + "#". The 
ZooKeeper server will append a
+  * 10-digit zero-padded number to this prefix using a one-up counter. The 
base path could be an HA
+  * service like the Manager or a non-HA service like a TabletServer.
+  *
+  * When an instance of this class has the lowest counter number at the base 
path, then it has the
+  * lock. When an instance of this class does not have the lowest counter 
number, then it watches the
+  * node with the next lowest counter number. When the node that has the next 
lowest counter number
+  * is deleted, then this instance could acquire the lock.
+  *
+  * Instance of this class also place a Watcher on the base path node. If the 
base path Watcher
+  * receives a Session Expired event, then it calls lostLock which should end 
up halting the Accumulo
+  * server process.
+  */
 +@SuppressFBWarnings(value = "CT_CONSTRUCTOR_THROW",
 +    justification = "Constructor validation is required for proper 
initialization")
  public class ServiceLock implements Watcher {
    private static final Logger LOG = 
LoggerFactory.getLogger(ServiceLock.class);
  
@@@ -89,28 -119,56 +108,56 @@@
      void failedToAcquireLock(Exception e);
    }
  
+   // the base path
    private final ServiceLockPath path;
+ 
 -  protected final ZooKeeper zooKeeper;
 +  protected final ZooSession zooKeeper;
+ 
+   // "zlock#" + UUID + "#"
    private final Prefix vmLockPrefix;
  
+   // A LockWatcher instance supplied to this class
+   // by the caller when trying to acquire the lock
+   // in ZooKeeper. This object does not represent
+   // a Watcher in ZooKeeper, but allows an instance
+   // of this class to communicate with the calling
+   // object by invoking callback methods.
    private LockWatcher lockWatcher;
-   private String lockNodeName;
+ 
+   // A variable which is initially null, then set
+   // to the createdNodeName when the lock is acquired.
+   // This variable is set to null when this instance
+   // loses the lock.
+   private volatile String lockNodeName;
+ 
+   // boolean to track if this instance has ever held the lock
    private volatile boolean lockWasAcquired;
-   private volatile boolean watchingParent;
  
-   private String createdNodeName;
-   private String watchingNodeName;
+   // boolean to track if there is a watcher on the base path.
+   private volatile boolean watchingBasePath;
+ 
+   // Represents the name of the ephemeral sequential node that
+   // the ZooKeeper server created for us with the unique one-up
+   // counter. This variable is set to null when this instance
+   // acquires the lock.
+   private volatile String createdNodeName;
+ 
+   // Represents the path of the ephemeral sequential node that
+   // has the next lowest counter value. An instance of this class
+   // will watch this node and will attempt to acquire the lock
+   // when this node is deleted.
+   private String watchingNodePath;
  
 -  public ServiceLock(ZooKeeper zookeeper, ServiceLockPath path, UUID uuid) {
 +  public ServiceLock(ZooSession zookeeper, ServiceLockPath path, UUID uuid) {
      this.zooKeeper = requireNonNull(zookeeper);
      this.path = requireNonNull(path);
      try {
        zooKeeper.exists(path.toString(), this);
-       watchingParent = true;
+       watchingBasePath = true;
        this.vmLockPrefix = new Prefix(ZLOCK_PREFIX + uuid.toString() + "#");
 -    } catch (Exception ex) {
 +    } catch (KeeperException | InterruptedException ex) {
        LOG.error("Error setting initial watch", ex);
 -      throw new RuntimeException(ex);
 +      throw new IllegalStateException(ex);
      }
    }
  
@@@ -145,12 -207,12 +196,12 @@@
  
    }
  
 -  public synchronized boolean tryLock(LockWatcher lw, byte[] data)
 +  public synchronized boolean tryLock(LockWatcher lw, ServiceLockData 
lockData)
        throws KeeperException, InterruptedException {
  
-     LockWatcherWrapper lww = new LockWatcherWrapper(lw);
+     TryLockWatcherWrapper lww = new TryLockWatcherWrapper(lw);
  
 -    lock(lww, data);
 +    lock(lww, lockData);
  
      if (lww.acquiredLock) {
        return true;
@@@ -273,16 -334,15 +321,16 @@@
  
      List<String> children = validateAndSort(path, 
zooKeeper.getChildren(path.toString(), null));
  
-     if (!children.contains(createdEphemeralNode)) {
-       LOG.error("Expected ephemeral node {} to be in the list of children 
{}", createdEphemeralNode,
+     if (!children.contains(createdNodeName)) {
+       LOG.error("Expected ephemeral node {} to be in the list of children 
{}", createdNodeName,
            children);
 -      throw new RuntimeException("Lock attempt ephemeral node no longer exist 
" + createdNodeName);
 +      throw new IllegalStateException(
-           "Lock attempt ephemeral node no longer exist " + 
createdEphemeralNode);
++          "Lock attempt ephemeral node no longer exist " + createdNodeName);
      }
  
-     if (children.get(0).equals(createdEphemeralNode)) {
+     if (children.get(0).equals(createdNodeName)) {
        LOG.debug("[{}] First candidate is my lock, acquiring...", 
vmLockPrefix);
-       if (!watchingParent) {
+       if (!watchingBasePath) {
          throw new IllegalStateException(
              "Can not acquire lock, no longer watching parent : " + path);
        }

Reply via email to