[jboss-cvs] JBossCache/src/org/jboss/cache/interceptors ...
Manik Surtani
msurtani at jboss.com
Mon Dec 4 19:01:52 EST 2006
User: msurtani
Date: 06/12/04 19:01:52
Modified: src/org/jboss/cache/interceptors Tag:
Branch_JBossCache_1_4_0
PessimisticLockInterceptor.java
Log:
ported fixes for JBCACHE-871 and JBCACHE-875 from the 1.3.0 branch
Revision Changes Path
No revision
No revision
1.20.2.2 +111 -37 JBossCache/src/org/jboss/cache/interceptors/PessimisticLockInterceptor.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: PessimisticLockInterceptor.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/interceptors/PessimisticLockInterceptor.java,v
retrieving revision 1.20.2.1
retrieving revision 1.20.2.2
diff -u -b -r1.20.2.1 -r1.20.2.2
--- PessimisticLockInterceptor.java 31 Oct 2006 17:10:46 -0000 1.20.2.1
+++ PessimisticLockInterceptor.java 5 Dec 2006 00:01:52 -0000 1.20.2.2
@@ -23,6 +23,7 @@
import javax.transaction.Transaction;
import java.util.Collections;
+import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -35,7 +36,7 @@
* current method and unlock when the method returns.
*
* @author Bela Ban
- * @version $Id: PessimisticLockInterceptor.java,v 1.20.2.1 2006/10/31 17:10:46 msurtani Exp $
+ * @version $Id: PessimisticLockInterceptor.java,v 1.20.2.2 2006/12/05 00:01:52 msurtani Exp $
*/
public class PessimisticLockInterceptor extends Interceptor
{
@@ -65,6 +66,7 @@
long lock_timeout = lock_acquisition_timeout;
Object[] args = m.getArgs();
InvocationContext ctx = getInvocationContext();
+ boolean storeLockedNode = false;
if (log.isTraceEnabled()) log.trace("PessimisticLockInterceptor invoked for method " + m);
if (ctx.getOptionOverrides() != null && ctx.getOptionOverrides().isSuppressLocking())
@@ -112,6 +114,8 @@
fqn = (Fqn) args[1];
lock_type = DataNode.LOCK_TYPE_WRITE;
recursive = true; // remove node and *all* child nodes
+ // JBCACHE-871 We need to store the node
+ storeLockedNode = true;
break;
case MethodDeclarations.removeKeyMethodLocal_id:
case MethodDeclarations.removeDataMethodLocal_id:
@@ -165,13 +169,13 @@
{
do
{
- lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, zeroLockTimeout ? 0 : lock_timeout, createIfNotExists);
+ lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, zeroLockTimeout ? 0 : lock_timeout, createIfNotExists, storeLockedNode);
}
while (!cache.exists(fqn)); // keep trying until we have the lock (fixes concurrent remove())
// terminates successfully, or with (Timeout)Exception
}
else
- lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, zeroLockTimeout ? 0 : lock_timeout, createIfNotExists);
+ lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, zeroLockTimeout ? 0 : lock_timeout, createIfNotExists, storeLockedNode);
}
else
{
@@ -180,6 +184,17 @@
}
if (m.getMethodId() == MethodDeclarations.lockMethodLocal_id)
return null;
+
+ // FIXME this should be done in UnlockInterceptor, but I didn't want
+ // to add the removedNodes map to TreeCache
+ if (storeLockedNode && ctx.getGlobalTransaction() == null)
+ {
+ //cache.getRemovedNodesMap().remove(fqn);
+ //cache.peek(fqn);
+ // do a REAL remove here.
+ cache.realRemove(fqn, true);
+ }
+
return super.invoke(m);
}
@@ -193,7 +208,7 @@
* @param recursive Lock children recursively
*/
private void lock(Fqn fqn, GlobalTransaction gtx, int lock_type, boolean recursive,
- long lock_timeout, boolean createIfNotExists)
+ long lock_timeout, boolean createIfNotExists, boolean isRemoveNodeOperation)
throws TimeoutException, LockingException, InterruptedException
{
DataNode n;
@@ -203,6 +218,7 @@
Object owner = (gtx != null) ? (Object) gtx : currentThread;
int treeNodeSize;
boolean acquired = false;
+ int currentLockType;
if (log.isTraceEnabled()) log.trace("Attempting to lock node " + fqn + " for owner " + owner);
@@ -220,10 +236,19 @@
lock_type = DataNode.LOCK_TYPE_NONE;
n = cache.getRoot();
- for (int i = 0; i < treeNodeSize; i++)
+ for (int i = -1; i < treeNodeSize; i++)
+ {
+ if (i == -1)
+ {
+ child_name = Fqn.ROOT.getName();
+ child_node = cache.getRoot();
+ }
+ else
{
child_name = fqn.get(i);
child_node = (DataNode) n.getOrCreateChild(child_name, gtx, createIfNotExists);
+ }
+
if (child_node == null)
{
if (log.isTraceEnabled())
@@ -239,35 +264,21 @@
}
else
{
- if (lock_type == DataNode.LOCK_TYPE_WRITE && i == (treeNodeSize - 1))
+ if (writeLockNeeded(lock_type, i, treeNodeSize, isRemoveNodeOperation, createIfNotExists, fqn, child_node.getFqn()))
{
- acquired = child_node.acquire(owner, lock_timeout, DataNode.LOCK_TYPE_WRITE);
+ currentLockType = DataNode.LOCK_TYPE_WRITE;
}
else
{
- acquired = child_node.acquire(owner, lock_timeout, DataNode.LOCK_TYPE_READ);
+ currentLockType = DataNode.LOCK_TYPE_READ;
}
}
+ // Try to acquire the lock; recording that we did if successful
+ acquireNodeLock(child_node, owner, gtx, currentLockType, lock_timeout);
- if (acquired)
- {
- if (gtx != null)
- {
- // add the lock to the list of locks maintained for this transaction
- // (needed for release of locks on commit or rollback)
- cache.getTransactionTable().addLock(gtx, child_node.getLock());
- }
- else
+ if (recursive && isTargetNode(i, treeNodeSize))
{
- IdentityLock l = child_node.getLock();
- List locks = getLocks(currentThread);
- if (!locks.contains(l))
- locks.add(l);
- }
- }
-
- if (recursive && i == (treeNodeSize - 1))
{
Set acquired_locks = child_node.acquireAll(owner, lock_timeout, lock_type);
if (acquired_locks.size() > 0)
@@ -278,15 +289,62 @@
}
else
{
- List locks = getLocks(currentThread);
+ List locks = getLocks(Thread.currentThread());
locks.addAll(acquired_locks);
}
}
}
+ }
n = child_node;
}
+
+ // Add the Fqn to be removed to the transaction entry so we can clean up after ourselves during commit/rollback
+ if (isRemoveNodeOperation && gtx != null) cache.getTransactionTable().get(gtx).addRemovedNode(fqn);
+ }
+
+ private boolean writeLockNeeded(int lock_type, int currentNodeIndex, int treeNodeSize, boolean isRemoveOperation, boolean createIfNotExists, Fqn targetFqn, Fqn currentFqn)
+ {
+ if (isRemoveOperation && currentNodeIndex == treeNodeSize - 2)
+ return true; // we're doing a remove and we've reached the PARENT node of the target to be removed.
+
+ if (!isTargetNode(currentNodeIndex, treeNodeSize) && !cache.exists(new Fqn(currentFqn, targetFqn.get(currentNodeIndex + 1))))
+ return createIfNotExists; // we're at a node in the tree, not yet at the target node, and we need to create the next node. So we need a WL here.
+
+ return lock_type == DataNode.LOCK_TYPE_WRITE && isTargetNode(currentNodeIndex, treeNodeSize) && createIfNotExists; //normal operation, write lock explicitly requested and this is the target to be written to.
+ }
+
+ private boolean isTargetNode(int nodePosition, int treeNodeSize)
+ {
+ return nodePosition == (treeNodeSize - 1);
+ }
+
+ private void acquireNodeLock(DataNode node, Object owner, GlobalTransaction gtx, int lock_type, long lock_timeout) throws LockingException, TimeoutException, InterruptedException
+ {
+ boolean acquired = node.acquire(owner, lock_timeout, lock_type);
+ if (acquired)
+ {
+ // Record the lock for release on method return or tx commit/rollback
+ recordNodeLock(gtx, node.getLock());
+ }
+ }
+
+ private void recordNodeLock(GlobalTransaction gtx, IdentityLock lock)
+ {
+ if (gtx != null)
+ {
+ // add the lock to the list of locks maintained for this transaction
+ // (needed for release of locks on commit or rollback)
+ cache.getTransactionTable().addLock(gtx, lock);
+ }
+ else
+ {
+ List locks = getLocks(Thread.currentThread());
+ if (!locks.contains(lock))
+ locks.add(lock);
+ }
}
+
private List getLocks(Thread currentThread)
{
// This sort of looks like a get/put race condition, but
@@ -338,6 +396,14 @@
return;
}
+ // first remove nodes that should be deleted.
+ Iterator removedNodes = entry.getRemovedNodes().iterator();
+ while (removedNodes.hasNext())
+ {
+ Fqn f = (Fqn) removedNodes.next();
+ cache.realRemove(f, false);
+ }
+
// Let's do it in stack style, LIFO
entry.releaseAllLocksLIFO(gtx);
@@ -375,6 +441,14 @@
return;
}
+ Iterator removedNodes = entry.getRemovedNodes().iterator();
+ while (removedNodes.hasNext())
+ {
+ Fqn f = (Fqn) removedNodes.next();
+ cache.realRemove(f, false);
+
+ }
+
// 1. Revert the modifications by running the undo-op list in reverse. This *cannot* throw any exceptions !
entry.undoOperations(cache);
More information about the jboss-cvs-commits
mailing list