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

Manik Surtani msurtani at jboss.com
Thu Dec 14 12:18:48 EST 2006


  User: msurtani
  Date: 06/12/14 12:18:48

  Modified:    src/org/jboss/cache/interceptors  
                        PessimisticLockInterceptor.java
                        OptimisticNodeInterceptor.java
  Log:
  The beginnings of porting JBCACHE-871 and JBCACHE-875 as well as rearranging the Node/Cache object model to something sensible
  
  Revision  Changes    Path
  1.37      +150 -47   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.36
  retrieving revision 1.37
  diff -u -b -r1.36 -r1.37
  --- PessimisticLockInterceptor.java	12 Dec 2006 14:51:44 -0000	1.36
  +++ PessimisticLockInterceptor.java	14 Dec 2006 17:18:48 -0000	1.37
  @@ -7,12 +7,14 @@
   package org.jboss.cache.interceptors;
   
   import org.jboss.cache.CacheSPI;
  +import org.jboss.cache.DataNode;
   import org.jboss.cache.Fqn;
   import org.jboss.cache.GlobalTransaction;
   import org.jboss.cache.InvocationContext;
   import org.jboss.cache.Node;
   import org.jboss.cache.TransactionEntry;
   import org.jboss.cache.TransactionTable;
  +import org.jboss.cache.TreeCacheProxyImpl;
   import org.jboss.cache.lock.IsolationLevel;
   import org.jboss.cache.lock.LockingException;
   import org.jboss.cache.lock.NodeLock;
  @@ -22,6 +24,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;
  @@ -34,7 +37,7 @@
    * current method and unlock when the method returns.
    *
    * @author Bela Ban
  - * @version $Id: PessimisticLockInterceptor.java,v 1.36 2006/12/12 14:51:44 msurtani Exp $
  + * @version $Id: PessimisticLockInterceptor.java,v 1.37 2006/12/14 17:18:48 msurtani Exp $
    */
   public class PessimisticLockInterceptor extends Interceptor
   {
  @@ -89,7 +92,8 @@
   
         boolean recursive = false;
         boolean createIfNotExists = false;
  -      boolean zeroLockTimeout = false; // only used if the call is an evict() call.  See JBCACHE-794
  +      boolean zeroLockTimeout = false;// only used if the call is an evict() call.  See JBCACHE-794
  +      boolean isDeleteOperation = false;// needed for JBCACHE-871
   
         // 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
  @@ -108,9 +112,10 @@
               lock_type = NodeLock.LockType.WRITE;
               break;
            case MethodDeclarations.removeNodeMethodLocal_id:
  +            isDeleteOperation = true;
               fqn = (Fqn) args[1];
               lock_type = NodeLock.LockType.WRITE;
  -            recursive = true; // remove node and *all* child nodes
  +            recursive = true;// remove node and *all* child nodes
               break;
            case MethodDeclarations.removeKeyMethodLocal_id:
            case MethodDeclarations.removeDataMethodLocal_id:
  @@ -162,9 +167,9 @@
         {
            do
            {
  -            lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, createIfNotExists, zeroLockTimeout ? 0 : lock_acquisition_timeout);
  +            lock(fqn, ctx.getGlobalTransaction(), lock_type, recursive, createIfNotExists, zeroLockTimeout ? 0 : lock_acquisition_timeout, isDeleteOperation);
            }
  -         while (createIfNotExists && !cache.hasChild(fqn)); // keep trying until we have the lock (fixes concurrent remove())
  +         while (createIfNotExists && !cache.hasChild(fqn));// keep trying until we have the lock (fixes concurrent remove())
         }
         else if (!lockNecessary)
         {
  @@ -177,7 +182,18 @@
         {
            return null;
         }
  -      return super.invoke(m);
  +      Object o = super.invoke(m);
  +      // FIXME this should be done in UnlockInterceptor, but I didn't want
  +      // to add the removedNodes map to TreeCache
  +      if (isDeleteOperation && ctx.getGlobalTransaction() == null)
  +      {
  +         //cache.getRemovedNodesMap().remove(fqn);
  +         //cache.peek(fqn);
  +         // do a REAL remove here.
  +         cache.peek(fqn).getNodeSPI().getLock().releaseAll(Thread.currentThread());
  +         ((TreeCacheProxyImpl) cache).realRemove(fqn, true);
  +      }
  +      return o;
      }
   
      private void obtainLocksForMove(Fqn parent, Fqn node) throws InterruptedException
  @@ -187,11 +203,11 @@
   
         // this call will ensure the node gets a WL and it's current parent gets RL.
         if (log.isTraceEnabled()) log.trace("Attempting to get WL on node to be moved [" + node + "]");
  -      lock(node, cache.getInvocationContext().getGlobalTransaction(), NodeLock.LockType.WRITE, true, false, lock_acquisition_timeout);
  +      lock(node, cache.getInvocationContext().getGlobalTransaction(), NodeLock.LockType.WRITE, true, false, lock_acquisition_timeout, false);
   
         //now for an RL for the new parent.
         if (log.isTraceEnabled()) log.trace("Attempting to get RL on new parent [" + parent + "]");
  -      lock(parent, cache.getInvocationContext().getGlobalTransaction(), NodeLock.LockType.READ, true, false, lock_acquisition_timeout);
  +      lock(parent, cache.getInvocationContext().getGlobalTransaction(), NodeLock.LockType.READ, true, false, lock_acquisition_timeout, false);
      }
   
   
  @@ -203,7 +219,7 @@
       * @param lock_type DataNode.LOCK_TYPE_READ, DataNode.LOCK_TYPE_WRITE or DataNode.LOCK_TYPE_NONE
       * @param recursive Lock children recursively
       */
  -   private void lock(Fqn fqn, GlobalTransaction gtx, NodeLock.LockType lock_type, boolean recursive, boolean createIfNotExists, long timeout)
  +   private void lock(Fqn fqn, GlobalTransaction gtx, NodeLock.LockType lock_type, boolean recursive, boolean createIfNotExists, long timeout, boolean isDeleteOperation)
              throws TimeoutException, LockingException, InterruptedException
      {
         Node n;
  @@ -212,8 +228,6 @@
         Thread currentThread = Thread.currentThread();
         Object owner = (gtx != null) ? gtx : currentThread;
         int treeNodeSize;
  -      boolean acquired;
  -
   
         if (log.isTraceEnabled()) log.trace("Attempting to lock node " + fqn + " for owner " + owner);
   
  @@ -235,11 +249,19 @@
   
         n = cache;
         treeNodeSize = fqn.size();
  -      for (int i = 0; i < treeNodeSize; i++)
  +      for (int i = -1; i < treeNodeSize; i++)
  +      {
  +         if (i == -1)
  +         {
  +            // this is the root node
  +            child_name = Fqn.ROOT.getName();
  +            child_node = cache.getRoot();
  +         }
  +         else
         {
            child_name = fqn.get(i);
  -
            child_node = n.getNodeSPI().getChildrenMap().get(child_name);
  +         }
            /*
            cache.getInvocationContext().getOptionOverrides().setBypassInterceptorChain(true);
            Fqn childFqn = new Fqn(child_name);
  @@ -260,6 +282,7 @@
               return;
            }
   
  +         NodeLock.LockType lockTypeRequired;
            if (lock_type == NodeLock.LockType.NONE)
            {
               // acquired=false;
  @@ -268,56 +291,110 @@
            }
            else
            {
  -            if (lock_type == NodeLock.LockType.WRITE && i == (treeNodeSize - 1))
  +            if (writeLockNeeded(lock_type, i, treeNodeSize, isDeleteOperation, createIfNotExists, fqn, child_node.getFqn()))
               {
                  //acquired=child_node.acquire(owner, lock_timeout, DataNode.LOCK_TYPE_WRITE);
  -               acquired = lockManager.acquire(child_node, owner, NodeLock.LockType.WRITE, timeout);
  +               //acquired = lockManager.acquire(child_node, owner, NodeLock.LockType.WRITE, timeout);
  +               lockTypeRequired = NodeLock.LockType.WRITE;
  +
               }
               else
               {
                  //acquired=child_node.acquire(owner, lock_timeout, DataNode.LOCK_TYPE_READ);
  -               acquired = lockManager.acquire(child_node, owner, NodeLock.LockType.READ, timeout);
  +               //acquired = lockManager.acquire(child_node, owner, NodeLock.LockType.READ, timeout);
  +               lockTypeRequired = NodeLock.LockType.READ;
               }
            }
   
  +         // reverse the "remove" if the node has been previously removed in the same tx, if this operation is a put()
  +         if (gtx != null && needToReverseRemove(child_node, tx_table.get(gtx), lock_type, isDeleteOperation, createIfNotExists))
  +         {
  +            reverseRemove(child_node);
  +         }
   
  -         if (acquired)
  +         acquireNodeLock(child_node, owner, gtx, lockTypeRequired, timeout);
  +
  +         if (recursive && isTargetNode(i, treeNodeSize))
  +         {
  +            //Set acquired_locks=child_node.acquireAll(owner, lock_timeout, lock_type);
  +            Set acquired_locks = lockManager.acquireAll(child_node, owner, lock_type, timeout);
  +            if (acquired_locks.size() > 0)
            {
               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, lockManager.getLock(child_node));
  +                  cache.getTransactionTable().addLocks(gtx, acquired_locks);
               }
               else
               {
  -               NodeLock l = lockManager.getLock(child_node);
                  List locks = getLocks(currentThread);
  -               if (!locks.contains(l))
  +                  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 (isDeleteOperation && gtx != null) cache.getTransactionTable().get(gtx).addRemovedNode(fqn);
  +   }
  +
  +   private boolean needToReverseRemove(Node n, TransactionEntry te, NodeLock.LockType lockTypeRequested, boolean isRemoveOperation, boolean createIfNotExists)
                  {
  -                  locks.add(l);
  +      return !isRemoveOperation && createIfNotExists && lockTypeRequested == NodeLock.LockType.WRITE && ((DataNode) n).isDeleted() && te.getRemovedNodes().contains(n.getFqn());
                  }
  +
  +   private void reverseRemove(Node n)
  +   {
  +      ((DataNode) n).markAsDeleted(false);
               }
  +
  +   private boolean writeLockNeeded(NodeLock.LockType 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 (recursive && i == (treeNodeSize - 1))
  +      if (!isTargetNode(currentNodeIndex, treeNodeSize) && !cache.hasChild(new Fqn(currentFqn, targetFqn.get(currentNodeIndex + 1))))
            {
  -            //Set acquired_locks=child_node.acquireAll(owner, lock_timeout, lock_type);
  -            Set acquired_locks = lockManager.acquireAll(child_node, owner, lock_type, timeout);
  -            if (acquired_locks.size() > 0)
  +         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 == NodeLock.LockType.WRITE && isTargetNode(currentNodeIndex, treeNodeSize) && (createIfNotExists || isRemoveOperation);//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(Node node, Object owner, GlobalTransaction gtx, NodeLock.LockType lock_type, long lock_timeout) throws LockingException, TimeoutException, InterruptedException
  +   {
  +      boolean acquired = lockManager.acquire(node, owner, lock_type, lock_timeout);
  +      if (acquired)
  +      {
  +         // Record the lock for release on method return or tx commit/rollback
  +         recordNodeLock(gtx, node.getNodeSPI().getLock());
  +      }
  +   }
  +
  +   private void recordNodeLock(GlobalTransaction gtx, NodeLock lock)
               {
                  if (gtx != null)
                  {
  -                  cache.getTransactionTable().addLocks(gtx, acquired_locks);
  +         // 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
                  {
  +         Thread currentThread = Thread.currentThread();
                     List locks = getLocks(currentThread);
  -                  locks.addAll(acquired_locks);
  -               }
  -            }
  +         if (!locks.contains(lock))
  +         {
  +            locks.add(lock);
  +            lock_table.put(currentThread, locks);
            }
  -         n = child_node;
         }
      }
   
  @@ -349,8 +426,15 @@
            if (child_node == null)
            {
               cache.getInvocationContext().getOptionOverrides().setBypassInterceptorChain(true);
  -            child_node = n.addChild(childFqn); //, gtx, true);
  +            child_node = n.addChild(childFqn);//, gtx, true);
  +         }
  +         // test if this node needs to be 'undeleted'
  +         // reverse the "remove" if the node has been previously removed in the same tx, if this operation is a put()
  +         if (gtx != null && needToReverseRemove(child_node, tx_table.get(gtx), NodeLock.LockType.WRITE, false, true))
  +         {
  +            reverseRemove(child_node);
            }
  +
            if (child_node == null)
            {
               if (log.isTraceEnabled())
  @@ -382,6 +466,15 @@
            return;
         }
   
  +      // first remove nodes that should be deleted.
  +      Iterator removedNodes = entry.getRemovedNodes().iterator();
  +      TreeCacheProxyImpl tcpi = (TreeCacheProxyImpl) cache;
  +      while (removedNodes.hasNext())
  +      {
  +         Fqn f = (Fqn) removedNodes.next();
  +         tcpi.realRemove(f, false);
  +      }
  +
         // Let's do it in stack style, LIFO
         entry.releaseAllLocksLIFO(gtx);
   
  @@ -421,6 +514,16 @@
            return;
         }
   
  +
  +      Iterator removedNodes = entry.getRemovedNodes().iterator();
  +      TreeCacheProxyImpl tcpi = (TreeCacheProxyImpl) cache;
  +      while (removedNodes.hasNext())
  +      {
  +         Fqn f = (Fqn) removedNodes.next();
  +         tcpi.realRemove(f, false);
  +
  +      }
  +
         // 1. Revert the modifications by running the undo-op list in reverse. This *cannot* throw any exceptions !
         entry.undoOperations(cache);
   
  @@ -428,16 +531,16 @@
         // put(/a/b/c) on /a, create b and c, plus undo operations _remove(a/b/c) and _remove(/a/b)
   
         // 2. Remove all temporary nodes. Need to do it backwards since node is LIFO.
  -//      for(ListIterator it=new LinkedList(entry.getNodes()).listIterator(entry.getNodes().size());
  -//          it.hasPrevious();) {
  -//         node_name=(Fqn)it.previous();
  -//         try {
  -//            cache._remove(tx, node_name, false);
  -//         }
  -//         catch(Throwable t) {
  -//            log.error("failed removing node \"" + node_name + "\"", t);
  -//         }
  -//      }
  +      //      for(ListIterator it=new LinkedList(entry.getNodes()).listIterator(entry.getNodes().size());
  +      //          it.hasPrevious();) {
  +      //         node_name=(Fqn)it.previous();
  +      //         try {
  +      //            cache._remove(tx, node_name, false);
  +      //         }
  +      //         catch(Throwable t) {
  +      //            log.error("failed removing node \"" + node_name + "\"", t);
  +      //         }
  +      //      }
   
         // 3. Finally, release all locks held by this TX
         // Let's do it in stack style, LIFO
  
  
  
  1.36      +7 -1      JBossCache/src/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java
  
  (In the diff below, changes in quantity of whitespace are not shown.)
  
  Index: OptimisticNodeInterceptor.java
  ===================================================================
  RCS file: /cvsroot/jboss/JBossCache/src/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java,v
  retrieving revision 1.35
  retrieving revision 1.36
  diff -u -b -r1.35 -r1.36
  --- OptimisticNodeInterceptor.java	12 Dec 2006 14:51:44 -0000	1.35
  +++ OptimisticNodeInterceptor.java	14 Dec 2006 17:18:48 -0000	1.36
  @@ -94,13 +94,17 @@
   
                  workspaceNode.setVersion(version);
                  if (log.isTraceEnabled())
  +               {
                     log.trace("Setting versioning for node " + workspaceNode.getFqn() + " to explicit");
  +               }
                  workspaceNode.setVersioningImplicit(false);
               }
               else
               {
                  if (log.isTraceEnabled())
  +               {
                     log.trace("Setting versioning for node " + workspaceNode.getFqn() + " to implicit");
  +               }
                  workspaceNode.setVersioningImplicit(true);
               }
            }
  @@ -108,8 +112,10 @@
            {
               // "fail-more-silently" patch thanks to Owen Taylor - JBCACHE-767
               if ((ctx.getOptionOverrides() == null || !ctx.getOptionOverrides().isFailSilently()) && MethodDeclarations.isPutMethod(m.getMethodId()))
  +            {
                  throw new CacheException("Unable to set node version for " + getFqn(args) + ", node is null.");
            }
  +         }
   
            switch (m.getMethodId())
            {
  @@ -316,7 +322,7 @@
            if (toDelete.getFqn().isChildOrEquals(nodeFqn))
            {
               if (debug) log.debug("marking node " + toDelete.getFqn() + " as deleted");
  -            toDelete.markAsDeleted();
  +            toDelete.markAsDeleted(true);
            }
            else
            {
  
  
  



More information about the jboss-cvs-commits mailing list