[jbosscache-commits] JBoss Cache SVN: r6901 - in core/branches/flat/src: main/java/org/jboss/starobrno/commands/read and 10 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Fri Oct 10 05:43:27 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-10-10 05:43:27 -0400 (Fri, 10 Oct 2008)
New Revision: 6901

Added:
   core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java
   core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java
Modified:
   core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java
   core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java
   core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java
   core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java
   core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java
   core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java
Log:
Fixed stuff

Modified: core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/cache/transaction/DummyBaseTransactionManager.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -21,6 +21,9 @@
  */
 package org.jboss.cache.transaction;
 
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
 import javax.transaction.HeuristicMixedException;
 import javax.transaction.HeuristicRollbackException;
 import javax.transaction.InvalidTransactionException;
@@ -41,6 +44,8 @@
 {
    static ThreadLocal<Transaction> thread_local = new ThreadLocal<Transaction>();
    private static final long serialVersionUID = -6716097342564237376l;
+   private static final Log log = LogFactory.getLog(DummyBaseTransactionManager.class);
+   private static final boolean trace = log.isTraceEnabled();
 
    /**
     * Starts a new transaction, and associate it with the calling thread.
@@ -214,6 +219,7 @@
    {
       Transaction retval = getTransaction();
       setTransaction(null);
+      if (trace) log.trace("Suspending tx " + retval);
       return retval;
    }
 
@@ -233,6 +239,7 @@
     */
    public void resume(Transaction tx) throws InvalidTransactionException, IllegalStateException, SystemException
    {
+      if (trace) log.trace("Resuming tx " + tx);
       setTransaction(tx);
    }
 

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/AbstractDataCommand.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -76,4 +76,12 @@
    {
       return (key != null ? key.hashCode() : 0);
    }
+
+
+   public String toString()
+   {
+      return getClass().getSimpleName() + "{" +
+            "key=" + key +
+            '}';
+   }
 }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GetKeyValueCommand.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -61,7 +61,7 @@
       MVCCEntry entry = ctx.lookupEntry(key);
       if (entry == null || entry.isNullEntry())
       {
-         if (trace) log.trace("Node not found");
+         if (trace) log.trace("Entry not found");
          return null;
       }
       if (entry.isDeleted())

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/write/EvictCommand.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -62,12 +62,4 @@
    {
       return METHOD_ID;
    }
-
-
-   public String toString()
-   {
-      return "AbstractDataCommand{" +
-            "key=" + key +
-            '}';
-   }
 }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/container/MVCCEntryCreator.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -79,7 +79,7 @@
       MVCCEntry mvccEntry;
       if (forceWriteLock)
       {
-         if (trace) log.trace("Forcing lock on reading key " + key);
+         if (trace) log.trace("Forcing lock on reading");
          return wrapEntryForWriting(ctx, key, false, false);
       }
       else if ((mvccEntry = ctx.lookupEntry(key)) == null)
@@ -88,12 +88,12 @@
          // simple implementation.  Peek the node, wrap it, put wrapped node in the context.
          Object value = container.get(key);
          mvccEntry = entryFactory.createWrappedEntry(key, value, false);
-         if (mvccEntry != null && putInContext) ctx.putLookedUpEntry(mvccEntry);
+         if (mvccEntry != null && putInContext) ctx.putLookedUpEntry(key, mvccEntry);
          return mvccEntry;
       }
       else
       {
-         if (trace) log.trace("Key " + key + " is already in context.");
+         if (trace) log.trace("Key is already in context");
          return mvccEntry;
       }
    }
@@ -110,7 +110,7 @@
             // create a copy of the underlying node
             mvccEntry.copyForUpdate(container, writeSkewCheck);
          }
-         if (trace) log.trace("Retrieving wrapped node " + key);
+         if (trace) log.trace("Exists in context.");
          if (mvccEntry.isDeleted() && createIfAbsent)
          {
             if (trace) log.trace("Node is deleted in current scope.  Need to un-delete.");
@@ -124,21 +124,23 @@
          Object value = container.get(key);
          if (value != null)
          {
+            if (trace) log.trace("Retrieved from container.");
             // exists in cache!  Just acquire lock if needed, and wrap.
             // do we need a lock?
             boolean needToCopy = false;
             if (acquireLock(ctx, key)) needToCopy = true;
             mvccEntry = entryFactory.createWrappedEntry(key, value, false);
-            ctx.putLookedUpEntry(mvccEntry);
+            ctx.putLookedUpEntry(key, mvccEntry);
             if (needToCopy) mvccEntry.copyForUpdate(container, writeSkewCheck);
          }
          else if (createIfAbsent) // else, do we need to create one?
          {
+            if (trace) log.trace("Creating new entry.");
             // now to lock and create the node.  Lock first to prevent concurrent creation!
             acquireLock(ctx, key);
             mvccEntry = entryFactory.createWrappedEntry(key, value, true);
             mvccEntry.setCreated(true);
-            ctx.putLookedUpEntry(mvccEntry);
+            ctx.putLookedUpEntry(key, mvccEntry);
             mvccEntry.copyForUpdate(container, writeSkewCheck);
          }
       }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/container/ReadCommittedEntry.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -202,4 +202,17 @@
       else
          unsetFlag(DELETED);
    }
+
+   public String toString()
+   {
+      return getClass().getSimpleName() + "(" + System.identityHashCode(this) + "){" +
+            "key=" + key +
+            ", value=" + value +
+            ", oldValue=" + oldValue +
+            ", isCreated=" + isCreated() +
+            ", isChanged=" + isChanged() +
+            ", isDeleted=" + isDeleted() +
+            ", isValid=" + isValid() +
+            '}';
+   }
 }
\ No newline at end of file

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/EntryLookup.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -24,7 +24,6 @@
 import org.jboss.starobrno.container.MVCCEntry;
 
 import java.util.Map;
-import java.util.Set;
 
 /**
  * // TODO: MANIK: Document this
@@ -38,9 +37,9 @@
 
    Map<Object, MVCCEntry> getLookedUpEntries();
 
-   void putLookedUpEntry(MVCCEntry e);
+   void putLookedUpEntry(Object key, MVCCEntry e);
 
-   void putLookedUpEntries(Set<MVCCEntry> lookedUpEntries);
+   void putLookedUpEntries(Map<Object, MVCCEntry> lookedUpEntries);
 
    void clearLookedUpEntries();
 }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContext.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -21,7 +21,6 @@
  */
 package org.jboss.starobrno.context;
 
-import org.jboss.starobrno.commands.VisitableCommand;
 import org.jboss.starobrno.config.Option;
 import org.jboss.starobrno.transaction.GlobalTransaction;
 
@@ -84,10 +83,6 @@
 
    long getLockAcquisitionTimeout(long timeout);
 
-   void setCommand(VisitableCommand cacheCommand);
-
-   VisitableCommand getCommand();
-
    boolean isValidTransaction();
 
    void throwIfNeeded(Throwable e) throws Throwable;

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -24,7 +24,6 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.util.Immutables;
-import org.jboss.starobrno.commands.VisitableCommand;
 import org.jboss.starobrno.config.Option;
 import org.jboss.starobrno.container.MVCCEntry;
 import org.jboss.starobrno.transaction.GlobalTransaction;
@@ -36,7 +35,6 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * // TODO: MANIK: Document this
@@ -51,13 +49,11 @@
 
    private Transaction transaction;
    private GlobalTransaction globalTransaction;
-   protected TransactionContext transactionContext;
+   protected volatile TransactionContext transactionContext;
    private Option optionOverrides;
    // defaults to true.
    private boolean originLocal = true;
    private boolean localRollbackOnly;
-   @Deprecated
-   private VisitableCommand command;
 
    /**
     * LinkedHashSet of locks acquired by the invocation. We use a LinkedHashSet because we need efficient Set semantics
@@ -80,8 +76,14 @@
     */
    public MVCCEntry lookupEntry(Object k)
    {
-      if (transactionContext != null) return transactionContext.lookupEntry(k);
-      return lookedUpEntries == null ? null : lookedUpEntries.get(k);
+      if (transactionContext != null)
+      {
+         return transactionContext.lookupEntry(k);
+      }
+      else
+      {
+         return lookedUpEntries == null ? null : lookedUpEntries.get(k);
+      }
    }
 
    /**
@@ -90,21 +92,20 @@
     * If a transaction is in progress, implementations should delegate to {@link org.jboss.cache.transaction.MVCCTransactionContext#putLookedUpNode(Fqn, NodeSPI)}
     * <p/>
     *
-    * @param f fqn to add
-    * @param n node to add
+    * @param key
     */
-   public void putLookedUpEntry(MVCCEntry e)
+   public void putLookedUpEntry(Object key, MVCCEntry e)
    {
       if (transactionContext != null)
-         transactionContext.putLookedUpEntry(e);
+         transactionContext.putLookedUpEntry(key, e);
       else
       {
          if (lookedUpEntries == null) lookedUpEntries = new HashMap<Object, MVCCEntry>(4);
-         lookedUpEntries.put(e.getKey(), e);
+         lookedUpEntries.put(key, e);
       }
    }
 
-   public void putLookedUpEntries(Set<MVCCEntry> lookedUpEntries)
+   public void putLookedUpEntries(Map<Object, MVCCEntry> lookedUpEntries)
    {
       if (transactionContext != null)
          transactionContext.putLookedUpEntries(lookedUpEntries);
@@ -113,20 +114,15 @@
          if (this.lookedUpEntries == null)
             this.lookedUpEntries = new HashMap<Object, MVCCEntry>();
 
-         for (MVCCEntry e : lookedUpEntries) this.lookedUpEntries.put(e.getKey(), e);
+         this.lookedUpEntries.putAll(lookedUpEntries);
       }
    }
 
    /**
     * Clears the registry of looked up nodes.
-    * <p/>
-    * If a transaction is in progress, implementations should delegate to {@link org.jboss.cache.transaction.MVCCTransactionContext#clearLookedUpNodes()}.
     */
    public void clearLookedUpEntries()
    {
-//      if (transactionContext != null)
-//         transactionContext.clearLookedUpEntries();
-//      else if (lookedUpEntries != null) lookedUpEntries.clear();
       if (lookedUpEntries != null) lookedUpEntries.clear();
    }
 
@@ -452,7 +448,6 @@
       optionOverrides = null;
       originLocal = true;
       invocationLocks = null;
-      command = null;
       if (lookedUpEntries != null)
       {
          lookedUpEntries.clear();
@@ -498,31 +493,6 @@
    }
 
    /**
-    * This is only used for backward compatibility with old interceptors implementation and should <b>NOT</b> be
-    * use by any new custom interceptors. The commands is now passed in as the second param in each implementing
-    * handlers (handler = method in ChainedInterceptor class)
-    *
-    * @param cacheCommand command to set
-    */
-   @Deprecated
-   @SuppressWarnings("deprecation")
-   public void setCommand(VisitableCommand cacheCommand)
-   {
-      this.command = cacheCommand;
-   }
-
-   /**
-    * @return command that is in scope
-    * @see #setCommand(org.jboss.cache.commands.VisitableCommand)
-    */
-   @Deprecated
-   @SuppressWarnings("deprecation")
-   public VisitableCommand getCommand()
-   {
-      return command;
-   }
-
-   /**
     * @return true if there is current transaction associated with the invocation, and this transaction is in a valid state.
     */
    public boolean isValidTransaction()
@@ -555,7 +525,6 @@
    protected void doCopy(InvocationContext c)
    {
       InvocationContextImpl copy = (InvocationContextImpl) c;
-      copy.command = command;
       copy.globalTransaction = globalTransaction;
       copy.invocationLocks = invocationLocks == null ? null : new LinkedHashSet(invocationLocks);
       copy.localRollbackOnly = localRollbackOnly;

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -37,7 +37,6 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * A transaction context specially geared to dealing with MVCC.
@@ -116,12 +115,11 @@
     * would delegate to this method if a transaction is in scope.
     * <p/>
     *
-    * @param f fqn to add
-    * @param n node to add
+    * @param key
     */
-   public void putLookedUpEntry(MVCCEntry entry)
+   public void putLookedUpEntry(Object key, MVCCEntry entry)
    {
-      lookedUpEntries.put(entry.getKey(), entry);
+      lookedUpEntries.put(key, entry);
    }
 
    /**
@@ -162,9 +160,9 @@
       lookedUpEntries.clear();
    }
 
-   public void putLookedUpEntries(Set<MVCCEntry> entries)
+   public void putLookedUpEntries(Map<Object, MVCCEntry> entries)
    {
-      for (MVCCEntry e : entries) lookedUpEntries.put(e.getKey(), e);
+      lookedUpEntries.putAll(entries);
    }
 
    public void addModification(VisitableCommand command)
@@ -291,7 +289,7 @@
    public String toString()
    {
       StringBuilder sb = new StringBuilder();
-      sb.append("TransactionEntry\nmodificationList: ").append(modificationList);
+      sb.append("TransactionContext (" + System.identityHashCode(this) + ") nmodificationList: ").append(modificationList);
       return sb.toString();
    }
 

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InterceptorChain.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -259,7 +259,6 @@
    @SuppressWarnings("deprecation")
    public Object invoke(InvocationContext ctx, VisitableCommand command)
    {
-      ctx.setCommand(command);
       try
       {
          return command.acceptVisitor(ctx, firstInChain);

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/InvocationContextInterceptor.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -60,7 +60,7 @@
    @Override
    public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
    {
-      return handleAll(ctx, command, ctx.getGlobalTransaction(), false);
+      return handleAll(ctx, command, ctx.getGlobalTransaction(), true);
    }
 
    @Override
@@ -102,7 +102,7 @@
    @Override
    public Object handleDefault(InvocationContext ctx, VisitableCommand command) throws Throwable
    {
-      return handleAll(ctx, command, null, false);
+      return handleAll(ctx, command, null, true);
    }
 
    @SuppressWarnings("deprecation")
@@ -199,9 +199,6 @@
             }
          }
 
-         // reset the context to prevent leakage of internals
-         ctx.setCommand(null);
-
          // TODO: Calling ctx.reset() here breaks stuff.  Check whether this is just becuse UTs expect stuff in the ctx or whether this really breaks functionality.
 //         ctx.reset();
          // instead, for now, just wipe contents of the looked up node map

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/LockingInterceptor.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -226,7 +226,7 @@
             Set<Object> keysToRemove = new HashSet<Object>();
             for (MVCCEntry e : ctx.getLookedUpEntries().values())
             {
-               if (e.isChanged()) keysToRemove.add(e.getKey());
+               if (!e.isChanged()) keysToRemove.add(e.getKey());
             }
             for (Object k : keysToRemove) ctx.removeKeyLocked(k);
          }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/interceptors/TxInterceptor.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -482,16 +482,7 @@
    {
       GlobalTransaction gtx = ctx.getGlobalTransaction();
       Object result;
-      VisitableCommand originalCommand = ctx.getCommand();
-      ctx.setCommand(command);
-      try
-      {
-         result = invokeNextInterceptor(ctx, command);
-      }
-      finally
-      {
-         ctx.setCommand(originalCommand);
-      }
+      result = invokeNextInterceptor(ctx, command);
       if (log.isDebugEnabled()) log.debug("Finished local commit/rollback method for " + gtx);
       return result;
    }
@@ -605,16 +596,7 @@
       Transaction currentTransaction = txManager.getTransaction();
       if (currentTransaction != null && ltx != null && currentTransaction.equals(ltx))
       {
-         VisitableCommand originalCommand = ctx.getCommand();
-         ctx.setCommand(prepareCommand);
-         try
-         {
-            result = invokeNextInterceptor(ctx, prepareCommand);
-         }
-         finally
-         {
-            ctx.setCommand(originalCommand);
-         }
+         result = invokeNextInterceptor(ctx, prepareCommand);
       }
       else
       {

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java	2008-10-10 08:18:13 UTC (rev 6900)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/notifications/NotifierImpl.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -35,7 +35,6 @@
 import org.jboss.starobrno.CacheException;
 import org.jboss.starobrno.CacheSPI;
 import org.jboss.starobrno.config.Configuration;
-import org.jboss.starobrno.container.MVCCEntry;
 import org.jboss.starobrno.context.InvocationContext;
 import org.jboss.starobrno.factories.annotations.Destroy;
 import org.jboss.starobrno.factories.annotations.Inject;
@@ -638,10 +637,7 @@
    {
       InvocationContext currentIC = cache.getInvocationContext();
       backup.clearLookedUpEntries();
-      for (MVCCEntry me : currentIC.getLookedUpEntries().values())
-      {
-         backup.putLookedUpEntry(me);
-      }
+      backup.putLookedUpEntries(currentIC.getLookedUpEntries());
       cache.setInvocationContext(backup);
    }
 
@@ -658,10 +654,7 @@
       cache.setInvocationContext(null);
       // get a new Invocation Context
       InvocationContext newContext = cache.getInvocationContext();
-      for (MVCCEntry me : ctx.getLookedUpEntries().values())
-      {
-         newContext.putLookedUpEntry(me);
-      }
+      newContext.putLookedUpEntries(ctx.getLookedUpEntries());
       return ctx;
    }
 

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheAPITest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,154 @@
+package org.jboss.starobrno.api;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.transaction.GenericTransactionManagerLookup;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.ConfigurationException;
+import org.jboss.starobrno.util.TestingUtil;
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests the {@link org.jboss.cache.Cache} public API at a high level
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
+ */
+
+ at Test(groups = {"functional", "pessimistic"})
+public class CacheAPITest
+{
+   private CacheSPI<String, String> cache;
+   final List<String> events = new ArrayList<String>();
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp() throws Exception
+   {
+      // start a single cache instance
+      CacheFactory<String, String> cf = new DefaultCacheFactory<String, String>();
+      cache = (CacheSPI<String, String>) cf.createCache("configs/local-tx.xml", false);
+      cache.getConfiguration().setEvictionConfig(null);
+      configure(cache.getConfiguration());
+      cache.start();
+      events.clear();
+   }
+
+   protected void configure(Configuration c)
+   {
+   }
+
+
+   @AfterMethod(alwaysRun = true)
+   public void tearDown()
+   {
+      TestingUtil.killCaches(cache);
+   }
+
+   /**
+    * Tests that the configuration contains the values expected, as well as immutability of certain elements
+    */
+   public void testConfiguration()
+   {
+      Configuration c = cache.getConfiguration();
+      assertEquals(Configuration.CacheMode.LOCAL, c.getCacheMode());
+      assertEquals(GenericTransactionManagerLookup.class.getName(), c.getTransactionManagerLookupClass());
+
+      // note that certain values should be immutable.  E.g., CacheMode cannot be changed on the fly.
+      try
+      {
+         c.setCacheMode(Configuration.CacheMode.REPL_SYNC);
+         assert false : "Should have thrown an Exception";
+      }
+      catch (ConfigurationException e)
+      {
+         // expected
+      }
+
+      // others should be changeable though.
+      c.setLockAcquisitionTimeout(100);
+   }
+
+   public void testGetMembersInLocalMode()
+   {
+      assert cache.getRPCManager() == null : "Cache members should be null if running in LOCAL mode";
+   }
+
+   /**
+    * All cache operations should happen on a {@link Node} - I.e., you look up a {@link Node} and perform data operations
+    * on this {@link Node}.  For convenience and familiarity with JBoss Cache 1.x, we provide some helpers in {@link Cache}
+    * which dives you direct data access to nodes.
+    * <p/>
+    * This test exercises these.
+    */
+   public void testConvenienceMethods()
+   {
+      String key = "key", value = "value";
+      Map<String, String> data = new HashMap<String, String>();
+      data.put(key, value);
+
+      assertNull(cache.get(key));
+
+      cache.put(key, value);
+
+      assertEquals(value, cache.get(key));
+
+      cache.remove(key);
+
+      assertNull(cache.get(key));
+
+      cache.putAll(data);
+
+      assertEquals(value, cache.get(key));
+   }
+
+   /**
+    * Tests basic eviction
+    */
+   public void testEvict()
+   {
+      String key1 = "keyOne", key2 = "keyTwo", value = "value";
+
+      cache.put(key1, value);
+      cache.put(key2, value);
+
+      assert cache.containsKey(key1);
+      assert cache.containsKey(key2);
+      assert cache.size() == 2;
+
+      // evict two
+      cache.evict(key2);
+
+      assert cache.containsKey(key1);
+      assert !cache.containsKey(key2);
+      assert cache.size() == 1;
+
+      cache.evict(key1);
+
+      assert !cache.containsKey(key1);
+      assert !cache.containsKey(key2);
+      assert cache.size() == 0;
+   }
+
+   public void testStopClearsData() throws Exception
+   {
+      String key = "key", value = "value";
+      cache.put(key, value);
+      assert cache.get(key).equals(value);
+      assert 1 == cache.size();
+      cache.stop();
+
+      cache.start();
+
+      assert !cache.containsKey(key);
+      assert cache.isEmpty();
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/CacheSPITest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,97 @@
+package org.jboss.starobrno.api;
+
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.starobrno.CacheSPI;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.Configuration.CacheMode;
+import org.jboss.starobrno.util.TestingUtil;
+import org.jboss.starobrno.util.internals.ViewChangeListener;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+ at Test(groups = {"functional", "pessimistic"})
+public class CacheSPITest
+{
+   private CacheSPI<Object, Object> cache1;
+   private CacheSPI<Object, Object> cache2;
+
+   @BeforeMethod(alwaysRun = true)
+   public void setUp() throws Exception
+   {
+
+      Configuration conf1 = new Configuration();
+      conf1.setCacheMode(CacheMode.REPL_SYNC);
+
+      Configuration conf2 = conf1.clone();
+
+      cache1 = (CacheSPI<Object, Object>) new DefaultCacheFactory<Object, Object>().createCache(conf1, false);
+      cache2 = (CacheSPI<Object, Object>) new DefaultCacheFactory<Object, Object>().createCache(conf2, false);
+   }
+
+   @AfterMethod(alwaysRun = true)
+   public void tearDown() throws Exception
+   {
+      if (cache1 != null)
+      {
+         try
+         {
+            cache1.stop();
+         }
+         catch (Exception e)
+         {
+         }
+      }
+
+      if (cache2 != null)
+      {
+         try
+         {
+            cache2.stop();
+         }
+         catch (Exception e)
+         {
+         }
+      }
+   }
+
+   public void testGetMembers() throws Exception
+   {
+      cache1.start();
+      List memb1 = cache1.getRPCManager().getMembers();
+      assert 1 == memb1.size();
+
+      Object coord = memb1.get(0);
+
+      cache2.start();
+      memb1 = cache1.getRPCManager().getMembers();
+      TestingUtil.blockUntilViewsReceived(5000, false, cache1, cache2);
+      List memb2 = cache2.getRPCManager().getMembers();
+      assert 2 == memb1.size();
+      assert memb1 == memb2;
+
+      cache1.stop();
+      TestingUtil.blockUntilViewsReceived(5000, false, cache2);
+      memb2 = cache2.getRPCManager().getMembers();
+      assert 1 == memb2.size();
+      assert !coord.equals(memb2.get(0));
+   }
+
+   public void testIsCoordinator() throws Exception
+   {
+      cache1.start();
+      assert cache1.getRPCManager().isCoordinator();
+
+      cache2.start();
+      assert cache1.getRPCManager().isCoordinator();
+      assert !cache2.getRPCManager().isCoordinator();
+      ViewChangeListener viewChangeListener = new ViewChangeListener(cache2);
+      cache1.stop();
+      // wait till cache2 gets the view change notification
+      assert viewChangeListener.waitForViewChange(60, TimeUnit.SECONDS) : "Should have received a view change!";
+      assert cache2.getRPCManager().isCoordinator();
+   }
+}
\ No newline at end of file

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/AbstractBatchTest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,24 @@
+package org.jboss.starobrno.api.batch;
+
+import org.jboss.starobrno.Cache;
+
+import java.util.concurrent.atomic.AtomicReference;
+
+public abstract class AbstractBatchTest
+{
+   protected String getOnDifferentThread(final Cache<String, String> cache, final String key) throws InterruptedException
+   {
+      final AtomicReference<String> ref = new AtomicReference<String>();
+      Thread t = new Thread()
+      {
+         public void run()
+         {
+            ref.set(cache.get(key));
+         }
+      };
+
+      t.start();
+      t.join();
+      return ref.get();
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithTM.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,123 @@
+package org.jboss.starobrno.api.batch;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+
+
+ at Test(groups = {"functional", "transaction"})
+public class BatchWithTM extends AbstractBatchTest
+{
+   public void testBatchWithOngoingTM() throws Exception
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache();
+         TransactionManager tm = getTransactionManager(cache);
+         tm.begin();
+         cache.put("k", "v");
+         cache.startBatch();
+         cache.put("k2", "v2");
+         tm.commit();
+
+         assert "v".equals(cache.get("k"));
+         assert "v2".equals(cache.get("k2"));
+
+         cache.endBatch(false); // should be a no op
+         assert "v".equals(cache.get("k"));
+         assert "v2".equals(cache.get("k2"));
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   public void testBatchWithoutOngoingTMSuspension() throws Exception
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache();
+         TransactionManager tm = getTransactionManager(cache);
+         assert tm.getTransaction() == null : "Should have no ongoing txs";
+         cache.startBatch();
+         cache.put("k", "v");
+         assert tm.getTransaction() == null : "Should have no ongoing txs";
+         cache.put("k2", "v2");
+
+         assert getOnDifferentThread(cache, "k") == null;
+         assert getOnDifferentThread(cache, "k2") == null;
+
+         try
+         {
+            tm.commit(); // should have no effect
+         }
+         catch (Exception e)
+         {
+            // the TM may barf here ... this is OK.
+         }
+
+         assert tm.getTransaction() == null : "Should have no ongoing txs";
+
+         assert getOnDifferentThread(cache, "k") == null;
+         assert getOnDifferentThread(cache, "k2") == null;
+
+         cache.endBatch(true); // should be a no op
+
+         assert "v".equals(getOnDifferentThread(cache, "k"));
+         assert "v2".equals(getOnDifferentThread(cache, "k2"));
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   public void testBatchRollback() throws Exception
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache();
+         TransactionManager tm = getTransactionManager(cache);
+         cache.startBatch();
+         cache.put("k", "v");
+         cache.put("k2", "v2");
+
+         assert getOnDifferentThread(cache, "k") == null;
+         assert getOnDifferentThread(cache, "k2") == null;
+
+         cache.endBatch(false);
+
+         assert getOnDifferentThread(cache, "k") == null;
+         assert getOnDifferentThread(cache, "k2") == null;
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   private TransactionManager getTransactionManager(Cache<String, String> c)
+   {
+      return c.getConfiguration().getRuntimeConfig().getTransactionManager();
+   }
+
+   private Cache<String, String> createCache()
+   {
+      CacheFactory<String, String> cf = new DefaultCacheFactory<String, String>();
+      Configuration c = new Configuration();
+      c.setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+      c.setInvocationBatchingEnabled(true);
+      assert c.getTransactionManagerLookupClass() != null : "Should have a transaction manager lookup class attached!!";
+      return cf.createCache(c);
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/batch/BatchWithoutTM.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,144 @@
+package org.jboss.starobrno.api.batch;
+
+import org.jboss.cache.CacheFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.config.ConfigurationException;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.Test;
+
+ at Test(groups = "functional")
+public class BatchWithoutTM extends AbstractBatchTest
+{
+   public void testBatchWithoutCfg()
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache(false);
+         try
+         {
+            cache.startBatch();
+            assert false : "Should have failed";
+         }
+         catch (ConfigurationException good)
+         {
+            // do nothing
+         }
+
+         try
+         {
+            cache.endBatch(true);
+            assert false : "Should have failed";
+         }
+         catch (ConfigurationException good)
+         {
+            // do nothing
+         }
+
+         try
+         {
+            cache.endBatch(false);
+            assert false : "Should have failed";
+         }
+         catch (ConfigurationException good)
+         {
+            // do nothing
+         }
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   public void testEndBatchWithoutStartBatch()
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache(true);
+         cache.endBatch(true);
+         cache.endBatch(false);
+         // should not fail.
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   public void testStartBatchIdempotency()
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache(true);
+         cache.startBatch();
+         cache.put("k", "v");
+         cache.startBatch();     // again
+         cache.put("k2", "v2");
+         cache.endBatch(true);
+
+         assert "v".equals(cache.get("k"));
+         assert "v2".equals(cache.get("k2"));
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   public void testBatchVisibility() throws InterruptedException
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache(true);
+         cache.startBatch();
+         cache.put("k", "v");
+         assert getOnDifferentThread(cache, "k") == null : "Other thread should not see batch update till batch completes!";
+
+         cache.endBatch(true);
+
+         assert "v".equals(getOnDifferentThread(cache, "k"));
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   public void testBatchRollback() throws Exception
+   {
+      Cache<String, String> cache = null;
+      try
+      {
+         cache = createCache(true);
+         cache.startBatch();
+         cache.put("k", "v");
+         cache.put("k2", "v2");
+
+         assert getOnDifferentThread(cache, "k") == null;
+         assert getOnDifferentThread(cache, "k2") == null;
+
+         cache.endBatch(false);
+
+         assert getOnDifferentThread(cache, "k") == null;
+         assert getOnDifferentThread(cache, "k2") == null;
+      }
+      finally
+      {
+         TestingUtil.killCaches(cache);
+      }
+   }
+
+   private Cache<String, String> createCache(boolean enableBatch)
+   {
+      CacheFactory<String, String> cf = new DefaultCacheFactory<String, String>();
+      Configuration c = new Configuration();
+      c.setInvocationBatchingEnabled(enableBatch);
+      return cf.createCache(c);
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockAssert.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,35 @@
+package org.jboss.starobrno.api.mvcc;
+
+import org.jboss.cache.util.concurrent.locks.LockContainer;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.util.TestingUtil;
+
+/**
+ * Helper class to assert lock status in MVCC
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+public class LockAssert
+{
+   public static void assertLocked(Object key, LockManager lockManager, InvocationContextContainer icc)
+   {
+      assert lockManager.isLocked(key) : key + " not locked!";
+//      assert icc.get().getKeysLocked().contains(key) : "Lock not recorded for " + key;
+   }
+
+   public static void assertNotLocked(Object key, InvocationContextContainer icc)
+   {
+      // can't rely on the negative test since other nodes may share the same lock with lock striping.
+//      assert !lockManager.isLocked(fqn) : fqn + " is locked!";
+      assert !icc.get().getKeysLocked().contains(key) : key + " lock recorded!";
+   }
+
+   public static void assertNoLocks(LockManager lockManager, InvocationContextContainer icc)
+   {
+      LockContainer lc = (LockContainer) TestingUtil.extractField(lockManager, "lockContainer");
+      assert lc.getNumLocksHeld() == 0 : "Stale locks exist! NumLocksHeld is " + lc.getNumLocksHeld() + " and lock info is " + lockManager.printLockInfo();
+      assert icc.get().getKeysLocked().isEmpty() : "Stale (?) locks recorded! " + icc.get().getKeysLocked();
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/LockTestBase.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,301 @@
+package org.jboss.starobrno.api.mvcc;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+
+/**
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+ at Test(groups = {"functional", "mvcc"})
+public abstract class LockTestBase
+{
+   protected Cache<String, String> cache;
+   protected TransactionManager tm;
+   protected LockManager lockManager;
+   protected InvocationContextContainer icc;
+   protected boolean repeatableRead = true;
+   protected boolean lockParentForChildInsertRemove = false;
+   private Log log = LogFactory.getLog(LockTestBase.class);
+
+
+   @BeforeMethod
+   public void setUp()
+   {
+      cache = new DefaultCacheFactory<String, String>().createCache(new Configuration(), false);
+      cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+      cache.getConfiguration().setIsolationLevel(repeatableRead ? IsolationLevel.REPEATABLE_READ : IsolationLevel.READ_COMMITTED);
+      cache.getConfiguration().setLockParentForChildInsertRemove(lockParentForChildInsertRemove);
+      // reduce lock acquisition timeout so this doesn't take forever to run
+      cache.getConfiguration().setLockAcquisitionTimeout(200); // 200 ms
+      cache.start();
+      lockManager = TestingUtil.extractComponentRegistry(cache).getComponent(LockManager.class);
+      icc = TestingUtil.extractComponentRegistry(cache).getComponent(InvocationContextContainer.class);
+      tm = TestingUtil.extractComponentRegistry(cache).getComponent(TransactionManager.class);
+   }
+
+   @AfterMethod
+   public void tearDown()
+   {
+      log.debug("**** - STARTING TEARDOWN - ****");
+      TestingUtil.killCaches(cache);
+   }
+
+   protected void assertLocked(Object key)
+   {
+      LockAssert.assertLocked(key, lockManager, icc);
+   }
+
+   protected void assertNotLocked(Object key)
+   {
+      LockAssert.assertNotLocked(key, icc);
+   }
+
+   protected void assertNoLocks()
+   {
+      LockAssert.assertNoLocks(lockManager, icc);
+   }
+
+   public void testLocksOnPutKeyVal() throws Exception
+   {
+      tm.begin();
+      cache.put("k", "v");
+      assertLocked("k");
+      tm.commit();
+
+      assertNoLocks();
+
+      tm.begin();
+      assert cache.get("k").equals("v");
+      assertNotLocked("k");
+      tm.commit();
+
+      assertNoLocks();
+
+      tm.begin();
+      cache.remove("k");
+      assertLocked("k");
+      tm.commit();
+
+      assertNoLocks();
+   }
+
+   public void testLocksOnPutData() throws Exception
+   {
+      tm.begin();
+      cache.putAll(Collections.singletonMap("k", "v"));
+      assertLocked("k");
+      assert "v".equals(cache.get("k"));
+      tm.commit();
+
+      assertNoLocks();
+
+      tm.begin();
+      assert "v".equals(cache.get("k"));
+      assertNoLocks();
+      tm.commit();
+
+      assertNoLocks();
+   }
+
+   public void testLocksOnEvictNode() throws Exception
+   {
+      // init some data on a node
+      cache.putAll(Collections.singletonMap("k", "v"));
+
+      assert "v".equals(cache.get("k"));
+
+      tm.begin();
+      cache.evict("k");
+      assertLocked("k");
+      tm.commit();
+      assert !cache.containsKey("k") : "Should not exist";
+      assertNoLocks();
+   }
+
+   public void testLocksOnRemoveNonexistentNode() throws Exception
+   {
+      assert !cache.containsKey("k") : "Should not exist";
+
+      tm.begin();
+      cache.remove("k");
+      assertLocked("k");
+      tm.commit();
+      assert !cache.containsKey("k") : "Should not exist";
+      assertNoLocks();
+   }
+
+   public void testLocksOnEvictNonexistentNode() throws Exception
+   {
+      assert !cache.containsKey("k") : "Should not exist";
+
+      tm.begin();
+      cache.evict("k");
+      assertLocked("k");
+      tm.commit();
+      assert !cache.containsKey("k") : "Should not exist";
+      assertNoLocks();
+   }
+
+   public void testLocksOnRemoveData() throws Exception
+   {
+      // init some data on a node
+      cache.put("k", "v");
+      cache.put("k2", "v2");
+
+      assert "v".equals(cache.get("k"));
+      assert "v2".equals(cache.get("k2"));
+
+      // remove
+      tm.begin();
+      cache.clear();
+      assertLocked("k");
+      assertLocked("k2");
+      tm.commit();
+
+      assert cache.isEmpty();
+      assertNoLocks();
+   }
+
+   public void testWriteDoesntBlockRead() throws Exception
+   {
+      cache.put("k", "v");
+
+      // start a write.
+      tm.begin();
+      cache.put("k2", "v2");
+      assertLocked("k2");
+      Transaction write = tm.suspend();
+
+      // now start a read and confirm that the write doesn't block it.
+      tm.begin();
+      assert "v".equals(cache.get("k"));
+      assert null == cache.get("k2") : "Should not see uncommitted changes";
+      Transaction read = tm.suspend();
+
+      // commit the write
+      tm.resume(write);
+      tm.commit();
+
+      assertNoLocks();
+
+      tm.resume(read);
+      if (repeatableRead)
+         assert null == cache.get("k2") : "Should have repeatable read";
+      else
+         assert "v2".equals(cache.get("k2")) : "Read committed should see committed changes";
+      tm.commit();
+      assertNoLocks();
+   }
+
+   public void testWriteDoesntBlockReadNonexistent() throws Exception
+   {
+      // start a write.
+      tm.begin();
+      cache.put("k", "v");
+      assertLocked("k");
+      Transaction write = tm.suspend();
+
+      // now start a read and confirm that the write doesn't block it.
+      tm.begin();
+      assert null == cache.get("k") : "Should not see uncommitted changes";
+      Transaction read = tm.suspend();
+
+      // commit the write
+      tm.resume(write);
+      tm.commit();
+
+      assertNoLocks();
+
+      tm.resume(read);
+      if (repeatableRead)
+      {
+         assert null == cache.get("k") : "Should have repeatable read";
+      }
+      else
+      {
+         assert "v".equals(cache.get("k")) : "Read committed should see committed changes";
+      }
+      tm.commit();
+      assertNoLocks();
+   }
+
+   public void testConcurrentWriters() throws Exception
+   {
+      tm.begin();
+      cache.put("k", "v");
+      Transaction t1 = tm.suspend();
+
+      tm.begin();
+      try
+      {
+         cache.put("k", "v");
+         assert false : "Should fail lock acquisition";
+      }
+      catch (TimeoutException expected)
+      {
+//         expected.printStackTrace();  // for debugging
+      }
+      tm.commit();
+      tm.resume(t1);
+      tm.commit();
+      assertNoLocks();
+   }
+
+   public void testRollbacks() throws Exception
+   {
+      cache.put("k", "v");
+      tm.begin();
+      assert "v".equals(cache.get("k"));
+      Transaction reader = tm.suspend();
+
+      tm.begin();
+      cache.put("k", "v2");
+      tm.rollback();
+
+      tm.resume(reader);
+      Object value = cache.get("k");
+      assert "v".equals(value) : "Expecting 'v' but was " + value;
+      tm.commit();
+
+      // even after commit
+      assert "v".equals(cache.get("k"));
+      assertNoLocks();
+   }
+
+   public void testRollbacksOnNullNode() throws Exception
+   {
+      tm.begin();
+      assert null == cache.get("k");
+      Transaction reader = tm.suspend();
+
+      tm.begin();
+      cache.put("k", "v");
+      assert "v".equals(cache.get("k"));
+      tm.rollback();
+
+      tm.resume(reader);
+      assert null == cache.get("k") : "Expecting null but was " + cache.get("k");
+      tm.commit();
+
+      // even after commit
+      assert null == cache.get("k");
+      assertNoLocks();
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/CacheAPIMVCCTest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,20 @@
+package org.jboss.starobrno.api.mvcc.read_committed;
+
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.starobrno.api.CacheAPITest;
+import org.jboss.starobrno.config.Configuration;
+import org.testng.annotations.Test;
+
+/**
+ * MVCC version of {@link org.jboss.cache.api.CacheAPITest}
+ */
+ at Test(groups = {"functional", "mvcc"})
+public class CacheAPIMVCCTest extends CacheAPITest
+{
+   @Override
+   protected void configure(Configuration c)
+   {
+      super.configure(c);
+      c.setIsolationLevel(IsolationLevel.READ_COMMITTED);
+   }
+}
\ No newline at end of file

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/read_committed/ReadCommittedLockTest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,13 @@
+package org.jboss.starobrno.api.mvcc.read_committed;
+
+import org.jboss.starobrno.api.mvcc.LockTestBase;
+import org.testng.annotations.Test;
+
+ at Test(groups = {"functional", "mvcc"})
+public class ReadCommittedLockTest extends LockTestBase
+{
+   public ReadCommittedLockTest()
+   {
+      repeatableRead = false;
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/CacheAPIMVCCTest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,20 @@
+package org.jboss.starobrno.api.mvcc.repeatable_read;
+
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.starobrno.api.CacheAPITest;
+import org.jboss.starobrno.config.Configuration;
+import org.testng.annotations.Test;
+
+/**
+ * MVCC version of {@link org.jboss.cache.api.CacheAPITest}
+ */
+ at Test(groups = {"functional", "mvcc"})
+public class CacheAPIMVCCTest extends CacheAPITest
+{
+   @Override
+   protected void configure(Configuration c)
+   {
+      super.configure(c);
+      c.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
+   }
+}
\ No newline at end of file

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/RepeatableReadLockTest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,90 @@
+package org.jboss.starobrno.api.mvcc.repeatable_read;
+
+import org.jboss.starobrno.api.mvcc.LockTestBase;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+
+ at Test(groups = {"functional", "mvcc"})
+public class RepeatableReadLockTest extends LockTestBase
+{
+   public RepeatableReadLockTest()
+   {
+      repeatableRead = true;
+   }
+
+   public void testRepeatableReadWithRemove() throws Exception
+   {
+      cache.put("k", "v");
+
+      tm.begin();
+      assert cache.get("k") != null;
+      Transaction reader = tm.suspend();
+
+      tm.begin();
+      assert cache.remove("k") != null;
+      assert cache.get("k") == null;
+      tm.commit();
+
+      assert cache.get("k") == null;
+
+      tm.resume(reader);
+      assert cache.get("k") != null;
+      assert "v".equals(cache.get("k"));
+      tm.commit();
+
+      assert cache.get("k") == null;
+      assertNoLocks();
+   }
+
+   public void testRepeatableReadWithEvict() throws Exception
+   {
+      cache.put("k", "v");
+
+      tm.begin();
+      assert cache.get("k") != null;
+      Transaction reader = tm.suspend();
+
+      tm.begin();
+      cache.evict("k");
+      assert cache.get("k") == null;
+      tm.commit();
+
+      assert cache.get("k") == null;
+
+      tm.resume(reader);
+      assert cache.get("k") != null;
+      assert "v".equals(cache.get("k"));
+      tm.commit();
+
+      assert cache.get("k") == null;
+      assertNoLocks();
+   }
+
+   public void testRepeatableReadWithNull() throws Exception
+   {
+      assert cache.get("k") == null;
+
+      tm.begin();
+      assert cache.get("k") == null;
+      Transaction reader = tm.suspend();
+
+      tm.begin();
+      cache.put("k", "v");
+      assert cache.get("k") != null;
+      assert "v".equals(cache.get("k"));
+      tm.commit();
+
+      assert cache.get("k") != null;
+      assert "v".equals(cache.get("k"));
+
+      tm.resume(reader);
+      Object o = cache.get("k");
+      assert o == null : "found value " + o;
+      tm.commit();
+
+      assert cache.get("k") != null;
+      assert "v".equals(cache.get("k"));
+      assertNoLocks();
+   }
+}

Added: core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java
===================================================================
--- core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java	                        (rev 0)
+++ core/branches/flat/src/test/java/org/jboss/starobrno/api/mvcc/repeatable_read/WriteSkewTest.java	2008-10-10 09:43:27 UTC (rev 6901)
@@ -0,0 +1,191 @@
+package org.jboss.starobrno.api.mvcc.repeatable_read;
+
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.transaction.DummyTransactionManagerLookup;
+import org.jboss.starobrno.Cache;
+import org.jboss.starobrno.api.mvcc.LockAssert;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.invocation.InvocationContextContainer;
+import org.jboss.starobrno.lock.LockManager;
+import org.jboss.starobrno.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+ at Test(groups = {"functional", "mvcc"})
+public class WriteSkewTest
+{
+   protected Cache<String, String> cache;
+   protected TransactionManager tm;
+   protected LockManager lockManager;
+   protected InvocationContextContainer icc;
+   protected boolean repeatableRead = true;
+
+   @BeforeMethod
+   public void setUp()
+   {
+      cache = new DefaultCacheFactory<String, String>().createCache(new Configuration(), false);
+      cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
+      cache.getConfiguration().setIsolationLevel(repeatableRead ? IsolationLevel.REPEATABLE_READ : IsolationLevel.READ_COMMITTED);
+      // reduce lock acquisition timeout so this doesn't take forever to run
+      cache.getConfiguration().setLockAcquisitionTimeout(200); // 200 ms
+   }
+
+   @AfterMethod
+   public void tearDown()
+   {
+      TestingUtil.killCaches(cache);
+   }
+
+   private void postStart()
+   {
+      lockManager = TestingUtil.extractComponentRegistry(cache).getComponent(LockManager.class);
+      icc = TestingUtil.extractComponentRegistry(cache).getComponent(InvocationContextContainer.class);
+      tm = TestingUtil.extractComponentRegistry(cache).getComponent(TransactionManager.class);
+   }
+
+   protected void assertNoLocks()
+   {
+      LockAssert.assertNoLocks(lockManager, icc);
+   }
+
+   public void testDontCheckWriteSkew() throws Exception
+   {
+      cache.getConfiguration().setWriteSkewCheck(false);
+      cache.start();
+      postStart();
+      doTest(true);
+   }
+
+   public void testCheckWriteSkew() throws Exception
+   {
+      cache.getConfiguration().setWriteSkewCheck(true);
+      cache.start();
+      postStart();
+      doTest(false);
+   }
+
+   private void doTest(final boolean allowWriteSkew) throws Exception
+   {
+      if (repeatableRead)
+      {
+         cache.put("k", "v");
+         final Set<Exception> w1exceptions = new HashSet<Exception>();
+         final Set<Exception> w2exceptions = new HashSet<Exception>();
+         final CountDownLatch w1Signal = new CountDownLatch(1);
+         final CountDownLatch w2Signal = new CountDownLatch(1);
+         final CountDownLatch threadSignal = new CountDownLatch(2);
+
+         Thread w1 = new Thread("Writer-1")
+         {
+            public void run()
+            {
+               boolean didCoundDown = false;
+               try
+               {
+                  tm.begin();
+                  assert "v".equals(cache.get("k"));
+                  threadSignal.countDown();
+                  didCoundDown = true;
+                  w1Signal.await();
+                  cache.put("k", "v2");
+                  tm.commit();
+               }
+               catch (Exception e)
+               {
+                  w1exceptions.add(e);
+               }
+               finally
+               {
+                  if (!didCoundDown) threadSignal.countDown();
+               }
+            }
+         };
+
+         Thread w2 = new Thread("Writer-2")
+         {
+            public void run()
+            {
+               boolean didCoundDown = false;
+               try
+               {
+                  tm.begin();
+                  assert "v".equals(cache.get("k"));
+                  threadSignal.countDown();
+                  didCoundDown = true;
+                  w2Signal.await();
+                  cache.put("k", "v3");
+                  tm.commit();
+               }
+               catch (Exception e)
+               {
+                  w2exceptions.add(e);
+                  // the exception will be thrown when doing a cache.put().  We should make sure we roll back the tx to release locks.
+                  if (!allowWriteSkew)
+                  {
+                     try
+                     {
+                        tm.rollback();
+                     }
+                     catch (SystemException e1)
+                     {
+                        // do nothing.
+                     }
+                  }
+               }
+               finally
+               {
+                  if (!didCoundDown) threadSignal.countDown();
+               }
+            }
+         };
+
+         w1.start();
+         w2.start();
+
+         threadSignal.await();
+         // now.  both txs have read.
+         // let tx1 start writing
+         w1Signal.countDown();
+         w1.join();
+
+         w2Signal.countDown();
+         w2.join();
+
+         if (allowWriteSkew)
+         {
+            // should have no exceptions!!
+            throwExceptions(w1exceptions, w2exceptions);
+            assert w2exceptions.size() == 0;
+            assert w1exceptions.size() == 0;
+            assert "v3".equals(cache.get("k")) : "W2 should have overwritten W1's work!";
+         }
+         else
+         {
+            // there should be a single exception from w2.
+            assert w2exceptions.size() == 1;
+            throwExceptions(w1exceptions);
+            assert w1exceptions.size() == 0;
+            assert "v2".equals(cache.get("k")) : "W2 should NOT have overwritten W1's work!";
+         }
+
+         assertNoLocks();
+      }
+   }
+
+   private void throwExceptions(Collection<Exception>... exceptions) throws Exception
+   {
+      for (Collection<Exception> ce : exceptions)
+      {
+         for (Exception e : ce) throw e;
+      }
+   }
+}




More information about the jbosscache-commits mailing list