diff --git a/conf/fork-stacks.xml b/conf/fork-stacks.xml
index 4be2478da75..612a3a56c56 100644
--- a/conf/fork-stacks.xml
+++ b/conf/fork-stacks.xml
@@ -11,9 +11,9 @@
-
+
-
+
diff --git a/conf/fork.xml b/conf/fork.xml
index dcb3bd0b6fd..44e12c5d150 100644
--- a/conf/fork.xml
+++ b/conf/fork.xml
@@ -23,7 +23,7 @@
xsi:schemaLocation="fork fork-stacks-4.2.xsd">
-
+
diff --git a/conf/jg-magic-map.xml b/conf/jg-magic-map.xml
index d7c25dc3400..83563dbcac9 100644
--- a/conf/jg-magic-map.xml
+++ b/conf/jg-magic-map.xml
@@ -42,7 +42,6 @@
-
diff --git a/conf/jg-messages.properties b/conf/jg-messages.properties
index afebca972ed..a858d417dc9 100644
--- a/conf/jg-messages.properties
+++ b/conf/jg-messages.properties
@@ -59,8 +59,6 @@ CouldNotOpenConnectionToDatabase = JGRP000115: Could not open connection to data
DefaultMembershipChangePolicyFailed = JGRP000119: default membership change policy failed
DidnTFindPhysicalAddressFor = JGRP000121: didn't find physical address for
DigestOrSenderIsNull = JGRP000122: digest or sender is null
-DiscardedLOCKDENIEDResponseWithLockId = JGRP000123: discarded LOCK-DENIED response with lock-id=
-DiscardedLOCKGRANTEDResponseWithLockId = JGRP000124: discarded LOCK-GRANTED response with lock-id=
ErrorBuildingURL = JGRP000126: Error building URL
ErrorCallingService = JGRP000127: Error calling service
ErrorClearingTable = JGRP000128: Error clearing table
diff --git a/conf/jg-protocol-ids.xml b/conf/jg-protocol-ids.xml
index 91f16f74c37..7243bb30b79 100644
--- a/conf/jg-protocol-ids.xml
+++ b/conf/jg-protocol-ids.xml
@@ -31,7 +31,6 @@
-
@@ -55,7 +54,6 @@
-
diff --git a/doc/manual/blocks.adoc b/doc/manual/blocks.adoc
index 236d58a013c..bac18cb21ee 100644
--- a/doc/manual/blocks.adoc
+++ b/doc/manual/blocks.adoc
@@ -718,141 +718,6 @@ Note that this class was written as a demo of how state can be shared between no
never been heavily tested and is therefore not meant to be used in production.
-[[LockService]]
-=== Cluster wide locking
-
-`LockService` can be used to acquire locks on a cluster-wide basis; ie. only one node can acquire a given lock. E.g. if
-member B acquires lock L, and member C also tries to acquire L, then C will block until B releases L
-(or leaves /crashes)
-
-The new service is implemented as a building block (`org.jgroups.blocks.locking.LockService`) and a protocol
-(`CENTRAL_LOCK` or `CENTRAL_LOCK2`). `LockService` looks up the protocol and talks to it via events. If no locking
-protocol is found, `LockService` won't start and will throw an exception.
-
-The main abstraction of a distributed lock is an implementation of `java.util.concurrent.locks.Lock`.
-
-Below is an example of how LockService is typically used:
-
-[source,java]
-----
-// locking.xml needs to contain a locking protocol, e.g. CENTRAL_LOCK
-JChannel ch=new JChannel("/home/bela/locking.xml");
-LockService lock_service=new LockService(ch);
-ch.connect("lock-cluster");
-Lock lock=lock_service.getLock("mylock"); // gets a cluster-wide lock
-lock.lock();
-try {
- // do something with the locked resource
-}
-finally {
- lock.unlock();
-}
-----
-
-In the example, we create a channel, then a `LockService`, then connect the channel. If the channel's
-configuration doesn't include a locking protocol, an exception will be thrown.
-Then we grab a lock named `"mylock"`, which we lock and subsequently unlock. If another member P had already
-acquired `"mylock"`, we'd block until P released the lock, or P left the cluster or crashed.
-
-Note that the owner of a lock is always a given thread in a cluster, so the owner is the JGroups address and
-the thread ID. *This means that different threads inside the same JVM trying to access the same named lock
-will compete for it.* If `thread-22` grabs the lock first, then `thread-5` will block until `thread-22`
-releases the lock.
-
-NOTE: If we want the lock owner to only be the address (and not the thread-id), then property
-`use_thread_id_for_lock_owner` can be set to `false`. This means that all threads in a given node can lock or unlock
-a given lock. Example: thread T1 locks "lock", but thread T2 can unlock it. This is _not_ the same semantics as
-`java.util.concurrent.locks.Lock`, but nevertheless useful in some scenarios. (Introduced in 3.6)
-
-JGroups includes a demo (`org.jgroups.demos.LockServiceDemo`), which can be used to interactively experiment
-with distributed locks. `LockServiceDemo -h` dumps all command line options.
-
-There are two protocols which provides locking: <> and <>.
-
-Note that the locking protocol has to be placed at or towards the top of the stack (close to the channel), because it
-requires reliable unicasts and multicasts (e.g. provided by `UNICAST3` and `NAKACK2`).
-
-
-[[LockingAndMerges]]
-==== Locking and merges
-
-The following scenario is susceptible to network partitioning and subsequent merging: we have a cluster
-view of `{A,B,C,D}` and then the cluster splits into `{A,B}` and `{C,D}`. Assume that B and D now acquire a
-lock `"mylock"`. This is what happens (with the locking protocol being `CENTRAL_LOCK`):
-
-* There are 2 coordinators: A for `{A,B}` and C for `{C,D}`
-* B successfully acquires `"mylock"` from A
-* D successfully acquires `"mylock"` from C
-* The partitions merge back into `{A,B,C,D}`. Now, only A is the coordinator, but C ceases
-to be a coordinator
-* Problem: D still holds a lock which should actually be invalid!
-There is no easy way (via the Lock API) to 'remove' the lock from D. We could for example simply release
-D's lock on `"mylock"`, but then there's no way telling D that the lock it holds is actually stale!
-
-Therefore the recommended solution here is for nodes to listen to `MergeView` changes if they expect
-merging to occur, and re-acquire all of their locks after a merge, e.g.:
-
-[source,java]
-----
-
-Lock l1, l2, l3;
-LockService lock_service;
-...
-public void viewAccepted(View view) {
- if(view instanceof MergeView) {
- new Thread() {
- public void run() {
- lock_service.unlockAll();
- // stop all access to resources protected by l1, l2 or l3
- // every thread needs to re-acquire the locks it holds
- }
- }.start();
- }
-}
-----
-
-==== Locking and merges (updated)
-With <>, merging of partitions is handled differently. Contrary to CENTRAL_LOCK, which has the coordinator
-back up its lock tables to one or more backup members, CENTRAL_LOCK2 doesn't do this.
-
-Instead, when the current coordinator leaves or crashes, the new coordinator fetches information about locks and pending
-lock/unlock requests from all members, and then builds its lock table based on this information.
-
-In the above scenario with both B and D holding `mylock`, in case of a merge (say A becomes the new coordinator), D
-will be told that its lock `mylock` has been *revoked*. This means that D needs to force-unlock D. This can be done
-in the `lockRevoked()` callback, e.g.:
-
-[source,java]
-----
-LockService lock_service;
-...
-public void lockRevoked(String lock_name, Owner current_owner) {
- lock_service.unlockForce(lock_name);
-}
-----
-
-This is maginally better than CENTRAL_LOCK, but admittedly less than ideal. Given the following code:
-
-[source,java]
-----
-Lock lock=lock_service.get("mylock";
-lock.lock();
-try {
- // do something while the lock is held
- longRunningAction();
-}
-finally {
- lock.unlock
-}
-----
-
-When `mylock` is revoked, `longRunningAction()` should be stopped immediately, or - even better - its changes should be
-undone (like in a transaction). However, this isn't feasible and would unnecessarily complicate the code.
-
-Here, we see that the `Lock` abstraction, as easy as it is and as often it is used *locally* (inside the same JVM),
-may not be the best abstraction for a distributed setting!
-
-
[[CounterService]]
=== Cluster wide atomic counters
diff --git a/doc/manual/protocols.adoc b/doc/manual/protocols.adoc
index d22460e68a8..64de1aa99d3 100644
--- a/doc/manual/protocols.adoc
+++ b/doc/manual/protocols.adoc
@@ -2161,41 +2161,6 @@ JIRA: https://issues.redhat.com/browse/JGRP-2402
${SOS}
-[[LockingProtocols]]
-==== Locking protocols
-
-The locking protocol is org.jgroups.protocols.CENTRAL_LOCK:
-
-${Locking}
-
-[[CENTRAL_LOCK]]
-===== CENTRAL_LOCK
-
-CENTRAL_LOCK has the current coordinator of a cluster grants locks, so every node has to communicate with the
-coordinator to acquire or release a lock. Lock requests by different nodes for the same lock are processed
-in the order in which they are received.
-
-A coordinator maintains a lock table. To prevent losing the knowledge of who holds which locks, the coordinator can push
-lock information to a number of backups defined by num_backups. If num_backups is 0, no replication of lock information
-happens. If num_backups is greater than 0, then the coordinator pushes information about acquired and released locks to
-all backup nodes. Topology changes might create new backup nodes, and lock information is pushed to those on
-becoming a new backup node.
-
-The advantage of CENTRAL_LOCK is that all lock requests are granted in the same order across the cluster.
-
-${CENTRAL_LOCK}
-
-
-[[CENTRAL_LOCK2]]
-===== CENTRAL_LOCK2
-
-In CENTRAL_LOCK2, the coordinator (= lock issuer) does not backup its lock table to other member(s), but instead a new
-coordinator fetches information about held locks and pending lock/unlock requests from existing members, before it
-starts processing lock requests. See <> for details.
-
-${CENTRAL_LOCK2}
-
-
[[COUNTER]]
diff --git a/src/org/jgroups/Event.java b/src/org/jgroups/Event.java
index 8bc995c03da..9b028b5df95 100644
--- a/src/org/jgroups/Event.java
+++ b/src/org/jgroups/Event.java
@@ -41,11 +41,6 @@ public class Event {
public static final int ADD_PHYSICAL_ADDRESS = 89; // arg = Tuple --> boolean
public static final int REMOVE_ADDRESS = 90; // arg = Address
public static final int GET_LOCAL_ADDRESS = 91; // arg = null --> UUID (local_addr)
- public static final int LOCK = 95; // arg = LockInfo
- public static final int UNLOCK = 96; // arg = LockInfo
- public static final int UNLOCK_ALL = 97; // arg = null
- public static final int LOCK_AWAIT = 98; // arg = LockInfo
- public static final int LOCK_SIGNAL = 99; // arg = AwaitInfo
public static final int IS_MERGE_IN_PROGRESS = 100; // returns true or false
public static final int GET_PHYSICAL_ADDRESSES = 102; // arg = null (returns all physical addresses)
public static final int SITE_UNREACHABLE = 104; // arg = SiteMaster (RELAY2/RELAY3)
@@ -56,7 +51,6 @@ public class Event {
public static final int GET_PING_DATA = 109; // arg = cluster_name
public static final int GET_SECRET_KEY = 111; // arg = null -> Tuple // PK+version
public static final int SET_SECRET_KEY = 112; // arg = Tuple // PK+version
- public static final int UNLOCK_FORCE = 113; // arg = lock name
public static final int INSTALL_MERGE_VIEW = 114; // arg = MergeView
public static final int IS_LOCAL_SITEMASTER = 115; // arg = SiteMaster(site), returns true / false
public static final int IS_LOCAL = 116; // arg = SiteAddress(site), returns true / false
@@ -124,11 +118,6 @@ public static String type2String(int t) {
case ADD_PHYSICAL_ADDRESS: return "ADD_PHYSICAL_ADDRESS";
case REMOVE_ADDRESS: return "REMOVE_ADDRESS";
case GET_LOCAL_ADDRESS: return "GET_LOCAL_ADDRESS";
- case LOCK: return "LOCK";
- case UNLOCK: return "UNLOCK";
- case UNLOCK_ALL: return "UNLOCK_ALL";
- case LOCK_AWAIT: return "LOCK_AWAIT";
- case LOCK_SIGNAL: return "LOCK_SIGNAL";
case IS_MERGE_IN_PROGRESS: return "IS_MERGE_IN_PROGRESS";
case GET_PHYSICAL_ADDRESSES: return "GET_PHYSICAL_ADDRESSES";
case SITE_UNREACHABLE: return "SITE_UNREACHABLE";
@@ -139,7 +128,6 @@ public static String type2String(int t) {
case GET_PING_DATA: return "GET_PING_DATA";
case GET_SECRET_KEY: return "GET_SECRET_KEY";
case SET_SECRET_KEY: return "SET_SECRET_KEY";
- case UNLOCK_FORCE: return "UNLOCK_FORCE";
case INSTALL_MERGE_VIEW: return "INSTALL_MERGE_VIEW";
case IS_LOCAL_SITEMASTER: return "IS_LOCAL_SITEMASTER";
case IS_LOCAL: return "IS_LOCAL";
diff --git a/src/org/jgroups/blocks/locking/AwaitInfo.java b/src/org/jgroups/blocks/locking/AwaitInfo.java
deleted file mode 100644
index 10f073a1d40..00000000000
--- a/src/org/jgroups/blocks/locking/AwaitInfo.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package org.jgroups.blocks.locking;
-
-
-public class AwaitInfo {
- protected final String name;
- protected final boolean all;
-
- public AwaitInfo(String name, boolean all) {
- this.name=name;
- this.all=all;
- }
-
- /**
- * @return Returns the name.
- */
- public String getName() {
- return name;
- }
-
- /**
- * @return Returns whether is all.
- */
- public boolean isAll() {
- return all;
- }
-
- public String toString() {
- return name + ", awaitAll=" + all;
- }
-}
diff --git a/src/org/jgroups/blocks/locking/LockInfo.java b/src/org/jgroups/blocks/locking/LockInfo.java
deleted file mode 100644
index bd1f24a76f8..00000000000
--- a/src/org/jgroups/blocks/locking/LockInfo.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.jgroups.blocks.locking;
-
-import java.util.concurrent.TimeUnit;
-
-/**
- * @author Bela Ban
- */
-public class LockInfo {
- protected final String name;
- protected final boolean is_trylock;
- protected final boolean lock_interruptibly;
- protected final boolean use_timeout;
- protected final long timeout;
- protected final TimeUnit time_unit;
-
- public LockInfo(String name, boolean is_trylock, boolean lock_interruptibly, boolean use_timeout,
- long timeout, TimeUnit time_unit) {
- this.name=name;
- this.is_trylock=is_trylock;
- this.lock_interruptibly=lock_interruptibly;
- this.use_timeout=use_timeout;
- this.timeout=timeout;
- this.time_unit=time_unit;
- }
-
-
- public boolean isTrylock() {
- return is_trylock;
- }
-
- public boolean isLockInterruptibly() {
- return lock_interruptibly;
- }
-
- public boolean isUseTimeout() {
- return use_timeout;
- }
-
- public String getName() {
- return name;
- }
-
- public long getTimeout() {
- return timeout;
- }
-
- public TimeUnit getTimeUnit() {
- return time_unit;
- }
-
- public String toString() {
- return name + ", trylock=" + is_trylock + ", timeout=" + timeout;
- }
-}
-
diff --git a/src/org/jgroups/blocks/locking/LockNotification.java b/src/org/jgroups/blocks/locking/LockNotification.java
deleted file mode 100644
index dabcf13ecf1..00000000000
--- a/src/org/jgroups/blocks/locking/LockNotification.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package org.jgroups.blocks.locking;
-
-import org.jgroups.util.Owner;
-
-/**
- * @author Bela Ban
- */
-public interface LockNotification {
- void lockCreated(String name);
- void lockDeleted(String name);
- void lockRevoked(String lock_name, Owner current_owner);
- void locked(String lock_name, Owner owner);
- void unlocked(String lock_name, Owner owner);
- void awaiting(String lock_name, Owner owner);
- void awaited(String lock_name, Owner owner);
-}
diff --git a/src/org/jgroups/blocks/locking/LockService.java b/src/org/jgroups/blocks/locking/LockService.java
deleted file mode 100644
index b8f9a048af3..00000000000
--- a/src/org/jgroups/blocks/locking/LockService.java
+++ /dev/null
@@ -1,251 +0,0 @@
-package org.jgroups.blocks.locking;
-
-import org.jgroups.Event;
-import org.jgroups.JChannel;
-import org.jgroups.protocols.Locking;
-
-import java.util.Date;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-
-/**
- * LockService is the main class for to use for distributed locking functionality. LockService needs access to a
- * {@link JChannel} and interacts with a locking protocol (e.g. {@link org.jgroups.protocols.CENTRAL_LOCK}) via events.
- * When no locking protocol is seen on the channel's stack, LockService will throw an exception at startup. An example
- * of using LockService is:
- *
- JChannel ch=new JChannel("/home/bela/locking.xml); // locking.xml needs to have a locking protocol towards the top
- LockService lock_service=new LockService(ch);
- ch.connect("lock-cluster");
- Lock lock=lock_service.getLock("mylock");
- lock.lock();
- try {
- // do something with the lock acquired
- }
- finally {
- lock.unlock();
- }
- *
- *
- * The exact semantics of this lock implemantation are defined in {@link LockImpl}.
- *
- * Note that, contrary to the semantics of {@link java.util.concurrent.locks.Lock}, unlock() can be called multiple
- * times; after a lock has been released, future calls to unlock() have no effect.
- * @author Bela Ban
- * @since 2.12
- * @deprecated See http://belaban.blogspot.com/2020/11/i-hate-distributed-locks.html.
- */
-@Deprecated
-public class LockService {
- protected JChannel ch;
- protected Locking lock_prot;
-
-
- public LockService() {
-
- }
-
- public LockService(JChannel ch) {
- setChannel(ch);
- }
-
- public void setChannel(JChannel ch) {
- this.ch=ch;
- lock_prot=ch.getProtocolStack().findProtocol(Locking.class);
- if(lock_prot == null)
- throw new IllegalStateException("Channel configuration must include a locking protocol " +
- "(subclass of " + Locking.class.getName() + ")");
- }
-
- public Lock getLock(String lock_name) {
- return new LockImpl(lock_name);
- }
-
- public void unlockAll() {
- ch.down(new Event(Event.UNLOCK_ALL));
- }
-
- public void unlockForce(String lock_name) {
- ch.down(new Event(Event.UNLOCK_FORCE, lock_name));
- }
-
- public void addLockListener(LockNotification listener) {
- lock_prot.addLockListener(listener);
- }
-
- public void removeLockListener(LockNotification listener) {
- lock_prot.removeLockListener(listener);
- }
-
- public String printLocks() {
- return lock_prot.printLocks();
- }
-
-
- /**
- * Implementation of {@link Lock}. This is a client stub communicates with a server equivalent. The semantics are
- * more or less those of {@link Lock}, but may differ slightly.
- * There is no reference counting of lock owners, so acquisition of a lock already held by a thread is a no-op.
- * Also, releasing the lock after it was already released is a no-op as well.
- *
- * An exact description is provided below.
- */
- protected class LockImpl implements Lock {
- protected final String name;
- protected final AtomicReference holder=new AtomicReference<>();
-
- public LockImpl(String name) {
- this.name=name;
- }
-
- /**
- * {@inheritDoc}
- * Blocks until the lock has been acquired. Masks interrupts; if an interrupt was received on entry or while
- * waiting for the lock acquisition, it won't cause the call to return. However, the thread's status will be
- * set to interrupted when the call returns.
- */
- @Override
- public void lock() {
- ch.down(new Event(Event.LOCK, new LockInfo(name, false, false, false, 0, TimeUnit.MILLISECONDS)));
- holder.set(Thread.currentThread());
- }
-
- /**
- * {@inheritDoc}
- * If the thread is interrupted at entry, the call will throw an InterruptedException immediately and the lock
- * won't be acquired. If the thread is interrupted while waiting for the lock acquition, an InterruptedException
- * will also be thrown immediately. The thread's interrupt status will not be set after the call returns.
- * @throws InterruptedException
- */
- public void lockInterruptibly() throws InterruptedException {
- ch.down(new Event(Event.LOCK, new LockInfo(name, false, true, false, 0, TimeUnit.MILLISECONDS)));
- Thread currentThread = Thread.currentThread();
- if(currentThread.isInterrupted())
- throw new InterruptedException();
- else
- holder.set(currentThread);
- }
-
- /**
- * {@inheritDoc}
- * If the thread is interrupted at entry or during the call, no InterruptedException will be thrown, but the
- * thread's status will be set to interrupted upon return. An interrupt has therefore no impact on the
- * return value (success or failure).
- */
- public boolean tryLock() {
- Boolean retval=(Boolean)ch.down(new Event(Event.LOCK, new LockInfo(name, true, false, false, 0, TimeUnit.MILLISECONDS)));
- if(retval != null && retval)
- holder.set(Thread.currentThread());
- return retval == null ? false : retval;
- }
-
- /**
- * {@inheritDoc}
- * * If the thread is interrupted at entry, the call will throw an InterruptedException immediately and the lock
- * won't be acquired. If the thread is interrupted while waiting for the lock acquition, an InterruptedException
- * will also be thrown immediately. The thread's interrupt status will not be set after the call returns.
- * @param time
- * @param unit
- * @return
- * @throws InterruptedException
- */
- public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
- Boolean retval=(Boolean)ch.down(new Event(Event.LOCK, new LockInfo(name, true, true, true, time, unit)));
- if(Thread.currentThread().isInterrupted())
- throw new InterruptedException();
- if(retval != null && retval)
- holder.set(Thread.currentThread());
- return retval == null ? false : retval;
- }
-
- /**
- * {@inheritDoc}
- * Releases a lock. Contrary to the parent's implementation, this method can be called more than once:
- * the release of a lock that has already been released, or is not owned by this thread is a no-op.
- */
- public void unlock() {
- ch.down(new Event(Event.UNLOCK, new LockInfo(name, false, false, false, 0, TimeUnit.MILLISECONDS)));
- holder.compareAndSet(Thread.currentThread(), null); // only set if the current thread is actually the holder
- }
-
- /**
- * This condition object is only allowed to work 1 for each lock.
- * If more than 1 condition is created for this lock, they both will
- * be awaiting/signalling on the same lock
- */
- public Condition newCondition() {
- return new ConditionImpl(name, holder);
- }
-
- public String toString() {
- return name + (holder.get() == null? " [unlocked]" : " [held by " + holder.get() + "]");
- }
- }
-
- private class ConditionImpl implements Condition {
- protected final String name;
- protected final AtomicReference holder;
-
- public ConditionImpl(String name, AtomicReference holder) {
- this.name=name;
- this.holder=holder;
- }
-
- @Override
- public void await() throws InterruptedException {
- ch.down(new Event(Event.LOCK_AWAIT, new LockInfo(name, false,
- true, false, 0, TimeUnit.MILLISECONDS)));
- if(Thread.currentThread().isInterrupted())
- throw new InterruptedException();
- }
-
- @Override
- public void awaitUninterruptibly() {
- ch.down(new Event(Event.LOCK_AWAIT, new LockInfo(name, false,
- false, false, 0, TimeUnit.MILLISECONDS)));
- }
-
- @Override
- public long awaitNanos(long nanosTimeout) throws InterruptedException {
- Long waitLeft = (Long)ch.down(new Event(Event.LOCK_AWAIT,
- new LockInfo(name, false, true, true, nanosTimeout,
- TimeUnit.NANOSECONDS)));
- if(Thread.currentThread().isInterrupted())
- throw new InterruptedException();
- return waitLeft;
- }
-
- @Override
- public boolean await(long time, TimeUnit unit)
- throws InterruptedException {
- return awaitNanos(unit.toNanos(time)) > 0;
- }
-
- @Override
- public boolean awaitUntil(Date deadline) throws InterruptedException {
- long waitUntilTime = deadline.getTime();
- long currentTime = System.currentTimeMillis();
-
- long waitTime = waitUntilTime - currentTime;
- return waitTime > 0 && await(waitTime, TimeUnit.MILLISECONDS);
- }
-
- @Override
- public void signal() {
- if (holder.get() != Thread.currentThread()) {
- throw new IllegalMonitorStateException();
- }
- ch.down(new Event(Event.LOCK_SIGNAL, new AwaitInfo(name, false)));
- }
-
- @Override
- public void signalAll() {
- if (holder.get() != Thread.currentThread()) {
- throw new IllegalMonitorStateException();
- }
- ch.down(new Event(Event.LOCK_SIGNAL, new AwaitInfo(name, true)));
- }
- }
-}
diff --git a/src/org/jgroups/demos/LockServiceDemo.java b/src/org/jgroups/demos/LockServiceDemo.java
deleted file mode 100644
index 072b9b2977b..00000000000
--- a/src/org/jgroups/demos/LockServiceDemo.java
+++ /dev/null
@@ -1,218 +0,0 @@
-package org.jgroups.demos;
-
-import org.jgroups.JChannel;
-import org.jgroups.blocks.locking.LockNotification;
-import org.jgroups.blocks.locking.LockService;
-import org.jgroups.jmx.JmxConfigurator;
-import org.jgroups.util.Owner;
-import org.jgroups.util.Util;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.locks.Lock;
-
-/**
- * Demos the LockService
- */
-public class LockServiceDemo implements LockNotification {
- protected String props;
- protected JChannel ch;
- protected LockService lock_service;
- protected String name;
-
- public LockServiceDemo(String props, String name) {
- this.props=props;
- this.name=name;
- }
-
- public void start() throws Exception {
-
- try {
- ch=new JChannel(props);
- if(name != null)
- ch.setName(name);
- lock_service=new LockService(ch);
- lock_service.addLockListener(this);
- ch.connect("lock-cluster");
- JmxConfigurator.registerChannel(ch, Util.getMBeanServer(), "lock-service", ch.getClusterName(), true);
- loop();
- }
- catch(Exception e) {
- e.printStackTrace();
- }
- finally {
- Util.close(ch);
- }
- }
-
- public void start(JChannel ch) throws Exception {
- this.ch=ch;
- lock_service=new LockService(ch);
- lock_service.addLockListener(this);
- ch.connect("lock-cluster");
- JmxConfigurator.registerChannel(ch, Util.getMBeanServer(), "lock-service", ch.getClusterName(), true);
-
- try {
- loop();
- }
- catch(Exception e) {
- e.printStackTrace();
- }
- finally {
- Util.close(ch);
- }
- }
-
- public void lockCreated(String lock_name) {
- System.out.println("server lock \"" + lock_name + "\" created");
- }
-
- public void lockDeleted(String name) {
- }
-
- public void lockRevoked(String lock_name, Owner current_owner) {
- System.out.printf("\"%s\" has been revoked (existing owner is %s); releasing lock\n", lock_name, current_owner);
- Lock lock=lock_service.getLock(lock_name);
- lock.unlock();
- }
-
- public void locked(String lock_name, Owner owner) {
- System.out.println("\"" + lock_name + "\" locked by " + owner);
- }
-
- public void unlocked(String lock_name, Owner owner) {
- System.out.println("\"" + lock_name + "\" unlocked by " + owner);
- }
-
- public void awaiting(String lock_name, Owner owner) {
- System.out.println("awaiting \"" + lock_name + "\" by " + owner);
- }
-
- public void awaited(String lock_name, Owner owner) {
- System.out.println("awaited \"" + lock_name + "\" by " + owner);
- }
-
- protected void loop() throws Exception {
- List lock_names;
- while(ch.isConnected()) {
- String line=Util.readStringFromStdin(": ");
- if(line == null || line.startsWith("quit") || line.startsWith("exit"))
- break;
-
- if(line.startsWith("lock")) {
- lock_names=parseLockNames(line.substring("lock".length()).trim());
- for(String lock_name: lock_names) {
- Lock lock=lock_service.getLock(lock_name);
- lock.lock();
- }
- }
- else if(line.startsWith("trylock")) {
- lock_names=parseLockNames(line.substring("trylock".length()).trim());
-
- String tmp=lock_names.get(lock_names.size() -1);
- long timeout=-1;
- try {
- timeout=Long.parseLong(tmp);
- lock_names.remove(lock_names.size() -1);
- }
- catch(NumberFormatException e) {
- }
-
- for(String lock_name: lock_names) {
- Lock lock=lock_service.getLock(lock_name);
- boolean rc;
- if(timeout < 0)
- rc=lock.tryLock();
- else
- rc=lock.tryLock(timeout, TimeUnit.MILLISECONDS);
- if(!rc)
- System.err.println("Failed locking \"" + lock_name + "\"");
- }
- }
- else if(line.startsWith("multilock")) { // multilock X 10
- List tokens=parseLockNames(line.substring("multilock".length()).trim());
- if(tokens == null || tokens.size() != 2) {
- help();
- break;
- }
- String lock_name=tokens.get(0);
- int num_iterations=Integer.valueOf(tokens.get(1));
- Lock lock=lock_service.getLock(lock_name);
- for(int i=0; i < num_iterations; i++) {
- lock.lock();
- lock.unlock();
- }
- }
- else if(line.startsWith("unlock")) {
- lock_names=parseLockNames(line.substring("unlock".length()).trim());
- for(String lock_name: lock_names) {
- if(lock_name.equalsIgnoreCase("all")) {
- lock_service.unlockAll();
- break;
- }
- else {
- Lock lock=lock_service.getLock(lock_name);
- if(lock != null)
- lock.unlock();
- }
- }
- }
- else if(line.startsWith("view"))
- System.out.println("View: " + ch.getView());
- else if(line.startsWith("help"))
- help();
- printLocks();
- }
- }
-
- protected static List parseLockNames(String line) {
- List lock_names=new ArrayList<>();
- if(line == null || line.isEmpty())
- return lock_names;
- StringTokenizer tokenizer=new StringTokenizer(line);
- while(tokenizer.hasMoreTokens())
- lock_names.add(tokenizer.nextToken());
- return lock_names;
- }
-
- protected void printLocks() {
- System.out.println("\n" + lock_service.printLocks());
- }
-
-
-
- public static void main(String[] args) throws Exception {
- String props=null;
- String name=null;
-
- for(int i=0; i < args.length; i++) {
- if(args[i].equals("-props")) {
- props=args[++i];
- continue;
- }
- if(args[i].equals("-name")) {
- name=args[++i];
- continue;
- }
-
- help();
- return;
- }
-
- LockServiceDemo demo=new LockServiceDemo(props, name);
- demo.start();
- }
-
- protected static void help() {
- System.out.println("\nLockServiceDemo [-props properties] [-name name]\n" +
- "Valid commands:\n\n" +
- "lock ()+\n" +
- "unlock ( | \"ALL\")+\n" +
- "trylock ()+ []\n" +
- "multilock \n");
- System.out.println("Example:\nlock lock lock2 lock3\nunlock all\ntrylock bela michelle 300");
- }
-
-}
diff --git a/src/org/jgroups/protocols/CENTRAL_LOCK.java b/src/org/jgroups/protocols/CENTRAL_LOCK.java
deleted file mode 100644
index e0081efb185..00000000000
--- a/src/org/jgroups/protocols/CENTRAL_LOCK.java
+++ /dev/null
@@ -1,211 +0,0 @@
-package org.jgroups.protocols;
-
-import org.jgroups.Address;
-import org.jgroups.View;
-import org.jgroups.annotations.ManagedAttribute;
-import org.jgroups.annotations.Property;
-import org.jgroups.blocks.locking.LockNotification;
-import org.jgroups.util.Owner;
-import org.jgroups.util.Util;
-
-import java.util.*;
-
-
-/**
- * Implementation of a locking protocol which acquires locks by contacting the coordinator.
Because the
- * coordinator maintains all locks, no total order configuration is required.
- * CENTRAL_LOCK has all members send lock and unlock requests to a central coordinator. The coordinator has a queue for
- * incoming requests, and grants locks based on order of arrival. To prevent all acquired locks from being forgotten
- * when the coordinator crashes, setting num_backups lets the coordinator backup lock information to a number of
- * backup nodes. Valid values for num_backups are 0 (no backup) to N-1, e.g. in a cluster of 4, we can have only 3 backup
- * nodes.
- * Say we have a cluster of {A,B,C,D,E} and num_backups=1. A is the coordinator, and A updates all locks (and released
- * locks) in B as well. When A crashes, everybody falls over to B for sending lock and unlock requests.
- * B in turn copies all existing locks over to C and - when locks are acquired or released - forwards this
- * information to C as well.
- * @author Bela Ban
- * @since 2.12
- * @see Locking
- * @deprecated See http://belaban.blogspot.com/2020/11/i-hate-distributed-locks.html.
- */
-@Deprecated
-public class CENTRAL_LOCK extends Locking implements LockNotification {
-
- @Property(description="Number of backups to the coordinator. Server locks get replicated to these nodes as well")
- protected int num_backups=1;
-
-
- protected Address coord;
-
- @ManagedAttribute
- protected boolean is_coord;
-
- protected final List backups=new ArrayList<>();
-
-
- public CENTRAL_LOCK() {
- super();
- addLockListener(this);
- }
-
- protected Owner getOwner() {
- return use_thread_id_for_lock_owner? super.getOwner(): new Owner(local_addr, -1);
- }
-
- public Address getCoord() {
- return coord;
- }
-
- public boolean isCoord() {
- return is_coord;
- }
-
- @ManagedAttribute
- public String getCoordinator() {
- return coord != null? coord.toString() : "n/a";
- }
-
- public int getNumberOfBackups() {
- return num_backups;
- }
-
- public CENTRAL_LOCK setNumberOfBackups(int num_backups) {
- this.num_backups=num_backups; return this;
- }
-
- @ManagedAttribute
- public String getBackups() {
- return backups != null? backups.toString() : null;
- }
-
- protected void sendGrantLockRequest(String lock_name, int lock_id, Owner owner, long timeout, boolean is_trylock) {
- Address dest=coord;
- if(dest == null)
- throw new IllegalStateException("No coordinator available, cannot send GRANT-LOCK request");
- sendRequest(dest, Type.GRANT_LOCK, lock_name, lock_id, owner, timeout, is_trylock);
- }
-
- protected void sendReleaseLockRequest(String lock_name, int lock_id, Owner owner) {
- Address dest=coord;
- if(dest == null)
- throw new IllegalStateException("No coordinator available, cannot send RELEASE-LOCK request");
- sendRequest(dest, Type.RELEASE_LOCK, lock_name, lock_id, owner, 0, false);
- }
-
- protected void sendCreateLockRequest(Address dest, String lock_name, Owner owner) {
- sendRequest(dest, Type.CREATE_LOCK, lock_name, owner, 0, false);
- }
-
- protected void sendDeleteLockRequest(Address dest, String lock_name) {
- sendRequest(dest, Type.DELETE_LOCK, lock_name, null, 0, false);
- }
-
- @Override
- protected void sendAwaitConditionRequest(String lock_name, Owner owner) {
- sendRequest(coord, Type.LOCK_AWAIT, lock_name, owner, 0, false);
- }
-
- @Override
- protected void sendSignalConditionRequest(String lock_name, boolean all) {
- sendRequest(coord, all ? Type.COND_SIG_ALL : Type.COND_SIG, lock_name, null, 0, false);
- }
-
- @Override
- protected void sendDeleteAwaitConditionRequest(String lock_name, Owner owner) {
- sendRequest(coord, Type.DELETE_LOCK_AWAIT, lock_name, owner, 0, false);
- }
-
- public void handleView(View view) {
- super.handleView(view);
- Address old_coord=coord;
- if(view.size() > 0) {
- coord=view.getCoord();
- is_coord=coord.equals(local_addr);
- log.debug("[%s] coord=%s, is_coord=%b", local_addr, coord, is_coord);
- }
-
- if(is_coord && num_backups > 0) {
- List new_backups=Util.pickNext(view.getMembers(), local_addr, num_backups);
- List copy_locks_list=null;
- synchronized(backups) {
- if(!backups.equals(new_backups)) {
- copy_locks_list=new ArrayList<>(new_backups);
- copy_locks_list.removeAll(backups);
- backups.clear();
- backups.addAll(new_backups);
- }
- }
-
- if(copy_locks_list != null && !copy_locks_list.isEmpty())
- copyLocksTo(copy_locks_list);
- }
-
- // For all non-acquired client locks, send the GRANT_LOCK request to the new coordinator (if changed)
- if(old_coord != null && !old_coord.equals(coord))
- client_lock_table.resendPendingLockRequests();
- }
-
- public void lockCreated(String name) {
- }
-
- public void lockDeleted(String name) {
- }
-
- public void locked(String lock_name, Owner owner) {
- if(is_coord)
- updateBackups(Type.CREATE_LOCK, lock_name, owner);
- }
-
- public void unlocked(String lock_name, Owner owner) {
- if(is_coord)
- updateBackups(Type.DELETE_LOCK, lock_name, owner);
- }
-
- public void lockRevoked(String lock_name, Owner current_owner) {
- log.warn("%s: lock %s has been revoked; the existing owner is %s", local_addr, lock_name, current_owner);
- }
-
- public void awaiting(String lock_name, Owner owner) {
- if(is_coord)
- updateBackups(Type.CREATE_AWAITER, lock_name, owner);
- }
-
- public void awaited(String lock_name, Owner owner) {
- if(is_coord)
- updateBackups(Type.DELETE_AWAITER, lock_name, owner);
- }
-
- protected void updateBackups(Type type, String lock_name, Owner owner) {
- synchronized(backups) {
- for(Address backup: backups)
- sendRequest(backup, type, lock_name, owner, 0, false);
- }
- }
-
-
-
- protected void copyLocksTo(List new_joiners) {
- Map copy;
-
- synchronized(server_locks) {
- copy=new HashMap<>(server_locks);
- }
-
- log.trace("[%s] copying locks to %s", local_addr, new_joiners);
- for(Map.Entry entry: copy.entrySet()) {
- for(Address joiner: new_joiners) {
- ServerLock lock = entry.getValue();
- if (lock.owner != null) {
- sendCreateLockRequest(joiner, entry.getKey(), entry.getValue().owner);
- }
- synchronized (lock.condition) {
- Queue queue = lock.condition.queue;
- for (Owner owner : queue) {
- sendAwaitConditionRequest(lock.lock_name, owner);
- }
- }
- }
- }
- }
-}
-
diff --git a/src/org/jgroups/protocols/CENTRAL_LOCK2.java b/src/org/jgroups/protocols/CENTRAL_LOCK2.java
deleted file mode 100644
index 46895ef92ba..00000000000
--- a/src/org/jgroups/protocols/CENTRAL_LOCK2.java
+++ /dev/null
@@ -1,300 +0,0 @@
-package org.jgroups.protocols;
-
-import org.jgroups.*;
-import org.jgroups.annotations.ManagedAttribute;
-import org.jgroups.annotations.ManagedOperation;
-import org.jgroups.annotations.Property;
-import org.jgroups.conf.AttributeType;
-import org.jgroups.util.*;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.stream.Stream;
-
-
-/**
- * Implementation of a locking protocol which acquires locks by asking the coordinator.
- * Because the coordinator maintains all locks, no total ordering of requests is required.
- * CENTRAL_LOCK2 has all members send lock and unlock requests to the current coordinator. The coordinator has a queue
- * for incoming requests, and grants locks based on order of arrival.
- * Contrary to {@link CENTRAL_LOCK}, CENTRAL_LOCK2 has no members who act as backups for lock information. Instead,
- * when the coord leaves or on a merge, the new coordinator runs a reconciliation protocol in which it fetches
- * information from all members about acquired locks and pending lock and unlock requests, and then creates its lock
- * table accordingly. During this phase, all regular request handling is paused.
- * This protocol requires less traffic than {@link CENTRAL_LOCK} (each request also has to be sent to the backup(s)),
- * but introduces communication between the new coord and all members (and thus a small pause) on coord change.
- *
- * The JIRA issue is https://issues.redhat.com/browse/JGRP-2249.
- * @author Bela Ban
- * @since 4.0.13
- * @see Locking
- * @see CENTRAL_LOCK
- * @deprecated See http://belaban.blogspot.com/2020/11/i-hate-distributed-locks.html.
- */
-@Deprecated
-public class CENTRAL_LOCK2 extends Locking {
- @Property(description="Max time (im ms) to wait for lock info responses from members in a lock reconciliation phase",
- type=AttributeType.TIME)
- protected long lock_reconciliation_timeout=10_000;
-
- protected Address coord;
-
- // collect information about held locks and pending lock requests from all members during a reconciliation round
- protected final ResponseCollector lock_info_responses=new ResponseCollector<>();
-
- // Queue to hold requests, typically only at the coordinator. Processed by RequestHandler
- protected final BlockingQueue req_queue=new LinkedBlockingQueue<>();
-
- // Thread which processes requests in req-queue (running only on coord)
- protected final Runner req_handler;
-
-
-
- public CENTRAL_LOCK2() {
- req_handler=new Runner(new DefaultThreadFactory("lock-handler", true, true),
- "lock-handler", this::processQueue, req_queue::clear);
- }
-
- @ManagedAttribute public boolean isCoord() {return Objects.equals(local_addr, coord);}
- @ManagedAttribute public String getCoordinator() {return coord != null? coord.toString() : "n/a";}
- @ManagedAttribute public boolean isRequestHandlerRunning() {return req_handler.isRunning();}
- @ManagedAttribute public int requestQueueSize() {return req_queue.size();}
-
- public void stop() {
- super.stop();
- req_handler.stop();
- }
-
- @Override
- public void handleView(View v) {
- Address old_coord=this.view != null? this.view.getCoord() : null;
- super.handleView(v);
- if(v.size() > 0) {
- coord=v.getCoord();
- log.debug("%s: coord=%s, is_coord=%b", local_addr, coord, isCoord());
- }
-
- if(Objects.equals(local_addr, coord)) {
- if(v instanceof MergeView || !Objects.equals(local_addr, old_coord)) {
- // I'm the new coord: run reconciliation to find all existing locks (and pending lock/unlock requests)
- runReconciliation();
- req_handler.start();
- }
- }
- else {
- if(Objects.equals(local_addr, old_coord)) {
- log.debug("%s: not coordinator anymore; stopping the request handler", local_addr);
- req_handler.stop(); // clears the req-queue
- server_locks.clear();
- }
- }
- }
-
- @Override
- protected void requestReceived(Request req) {
- if(req == null) return;
- switch(req.type) {
-
- // requests to be handled by the coord:
- case GRANT_LOCK:
- case RELEASE_LOCK:
- case CREATE_LOCK:
- case DELETE_LOCK:
- case COND_SIG:
- case COND_SIG_ALL:
- case LOCK_AWAIT:
- case DELETE_LOCK_AWAIT:
- case CREATE_AWAITER:
- case DELETE_AWAITER:
- req_queue.add(req);
- break;
-
- // requests/responses to be handled by clients
- case LOCK_GRANTED:
- case RELEASE_LOCK_OK:
- case LOCK_DENIED:
- case SIG_RET:
- case LOCK_INFO_REQ:
- case LOCK_INFO_RSP:
- case LOCK_REVOKED:
- if(log.isTraceEnabled())
- log.trace("%s <-- %s: %s", local_addr, req.sender, req);
- handleRequest(req);
- break;
-
- default:
- log.error("%s: request of type %s not known", local_addr, req.type);
- break;
- }
- }
-
- protected void processQueue() {
- Request req=null;
- try {
- req=req_queue.take();
- }
- catch(InterruptedException ignore) {
- }
- try {
- if(req != null && log.isTraceEnabled())
- log.trace("%s <-- %s: %s", local_addr, req.sender, req);
- handleRequest(req);
- }
- catch(Throwable t) {
- log.error("%s: failed handling request %s: %s", local_addr, req, t);
- }
- }
-
- protected void handleLockInfoRequest(Address requester) {
- if(requester != null && !Objects.equals(coord, requester)) {
- log.trace("%s: changed coord from %s to %s as a result of getting a LOCK_INFO_REQ",
- local_addr, coord, requester);
- coord=requester;
- }
- LockInfoResponse response=createLockInfoResponse();
- if(log.isTraceEnabled())
- log.trace("%s --> %s LOCK-INFO-RSP:\n%s", local_addr, requester, response.printDetails());
- send(requester, new Request(Type.LOCK_INFO_RSP).infoRsp(response));
- }
-
- @Override
- protected void handleLockInfoResponse(Address sender, Request rsp) {
- lock_info_responses.add(sender, rsp.info_rsp);
- }
-
- @Override
- protected void handleLockRevoked(Request rsp) {
- notifyLockRevoked(rsp.lock_name, rsp.owner);
- }
-
- /** Grabs information about locks held and pending lock/unlock requests from all members */
- @ManagedOperation(description="Runs the reconciliation protocol to fetch information about owned locks and pending " +
- "lock/unlock requests from each member to establish the server lock table. Only run by a coordinator.")
- public void runReconciliation() {
- if(!isCoord()) {
- log.warn("%s: reconciliation protocol is not run as I'm not the coordinator (%s is)",
- local_addr, getCoordinator());
- return;
- }
- Request lock_info_req=new Request(Type.LOCK_INFO_REQ);
- Address[] mbrs=view.getMembersRaw();
- log.debug("%s: running reconciliation protocol on %d members", local_addr, mbrs != null? mbrs.length : 0);
- lock_info_responses.reset(mbrs);
- lock_info_responses.add(local_addr, createLockInfoResponse());
- log.trace("%s --> ALL: %s", local_addr, lock_info_req);
-
- // we cannot use a multicast as this may happen as a result of a MergeView and not everybody may have the view yet
- sendLockInfoRequestTo(lock_info_req, mbrs, local_addr);
- if(!lock_info_responses.waitForAllResponses(lock_reconciliation_timeout)) {
- List missing=lock_info_responses.getMissing();
- log.warn("%s: failed getting lock information from all members, missing responses: %d (from %s)",
- local_addr, missing.size(), missing);
- }
-
- // 1. Add all existing locks to the server lock table
- Collection responses=lock_info_responses.getResults().values();
- responses.stream().filter(rsp -> rsp != null && rsp.existing_locks != null)
- .map(rsp -> rsp.existing_locks).flatMap(Collection::stream)
- .forEach(t -> {
- String lock_name=t.getVal1();
- Owner owner=t.getVal2();
- ServerLock srv_lock=new ServerLock(lock_name, owner);
- ServerLock ret=server_locks.putIfAbsent(lock_name, srv_lock);
- if(ret != null) {
- if(!Objects.equals(owner, ret.owner)) {
- log.warn("%s: lock %s requested by %s is already present: %s", local_addr, lock_name, owner, ret);
- send(owner.getAddress(), new Request(Type.LOCK_REVOKED, lock_name, ret.owner, 0));
- }
- }
- else {
- notifyLockCreated(lock_name);
- log.trace("%s: added lock %s", local_addr, lock_name);
- }
- });
-
- // 2. Process all pending requests
- responses.stream().filter(rsp -> rsp != null && rsp.pending_requests != null && !rsp.pending_requests.isEmpty())
- .map(rsp -> rsp.pending_requests).flatMap(Collection::stream)
- .forEach(req -> {
- try {
- if(log.isTraceEnabled())
- log.trace("%s: processing request %s", local_addr, req);
- handleRequest(req);
- }
- catch(Throwable t) {
- log.error("%s: failed handling request %s: %s", local_addr, req, t);
- }
- });
- }
-
-
- protected void sendLockInfoRequestTo(Request req, Address[] mbrs, Address exclude) {
- Stream.of(mbrs).filter(m -> m != null && !Objects.equals(m, exclude)).forEach(dest -> {
- try {
- Message msg=new BytesMessage(dest, Util.streamableToBuffer(req)).putHeader(id, new LockingHeader());
- if(bypass_bundling)
- msg.setFlag(Message.Flag.DONT_BUNDLE);
- down_prot.down(msg);
- }
- catch(Throwable t) {
- log.error("%s: failed sending LOCK_INFO_REQ to %s: %s", local_addr, dest, t);
- }
- });
- }
-
-
- protected Owner getOwner() {
- return use_thread_id_for_lock_owner? super.getOwner(): new Owner(local_addr, -1);
- }
-
- protected void sendGrantLockRequest(String lock_name, int lock_id, Owner owner, long timeout, boolean is_trylock) {
- Address dest=coord;
- if(dest == null)
- throw new IllegalStateException("No coordinator available, cannot send GRANT-LOCK request");
- sendRequest(dest, Type.GRANT_LOCK, lock_name, lock_id, owner, timeout, is_trylock);
- }
-
- protected void sendReleaseLockRequest(String lock_name, int lock_id, Owner owner) {
- Address dest=coord;
- if(dest == null)
- throw new IllegalStateException("No coordinator available, cannot send RELEASE-LOCK request");
- sendRequest(dest, Type.RELEASE_LOCK, lock_name, lock_id, owner, 0, false);
- }
-
- @Override
- protected void sendAwaitConditionRequest(String lock_name, Owner owner) {
- sendRequest(coord, Type.LOCK_AWAIT, lock_name, owner, 0, false);
- }
-
- @Override
- protected void sendSignalConditionRequest(String lock_name, boolean all) {
- sendRequest(coord, all ? Type.COND_SIG_ALL : Type.COND_SIG, lock_name, null, 0, false);
- }
-
- @Override
- protected void sendDeleteAwaitConditionRequest(String lock_name, Owner owner) {
- sendRequest(coord, Type.DELETE_LOCK_AWAIT, lock_name, owner, 0, false);
- }
-
-
- protected LockInfoResponse createLockInfoResponse() {
- LockInfoResponse rsp=new LockInfoResponse();
- List> locks=client_lock_table.getLockInfo(); // successfully acquired locks
- for(Tuple t: locks)
- rsp.add(t);
-
- List pending_reqs=client_lock_table.getPendingRequests(local_addr); // pending lock/unlock requests
- if(pending_reqs != null && !pending_reqs.isEmpty())
- rsp.pending_requests=pending_reqs;
- return rsp;
- }
-
-
-
-
-
-}
-
diff --git a/src/org/jgroups/protocols/Locking.java b/src/org/jgroups/protocols/Locking.java
deleted file mode 100644
index d7643fdfd1f..00000000000
--- a/src/org/jgroups/protocols/Locking.java
+++ /dev/null
@@ -1,1742 +0,0 @@
-package org.jgroups.protocols;
-
-import org.jgroups.*;
-import org.jgroups.annotations.MBean;
-import org.jgroups.annotations.ManagedAttribute;
-import org.jgroups.annotations.ManagedOperation;
-import org.jgroups.annotations.Property;
-import org.jgroups.blocks.locking.AwaitInfo;
-import org.jgroups.blocks.locking.LockInfo;
-import org.jgroups.blocks.locking.LockNotification;
-import org.jgroups.stack.Protocol;
-import org.jgroups.util.*;
-
-import java.io.DataInput;
-import java.io.DataOutput;
-import java.io.IOException;
-import java.util.*;
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.LockSupport;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-
-/**
- * Base locking protocol, handling most of the protocol communication with other instances. To use distributed locking,
- * {@link org.jgroups.blocks.locking.LockService} is placed on a channel. LockService talks to a subclass of Locking
- * via events.
- * @author Bela Ban
- * @since 2.12
- * @see CENTRAL_LOCK
- * @see CENTRAL_LOCK2
- * @deprecated See http://belaban.blogspot.com/2020/11/i-hate-distributed-locks.html.
- */
-@Deprecated
-@MBean(description="Based class for locking functionality")
-abstract public class Locking extends Protocol {
-
- @Property(description="bypasses message bundling if set")
- protected boolean bypass_bundling=true;
-
- @Property(description="Number of locks to be used for lock striping (for synchronized access to the server_lock entries)")
- protected int lock_striping_size=10;
-
- @Property(description="By default, a lock owner is address:thread-id. If false, we only use the node's address. " +
- "See https://issues.redhat.com/browse/JGRP-1886 for details")
- protected boolean use_thread_id_for_lock_owner=true;
-
- protected View view;
-
- // server side locks
- protected final ConcurrentMap server_locks=Util.createConcurrentMap(20);
-
- // protected access to the same locks in server_locks
- protected Lock[] lock_stripes;
-
- // client side locks
- protected final ClientLockTable client_lock_table=new ClientLockTable();
-
- protected final Set lock_listeners=new CopyOnWriteArraySet<>();
-
- protected final static AtomicInteger current_lock_id=new AtomicInteger(1);
-
-
-
- public enum Type {
- GRANT_LOCK, // request to acquire a lock
- LOCK_GRANTED, // response to sender of GRANT_LOCK on succcessful lock acquisition
- LOCK_DENIED, // response to sender of GRANT_LOCK on unsuccessful lock acquisition (e.g. on tryLock())
- RELEASE_LOCK, // request to release a lock
- RELEASE_LOCK_OK, // response to RELEASE_LOCK request
- CREATE_LOCK, // request to create a server lock (sent by coordinator to backups). Used by LockService
- DELETE_LOCK, // request to delete a server lock (sent by coordinator to backups). Used by LockService
-
- LOCK_AWAIT, // request to await until condition is signaled
- COND_SIG, // request to signal awaiting thread
- COND_SIG_ALL, // request to signal all awaiting threads
- SIG_RET, // response to alert of signal
- DELETE_LOCK_AWAIT, // request to delete a waiter
- CREATE_AWAITER, // request to create a server lock await (sent by coordinator to backups). Used by LockService
- DELETE_AWAITER, // request to delete a server lock await (sent by coordinator to backups). Used by LockService
-
- LOCK_INFO_REQ, // request to get information about all acquired locks and all pending lock/unlock requests
- LOCK_INFO_RSP, // response to LOCK_INFO_REQ
- LOCK_REVOKED // sent on reconciliation when a lock is already present (possible on a merge when both sides hold the same lock)
- }
-
-
-
- public Locking() {
- }
-
-
- public boolean bypassBundling() {return bypass_bundling;}
- public Locking bypassBundling(boolean b) {this.bypass_bundling=b; return this;}
- public int getLockStripingSize() {return lock_striping_size;}
- public Locking setLockStripingSize(int l) {this.lock_striping_size=l; return this;}
- public boolean useThreadIdForLockOwner() {return use_thread_id_for_lock_owner;}
- public Locking useThreadIdForLockOwner(boolean u) {this.use_thread_id_for_lock_owner=u; return this;}
-
-
- public void addLockListener(LockNotification listener) {
- if(listener != null)
- lock_listeners.add(listener);
- }
-
- public void removeLockListener(LockNotification listener) {
- if(listener != null)
- lock_listeners.remove(listener);
- }
-
- @ManagedAttribute
- public String getView() {
- return view != null? view.toString() : null;
- }
-
- @ManagedAttribute(description="Number of server locks (only on coord)")
- public int getNumServerLocks() {return server_locks.size();}
-
- @ManagedAttribute(description="Number of client locks")
- public int getNumClientLocks() {return client_lock_table.numLocks();}
-
- public void init() throws Exception {
- super.init();
- lock_stripes=new Lock[lock_striping_size];
- for(int i=0; i < lock_stripes.length; i++)
- lock_stripes[i]=new ReentrantLock();
- }
-
- public Object down(Event evt) {
- switch(evt.getType()) {
- case Event.LOCK:
- LockInfo info=evt.getArg();
- ClientLock lock=getLock(info.getName());
- if(!info.isTrylock()) {
- if(info.isLockInterruptibly()) {
- try {
- lock.lockInterruptibly();
- }
- catch(InterruptedException e) {
- Thread.currentThread().interrupt(); // has to be checked by caller who has to rethrow ...
- }
- }
- else
- lock.lock();
- }
- else {
- if(info.isUseTimeout()) {
- try {
- return lock.tryLock(info.getTimeout(), info.getTimeUnit());
- }
- catch(InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- else
- return lock.tryLock();
- }
- return null;
-
-
- case Event.UNLOCK:
- info=evt.getArg();
- lock=getLock(info.getName(), false);
- if(lock != null)
- lock.unlock();
- return null;
-
- case Event.UNLOCK_ALL:
- unlockAll();
- return null;
-
- case Event.UNLOCK_FORCE:
- unlockForce(evt.arg());
- break;
-
-
- case Event.LOCK_AWAIT:
- info=evt.getArg();
- lock=getLock(info.getName(), false);
- if (lock == null || !lock.acquired) {
- throw new IllegalMonitorStateException();
- }
- Condition condition = lock.newCondition();
- if (info.isUseTimeout()) {
- try {
- return condition.awaitNanos(info.getTimeUnit().toNanos(info.getTimeout()));
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- else if (info.isLockInterruptibly()) {
- try {
- condition.await();
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- }
- else {
- condition.awaitUninterruptibly();
- }
- return null;
- case Event.LOCK_SIGNAL:
- AwaitInfo awaitInfo =evt.getArg();
- lock=getLock(awaitInfo.getName(), false);
- if (lock == null || !lock.acquired) {
- throw new IllegalMonitorStateException();
- }
- sendSignalConditionRequest(awaitInfo.getName(), awaitInfo.isAll());
- return null;
-
- case Event.VIEW_CHANGE:
- handleView(evt.getArg());
- break;
- }
- return down_prot.down(evt);
- }
-
- public Object up(Event evt) {
- switch(evt.getType()) {
- case Event.VIEW_CHANGE:
- handleView(evt.getArg());
- break;
- }
- return up_prot.up(evt);
- }
-
- public Object up(Message msg) {
- LockingHeader hdr=msg.getHeader(id);
- if(hdr == null)
- return up_prot.up(msg);
-
- Request req=null;
- try {
- req=Util.streamableFromBuffer(Request::new, msg.getArray(), msg.getOffset(), msg.getLength())
- .sender(msg.getSrc());
- }
- catch(Exception ex) {
- log.error("%s: failed deserializing request", local_addr, ex);
- return null;
- }
-
- if(req.type != Type.LOCK_INFO_REQ && req.type != Type.LOCK_INFO_RSP && req.type != Type.LOCK_REVOKED
- && null != view && !view.containsMember(msg.getSrc())) {
- log.error("%s: received request from '%s' but member is not present in the current view - ignoring request",
- local_addr, msg.getSrc());
- return null;
- }
- requestReceived(req);
- return null;
- }
-
- protected void requestReceived(Request req) {
- if(log.isTraceEnabled())
- log.trace("%s <-- %s: %s", local_addr, req.sender, req);
- handleRequest(req);
- }
-
- protected void handleRequest(Request req) {
- if(req == null) return;
- switch(req.type) {
- case GRANT_LOCK:
- case RELEASE_LOCK:
- handleLockRequest(req);
- break;
- case LOCK_GRANTED:
- handleLockGrantedResponse(req.lock_name, req.lock_id, req.owner);
- break;
- case RELEASE_LOCK_OK:
- handleLockReleasedResponse(req.lock_name, req.lock_id, req.owner);
- break;
- case LOCK_DENIED:
- handleLockDeniedResponse(req.lock_name, req.lock_id, req.owner);
- break;
- case CREATE_LOCK:
- handleCreateLockRequest(req.lock_name, req.owner);
- break;
- case DELETE_LOCK:
- handleDeleteLockRequest(req.lock_name);
- break;
- case COND_SIG:
- case COND_SIG_ALL:
- handleSignalRequest(req);
- break;
- case LOCK_AWAIT:
- handleAwaitRequest(req.lock_name, req.owner);
- handleLockRequest(req);
- break;
- case DELETE_LOCK_AWAIT:
- handleDeleteAwaitRequest(req.lock_name, req.owner);
- break;
- case SIG_RET:
- handleSignalResponse(req.lock_name, req.owner);
- break;
- case CREATE_AWAITER:
- handleCreateAwaitingRequest(req.lock_name, req.owner);
- break;
- case DELETE_AWAITER:
- handleDeleteAwaitingRequest(req.lock_name, req.owner);
- break;
- case LOCK_INFO_REQ:
- handleLockInfoRequest(req.sender);
- break;
- case LOCK_INFO_RSP:
- handleLockInfoResponse(req.sender, req);
- break;
- case LOCK_REVOKED:
- handleLockRevoked(req);
- break;
- default:
- log.error("%s: request of type %s not known", local_addr, req.type);
- break;
- }
- }
-
- protected ClientLock getLock(String name) {
- return client_lock_table.getLock(name,getOwner(),true);
- }
-
- protected ClientLock getLock(String name, boolean create_if_absent) {
- return client_lock_table.getLock(name,getOwner(),create_if_absent);
- }
-
- @ManagedOperation(description="Unlocks all currently held locks")
- public void unlockAll() {
- client_lock_table.unlockAll();
- }
-
- @ManagedOperation(description="Forcefully removes the client lock")
- public void unlockForce(String lock_name) {
- client_lock_table.unlockForce(lock_name);
- }
-
-
- @ManagedOperation(description="Dumps all locks")
- public String printLocks() {
- StringBuilder sb=new StringBuilder();
- Collection values=server_locks.values();
- if(values != null && !values.isEmpty()) {
- sb.append("server locks: ");
- for(ServerLock sl : server_locks.values())
- sb.append(sl).append("\n");
- }
-
- String client_locks=client_lock_table.printLocks();
- if(client_locks != null && !client_locks.isEmpty())
- sb.append("my locks: ").append(client_lock_table.printLocks());
- return sb.toString();
- }
-
-
- @ManagedOperation(description="Dumps all server locks")
- public Object printServerLocks() {
- return server_locks.values().stream().map(ServerLock::toString).collect(Collectors.joining(", "));
- }
-
- protected void handleView(View view) {
- this.view=view;
- log.debug("%s: view=%s", local_addr, view);
- List members=view.getMembers();
- List responses=new ArrayList<>();
- for(Map.Entry entry: server_locks.entrySet()) {
- String lock_name=entry.getKey();
- ServerLock server_lock=entry.getValue();
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- Response rsp=server_lock.handleView(members);
- if(rsp != null)
- responses.add(rsp);
- if(server_lock.isEmpty() && server_lock.owner == null && server_lock.condition.queue.isEmpty())
- server_locks.remove(lock_name);
- }
- finally {
- lock.unlock();
- }
- }
-
- // do the sending outside the lock scope (might block on credits or TCP send)
- for(Response rsp: responses)
- sendLockResponse(rsp.type, rsp.owner, rsp.lock_name, rsp.lock_id);
- }
-
-
-
- protected ClientLock createLock(String lock_name, Owner owner) {
- return new ClientLock(lock_name, owner);
- }
-
- /** Gets a lock from locks based on the hash of the lock name */
- protected Lock _getLock(String lock_name) {
- int index=lock_name != null? Math.abs(lock_name.hashCode() % lock_stripes.length) : 0;
- return lock_stripes[index];
- }
-
- protected Owner getOwner() {
- return new Owner(local_addr, Thread.currentThread().getId());
- }
-
- abstract protected void sendGrantLockRequest(String lock_name, int lock_id, Owner owner, long timeout, boolean is_trylock);
- abstract protected void sendReleaseLockRequest(String lock_name, int lock_id, Owner owner);
- abstract protected void sendAwaitConditionRequest(String lock_name, Owner owner);
- abstract protected void sendSignalConditionRequest(String lock_name, boolean all);
- abstract protected void sendDeleteAwaitConditionRequest(String lock_name, Owner owner);
-
-
- protected void sendRequest(Address dest, Type type, String lock_name, Owner owner, long timeout, boolean is_trylock) {
- send(dest, new Request(type, lock_name, owner, timeout, is_trylock));
- }
-
- protected void sendRequest(Address dest, Type type, String lock_name, int lock_id, Owner owner, long timeout, boolean is_trylock) {
- send(dest, new Request(type, lock_name, owner, timeout, is_trylock).lockId(lock_id));
- }
-
- protected void sendLockResponse(Type type, Owner dest, String lock_name, int lock_id) {
- send(dest.getAddress(), new Request(type, lock_name, dest, 0).lockId(lock_id));
- }
-
- protected void sendSignalResponse(Owner dest, String lock_name) {
- send(dest.getAddress(), new Request(Type.SIG_RET, lock_name, dest, 0));
- }
-
- protected void send(Address dest, Request req) {
- ByteArray array=null;
- try {
- array=Util.streamableToBuffer(req);
- }
- catch(Exception e) {
- log.warn("%s: failed serializing request: %s", local_addr, e);
- }
- Message msg=new BytesMessage(dest, array).putHeader(id, new LockingHeader());
- if(bypass_bundling)
- msg.setFlag(Message.Flag.DONT_BUNDLE);
- log.trace("%s --> %s: %s", local_addr, dest == null? "ALL" : dest, req);
- try {
- down_prot.down(msg);
- }
- catch(Exception ex) {
- log.error("%s: failed sending %s request: %s", local_addr, req.type, ex);
- }
- }
-
-
- protected void handleLockRequest(Request req) {
- Response rsp=null;
- Lock lock=_getLock(req.lock_name);
- lock.lock();
- try {
- ServerLock server_lock=server_locks.get(req.lock_name);
- if(server_lock == null) {
- server_lock=new ServerLock(req.lock_name);
- ServerLock tmp=server_locks.putIfAbsent(req.lock_name, server_lock);
- if(tmp != null)
- server_lock=tmp;
- else
- notifyLockCreated(req.lock_name);
- }
- rsp=server_lock.handleRequest(req);
- if(server_lock.isEmpty() && server_lock.owner == null && server_lock.condition.queue.isEmpty())
- server_locks.remove(req.lock_name);
- }
- finally {
- lock.unlock();
- }
-
- // moved outside the lock scope
- if(rsp != null)
- sendLockResponse(rsp.type, rsp.owner, rsp.lock_name, rsp.lock_id);
- }
-
-
- protected void handleLockGrantedResponse(String lock_name, int lock_id, Owner owner) {
- ClientLock lock=client_lock_table.getLock(lock_name,owner,false);
- if(lock != null)
- lock.handleLockGrantedResponse(lock_id);
- }
-
- protected void handleLockReleasedResponse(String lock_name, int lock_id, Owner owner) {
- ClientLock lock=client_lock_table.getLock(lock_name,owner,false);
- if(lock != null)
- lock.handleLockReleasedResponse(lock_id);
- }
-
- protected void handleLockDeniedResponse(String lock_name, int lock_id, Owner owner) {
- ClientLock lock=client_lock_table.getLock(lock_name,owner,false);
- if(lock != null)
- lock.lockDenied(lock_id);
- }
-
- protected void handleLockInfoRequest(Address requester) {
-
- }
-
- protected void handleLockInfoResponse(Address sender, Request rsp) {
-
- }
-
- protected void handleLockRevoked(Request rsp) {
-
- }
-
- protected void handleAwaitRequest(String lock_name, Owner owner) {
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- ServerLock server_lock=server_locks.get(lock_name);
- if (server_lock != null)
- server_lock.condition.addWaiter(owner);
- else
- log.error(Util.getMessage("ConditionAwaitWasReceivedButLockWasNotCreatedWaiterMayBlockForever"));
- }
- finally {
- lock.unlock();
- }
- }
-
- protected void handleDeleteAwaitRequest(String lock_name, Owner owner) {
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- ServerLock server_lock=server_locks.get(lock_name);
- if (server_lock != null)
- server_lock.condition.removeWaiter(owner);
- else
- log.error(Util.getMessage("ConditionAwaitDeleteWasReceivedButLockWasGone"));
- }
- finally {
- lock.unlock();
- }
- }
-
- protected void handleSignalResponse(String lock_name, Owner owner) {
- ClientLock lock=client_lock_table.getLock(lock_name,owner,false);
- if(lock != null) {
- lock.condition.signaled();
- }
- else {
- log.error(Util.getMessage("ConditionResponseWasClientLockWasNotPresentIgnoredSignal"));
- }
- }
-
- protected void handleSignalRequest(Request req) {
- Response rsp=null;
- Lock lock=_getLock(req.lock_name);
- lock.lock();
- try {
- ServerLock server_lock=server_locks.get(req.lock_name);
- if (server_lock != null)
- rsp=server_lock.handleRequest(req);
- else
- log.error(Util.getMessage("ConditionSignalWasReceivedButLockWasNotCreatedCouldnTNotifyAnyone"));
- }
- finally {
- lock.unlock();
- }
-
- // moved outside the lock scope
- if(rsp != null)
- sendLockResponse(rsp.type, rsp.owner, rsp.lock_name, rsp.lock_id);
- }
-
- protected void handleCreateLockRequest(String lock_name, Owner owner) {
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- server_locks.put(lock_name, new ServerLock(lock_name, owner));
- }
- finally {
- lock.unlock();
- }
- }
-
-
- protected void handleDeleteLockRequest(String lock_name) {
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- ServerLock server_lock = server_locks.get(lock_name);
- if(server_lock == null)
- return;
- if (server_lock.condition.queue.isEmpty())
- server_locks.remove(lock_name);
- else
- server_lock.owner= null;
- }
- finally {
- lock.unlock();
- }
- }
-
-
- protected void handleCreateAwaitingRequest(String lock_name, Owner owner) {
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- ServerLock server_lock = server_locks.get(lock_name);
- if (server_lock == null) {
- server_lock = new ServerLock(lock_name);
- ServerLock tmp=server_locks.putIfAbsent(lock_name,server_lock);
- if(tmp != null)
- server_lock=tmp;
- }
- server_lock.condition.queue.add(owner);
- }
- finally {
- lock.unlock();
- }
- }
-
-
- protected void handleDeleteAwaitingRequest(String lock_name, Owner owner) {
- Lock lock=_getLock(lock_name);
- lock.lock();
- try {
- ServerLock server_lock = server_locks.get(lock_name);
- if (server_lock != null) {
- server_lock.condition.queue.remove(owner);
- if (server_lock.condition.queue.isEmpty() && server_lock.owner == null) {
- server_locks.remove(lock_name);
- }
- }
- }
- finally {
- lock.unlock();
- }
- }
-
-
-
- protected void notifyLockCreated(String lock_name) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.lockCreated(lock_name);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
- protected void notifyLockDeleted(String lock_name) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.lockDeleted(lock_name);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
- protected void notifyLockRevoked(String lock_name, Owner current_owner) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.lockRevoked(lock_name, current_owner);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
- protected void notifyLocked(String lock_name, Owner owner) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.locked(lock_name,owner);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
- protected void notifyUnlocked(String lock_name, Owner owner) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.unlocked(lock_name,owner);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
- protected void notifyAwaiting(String lock_name, Owner owner) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.awaiting(lock_name,owner);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
- protected void notifyAwaited(String lock_name, Owner owner) {
- for(LockNotification listener: lock_listeners) {
- try {
- listener.awaited(lock_name,owner);
- }
- catch(Throwable t) {
- log.error("%s: failed notifying %s: %s", local_addr, listener, t.toString());
- }
- }
- }
-
-
-
- /**
- * Server side queue for handling of lock requests (lock, release).
- * @author Bela Ban
- */
- protected class ServerLock {
- protected final String lock_name;
- protected Owner owner;
- protected final List queue=new ArrayList<>();
- protected final ServerCondition condition;
-
- public ServerLock(String lock_name) {
- this.lock_name=lock_name;
- this.condition=new ServerCondition(this);
- }
-
- protected ServerLock(String lock_name, Owner owner) {
- this.lock_name=lock_name;
- this.owner=owner;
- this.condition=new ServerCondition(this);
- }
-
- protected Response handleRequest(Request req) {
- switch(req.type) {
- case GRANT_LOCK:
- if(owner == null) {
- setOwner(req.owner);
- return new Response(Type.LOCK_GRANTED, req.owner, req.lock_name, req.lock_id);
- }
- if(owner.equals(req.owner))
- return new Response(Type.LOCK_GRANTED, req.owner, req.lock_name, req.lock_id);
-
- if(req.is_trylock && req.timeout <= 0)
- return new Response(Type.LOCK_DENIED, req.owner, req.lock_name, req.lock_id);
- addToQueue(req);
- break;
- case RELEASE_LOCK:
- case LOCK_AWAIT:
- if(Objects.equals(owner, req.owner)) {
- setOwner(null);
- if(req.type == Type.RELEASE_LOCK)
- sendLockResponse(Type.RELEASE_LOCK_OK, req.owner, req.lock_name, req.lock_id);
- }
- else
- addToQueue(req);
- break;
- case COND_SIG:
- condition.signal(false);
- break;
- case COND_SIG_ALL:
- condition.signal(true);
- break;
- default:
- throw new IllegalArgumentException("type " + req.type + " is invalid here");
- }
-
- return processQueue();
- }
-
- protected Response handleView(List members) {
- if(owner != null && !members.contains(owner.getAddress())) {
- Owner tmp=owner;
- setOwner(null);
- log.debug("%s: unlocked \"%s\" because owner %s left", local_addr, lock_name, tmp);
- }
-
- synchronized(queue) {
- queue.removeIf(req -> !members.contains(req.owner.getAddress()));
- }
-
- condition.queue.removeIf(own -> !members.contains(own.getAddress()));
- return processQueue();
- }
-
-
- protected void addToQueue(Request req) {
- synchronized(queue) {
- if(queue.isEmpty()) {
- if(req.type == Type.GRANT_LOCK)
- queue.add(req);
- return; // RELEASE_LOCK is discarded on an empty queue
- }
- }
-
- // at this point the queue is not empty
- switch(req.type) {
-
- // If there is already a lock request from the same owner, discard the new lock request
- case GRANT_LOCK:
- synchronized(queue) {
- if(!isRequestPresent(Type.GRANT_LOCK, req.owner))
- queue.add(req);
- }
- break;
-
- case RELEASE_LOCK:
- // Release the lock request from the same owner already in the queue
- // If there is no lock request, discard the unlock request
- removeRequest(Type.GRANT_LOCK, req.owner);
- break;
- }
- }
-
- /** Checks if a certain request from a given owner is already in the queue */
- protected boolean isRequestPresent(Type type, Owner owner) { // holds lock on queue
- for(Request req: queue)
- if(req.type == type && req.owner.equals(owner))
- return true;
- return false;
- }
-
- protected void removeRequest(Type type, Owner owner) {
- synchronized(queue) {
- queue.removeIf(req -> req.type == type && req.owner.equals(owner));
- }
- }
-
- protected Request getNextRequest() {
- synchronized(queue) {
- return !queue.isEmpty()? queue.remove(0) : null;
- }
- }
-
- protected Response processQueue() {
- if(owner != null)
- return null;
- Request req;
- while((req=getNextRequest()) != null) {
- switch(req.type) {
- case GRANT_LOCK:
- setOwner(req.owner);
- return new Response(Type.LOCK_GRANTED, req.owner, req.lock_name, req.lock_id);
- case RELEASE_LOCK:
- if(owner == null)
- break;
- if(owner.equals(req.owner))
- setOwner(null);
- return new Response(Type.RELEASE_LOCK_OK, req.owner, req.lock_name, req.lock_id);
- }
- }
- return null;
- }
-
- protected void setOwner(Owner owner) {
- if(owner == null) {
- if(this.owner != null) {
- Owner tmp=this.owner;
- this.owner=null;
- notifyUnlocked(lock_name, tmp);
- }
- }
- else {
- this.owner=owner;
- notifyLocked(lock_name, owner);
- }
- }
-
- public boolean isEmpty() {
- synchronized(queue) {
- return queue.isEmpty();
- }
- }
-
- public String toString() {
- StringBuilder sb=new StringBuilder(lock_name + ": ").append(owner);
- synchronized(queue) {
- if(!queue.isEmpty()) {
- sb.append(", queue: ");
- for(Request req : queue) {
- sb.append(req.toStringShort()).append(" ");
- }
- }
- }
- return sb.toString();
- }
- }
-
- protected class ServerCondition {
- protected final ServerLock lock;
- protected final Queue queue=new ArrayDeque<>();
-
- public ServerCondition(ServerLock lock) {
- this.lock = lock;
- }
-
- public void addWaiter(Owner waiter) {
- notifyAwaiting(lock.lock_name, waiter);
- log.trace("%s: waiter %s was added for %s", local_addr, waiter, lock.lock_name);
- queue.add(waiter);
- }
-
- public void removeWaiter(Owner waiter) {
- notifyAwaited(lock.lock_name, waiter);
- log.trace("%s: waiter %s was removed for %s", local_addr, waiter, lock.lock_name);
- queue.remove(waiter);
- }
-
- public void signal(boolean all) {
- if (queue.isEmpty())
- log.trace("%s: signal for %s ignored since, no one is waiting in queue", local_addr, lock.lock_name);
-
- Owner entry;
- if (all) {
- while ((entry = queue.poll()) != null) {
- notifyAwaited(lock.lock_name, entry);
- log.trace("%s: signalled %s for %s", local_addr, entry, lock.lock_name);
- sendSignalResponse(entry, lock.lock_name);
- }
- }
- else {
- entry = queue.poll();
- if (entry != null) {
- notifyAwaited(lock.lock_name, entry);
- log.trace("%s: signalled %s for %s", local_addr, entry, lock.lock_name);
- sendSignalResponse(entry, lock.lock_name);
- }
- }
- }
- }
-
-
- /**
- * Implementation of {@link Lock}. This is a client stub communicates with a server equivalent. The semantics are
- * more or less those of {@link Lock}, but may differ slightly.
- * For details see {@link org.jgroups.blocks.locking.LockService}.
- */
- protected class ClientLock implements Lock, Comparable {
- protected final String name;
- protected Owner owner;
- protected volatile boolean acquired;
- protected volatile boolean denied;
- protected volatile boolean is_trylock;
- protected long timeout;
- protected final ClientCondition condition;
-
- // unique for locks for the same name:owner, can wrap around (that's ok)
- protected final int lock_id=current_lock_id.getAndIncrement();
-
-
-
- public ClientLock(String name) {
- this.name=name;
- this.condition = new ClientCondition(this);
- }
-
- public ClientLock(String name, Owner owner) {
- this(name);
- this.owner=owner;
- }
-
- public boolean isHeld() {return acquired && !denied;}
-
- public void lock() {
- try {
- acquire(false);
- }
- catch(InterruptedException e) { // should never happen
- Thread.currentThread().interrupt(); // just a second line of defense
- }
- }
-
- public void lockInterruptibly() throws InterruptedException {
- acquire(true);
- }
-
- public boolean tryLock() {
- try {
- return acquireTryLock(0, false);
- }
- catch(InterruptedException e) {
- Thread.currentThread().interrupt();
- return false;
- }
- }
-
- public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
- return acquireTryLock(TimeUnit.MILLISECONDS.convert(time, unit), true);
- }
-
- public synchronized void unlock() {
- _unlock(false);
- }
-
- public Condition newCondition() {
- // Currently only 1 condition per Lock is supported
- return condition;
- }
-
- public String toString() {
- return String.format("%s (id=%d, locked=%b, owner=%s)", name, lock_id, acquired, owner != null? owner : "n/a");
- }
-
- protected synchronized void lockGranted(int lock_id) {
- if(this.lock_id != lock_id) {
- log.error(Util.getMessage("DiscardedLOCKGRANTEDResponseWithLockId") + lock_id + ", my lock-id=" + this.lock_id);
- return;
- }
- acquired=true;
- this.notifyAll();
- }
-
- protected synchronized void lockDenied(int lock_id) {
- if(this.lock_id != lock_id) {
- log.error(Util.getMessage("DiscardedLOCKDENIEDResponseWithLockId") + lock_id + ", my lock_id=" + this.lock_id);
- return;
- }
- denied=true;
- this.notifyAll();
- }
-
- protected void handleLockGrantedResponse(int lock_id) {
- lockGranted(lock_id);
- }
-
- protected void handleLockReleasedResponse(int lock_id) {
- if(this.lock_id != lock_id) {
- log.error(Util.getMessage("DiscardedLOCKGRANTEDResponseWithLockId") + lock_id + ", my lock-id=" + this.lock_id);
- return;
- }
- _unlockOK();
- }
-
- protected synchronized void acquire(boolean throwInterrupt) throws InterruptedException {
- if(acquired)
- return;
- if(throwInterrupt && Thread.interrupted())
- throw new InterruptedException();
- owner=getOwner();
- sendGrantLockRequest(name, lock_id, owner, 0, false);
- boolean interrupted=false;
- while(!acquired) {
- try {
- this.wait();
- }
- catch(InterruptedException e) {
- if(throwInterrupt && !acquired) {
- _unlock(true);
- throw e;
- }
- // If we don't throw exceptions then we just set the interrupt flag and let it loop around
- interrupted=true;
- }
- }
- if(interrupted)
- Thread.currentThread().interrupt();
- }
-
- protected synchronized void _unlock(boolean force) {
- if(!acquired && !denied && !force)
- return;
- this.timeout=0;
- this.is_trylock=false;
- if(!denied) {
- if(!force)
- client_lock_table.addToPendingReleaseRequests(this);
- sendReleaseLockRequest(name, lock_id, owner); // lock will be released on RELEASE_LOCK_OK response
- if(force && client_lock_table.removeClientLock(name,owner))
- notifyLockDeleted(name);
-
- if(!force) {
- //unlock will return only when get RELEASE_LOCK_OK or timeLeft after some seconds
- long time_left=10000;
- while(acquired || denied) {
- long start=System.currentTimeMillis();
- try {
- wait(time_left);
- }
- catch(InterruptedException ie) {
- break;
- }
- long duration=System.currentTimeMillis() - start;
- if(duration > 0)
- time_left-=duration;
- if(time_left <= 0) {
- log.warn("%s: timeout waiting for RELEASE_LOCK_OK response for lock %s", local_addr, this);
- break;
- }
- }
- }
- }
- else
- _unlockOK();
- }
-
- protected synchronized void _unlockOK() {
- acquired=denied=false;
- notifyAll();
- if(client_lock_table.removeClientLock(name,owner))
- notifyLockDeleted(name);
- owner=null;
- }
-
- protected synchronized boolean acquireTryLock(long timeout, boolean use_timeout) throws InterruptedException {
- if(denied)
- return false;
- if(!acquired) {
- if(use_timeout && Thread.interrupted())
- throw new InterruptedException();
- is_trylock=true;
- this.timeout=timeout;
- if(owner == null)
- owner=getOwner();
- sendGrantLockRequest(name, lock_id, owner, timeout, true);
-
- boolean interrupted = false;
- while(!acquired && !denied) {
- if(use_timeout) {
- long timeout_ns=TimeUnit.NANOSECONDS.convert(timeout, TimeUnit.MILLISECONDS),
- wait_time=timeout_ns,
- start=System.nanoTime();
-
- while(wait_time > 0 && !acquired && !denied) {
- try {
- long wait_ms=TimeUnit.MILLISECONDS.convert(wait_time, TimeUnit.NANOSECONDS);
- if(wait_ms <= 0)
- break;
- this.wait(wait_ms);
- }
- catch(InterruptedException e) {
- interrupted=true;
- }
- finally {
- wait_time=timeout_ns - (System.nanoTime() - start);
- this.timeout=TimeUnit.MILLISECONDS.convert(wait_time, TimeUnit.NANOSECONDS);
- }
- }
- break;
- }
- else {
- try {
- this.wait();
- }
- catch(InterruptedException e) {
- interrupted = true;
- }
- }
- }
- if(interrupted)
- Thread.currentThread().interrupt();
- }
- boolean retval=acquired && !denied;
- if(!acquired || denied)
- _unlock(true);
- return retval;
- }
-
- public boolean equals(Object obj) {
- return this == obj || Objects.equals(owner, ((ClientLock)obj).owner);
- }
-
- public int compareTo(ClientLock o) {
- int rc=owner.compareTo(o.owner);
- return rc != 0? rc : name.compareTo(o.name);
- }
- }
-
- /** Manages access to client locks */
- protected class ClientLockTable {
- protected final ConcurrentMap> table=Util.createConcurrentMap(20);
- protected final Set pending_release_reqs=new ConcurrentSkipListSet<>();
-
-
- protected int numLocks() {return table.size();}
-
- protected synchronized ClientLock getLock(String name, Owner owner, boolean create_if_absent) {
- Map owners=table.get(name);
- if(owners == null) {
- if(!create_if_absent)
- return null;
- owners=Util.createConcurrentMap(20);
- Map existing=table.putIfAbsent(name,owners);
- if(existing != null)
- owners=existing;
- }
- ClientLock lock=owners.get(owner);
- if(lock == null) {
- if(!create_if_absent)
- return null;
- lock=createLock(name, owner);
- owners.put(owner, lock);
- }
- return lock;
- }
-
- protected synchronized boolean removeClientLock(String lock_name, Owner owner) {
- pending_release_reqs.removeIf(cl -> Objects.equals(cl.name, lock_name) && Objects.equals(cl.owner, owner));
- Map owners=table.get(lock_name);
- if(owners != null) {
- ClientLock lock=owners.remove(owner);
- if(lock != null && owners.isEmpty())
- table.remove(lock_name);
- return lock != null;
- }
- return false;
- }
-
- protected void unlockAll() {
- List lock_list=new ArrayList<>();
- synchronized(this) {
- table.values().forEach(map -> lock_list.addAll(map.values()));
- }
- lock_list.forEach(ClientLock::unlock);
- }
-
- protected void unlockForce(String lock_name) {
- Map owners=table.get(lock_name);
- if(owners != null) {
- for(ClientLock cl : owners.values())
- cl._unlock(true);
- }
- pending_release_reqs.removeIf(cl -> Objects.equals(cl.name, lock_name));
- }
-
- protected void resendPendingLockRequests() {
- final List pending_lock_reqs=new ArrayList<>();
- synchronized(this) {
- if(!table.isEmpty()) {
- table.values().forEach(map -> map.values().stream().filter(lock -> !lock.acquired && !lock.denied)
- .forEach(pending_lock_reqs::add));
- }
- }
- if(!pending_lock_reqs.isEmpty()) { // send outside of the synchronized block
- if(log.isTraceEnabled()) {
- String tmp=pending_lock_reqs.stream().map(ClientLock::toString).collect(Collectors.joining(", "));
- log.trace("%s: resending pending lock requests: %s", local_addr, tmp);
- }
- pending_lock_reqs.forEach(l -> sendGrantLockRequest(l.name, l.lock_id, l.owner, l.timeout, l.is_trylock));
- }
-
- if(!pending_release_reqs.isEmpty()) {
- if(log.isTraceEnabled()) {
- String tmp=pending_release_reqs.stream().map(ClientLock::toString).collect(Collectors.joining(", "));
- log.trace("%s: resending pending unlock requests: %s", local_addr, tmp);
- }
- pending_release_reqs.forEach(cl -> sendReleaseLockRequest(cl.name, cl.lock_id, cl.owner));
- }
- }
-
- protected synchronized Collection