You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by oz...@apache.org on 2005/01/08 19:53:18 UTC
cvs commit: jakarta-commons/transaction/src/java/org/apache/commons/transaction/locking GenericLock.java
ozeigermann 2005/01/08 10:53:18
Modified: transaction/src/java/org/apache/commons/transaction/locking
GenericLock.java
Log:
Added extended means for waiter management
Revision Changes Path
1.10 +109 -37 jakarta-commons/transaction/src/java/org/apache/commons/transaction/locking/GenericLock.java
Index: GenericLock.java
===================================================================
RCS file: /home/cvs/jakarta-commons/transaction/src/java/org/apache/commons/transaction/locking/GenericLock.java,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -r1.9 -r1.10
--- GenericLock.java 7 Jan 2005 23:33:24 -0000 1.9
+++ GenericLock.java 8 Jan 2005 18:53:18 -0000 1.10
@@ -23,9 +23,13 @@
package org.apache.commons.transaction.locking;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -128,7 +132,15 @@
public static final int COMPATIBILITY_REENTRANT_AND_SUPPORT = 3;
protected Object resourceId;
- protected Map owners = new HashMap();
+ // XXX needs to be synchronized to allow for unsynchronized access for deadlock detection
+ // in getConflictingOwners to avoid deadlocks between lock to acquire and lock to check for
+ // deadlocks
+ protected Map owners = Collections.synchronizedMap(new HashMap());
+ // XXX needs to be synchronized to allow for unsynchronized access for deadlock detection
+ // in getConflictingWaiters to avoid deadlocks between lock to acquire and lock to check for
+ // deadlocks
+ // Note: having this as a list allows for fair mechanisms in sub classes
+ protected List waitingOwners = Collections.synchronizedList(new ArrayList());
private int maxLockLevel;
protected LoggerFacade logger;
protected int waiters = 0;
@@ -283,8 +295,10 @@
+ System.currentTimeMillis());
}
+ LockOwner waitingOwner = new LockOwner(ownerId, targetLockLevel, compatibility,
+ preferred);
try {
- waiters++;
+ registerWaiter(waitingOwner);
if (preferred) {
// while waiting we already make our claim we are next
LockOwner oldLock = null;
@@ -293,7 +307,8 @@
oldLock = (LockOwner) owners.get(ownerId);
// this creates a new owner, so we do not need to
// copy the old one
- setLockLevel(ownerId, null, targetLockLevel, preferred);
+ setLockLevel(ownerId, null, targetLockLevel, compatibility,
+ preferred);
// finally wait
wait(remaining);
@@ -315,7 +330,7 @@
wait(remaining);
}
} finally {
- waiters--;
+ unregisterWaiter(waitingOwner);
}
if (tryLock(ownerId, targetLockLevel, compatibility, preferred)) {
@@ -337,6 +352,21 @@
}
}
+ protected void registerWaiter(LockOwner waitingOwner) {
+ synchronized (waitingOwners) {
+ unregisterWaiter(waitingOwner);
+ waiters++;
+ waitingOwners.add(waitingOwner);
+ }
+ }
+
+ protected void unregisterWaiter(LockOwner waitingOwner) {
+ synchronized (waitingOwners) {
+ if (waitingOwners.remove(waitingOwner))
+ waiters--;
+ }
+ }
+
/**
* @see org.apache.commons.transaction.locking.MultiLevelLock#release(Object)
*/
@@ -357,7 +387,7 @@
/**
* @see org.apache.commons.transaction.locking.MultiLevelLock#getLockLevel(Object)
*/
- public synchronized int getLockLevel(Object ownerId) {
+ public int getLockLevel(Object ownerId) {
LockOwner owner = (LockOwner) owners.get(ownerId);
if (owner == null) {
return 0;
@@ -406,12 +436,18 @@
for (Iterator it = owners.values().iterator(); it.hasNext();) {
LockOwner owner = (LockOwner) it.next();
- buf.append("- ").append(owner.ownerId.toString()).append(": ").append(owner.lockLevel)
- .append(owner.intention ? " intention" : " acquired").append("\n");
+ buf.append("- ").append(owner.toString()).append("\n");
}
- buf.append(waiters).append(" waiting\n");
- return buf.toString();
+ if (waiters != 0) {
+ buf.append(waiters).append(" waiting:\n");
+ for (Iterator it = waitingOwners.iterator(); it.hasNext();) {
+ LockOwner owner = (LockOwner) it.next();
+ buf.append("- ").append(owner.toString()).append("\n");
+ }
+ }
+
+ return buf.toString();
}
protected synchronized LockOwner getMaxLevelOwner() {
@@ -443,10 +479,9 @@
}
protected synchronized void setLockLevel(Object ownerId, LockOwner lock, int targetLockLevel,
- boolean intention) {
+ int compatibility, boolean intention) {
// be sure there exists at most one lock per owner
if (lock != null) {
-
if (logger.isFinestEnabled()) {
logger.logFinest(
ownerId.toString()
@@ -457,11 +492,7 @@
+ " at "
+ System.currentTimeMillis());
}
-
- lock.lockLevel = targetLockLevel;
- lock.intention = intention;
} else {
-
if (logger.isFinestEnabled()) {
logger.logFinest(
ownerId.toString()
@@ -472,9 +503,8 @@
+ " at "
+ System.currentTimeMillis());
}
-
- owners.put(ownerId, new LockOwner(ownerId, targetLockLevel, intention));
}
+ owners.put(ownerId, new LockOwner(ownerId, targetLockLevel, compatibility, intention));
}
protected synchronized boolean tryLock(Object ownerId, int targetLockLevel, int compatibility,
@@ -509,6 +539,7 @@
highestOwner = getMaxLevelOwner();
}
+ int i;
// what is our current lock level?
int currentLockLevel;
if (highestOwner != null) {
@@ -520,7 +551,7 @@
// we are only allowed to acquire our locks if we do not compromise locks of any other lock owner
if (isCompatible(targetLockLevel, currentLockLevel)) {
// if we really have the lock, it no longer is an intention
- setLockLevel(ownerId, myLock, targetLockLevel, false);
+ setLockLevel(ownerId, myLock, targetLockLevel, compatibility, false);
return true;
} else {
return false;
@@ -531,35 +562,60 @@
return (targetLockLevel <= getLevelMaxLock() - currentLockLevel);
}
- protected synchronized Set getConflictingOwners(Object ownerId, int targetLockLevel,
- int compatibility) {
+ protected Set getConflictingOwners(Object ownerId, int targetLockLevel, int compatibility) {
LockOwner myLock = (LockOwner) owners.get(ownerId);
if (myLock != null && targetLockLevel <= myLock.lockLevel) {
// shortcut as we already have the lock
return null;
}
+
+ LockOwner testLock = new LockOwner(ownerId, targetLockLevel, compatibility, false);
+ List ownersCopy;
+ synchronized (owners) {
+ ownersCopy = new ArrayList(owners.values());
+ }
+ return getConflictingOwners(testLock, ownersCopy);
+
+ }
+ protected Collection getConflictingWaiters(Object ownerId) {
+ LockOwner owner = (LockOwner) owners.get(ownerId);
+ if (owner != null) {
+ List waiterCopy;
+ synchronized (waitingOwners) {
+ waiterCopy = new ArrayList(waitingOwners);
+ }
+ Collection conflicts = getConflictingOwners(owner, waiterCopy);
+ return conflicts;
+ }
+ return null;
+ }
+
+ protected Set getConflictingOwners(LockOwner myOwner, Collection ownersToTest) {
+
+ if (myOwner == null) return null;
+
Set conflicts = new HashSet();
// check if any locks conflict with ours
- for (Iterator it = owners.values().iterator(); it.hasNext();) {
+ for (Iterator it = ownersToTest.iterator(); it.hasNext();) {
LockOwner owner = (LockOwner) it.next();
// we do not interfere with ourselves, except when explicitely said so
- if ((compatibility == COMPATIBILITY_REENTRANT || compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT)
- && owner.ownerId.equals(ownerId))
+ if ((myOwner.compatibility == COMPATIBILITY_REENTRANT || myOwner.compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT)
+ && owner.ownerId.equals(myOwner.ownerId))
continue;
// otherwise find out the lock level of the owner and see if we conflict with it
int onwerLockLevel = owner.lockLevel;
- if (compatibility == COMPATIBILITY_SUPPORT
- || compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT
- && targetLockLevel == onwerLockLevel)
+ if (myOwner.compatibility == COMPATIBILITY_SUPPORT
+ || myOwner.compatibility == COMPATIBILITY_REENTRANT_AND_SUPPORT
+ && myOwner.lockLevel == onwerLockLevel)
continue;
- if (!isCompatible(targetLockLevel, onwerLockLevel)) {
+ if (!isCompatible(myOwner.lockLevel, onwerLockLevel)) {
conflicts.add(owner.ownerId);
}
}
@@ -567,18 +623,34 @@
}
protected static class LockOwner {
- public Object ownerId;
- public int lockLevel;
- public boolean intention;
+ public final Object ownerId;
+ public final int lockLevel;
+ public final boolean intention;
+ public final int compatibility;
- public LockOwner(Object ownerId, int lockLevel, boolean intention) {
+ public LockOwner(Object ownerId, int lockLevel, int compatibility, boolean intention) {
this.ownerId = ownerId;
this.lockLevel = lockLevel;
this.intention = intention;
+ this.compatibility = compatibility;
}
- public LockOwner(Object ownerId, int lockLevel) {
- this(ownerId, lockLevel, false);
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append(ownerId.toString()).append(": level ").append(lockLevel).append(", complevel ")
+ .append(compatibility).append(intention ? ", intention/preferred" : "");
+ return buf.toString();
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof LockOwner) {
+ return ((LockOwner)o).ownerId.equals(ownerId);
+ }
+ return false;
+ }
+
+ public int hashCode() {
+ return ownerId.hashCode();
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org