[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