Permalink
Browse files

Merged branch JGRP-1298 (support for Condition objects, contributed b…

  • Loading branch information...
2 parents 7ac81b8 + 6c39b0e commit 2e43ba918788dbe8663dc5bb4ef47967eea2eac9 @belaban committed Mar 3, 2011
@@ -55,6 +55,8 @@
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 USER_DEFINED = 1000; // arg = <user def., e.g. evt type + data>
@@ -149,6 +151,8 @@ public static String type2String(int t) {
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 USER_DEFINED: return "USER_DEFINED";
default: return "UNDEFINED(" + t + ")";
@@ -0,0 +1,30 @@
+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;
+ }
+}
@@ -8,4 +8,6 @@
void lockDeleted(String name);
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);
}
@@ -1,14 +1,16 @@
package org.jgroups.blocks.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;
+
import org.jgroups.Event;
import org.jgroups.JChannel;
import org.jgroups.annotations.Experimental;
import org.jgroups.protocols.Locking;
-import java.util.concurrent.TimeUnit;
-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.<p/>
@@ -78,39 +80,121 @@ public String printLocks() {
protected class LockImpl implements Lock {
protected final String name;
+ protected final AtomicReference<Thread> holder = new AtomicReference<Thread>();
public LockImpl(String name) {
this.name=name;
}
public void lock() {
ch.down(new Event(Event.LOCK, new LockInfo(name, false, false, false, 0, TimeUnit.MILLISECONDS)));
+ holder.set(Thread.currentThread());
}
public void lockInterruptibly() throws InterruptedException {
ch.down(new Event(Event.LOCK, new LockInfo(name, false, true, false, 0, TimeUnit.MILLISECONDS)));
- if(Thread.currentThread().isInterrupted())
+ Thread currentThread = Thread.currentThread();
+ if(currentThread.isInterrupted())
throw new InterruptedException();
+ else
+ holder.set(Thread.currentThread());
}
public boolean tryLock() {
Boolean retval=(Boolean)ch.downcall(new Event(Event.LOCK, new LockInfo(name, true, false, false, 0, TimeUnit.MILLISECONDS)));
+ if (retval == Boolean.TRUE) {
+ holder.set(Thread.currentThread());
+ }
return retval.booleanValue();
}
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
Boolean retval=(Boolean)ch.downcall(new Event(Event.LOCK, new LockInfo(name, true, true, true, time, unit)));
if(Thread.currentThread().isInterrupted())
throw new InterruptedException();
+ if (retval == Boolean.TRUE) {
+ holder.set(Thread.currentThread());
+ }
return retval.booleanValue();
}
public void unlock() {
ch.down(new Event(Event.UNLOCK, new LockInfo(name, false, false, false, 0, TimeUnit.MILLISECONDS)));
+ holder.set(null);
}
+ /**
+ * 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() {
- throw new UnsupportedOperationException();
+ return new ConditionImpl(name, holder);
+ }
+ }
+
+ private class ConditionImpl implements Condition {
+ protected final String name;
+ protected final AtomicReference<Thread> holder;
+
+ public ConditionImpl(String name, AtomicReference<Thread> 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.downcall(new Event(Event.LOCK_AWAIT,
+ new LockInfo(name, false, true, true, nanosTimeout,
+ TimeUnit.NANOSECONDS)));
+ if(Thread.currentThread().isInterrupted())
+ throw new InterruptedException();
+ return waitLeft.longValue();
+ }
+
+ @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)));
}
}
}
@@ -1,17 +1,18 @@
package org.jgroups.demos;
-import org.jgroups.ChannelException;
-import org.jgroups.JChannel;
-import org.jgroups.blocks.locking.*;
-import org.jgroups.jmx.JmxConfigurator;
-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;
+import org.jgroups.JChannel;
+import org.jgroups.blocks.locking.LockNotification;
+import org.jgroups.blocks.locking.LockService;
+import org.jgroups.blocks.locking.Owner;
+import org.jgroups.jmx.JmxConfigurator;
+import org.jgroups.util.Util;
+
/**
* Demos the LockService
*/
@@ -60,6 +61,13 @@ 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<String> lock_names;
@@ -167,5 +175,4 @@ protected static void help() {
System.out.println("Example:\nlock lock lock2 lock3\nunlock all\ntrylock bela michelle 300");
}
-
}
@@ -1,5 +1,11 @@
package org.jgroups.protocols;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+
import org.jgroups.Address;
import org.jgroups.View;
import org.jgroups.annotations.Experimental;
@@ -9,11 +15,6 @@
import org.jgroups.blocks.locking.Owner;
import org.jgroups.util.Util;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
/**
* Implementation of a locking protocol which acquires locks by contacting the coordinator.</p> Because the
@@ -97,6 +98,20 @@ 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);
@@ -156,6 +171,16 @@ public void unlocked(String lock_name, Owner owner) {
if(is_coord)
updateBackups(Type.DELETE_LOCK, lock_name, 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) {
@@ -176,11 +201,19 @@ protected void copyLocksTo(List<Address> new_joiners) {
if(log.isTraceEnabled())
log.trace("copying locks to " + new_joiners);
for(Map.Entry<String,ServerLock> entry: copy.entrySet()) {
- for(Address joiner: new_joiners)
- sendCreateLockRequest(joiner, entry.getKey(), entry.getValue().current_owner);
+ for(Address joiner: new_joiners) {
+ ServerLock lock = entry.getValue();
+ if (lock.current_owner != null) {
+ sendCreateLockRequest(joiner, entry.getKey(), entry.getValue().current_owner);
+ }
+ synchronized (lock.condition) {
+ Queue<Owner> queue = lock.condition.queue;
+ for (Owner owner : queue) {
+ sendAwaitConditionRequest(lock.lock_name, owner);
+ }
+ }
+ }
}
}
-
-
}
Oops, something went wrong.

0 comments on commit 2e43ba9

Please sign in to comment.