org.jgroups.protocols.Locking Maven / Gradle / Ivy
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.Bits;
import org.jgroups.util.Owner;
import org.jgroups.util.Streamable;
import org.jgroups.util.Util;
import java.io.DataInput;
import java.io.DataOutput;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
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;
/**
* 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 org.jgroups.protocols.CENTRAL_LOCK
*/
@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;
protected Address local_addr;
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);
protected static 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
CREATE_LOCK, // request to create a server lock (sent by coordinator to backups). Used by CentralLockService
DELETE_LOCK, // request to delete a server lock (sent by coordinator to backups). Used by CentralLockService
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 CentralLockService
DELETE_AWAITER // request to delete a server lock await (sent by coordinator to backups). Used by CentralLockService
}
public Locking() {
}
public boolean getBypassBundling() {
return bypass_bundling;
}
public void setBypassBundling(boolean bypass_bundling) {
this.bypass_bundling=bypass_bundling;
}
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 getAddress() {
return local_addr != null? local_addr.toString() : null;
}
@ManagedAttribute
public String getView() {
return view != null? view.toString() : null;
}
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=(LockInfo)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=(LockInfo)evt.getArg();
lock=getLock(info.getName(), false);
if(lock != null)
lock.unlock();
return null;
case Event.UNLOCK_ALL:
unlockAll();
return null;
case Event.LOCK_AWAIT:
info=(LockInfo)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 = (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.SET_LOCAL_ADDRESS:
local_addr=(Address)evt.getArg();
break;
case Event.VIEW_CHANGE:
handleView((View)evt.getArg());
break;
}
return down_prot.down(evt);
}
public Object up(Event evt) {
switch(evt.getType()) {
case Event.MSG:
Message msg=(Message)evt.getArg();
LockingHeader hdr=(LockingHeader)msg.getHeader(id);
if(hdr == null)
break;
Request req=(Request)msg.getObject();
log.trace("[%s] <-- [%s] %s", local_addr, msg.getSrc(), req);
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 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;
default:
log.error("Request of type %s not known", req.type);
break;
}
return null;
case Event.VIEW_CHANGE:
handleView((View)evt.getArg());
break;
}
return up_prot.up(evt);
}
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="Dumps all locks")
public String printLocks() {
StringBuilder sb=new StringBuilder();
sb.append("server locks:\n");
for(Map.Entry entry: server_locks.entrySet())
sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
sb.append("\nmy locks: ").append(client_lock_table.toString());
return sb.toString();
}
protected void handleView(View view) {
this.view=view;
log.debug("view=%s", 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.current_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, 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) {
// Message msg=new Message(dest, req).putHeader(id, new LockingHeader()).setFlag(Message.Flag.OOB);
Message msg=new Message(dest, req).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(new Event(Event.MSG, msg));
}
catch(Exception ex) {
log.error("failed sending %s request: %s", 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.current_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 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 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("Condition await was received but lock was not created. Waiter may block forever");
}
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("Condition await delete was received, but lock was gone");
}
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("Condition response was client lock was not present. Ignored signal.");
}
}
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("Condition signal was received but lock was not created. Couldn't notify anyone.");
}
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.current_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.current_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("failed notifying %s: %s", listener, t.toString());
}
}
}
protected void notifyLockDeleted(String lock_name) {
for(LockNotification listener: lock_listeners) {
try {
listener.lockDeleted(lock_name);
}
catch(Throwable t) {
log.error("failed notifying %s: %s", 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("failed notifying %s: %s", 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("failed notifying %s: %s", 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("failed notifying %s: %s", 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("failed notifying %s: %s", 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 current_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.current_owner=owner;
this.condition=new ServerCondition(this);
}
protected Response handleRequest(Request req) {
switch(req.type) {
case GRANT_LOCK:
if(current_owner == null) {
setOwner(req.owner);
return new Response(Type.LOCK_GRANTED, req.owner, req.lock_name, req.lock_id);
}
if(current_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(current_owner == null)
break;
if(current_owner.equals(req.owner))
setOwner(null);
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(current_owner != null && !members.contains(current_owner.getAddress())) {
Owner tmp=current_owner;
setOwner(null);
log.debug("unlocked \"%s\" because owner %s left", lock_name, tmp);
}
synchronized(queue) {
for(Iterator it=queue.iterator(); it.hasNext(); ) {
Request req=it.next();
if(!members.contains(req.owner.getAddress()))
it.remove();
}
}
for(Iterator it=condition.queue.iterator(); it.hasNext();) {
Owner own=it.next();
if(!members.contains(own.getAddress()))
it.remove();
}
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) {
for(Iterator it=queue.iterator(); it.hasNext(); ) {
Request req=it.next();
if(req.type == type && req.owner.equals(owner))
it.remove();
}
}
}
protected Request getNextRequest() {
synchronized(queue) {
return !queue.isEmpty()? queue.remove(0) : null;
}
}
protected Response processQueue() {
if(current_owner != null)
return null;
Request req;
while((req=getNextRequest()) != null) {
if(req.type == Type.GRANT_LOCK) {
setOwner(req.owner);
return new Response(Type.LOCK_GRANTED, req.owner, req.lock_name, req.lock_id);
}
}
return null;
}
protected void setOwner(Owner owner) {
if(owner == null) {
if(current_owner != null) {
Owner tmp=current_owner;
current_owner=null;
notifyUnlocked(lock_name, tmp);
}
}
else {
current_owner=owner;
notifyLocked(lock_name, owner);
}
}
public boolean isEmpty() {
synchronized(queue) {
return queue.isEmpty();
}
}
public String toString() {
StringBuilder sb=new StringBuilder();
sb.append(current_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("Waiter [%s] was added for %s", waiter, lock.lock_name);
queue.add(waiter);
}
public void removeWaiter(Owner waiter) {
notifyAwaited(lock.lock_name, waiter);
log.trace("Waiter [%s] was removed for %s", waiter, lock.lock_name);
queue.remove(waiter);
}
public void signal(boolean all) {
if (queue.isEmpty())
log.trace("Signal for [%s] ignored since, no one is waiting in queue", lock.lock_name);
Owner entry;
if (all) {
while ((entry = queue.poll()) != null) {
notifyAwaited(lock.lock_name, entry);
log.trace("Signalled %s for %s", entry, lock.lock_name);
sendSignalResponse(entry, lock.lock_name);
}
}
else {
entry = queue.poll();
if (entry != null) {
notifyAwaited(lock.lock_name, entry);
log.trace("Signalled %s for %s", 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 {
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 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 name + " (id=" + lock_id + ", locked=" + acquired + ")";
}
protected synchronized void lockGranted(int lock_id) {
if(this.lock_id != lock_id) {
log.error("discarded LOCK-GRANTED response with lock-id=" + 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("discarded LOCK-DENIED response with lock-id=" + lock_id + ", my lock_id=" + this.lock_id);
return;
}
denied=true;
this.notifyAll();
}
protected void handleLockGrantedResponse(int lock_id) {
lockGranted(lock_id);
}
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)
sendReleaseLockRequest(name, owner);
acquired=denied=false;
notifyAll();
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 {
this.wait(TimeUnit.MILLISECONDS.convert(wait_time, TimeUnit.NANOSECONDS));
}
catch(InterruptedException e) {
//if (!acquired && !denied) {
// _unlock(true);
//throw 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;
}
}
/** Manages access to client locks */
protected class ClientLockTable {
protected final ConcurrentMap> table=Util.createConcurrentMap(20);
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=new HashMap<>();
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 void removeClientLock(String lock_name, Owner owner) {
Map owners=table.get(lock_name);
if(owners != null) {
ClientLock lock=owners.remove(owner);
if(lock != null) {
if(owners.isEmpty())
table.remove(lock_name);
}
}
}
protected void unlockAll() {
List lock_list=new ArrayList<>();
synchronized(this) {
Collection
© 2015 - 2025 Weber Informatics LLC | Privacy Policy