[jboss-cvs] JBossCache/src/org/jboss/cache/interceptors ...

Brian Stansberry brian.stansberry at jboss.com
Wed Nov 22 16:37:37 EST 2006


  User: bstansberry
  Date: 06/11/22 16:37:37

  Modified:    src/org/jboss/cache/interceptors  Tag:
                        JBossCache_1_3_0_SP3_JBCACHE-873
                        PessimisticLockInterceptor.java
  Log:
  [JBCACHE-873] Fix JBCACHE-871 for Siemens
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.14.6.1  +88 -31    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.14
  retrieving revision 1.14.6.1
  diff -u -b -r1.14 -r1.14.6.1
  --- PessimisticLockInterceptor.java	14 Feb 2006 08:10:51 -0000	1.14
  +++ PessimisticLockInterceptor.java	22 Nov 2006 21:37:37 -0000	1.14.6.1
  @@ -13,6 +13,8 @@
   import org.jboss.cache.lock.TimeoutException;
   import org.jgroups.blocks.MethodCall;
   
  +import EDU.oswego.cs.dl.util.concurrent.ConcurrentHashMap;
  +
   import javax.transaction.Transaction;
   import java.lang.reflect.Method;
   import java.util.*;
  @@ -22,7 +24,7 @@
    * scope of the TX. When no TX is present, we keep track of the locks acquired during the current method and unlock
    * when the method returns
    * @author Bela Ban
  - * @version $Id: PessimisticLockInterceptor.java,v 1.14 2006/02/14 08:10:51 bela Exp $
  + * @version $Id: PessimisticLockInterceptor.java,v 1.14.6.1 2006/11/22 21:37:37 bstansberry Exp $
    */
   public class PessimisticLockInterceptor extends Interceptor {
      TransactionTable           tx_table=null;
  @@ -30,6 +32,7 @@
      /** Map<Object, java.util.List>. Keys = threads, values = lists of locks held by that thread */
      Map                        lock_table;
      private long               lock_acquisition_timeout;
  +   Map removedNodes = new ConcurrentHashMap();
   
   
      public void setCache(TreeCache cache) {
  @@ -60,6 +63,7 @@
         boolean recursive=false;
         boolean createIfNotExists=false;
   
  +      boolean storeLockedNode = false;
   
         // 1. Determine the type of lock (read, write, or none) depending on the method. If no lock is required, invoke
         //    the method, then return immediately
  @@ -76,6 +80,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;
         }
         else if(meth.equals(TreeCache.removeKeyMethodLocal) || meth.equals(TreeCache.removeDataMethodLocal)) {
            fqn=(Fqn)args[1];
  @@ -129,13 +135,13 @@
         if(fqn != null) {
            if(createIfNotExists) {
               do {
  -               lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, lock_timeout, createIfNotExists);
  +               lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, 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, lock_timeout, createIfNotExists);
  +            lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, lock_timeout, createIfNotExists, storeLockedNode);
         }
         else {
            if(log.isTraceEnabled())
  @@ -144,6 +150,14 @@
         if(meth.equals(TreeCache.lockMethodLocal))
            return null;
         retval=super.invoke(m);
  +      
  +      // FIXME this should be done in UnlockInterceptor, but I didn't want
  +      // to add the removedNodes map to TreeCache
  +      if (storeLockedNode && ctx.getGlobalTransaction() == null)
  +      {
  +         removedNodes.remove(fqn);
  +      }
  +      
         return retval;
      }
   
  @@ -157,13 +171,14 @@
       * @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 storeRemovalNode)
            throws TimeoutException, LockingException, InterruptedException {
         DataNode       n, child_node=null;
         Object         child_name, owner=gtx != null? gtx : (Object)Thread.currentThread();
         int            treeNodeSize;
         boolean        acquired=false;
         IsolationLevel isolation_level;
  +      int currentLockType;
   
   
          if (log.isTraceEnabled()) log.trace("Attempting to lock node " + fqn + " for owner " + owner);
  @@ -182,7 +197,20 @@
         n=cache.getRoot();
         for(int i=0; i < treeNodeSize; i++) {
            child_name=fqn.get(i);
  -         child_node=(DataNode) n.getOrCreateChild(child_name, gtx, createIfNotExists);
  +         child_node = (DataNode) n.getChild(child_name);
  +         if (child_node == null)
  +         {
  +            // JBCACHE-871 -- If this is a node removed by another incomplete 
  +            // invocation or an uncommitted transaction, we won't be able to find
  +            // the node in the cache; so first check for it in the removedNodes map
  +            DataNode removed = (DataNode) removedNodes.get(fqn.getFqnChild(i +1));
  +            if (removed != null && lock_type != DataNode.LOCK_TYPE_NONE)
  +            {
  +               acquireNodeLock(removed, owner, gtx, lock_type, lock_timeout);
  +            }
  +            child_node = (DataNode) n.getOrCreateChild(child_name, gtx, createIfNotExists);
  +         }
  +         
            if(child_node == null) {
               if(log.isTraceEnabled())
                  log.trace("failed to find or create child " + child_name + " of node " + n.getFqn());
  @@ -194,34 +222,19 @@
               n=child_node;
               continue;
            }
  -         else {
  -            if(lock_type == DataNode.LOCK_TYPE_WRITE && i == (treeNodeSize - 1)) {
  -               acquired=child_node.acquire(owner, lock_timeout, DataNode.LOCK_TYPE_WRITE);
  -            }
  -            else {
  -               acquired=child_node.acquire(owner, lock_timeout, DataNode.LOCK_TYPE_READ);
  -            }
  -         }
  -
   
  -         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 {
  -               IdentityLock l=child_node.getLock();
  -               List locks=(List)lock_table.get(Thread.currentThread());
  -               if(locks == null) {
  -                  locks=Collections.synchronizedList(new LinkedList());
  -                  lock_table.put(Thread.currentThread(), locks);
  -               }
  -               if(!locks.contains(l))
  -                  locks.add(l);
  +         if (lock_type == DataNode.LOCK_TYPE_WRITE && i == (treeNodeSize - 1))
  +         {
  +            currentLockType = DataNode.LOCK_TYPE_WRITE;
               }
  +         else
  +         {
  +            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(recursive && i == (treeNodeSize - 1)) {
               Set acquired_locks=child_node.acquireAll(owner, lock_timeout, lock_type);
               if(acquired_locks.size() > 0) {
  @@ -240,6 +253,50 @@
            }
            n=child_node;
         }
  +      
  +      if (storeRemovalNode && n != null)
  +      {
  +         removedNodes.put(fqn, n);
  +      }
  +   }
  +   
  +   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
  +      // since we key off the Thread, it's not
  +      List locks = (List) lock_table.get(currentThread);
  +      if (locks == null)
  +      {
  +         locks = Collections.synchronizedList(new LinkedList());
  +         lock_table.put(currentThread, locks);
  +      }
  +      return locks;
      }
   
   
  
  
  



More information about the jboss-cvs-commits mailing list