[jbosscache-commits] JBoss Cache SVN: r6028 - in core/trunk/src/main/java/org/jboss/cache: transaction and 1 other directory.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Jun 25 09:23:13 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-06-25 09:23:13 -0400 (Wed, 25 Jun 2008)
New Revision: 6028

Modified:
   core/trunk/src/main/java/org/jboss/cache/InvocationContext.java
   core/trunk/src/main/java/org/jboss/cache/transaction/TransactionEntry.java
Log:
Updated interface methods to simplify collection and recording of locks.

Modified: core/trunk/src/main/java/org/jboss/cache/InvocationContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InvocationContext.java	2008-06-25 13:21:38 UTC (rev 6027)
+++ core/trunk/src/main/java/org/jboss/cache/InvocationContext.java	2008-06-25 13:23:13 UTC (rev 6028)
@@ -18,8 +18,11 @@
 
 import javax.transaction.Transaction;
 import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 
 /**
  * This context holds information specific to a method invocation.
@@ -27,7 +30,7 @@
  * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
  */
 @SuppressWarnings("deprecation")
-public class InvocationContext implements Cloneable
+public class InvocationContext
 {
    private static final Log log = LogFactory.getLog(InvocationContext.class);
    private static final boolean trace = log.isTraceEnabled();
@@ -44,46 +47,39 @@
    private MethodCall methodCall;
    @Deprecated
    private VisitableCommand command;
-   List<NodeLock> invocationLocks;
 
-   // used to store cache peeks within the scope of a single context. Performing a cache peek can be a huge bottle neck.
-   // See JBCACHE-811
-   // backing out for now
-   //private Map<Fqn, NodeSPI> peekedNodes = new HashMap<Fqn, NodeSPI>();
-
    /**
-    * Retrieves a node that may have previously been "peeked" within the scope of the same invocation.
-    *
-    * @param f fqn of node to find
-    * @return node, if previously peeked, or null if not.
-    * @since 2.1.0
+    * LinkedHashSet of locks acquired by the invocation. We use a LinkedHashSet because we need efficient Set semantics
+    * but also need guaranteed ordering for use by lock release code (see JBCCACHE-874).
+    * <p/>
+    * This needs to be unchecked since we support both MVCC (Fqns held here) or legacy Opt/Pess locking (NodeLocks held here).
+    * once we drop support for opt/pess locks we can genericise this to contain Fqns. - Manik Surtani, June 2008
     */
-//   public NodeSPI getPeekedNode(Fqn f)
-//   {
-//      return peekedNodes.get(f);
-//   }
+   private LinkedHashSet invocationLocks;
 
-   /**
-    * Adds a node to the previously peeked list.
-    *
-    * @param n node to add
-    * @param f fqn of node
-    * @since 2.1.0
-    */
-//   public void savePeekedNode(NodeSPI n, Fqn f)
-//   {
-//      peekedNodes.put(f, n);
-//   }
+   private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>();
 
-   /**
-    * Wipe list of previously peeked nodes.
-    *
-    * @since 2.1.0
-    */
-//   public void wipePeekedNodes()
-//   {
-//      peekedNodes.clear();
-//   }
+   public NodeSPI lookUpNode(Fqn fqn)
+   {
+      // TODO: should delegate to TransactionEntry if one is in scope
+      return lookedUpNodes.get(fqn);
+   }
+
+   public void putLookedUpNode(Fqn f, NodeSPI n)
+   {
+      lookedUpNodes.put(f, n);
+   }
+
+   public void clearLookedUpNodes()
+   {
+      lookedUpNodes.clear();
+   }
+
+   public Map<Fqn, NodeSPI> getLookedUpNodes()
+   {
+      return lookedUpNodes;
+   }
+
    public void setLocalRollbackOnly(boolean localRollbackOnly)
    {
       this.localRollbackOnly = localRollbackOnly;
@@ -188,26 +184,139 @@
       return originLocal;
    }
 
-   public List<NodeLock> getInvocationLocksAcquired()
+   /**
+    * Returns an immutable,  defensive copy of the List of locks currently maintained for the current scope.
+    * <p/>
+    * Note that if a transaction is in scope, these locks are retrieved from the {@link org.jboss.cache.transaction.TransactionEntry} rather than
+    * this {@link org.jboss.cache.InvocationContext}.  Retrieving locks from here will ensure they are retrieved from  the appropriate
+    * scope.
+    * <p/>
+    * Note that currently (as of 3.0.0) this list is unchecked.  This is to allow support for both MVCC (which uses Fqns as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to return <tt>List<Fqn></tt>.
+    *
+    * @return locks held in current scope.
+    */
+   @SuppressWarnings("unchecked")
+   public List getLocks()
    {
-      return invocationLocks;
+      // first check transactional scope
+      if (transactionEntry != null) return transactionEntry.getLocks();
+      return Collections.unmodifiableList(new ArrayList(invocationLocks));
    }
 
-   public void addInvocationLocksAcquired(Collection<NodeLock> locks)
+   /**
+    * Adds a List of locks to the currently maintained collection of locks acquired.
+    * <p/>
+    * Note that if a transaction is in scope, these locks are recorded on the {@link org.jboss.cache.transaction.TransactionEntry} rather than
+    * this {@link org.jboss.cache.InvocationContext}.  Adding locks here will ensure they are promoted to the appropriate
+    * scope.
+    * <p/>
+    * Note that currently (as of 3.0.0) this list is unchecked.  This is to allow support for both MVCC (which uses Fqns as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept <tt>List<Fqn></tt>.
+    *
+    * @param locks locks to add
+    */
+   @SuppressWarnings("unchecked")
+   public void addAllLocks(List locks)
    {
-      // no need to worry about concurrency here - a context is only valid for a single thread.
-      if (invocationLocks == null) invocationLocks = new ArrayList<NodeLock>(5);
-      invocationLocks.addAll(locks);
+      // first check transactional scope
+      if (transactionEntry != null)
+      {
+         transactionEntry.addAllLocks(locks);
+      }
+      else
+      {
+         // no need to worry about concurrency here - a context is only valid for a single thread.
+         if (invocationLocks == null) invocationLocks = new LinkedHashSet(5);
+         invocationLocks.addAll(locks);
+      }
    }
 
-   public void addInvocationLockAcquired(NodeLock l)
+   /**
+    * Adds a lock to the currently maintained collection of locks acquired.
+    * <p/>
+    * Note that if a transaction is in scope, this lock is recorded on the {@link org.jboss.cache.transaction.TransactionEntry} rather than
+    * this {@link org.jboss.cache.InvocationContext}.  Adding a lock here will ensure it is promoted to the appropriate
+    * scope.
+    * <p/>
+    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link Fqn}s as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link Fqn}.
+    *
+    * @param lock lock to add
+    */
+   @SuppressWarnings("unchecked")
+   public void addLock(Object lock)
    {
-      // no need to worry about concurrency here - a context is only valid for a single thread.
-      if (invocationLocks == null) invocationLocks = new ArrayList<NodeLock>(5);
-      invocationLocks.add(l);
+      // first check transactional scope
+      if (transactionEntry != null)
+      {
+         transactionEntry.addLock(lock);
+      }
+      else
+      {
+         // no need to worry about concurrency here - a context is only valid for a single thread.
+         if (invocationLocks == null) invocationLocks = new LinkedHashSet(5);
+         invocationLocks.add(lock);
+      }
    }
 
    /**
+    * Removes a lock from the currently maintained collection of locks acquired.
+    * <p/>
+    * Note that if a transaction is in scope, this lock is removed from the {@link org.jboss.cache.transaction.TransactionEntry} rather than
+    * this {@link org.jboss.cache.InvocationContext}.  Removing a lock here will ensure it is removed in the appropriate
+    * scope.
+    * <p/>
+    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link Fqn}s as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link Fqn}.
+    *
+    * @param lock lock to remove
+    */
+   @SuppressWarnings("unchecked")
+   public void removeLock(Object lock)
+   {
+      // first check transactional scope
+      if (transactionEntry != null)
+      {
+         transactionEntry.removeLock(lock);
+      }
+      else
+      {
+         // no need to worry about concurrency here - a context is only valid for a single thread.
+         if (invocationLocks != null) invocationLocks.remove(lock);
+      }
+   }
+
+   /**
+    * Clears all locks from the currently maintained collection of locks acquired.
+    * <p/>
+    * Note that if a transaction is in scope, locks are cleared from the {@link org.jboss.cache.transaction.TransactionEntry} rather than
+    * this {@link org.jboss.cache.InvocationContext}.  Clearing locks here will ensure they are cleared in the appropriate
+    * scope.
+    * <p/>
+    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link Fqn}s as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link Fqn}.
+    */
+   public void clearLocks()
+   {
+      // first check transactional scope
+      if (transactionEntry != null)
+      {
+         transactionEntry.clearLocks();
+      }
+      else
+      {
+         // no need to worry about concurrency here - a context is only valid for a single thread.
+         if (invocationLocks != null) invocationLocks.clear();
+      }
+   }
+
+   /**
     * @return true if options exist to suppress locking - false otherwise.  Note that this is only used by the {@link org.jboss.cache.interceptors.PessimisticLockInterceptor}.
     */
    public boolean isLockingSuppressed()
@@ -268,12 +377,20 @@
       command = null;
    }
 
-   @Override
-   public InvocationContext clone() throws CloneNotSupportedException
+   /**
+    * This is a "copy-factory-method" that should be used whenever a clone of this class is needed.  The resulting instance
+    * is equal() to, but not ==, to the template passed in.
+    *
+    * @param template template to copy
+    * @return a new InvocationContext
+    */
+   public static InvocationContext copy(InvocationContext template)
    {
-      InvocationContext clone = (InvocationContext) super.clone();
-      clone.setOptionOverrides(getOptionOverrides().clone());
-      return clone;
+      // TODO: Remove all use of cloning and replace with copy factory methods.
+//      InvocationContext clone = (InvocationContext) super.clone();
+//      clone.setOptionOverrides(getOptionOverrides().clone());
+//      return clone;
+      return null;
    }
 
    /**

Modified: core/trunk/src/main/java/org/jboss/cache/transaction/TransactionEntry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/TransactionEntry.java	2008-06-25 13:21:38 UTC (rev 6027)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/TransactionEntry.java	2008-06-25 13:23:13 UTC (rev 6028)
@@ -12,6 +12,7 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.Modification;
+import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.ReversibleCommand;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
@@ -22,12 +23,13 @@
 import javax.transaction.SystemException;
 import javax.transaction.Transaction;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.Map;
 
 /**
  * Information associated with a {@link GlobalTransaction} about the transaction state.
@@ -72,13 +74,16 @@
    private List<ReversibleCommand> localModifications;
 
    /**
-    * LinkedHashSet<IdentityLock> of locks acquired by the transaction. We use
-    * a LinkedHashSet because we need efficient Set semantics (same lock can
-    * be added multiple times) but also need guaranteed ordering for use
-    * by lock release code (see JBCCACHE-874).
+    * LinkedHashSet of locks acquired by the transaction. We use a LinkedHashSet because we need efficient Set semantics
+    * but also need guaranteed ordering for use by lock release code (see JBCCACHE-874).
+    * <p/>
+    * This needs to be unchecked since we support both MVCC (Fqns held here) or legacy Opt/Pess locking (NodeLocks held here).
+    * once we drop support for opt/pess locks we can genericise this to contain Fqns. - Manik Surtani, June 2008
     */
-   private final LinkedHashSet<NodeLock> locks = new LinkedHashSet<NodeLock>();
+   private LinkedHashSet transactionLocks;
+   private final Map<Fqn, NodeSPI> lookedUpNodes = new HashMap<Fqn, NodeSPI>();
 
+
    /**
     * A list of dummy uninitialised nodes created by the cache loader interceptor to load data for a
     * given node in this tx.
@@ -170,49 +175,106 @@
    }
 
    /**
-    * Adds a lock to the end of the lock list, if it isn't already present.
+    * Adds a lock to the currently maintained collection of locks acquired.
+    * <p/>
+    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#addLock(Object)} instead,
+    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
+    * <p/>
+    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link Fqn}s as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link Fqn}.
+    *
+    * @param lock lock to add
+    * @see org.jboss.cache.InvocationContext#addLock(Object)
     */
-   public void addLock(NodeLock l)
+   @SuppressWarnings("unchecked")
+   public void addLock(Object lock)
    {
-      if (l != null)
-      {
-         synchronized (locks)
-         {
-            locks.add(l);
-         }
-      }
+      // no need to worry about concurrency here - a context is only valid for a single thread.
+      if (transactionLocks == null) transactionLocks = new LinkedHashSet(5);
+      transactionLocks.add(lock);
    }
 
    /**
-    * Add multiple locks to the lock list.
+    * Removes a lock from the currently maintained collection of locks acquired.
+    * <p/>
+    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#removeLock(Object)}  instead,
+    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
+    * <p/>
+    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link Fqn}s as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link Fqn}.
     *
-    * @param newLocks Collection<NodeLock>
+    * @param lock lock to remove
+    * @see org.jboss.cache.InvocationContext#removeLock(Object)
     */
-   public void addLocks(Collection<NodeLock> newLocks)
+   @SuppressWarnings("unchecked")
+   public void removeLock(Object lock)
    {
-      if (newLocks != null)
-      {
-         synchronized (locks)
-         {
-            locks.addAll(newLocks);
-         }
-      }
+      // no need to worry about concurrency here - a context is only valid for a single thread.
+      if (transactionLocks != null) transactionLocks.remove(lock);
    }
 
    /**
-    * Returns the locks in use.
+    * Clears all locks from the currently maintained collection of locks acquired.
+    * <p/>
+    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#clearLocks()} instead,
+    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
+    * <p/>
+    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link Fqn}s as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link Fqn}.
     *
-    * @return a defensive copy of the internal data structure.
+    * @see org.jboss.cache.InvocationContext#clearLocks()
     */
-   public List<NodeLock> getLocks()
+   public void clearLocks()
    {
-      synchronized (locks)
-      {
-         return new ArrayList<NodeLock>(locks);
-      }
+      if (transactionLocks != null) transactionLocks.clear();
    }
 
+
    /**
+    * Adds a List of locks to the currently maintained collection of locks acquired.
+    * <p/>
+    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#addAllLocks(java.util.List)} instead,
+    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
+    * <p/>
+    * Note that currently (as of 3.0.0) this list is unchecked.  This is to allow support for both MVCC (which uses Fqns as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to accept <tt>List<Fqn></tt>.
+    *
+    * @param newLocks locks to add
+    * @see org.jboss.cache.InvocationContext#addAllLocks(java.util.List)
+    */
+   @SuppressWarnings("unchecked")
+   public void addAllLocks(List newLocks)
+   {
+      // no need to worry about concurrency here - a context is only valid for a single thread.
+      if (transactionLocks == null) transactionLocks = new LinkedHashSet(5);
+      transactionLocks.addAll(newLocks);
+   }
+
+   /**
+    * Returns an immutable,  defensive copy of the List of locks currently maintained for the transaction.
+    * <p/>
+    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#getLocks()} instead,
+    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
+    * <p/>
+    * Note that currently (as of 3.0.0) this list is unchecked.  This is to allow support for both MVCC (which uses Fqns as locks)
+    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link NodeLock} as locks).  Once support for
+    * legacy node locking schemes are dropped, this method will be more strongly typed to return <tt>List<Fqn></tt>.
+    *
+    * @return locks held in current scope.
+    * @see org.jboss.cache.InvocationContext#getLocks()
+    */
+   @SuppressWarnings("unchecked")
+   public List getLocks()
+   {
+      return Collections.unmodifiableList(new ArrayList(transactionLocks));
+   }
+
+
+   /**
     * Gets the value of the forceAsyncReplication flag.  Used by ReplicationInterceptor and OptimisticReplicationInterceptor
     * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
     * a transactional context.
@@ -305,12 +367,8 @@
    @Override
    public String toString()
    {
-      StringBuffer sb = new StringBuffer();
+      StringBuilder sb = new StringBuilder();
       sb.append("TransactionEntry\nmodificationList: ").append(modificationList);
-      synchronized (locks)
-      {
-         sb.append("\nlocks: ").append(locks);
-      }
       return sb.toString();
    }
 
@@ -370,7 +428,27 @@
       return localModifications != null && !localModifications.isEmpty();
    }
 
+   public NodeSPI lookUpNode(Fqn fqn)
+   {
+      return lookedUpNodes.get(fqn);
+   }
 
+   public void putLookedUpNode(Fqn f, NodeSPI n)
+   {
+      lookedUpNodes.put(f, n);
+   }
+
+   public void clearLookedUpNodes()
+   {
+      lookedUpNodes.clear();
+   }
+
+   public Map<Fqn, NodeSPI> getLookedUpNodes()
+   {
+      return lookedUpNodes;
+   }
+
+
    /**
     * Cleans up internal state
     */
@@ -380,7 +458,7 @@
       if (modificationList != null) modificationList = null;
       if (localModifications != null) localModifications = null;
       option = null;
-      locks.clear();
+      transactionLocks.clear();
       if (dummyNodesCreatedByCacheLoader != null) dummyNodesCreatedByCacheLoader.clear();
       removedNodes.clear();
    }




More information about the jbosscache-commits mailing list