You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by dl...@apache.org on 2026/03/10 12:37:17 UTC
(accumulo) branch main updated (af4955d592 -> e46bee5653)
This is an automated email from the ASF dual-hosted git repository.
dlmarion pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git
from af4955d592 Merge branch '2.1'
add 249fac277d Fixed concurrency issue in ServiceLock.determineLockOwnership (#6199)
new e46bee5653 Merge branch '2.1'
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../org/apache/accumulo/core/lock/ServiceLock.java | 152 ++++++++++++++-------
.../apache/accumulo/test/lock/ServiceLockIT.java | 2 +-
2 files changed, 103 insertions(+), 51 deletions(-)
(accumulo) 01/01: Merge branch '2.1'
Posted by dl...@apache.org.
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 <dl...@apache.org>
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);
}