[jbosscache-commits] JBoss Cache SVN: r6215 - in core/trunk/src: main/java/org/jboss/cache/factories and 9 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Tue Jul 8 12:27:16 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-07-08 12:27:15 -0400 (Tue, 08 Jul 2008)
New Revision: 6215

Added:
   core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
   core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
   core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
   core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java
   core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java
   core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
Log:
MVCC + CacheLoading and Passivation - preliminary work

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -118,7 +118,7 @@
          else
          {
             if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
-            NodeSPI parentNode = lookupForEviction(ctx, fqn.getParent());
+            NodeSPI parentNode = lookupInAllScopes(ctx, fqn.getParent());
 
             if (parentNode != null)
             {
@@ -136,6 +136,16 @@
       }
    }
 
+   private NodeSPI lookupInAllScopes(InvocationContext ctx, Fqn fqn)
+   {
+      NodeSPI nodeSPI = lookupForEviction(ctx, fqn);
+      if (nodeSPI == null)
+      {
+         nodeSPI = dataContainer.peek(fqn);
+      }
+      return nodeSPI;
+   }
+
    protected NodeSPI lookupForEviction(InvocationContext ctx, Fqn fqn)
    {
       return ctx.lookUpNode(fqn);

Modified: core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/factories/InterceptorChainFactory.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -87,6 +87,18 @@
 
       if (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
       {
+         // if MVCC, then the CLI or AI must come before the MVCCLI.
+         if (configuration.isUsingCacheLoaders())
+         {
+            if (configuration.getCacheLoaderConfig().isPassivation())
+            {
+               interceptorChain.appendIntereceptor(createInterceptor(ActivationInterceptor.class));
+            }
+            else
+            {
+               interceptorChain.appendIntereceptor(createInterceptor(CacheLoaderInterceptor.class));
+            }
+         }
          interceptorChain.appendIntereceptor(createInterceptor(MVCCLockingInterceptor.class));
       }
       else if (configuration.getNodeLockingScheme() == NodeLockingScheme.PESSIMISTIC)
@@ -98,12 +110,14 @@
       {
          if (configuration.getCacheLoaderConfig().isPassivation())
          {
-            interceptorChain.appendIntereceptor(createInterceptor(ActivationInterceptor.class));
+            if (configuration.getNodeLockingScheme() != NodeLockingScheme.MVCC)
+               interceptorChain.appendIntereceptor(createInterceptor(LegacyActivationInterceptor.class));
             interceptorChain.appendIntereceptor(createInterceptor(PassivationInterceptor.class));
          }
          else
          {
-            interceptorChain.appendIntereceptor(createInterceptor(CacheLoaderInterceptor.class));
+            if (configuration.getNodeLockingScheme() != NodeLockingScheme.MVCC)
+               interceptorChain.appendIntereceptor(createInterceptor(LegacyCacheLoaderInterceptor.class));
             interceptorChain.appendIntereceptor(createInterceptor(CacheStoreInterceptor.class));
          }
       }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -4,7 +4,6 @@
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.NodeSPI;
-import org.jboss.cache.commands.WriteCommand;
 import org.jboss.cache.commands.read.GetChildrenNamesCommand;
 import org.jboss.cache.commands.read.GetDataMapCommand;
 import org.jboss.cache.commands.read.GetKeyValueCommand;
@@ -27,11 +26,9 @@
 import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.loader.CacheLoader;
 import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.lock.LockManager;
-import org.jboss.cache.lock.LockType;
-import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.mvcc.MVCCNodeHelper;
+import org.jboss.cache.mvcc.NullMarkerNode;
 import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.transaction.TransactionContext;
 import org.jboss.cache.transaction.TransactionTable;
 
 import java.util.Collections;
@@ -52,7 +49,6 @@
    private long cacheLoads = 0;
    private long cacheMisses = 0;
    private CacheLoaderManager clm;
-   private LockManager lockManager;
 
    protected TransactionTable txTable = null;
    protected CacheLoader loader;
@@ -62,7 +58,9 @@
    protected boolean isActivation = false;
    protected boolean usingVersionedInvalidation = false;
 
+   protected MVCCNodeHelper helper;
 
+
    /**
     * True if CacheStoreInterceptor is in place.
     * This allows us to skip loading keys for remove(Fqn, key) and put(Fqn, key).
@@ -72,15 +70,15 @@
 
    @Inject
    protected void injectDependencies(TransactionTable txTable, CacheLoaderManager clm, Configuration configuration,
-                                     DataContainer dataContainer, LockManager lockManager, Notifier notifier)
+                                     DataContainer dataContainer, Notifier notifier, MVCCNodeHelper helper)
    {
       this.txTable = txTable;
       this.clm = clm;
       CacheMode mode = configuration.getCacheMode();
       usingVersionedInvalidation = configuration.getNodeLockingScheme().isVersionedScheme() && mode.isInvalidation();
       this.dataContainer = dataContainer;
-      this.lockManager = lockManager;
       this.notifier = notifier;
+      this.helper = helper;
    }
 
    @Start
@@ -94,7 +92,7 @@
    {
       if (command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), null, false, true, false, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), null, false, true, false, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -104,7 +102,7 @@
    {
       if (command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, useCacheStore, !useCacheStore, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, useCacheStore, !useCacheStore, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -122,9 +120,9 @@
       {
          if (command.getTo() != null)
          {
-            loadIfNeeded(ctx, command.getTo(), null, false, false, true, ctx.getTransactionContext(), false, true, false);
+            loadIfNeeded(ctx, command.getTo(), null, false, false, true, false, true, false);
          }
-         loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), true, true, false);
+         loadIfNeeded(ctx, command.getFqn(), null, false, false, true, true, true, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -134,7 +132,7 @@
    {
       if (command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, true, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, true, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -145,7 +143,7 @@
    {
       if (command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), false, false, !usingVersionedInvalidation);
+         loadIfNeeded(ctx, command.getFqn(), null, false, false, true, false, false, !usingVersionedInvalidation);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -156,7 +154,7 @@
       Fqn fqn = command.getFqn();
       if (fqn != null)
       {
-         loadIfNeeded(ctx, fqn, null, false, false, false, ctx.getTransactionContext(), false, false, true);
+         loadIfNeeded(ctx, fqn, null, false, false, false, false, false, true);
          NodeSPI n = dataContainer.peek(fqn, true, true);
          loadChildren(fqn, n, false, false, ctx);
       }
@@ -169,7 +167,7 @@
    {
       if (command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), null, true, false, true, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -179,7 +177,7 @@
    {
       if (command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), null, true, false, true, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -216,7 +214,7 @@
    {
       if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC && command.getFqn() != null)
       {
-         loadIfNeeded(ctx, command.getFqn(), null, false, false, false, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), null, false, false, false, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -226,7 +224,7 @@
    {
       if (command.getFqn() != null && !useCacheStore)
       {
-         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, false, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, false, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -237,73 +235,42 @@
       Fqn fqn = command.getFqn();
       if (fqn != null && !useCacheStore)
       {
-         loadIfNeeded(ctx, fqn, null, false, true, false, ctx.getTransactionContext(), false, false, false);
+         loadIfNeeded(ctx, fqn, null, false, true, false, false, false, false);
       }
       return invokeNextInterceptor(ctx, command);
    }
 
-   private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireLock, TransactionContext transactionContext, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
+   private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireWriteLock, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
    {
-      NodeSPI n = dataContainer.peek(fqn, true, true);
-      Object lockOwner = lockManager.getLockOwner(ctx);
-      boolean needLock = n != null && !lockManager.ownsLock(fqn, lockOwner);
-      boolean mustLoad = false;
-      try
+      NodeSPI n = helper.wrapNodeForReading(ctx, fqn);
+      if (n instanceof NullMarkerNode)
       {
-         if (needLock)
-         {
-            if (!lockManager.lock(n, LockType.READ, lockOwner))
-               throw new TimeoutException("Unable to acquire lock on " + fqn + ". Lock info: " + lockManager.printLockInfo(n));
-         }
-         mustLoad = mustLoad(n, key, allKeys || isMove);
+         ctx.getLookedUpNodes().remove(fqn);
+         n = null;
       }
-      finally
-      {
-         if (needLock) lockManager.unlock(n, lockOwner);
-      }
+      boolean mustLoad = mustLoad(n, key, allKeys || isMove);
 
-      if (trace)
-      {
-         log.trace("load element " + fqn + " mustLoad=" + mustLoad);
-      }
+      if (trace) log.trace("load element " + fqn + " mustLoad=" + mustLoad);
+
       if (mustLoad)
       {
-         if (initNode)
+         if (acquireWriteLock || initNode)
          {
-            n = createTempNode(fqn, transactionContext);
+            boolean isNew = n == null;
+            n = helper.wrapNodeForWriting(ctx, fqn, true, false, true, false, true); // won't create any nodes but will acquire locks.
+            if (isNew && n != null) n.setDataLoaded(false);
          }
 
-         // Only attempt to acquire this lock if we need to - i.e., if
-         // the lock hasn't already been acquired by the Lock
-         // interceptor.  CRUD methods (put, remove) would have acquired
-         // this lock - even if the node is not in memory and needs to be
-         // loaded.  Non-CRUD methods (put) would NOT have acquired this
-         // lock so if we are to load the node from cache loader, we need
-         // to acquire a write lock here.  as a 'catch-all', DO NOT
-         // attempt to acquire a lock here *anyway*, even for CRUD
-         // methods - this leads to a deadlock when you have threads
-         // simultaneously trying to create a node.  See
-         // org.jboss.cache.loader.deadlock.ConcurrentCreationDeadlockTest
-         // - Manik Surtani (21 March 2006)
-         if (acquireLock)
+         if (n == null || !n.isDeleted())
          {
-            lock(fqn, LockType.WRITE, false, ctx);// non-recursive for now
-         }
-
-//         if (!initNode && !wasRemovedInTx(fqn, ctx.getGlobalTransaction()))
-         if (!wasRemovedInTx(fqn, ctx))
-         {
-            if (bypassLoadingData)
+            if (n == null && loader.exists(fqn))
             {
-               if (n == null && loader.exists(fqn))
-               {
-                  // just create a dummy node in memory
-                  n = createTempNode(fqn, transactionContext);
-               }
+               // just create a dummy node in memory
+               n = helper.wrapNodeForWriting(ctx, fqn, true, true, true, false, false); // won't create any nodes but will acquire locks.
             }
-            else
+            if (!bypassLoadingData)
             {
-               n = loadNode(ctx, fqn, n, transactionContext);
+               n = loadNode(ctx, fqn, n);
             }
          }
       }
@@ -363,16 +330,16 @@
       // Create if node had not been created already
       if (node == null)
       {
-         node = createNodes(fqn, null);// dont care about local transactions
+         node = helper.wrapNodeForWriting(ctxt, fqn, true, true, true, false, false);
       }
 
       // Create one DataNode per child, mark as UNINITIALIZED
       for (Object name : childrenNames)
       {
-         Fqn childFqn = Fqn.fromElements(name);// this is a RELATIVE Fqn!!
+         Fqn childFqn = Fqn.fromRelativeElements(fqn, name);
 
          // create child if it didn't exist
-         NodeSPI child = node.addChildDirect(childFqn);
+         NodeSPI child = helper.wrapNodeForWriting(ctxt, childFqn, true, true, true, false, false);
          if ((isMove || isActivation) && recursive)
          {
             // load data for children as well!
@@ -385,7 +352,6 @@
             loadChildren(child.getFqn(), child, true, isMove, ctxt);
          }
       }
-      lock(fqn, recursive ? LockType.WRITE : LockType.READ, true, ctxt);// recursive=true: lock entire subtree
       node.setChildrenLoaded(true);
    }
 
@@ -454,41 +420,14 @@
       return retval;
    }
 
-   protected void lock(Fqn fqn, LockType lockType, boolean recursive, InvocationContext ctx) throws Throwable
-   {
-      if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC) return;
-
-      if (recursive)
-         lockManager.lockAllAndRecord(fqn, lockType, ctx);
-      else
-         lockManager.lockAndRecord(fqn, lockType, ctx);
-   }
-
    /**
-    * Returns true if the FQN or parent was removed during the current
-    * transaction.
-    * This is O(N) WRT to the number of modifications so far.
-    */
-   private boolean wasRemovedInTx(Fqn fqn, InvocationContext ctx)
-   {
-      TransactionContext transactionContext = ctx.getTransactionContext();
-      if (transactionContext == null) return false;
-
-      for (WriteCommand txCacheCommand : transactionContext.getModifications())
-      {
-         if (txCacheCommand instanceof RemoveNodeCommand && fqn.isChildOrEquals(txCacheCommand.getFqn())) return true;
-      }
-      return false;
-   }
-
-   /**
     * Loads a node from disk; if it exists creates parent TreeNodes.
     * If it doesn't exist on disk but in memory, clears the
     * uninitialized flag, otherwise returns null.
     */
-   private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n, TransactionContext transactionContext) throws Exception
+   private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n) throws Exception
    {
-      if (trace) log.trace("loadNode " + fqn);
+      if (trace) log.trace("loadNode " + fqn + " node is " + n);
       Map nodeData = loadData(fqn);
       if (nodeData != null)
       {
@@ -500,8 +439,6 @@
             notifier.notifyNodeActivated(fqn, true, Collections.emptyMap(), ctx);
          }
 
-         n = createNodes(fqn, transactionContext);
-//         n.clearDataDirect();
          n.setInternalState(nodeData);
 
          // set this node as valid?
@@ -521,44 +458,6 @@
       return n;
    }
 
-   /**
-    * Creates a new memory node in preparation for storage.
-    */
-   private NodeSPI createTempNode(Fqn fqn, TransactionContext transactionContext) throws Exception
-   {
-      NodeSPI n = createNodes(fqn, transactionContext);
-      n.setDataLoaded(false);
-      if (trace)
-      {
-         log.trace("createTempNode n " + n);
-      }
-      return n;
-   }
-
-   @SuppressWarnings("unchecked")
-   private NodeSPI createNodes(Fqn fqn, TransactionContext transactionContext) throws Exception
-   {
-      Object[] results = dataContainer.createNodes(fqn);
-      List<NodeSPI> createdNodes = (List<NodeSPI>) results[0];
-
-      NodeSPI lastCreated = null;
-      for (NodeSPI node : createdNodes)
-      {
-         node.setDataLoaded(false);
-         if (transactionContext != null)
-         {
-            transactionContext.addDummyNodeCreatedByCacheLoader(node.getFqn());
-         }
-         lastCreated = node;
-      }
-
-      // mark the leaf node as data loaded since that is what we are doing in this interceptor.
-      if (lastCreated != null) lastCreated.setDataLoaded(true);
-
-      // regardless of whether the last node was created, return it.
-      return (NodeSPI) results[1];
-   }
-
    private Map loadData(Fqn fqn) throws Exception
    {
 

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,7 +1,6 @@
 package org.jboss.cache.interceptors;
 
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.Modification;
 import org.jboss.cache.NodeSPI;
@@ -54,7 +53,6 @@
    private Map<GlobalTransaction, Set<Fqn>> preparingTxs = new ConcurrentHashMap<GlobalTransaction, Set<Fqn>>();
    private long cacheStores = 0;
    private CacheLoader loader;
-   private DataContainer dataContainer;
    private CacheLoaderManager loaderManager;
 
    public CacheStoreInterceptor()
@@ -64,13 +62,12 @@
    }
 
    @Inject
-   protected void init(DataContainer dataContainer, CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig)
+   protected void init(CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig)
    {
       // never inject a CacheLoader at this stage - only a CacheLoaderManager, since the CacheLoaderManager only creates a CacheLoader instance when it @Starts.
       this.loaderManager = loaderManager;
       this.loaderConfig = clConfig;
       txMgr = txManager;
-      this.dataContainer = dataContainer;
    }
 
    @Start
@@ -89,9 +86,7 @@
       if (!ctx.isOriginLocal() && loaderConfig.isShared())
       {
          if (trace)
-         {
             log.trace("Passing up method call and bypassing this interceptor since the cache loader is shared and this call originated remotely.");
-         }
          return true;
       }
       return false;
@@ -131,9 +126,9 @@
             Object returnValue = invokeNextInterceptor(ctx, command);
             // persist additional internal state, if any, and then clean up internal resources
             Set<Fqn> affectedFqns = preparingTxs.remove(gtx);
-            if (affectedFqns != null)
+            if (affectedFqns != null && !affectedFqns.isEmpty())
             {
-               storeInternalState(affectedFqns);
+               storeInternalState(affectedFqns, ctx);
             }
             return returnValue;
          }
@@ -220,7 +215,7 @@
       {
          loader.removeData(command.getFqn());
          // we need to mark this node as data loaded
-         NodeSPI n = dataContainer.peek(command.getFqn(), false, false);
+         NodeSPI n = ctx.lookUpNode(command.getFqn());
          if (n != null)
          {
             n.setDataLoaded(true);
@@ -283,15 +278,15 @@
       return txMgr != null && txMgr.getTransaction() != null;
    }
 
-   private void storeInternalState(Set<Fqn> affectedFqns) throws Exception
+   private void storeInternalState(Set<Fqn> affectedFqns, InvocationContext ctx) throws Exception
    {
       if (configuration.getNodeLockingScheme().isVersionedScheme())
       {
          for (Fqn f : affectedFqns)
          {
             // NOT going to store tombstones!!
-            NodeSPI n = dataContainer.peek(f, false, false);
-            if (n != null)
+            NodeSPI n = ctx.lookUpNode(f);
+            if (n != null && !n.isDeleted())
             {
                Map internalState = n.getInternalState(true);
                loader.put(f, internalState);

Copied: core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java (from rev 6207, core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyActivationInterceptor.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -0,0 +1,391 @@
+package org.jboss.cache.interceptors;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Modification;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.AbstractVisitor;
+import org.jboss.cache.commands.read.GetChildrenNamesCommand;
+import org.jboss.cache.commands.read.GetKeyValueCommand;
+import org.jboss.cache.commands.read.GetKeysCommand;
+import org.jboss.cache.commands.read.GetNodeCommand;
+import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
+import org.jboss.cache.commands.tx.PrepareCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.commands.write.RemoveNodeCommand;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.TransactionContext;
+
+import javax.transaction.SystemException;
+import javax.transaction.TransactionManager;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Loads nodes that don't exist at the time of the call into memory from the CacheLoader.
+ * If the nodes were evicted earlier then we remove them from the cache loader after
+ * their attributes have been initialized and their children have been loaded in memory.
+ *
+ * @author <a href="mailto:{hmesha at novell.com}">{Hany Mesha}</a>
+ * @version $Id$
+ */
+public class LegacyActivationInterceptor extends LegacyCacheLoaderInterceptor implements ActivationInterceptorMBean
+{
+
+   protected TransactionManager txMgr = null;
+   private long activations = 0;
+   ActivationModificationsBuilder builder;
+
+   /**
+    * List<Transaction> that we have registered for
+    */
+   protected ConcurrentHashMap transactions = new ConcurrentHashMap(16);
+   protected static final Object NULL = new Object();
+
+   public LegacyActivationInterceptor()
+   {
+      isActivation = true;
+      useCacheStore = false;
+   }
+
+   @Inject
+   public void injectTransactionManager(TransactionManager txMgr)
+   {
+      this.txMgr = txMgr;
+   }
+
+   @Start
+   public void createModificationsBuilder()
+   {
+      builder = new ActivationModificationsBuilder();
+   }
+
+   @Override
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
+   {
+      Object returnValue = super.visitClearDataCommand(ctx, command);
+      if (trace)
+         log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
+      loader.removeData(command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
+   {
+      Object returnValue = super.visitRemoveNodeCommand(ctx, command);
+      if (trace)
+         log.trace("This is a remove operation; removing the node from the loader, no activation processing needed.");
+      loader.remove(command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetKeysCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetNodeCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
+   {
+      Object returnValue = super.visitGetKeyValueCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
+   {
+      return visitPutKeyValueCommand(ctx, command);
+   }
+
+   @Override
+   public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+   {
+      Object returnValue = super.visitPutKeyValueCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+   {
+      Object returnValue = super.visitPutDataMapCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
+   {
+      Object returnValue = super.visitRemoveKeyCommand(ctx, command);
+      removeNodeFromCacheLoader(ctx, command.getFqn());
+      return returnValue;
+   }
+
+   @Override
+   public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
+   {
+      Object returnValue = super.visitMoveCommand(ctx, command);
+      if (trace)
+         log.trace("This is a move operation; removing the FROM node from the loader, no activation processing needed.");
+      loader.remove(command.getFqn());
+      removeNodeFromCacheLoader(ctx, command.getFqn().getParent());
+      removeNodeFromCacheLoader(ctx, command.getTo());
+      return returnValue;
+   }
+
+
+   /**
+    * Remove the node from the cache loader if it exists in memory,
+    * its attributes have been initialized, its children have been loaded,
+    * AND it was found in the cache loader (nodeLoaded = true).
+    * Then notify the listeners that the node has been activated.
+    */
+   private void removeNodeFromCacheLoader(InvocationContext ctx, Fqn fqn) throws Throwable
+   {
+      NodeSPI n;
+      if (((n = dataContainer.peek(fqn, true, false)) != null) && n.isDataLoaded() && loader.exists(fqn))
+      {
+         // node not null and attributes have been loaded?
+         if (!n.getChildrenDirect().isEmpty())
+         {
+            boolean result = childrenLoaded(n);
+            if (result)
+            {
+               log.debug("children all initialized");
+               remove(fqn);
+            }
+         }
+         else if (loaderNoChildren(fqn))
+         {
+            if (log.isDebugEnabled()) log.debug("no children " + n);
+            remove(fqn);
+         }
+      }
+   }
+
+   private static boolean childrenLoaded(NodeSPI<?, ?> node)
+   {
+      if (!node.isChildrenLoaded())
+      {
+         return false;
+      }
+      for (NodeSPI child : node.getChildrenDirect())
+      {
+         if (!child.isDataLoaded())
+         {
+            return false;
+         }
+      }
+      return true;
+
+   }
+
+   @Override
+   public Object visitOptimisticPrepareCommand(InvocationContext ctx, OptimisticPrepareCommand command) throws Throwable
+   {
+      Object retval = invokeNextInterceptor(ctx, command);
+      if (inTransaction())
+      {
+         prepareCacheLoader(ctx);
+      }
+      return retval;
+   }
+
+   private boolean inTransaction() throws SystemException
+   {
+      return txMgr != null && txMgr.getTransaction() != null;
+   }
+
+   @Override
+   public Object visitPrepareCommand(InvocationContext ctx, PrepareCommand command) throws Throwable
+   {
+      Object retval = invokeNextInterceptor(ctx, command);
+      if (inTransaction())
+      {
+         prepareCacheLoader(ctx);
+      }
+      return retval;
+   }
+
+   private void remove(Fqn fqn) throws Exception
+   {
+      loader.remove(fqn);
+      if (getStatisticsEnabled()) activations++;
+   }
+
+   /**
+    * Returns true if the loader indicates no children for this node.
+    * Return false on error.
+    */
+   private boolean loaderNoChildren(Fqn fqn)
+   {
+      try
+      {
+         Set childrenNames = loader.getChildrenNames(fqn);
+         return (childrenNames == null);
+      }
+      catch (Exception e)
+      {
+         log.error("failed getting the children names for " + fqn + " from the cache loader", e);
+         return false;
+      }
+   }
+
+   public long getActivations()
+   {
+      return activations;
+   }
+
+   @Override
+   public void resetStatistics()
+   {
+      super.resetStatistics();
+      activations = 0;
+   }
+
+   @Override
+   public Map<String, Object> dumpStatistics()
+   {
+      Map<String, Object> retval = super.dumpStatistics();
+      if (retval == null)
+      {
+         retval = new HashMap<String, Object>();
+      }
+      retval.put("Activations", activations);
+      return retval;
+   }
+
+   private void prepareCacheLoader(InvocationContext ctx) throws Throwable
+   {
+      GlobalTransaction gtx = ctx.getGlobalTransaction();
+      TransactionContext tCtx = ctx.getTransactionContext();
+      if (tCtx == null)
+      {
+         throw new Exception("tCtx for transaction " + gtx + " not found in transaction table");
+      }
+      List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+
+      builder.visitCollection(ctx, tCtx.getModifications());
+      if (cacheLoaderModifications.size() > 0)
+      {
+         loader.prepare(gtx, cacheLoaderModifications, false);
+      }
+   }
+
+   public class ActivationModificationsBuilder extends AbstractVisitor
+   {
+
+      private List<Modification> cacheLoaderModifications = new ArrayList<Modification>();
+      private int txActs = 0;
+
+      @Override
+      public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand removeNodeCommand) throws Throwable
+      {
+         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, removeNodeCommand.getFqn());
+         cacheLoaderModifications.add(mod);
+         return null;
+      }
+
+      @Override
+      public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+      {
+         Fqn fqn = command.getFqn();
+         handlePutCommand(ctx, fqn);
+         return null;
+      }
+
+      @Override
+      public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+      {
+         Fqn fqn = command.getFqn();
+         handlePutCommand(ctx, fqn);
+         return null;
+      }
+
+      // On the way out, remove the node from the cache loader.
+      // Only remove the node if it exists in memory, its attributes have
+      // been initialized, its children have been loaded
+      // AND it was found in the cache loader (nodeLoaded = true).
+      // Then notify the listeners that the node has been activated.
+      private void handlePutCommand(InvocationContext ctx, Fqn fqn)
+            throws Exception
+      {
+         if (fqn != null && dataContainer.peek(fqn, false, false) != null && loader.exists(fqn))
+         {
+            NodeSPI n = dataContainer.peek(fqn, true, false);// don't load
+            // node not null and attributes have been loaded?
+            if (n != null && n.isDataLoaded())
+            {
+               // has children?
+               boolean result = childrenLoaded(n);
+               if (!n.getChildrenDirect().isEmpty() && result)
+               {
+                  // children have been loaded, remove the node
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+                  txActs++;
+               }
+               // doesn't have children, check the cache loader
+               else if (loaderNoChildren(fqn))
+               {
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+                  txActs++;
+               }
+            }
+         }
+      }
+
+      private boolean loaderNoChildren(Fqn fqn) throws Exception
+      {
+         return loader.getChildrenNames(fqn) != null;
+      }
+
+      private void addRemoveMod(InvocationContext ctx, List<Modification> l, Fqn fqn, Map data)
+      {
+         Modification mod = new Modification(Modification.ModificationType.REMOVE_NODE, fqn);
+         l.add(mod);
+         notifier.notifyNodeActivated(fqn, false, data, ctx);
+      }
+
+      public List<Modification> getCacheLoaderModifications()
+      {
+         return cacheLoaderModifications;
+      }
+
+      public int getTxActs()
+      {
+         return txActs;
+      }
+   }
+}
\ No newline at end of file

Copied: core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java (from rev 6207, core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/LegacyCacheLoaderInterceptor.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -0,0 +1,583 @@
+package org.jboss.cache.interceptors;
+
+import org.jboss.cache.CacheException;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.WriteCommand;
+import org.jboss.cache.commands.read.GetChildrenNamesCommand;
+import org.jboss.cache.commands.read.GetDataMapCommand;
+import org.jboss.cache.commands.read.GetKeyValueCommand;
+import org.jboss.cache.commands.read.GetKeysCommand;
+import org.jboss.cache.commands.read.GetNodeCommand;
+import org.jboss.cache.commands.tx.RollbackCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
+import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.commands.write.PutDataMapCommand;
+import org.jboss.cache.commands.write.PutForExternalReadCommand;
+import org.jboss.cache.commands.write.PutKeyValueCommand;
+import org.jboss.cache.commands.write.RemoveKeyCommand;
+import org.jboss.cache.commands.write.RemoveNodeCommand;
+import org.jboss.cache.config.Configuration;
+import static org.jboss.cache.config.Configuration.CacheMode;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.interceptors.base.CommandInterceptor;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.lock.LockType;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.transaction.TransactionContext;
+import org.jboss.cache.transaction.TransactionTable;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Loads nodes that don't exist at the time of the call into memory from the CacheLoader
+ *
+ * @author Bela Ban
+ * @version $Id$
+ */
+public class LegacyCacheLoaderInterceptor extends CommandInterceptor implements CacheLoaderInterceptorMBean
+{
+   private long cacheLoads = 0;
+   private long cacheMisses = 0;
+   private CacheLoaderManager clm;
+   private LockManager lockManager;
+
+   protected TransactionTable txTable = null;
+   protected CacheLoader loader;
+   protected DataContainer dataContainer;
+   protected Notifier notifier;
+
+   protected boolean isActivation = false;
+   protected boolean usingVersionedInvalidation = false;
+
+
+   /**
+    * True if CacheStoreInterceptor is in place.
+    * This allows us to skip loading keys for remove(Fqn, key) and put(Fqn, key).
+    * It also affects removal of node data and listing children.
+    */
+   protected boolean useCacheStore = true;
+
+   @Inject
+   protected void injectDependencies(TransactionTable txTable, CacheLoaderManager clm, Configuration configuration,
+                                     DataContainer dataContainer, LockManager lockManager, Notifier notifier)
+   {
+      this.txTable = txTable;
+      this.clm = clm;
+      CacheMode mode = configuration.getCacheMode();
+      usingVersionedInvalidation = configuration.getNodeLockingScheme().isVersionedScheme() && mode.isInvalidation();
+      this.dataContainer = dataContainer;
+      this.lockManager = lockManager;
+      this.notifier = notifier;
+   }
+
+   @Start
+   protected void startInterceptor()
+   {
+      loader = clm.getCacheLoader();
+   }
+
+   @Override
+   public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), null, false, true, false, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, useCacheStore, !useCacheStore, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitPutForExternalReadCommand(InvocationContext ctx, PutForExternalReadCommand command) throws Throwable
+   {
+      return visitPutKeyValueCommand(ctx, command);
+   }
+
+   @Override
+   public Object visitMoveCommand(InvocationContext ctx, MoveCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         if (command.getTo() != null)
+         {
+            loadIfNeeded(ctx, command.getTo(), null, false, false, true, ctx.getTransactionContext(), false, true, false);
+         }
+         loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), true, true, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, true, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+
+   @Override
+   public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), null, false, false, true, ctx.getTransactionContext(), false, false, !usingVersionedInvalidation);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
+   {
+      Fqn fqn = command.getFqn();
+      if (fqn != null)
+      {
+         loadIfNeeded(ctx, fqn, null, false, false, false, ctx.getTransactionContext(), false, false, true);
+         NodeSPI n = dataContainer.peek(fqn, true, true);
+         loadChildren(fqn, n, false, false, ctx);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+
+   @Override
+   public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitGetDataMapCommand(InvocationContext ctx, GetDataMapCommand command) throws Throwable
+   {
+      if (command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), null, true, false, true, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitRollbackCommand(InvocationContext ctx, RollbackCommand command) throws Throwable
+   {
+      // clean up nodesCreated map
+      if (trace) log.trace("Removing temporarily created nodes from treecache");
+
+      // this needs to be done in reverse order.
+      List list = ctx.getTransactionContext().getDummyNodesCreatedByCacheLoader();
+      if (list != null && list.size() > 0)
+      {
+         ListIterator i = list.listIterator(list.size());
+         while (i.hasPrevious())
+         {
+            Fqn fqn = (Fqn) i.previous();
+            try
+            {
+               dataContainer.evict(fqn, false);
+            }
+            catch (CacheException e)
+            {
+               if (trace) log.trace("Unable to evict node " + fqn, e);
+            }
+         }
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitRemoveNodeCommand(InvocationContext ctx, RemoveNodeCommand command) throws Throwable
+   {
+      if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC && command.getFqn() != null)
+      {
+         loadIfNeeded(ctx, command.getFqn(), null, false, false, false, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
+   {
+      if (command.getFqn() != null && !useCacheStore)
+      {
+         loadIfNeeded(ctx, command.getFqn(), command.getKey(), false, false, false, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   @Override
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
+   {
+      Fqn fqn = command.getFqn();
+      if (fqn != null && !useCacheStore)
+      {
+         loadIfNeeded(ctx, fqn, null, false, true, false, ctx.getTransactionContext(), false, false, false);
+      }
+      return invokeNextInterceptor(ctx, command);
+   }
+
+   private void loadIfNeeded(InvocationContext ctx, Fqn fqn, Object key, boolean allKeys, boolean initNode, boolean acquireLock, TransactionContext transactionContext, boolean recursive, boolean isMove, boolean bypassLoadingData) throws Throwable
+   {
+      NodeSPI n = dataContainer.peek(fqn, true, true);
+      Object lockOwner = lockManager.getLockOwner(ctx);
+      boolean needLock = n != null && !lockManager.ownsLock(fqn, lockOwner);
+      boolean mustLoad = false;
+      try
+      {
+         if (needLock)
+         {
+            if (!lockManager.lock(n, LockType.READ, lockOwner))
+               throw new TimeoutException("Unable to acquire lock on " + fqn + ". Lock info: " + lockManager.printLockInfo(n));
+         }
+         mustLoad = mustLoad(n, key, allKeys || isMove);
+      }
+      finally
+      {
+         if (needLock) lockManager.unlock(n, lockOwner);
+      }
+
+      if (trace)
+      {
+         log.trace("load element " + fqn + " mustLoad=" + mustLoad);
+      }
+      if (mustLoad)
+      {
+         if (initNode)
+         {
+            n = createTempNode(fqn, transactionContext);
+         }
+
+         // Only attempt to acquire this lock if we need to - i.e., if
+         // the lock hasn't already been acquired by the Lock
+         // interceptor.  CRUD methods (put, remove) would have acquired
+         // this lock - even if the node is not in memory and needs to be
+         // loaded.  Non-CRUD methods (put) would NOT have acquired this
+         // lock so if we are to load the node from cache loader, we need
+         // to acquire a write lock here.  as a 'catch-all', DO NOT
+         // attempt to acquire a lock here *anyway*, even for CRUD
+         // methods - this leads to a deadlock when you have threads
+         // simultaneously trying to create a node.  See
+         // org.jboss.cache.loader.deadlock.ConcurrentCreationDeadlockTest
+         // - Manik Surtani (21 March 2006)
+         if (acquireLock)
+         {
+            lock(fqn, LockType.WRITE, false, ctx);// non-recursive for now
+         }
+
+//         if (!initNode && !wasRemovedInTx(fqn, ctx.getGlobalTransaction()))
+         if (!wasRemovedInTx(fqn, ctx))
+         {
+            if (bypassLoadingData)
+            {
+               if (n == null && loader.exists(fqn))
+               {
+                  // just create a dummy node in memory
+                  n = createTempNode(fqn, transactionContext);
+               }
+            }
+            else
+            {
+               n = loadNode(ctx, fqn, n, transactionContext);
+            }
+         }
+      }
+
+      // The complete list of children aren't known without loading them
+      if (recursive)
+      {
+         loadChildren(fqn, n, recursive, isMove, ctx);
+      }
+   }
+
+   /**
+    * Load the children.
+    *
+    * @param node may be null if the node was not found.
+    * @param ctxt
+    */
+   private void loadChildren(Fqn fqn, NodeSPI node, boolean recursive, boolean isMove, InvocationContext ctxt) throws Throwable
+   {
+
+      if (node != null && node.isChildrenLoaded())
+      {
+         if (trace) log.trace("Children already loaded!");
+         return;
+      }
+      Set childrenNames;
+      try
+      {
+         childrenNames = loader.getChildrenNames(fqn);
+      }
+      catch (Exception e)
+      {
+         if (log.isInfoEnabled()) log.info("Cache loader was unable to load state", e);
+         // return!
+         return;
+      }
+
+      if (trace)
+      {
+         log.trace("load children " + fqn + " children=" + childrenNames);
+      }
+
+      // For getChildrenNames null means no children
+      if (childrenNames == null)
+      {
+         if (node != null)
+         {
+            if (useCacheStore)
+            {
+               node.removeChildrenDirect();//getChildrenMapDirect().clear();
+            }
+            node.setChildrenLoaded(true);
+         }
+         return;
+      }
+
+      // Create if node had not been created already
+      if (node == null)
+      {
+         node = createNodes(fqn, null);// dont care about local transactions
+      }
+
+      // Create one DataNode per child, mark as UNINITIALIZED
+      for (Object name : childrenNames)
+      {
+         Fqn childFqn = Fqn.fromElements(name);// this is a RELATIVE Fqn!!
+
+         // create child if it didn't exist
+         NodeSPI child = node.addChildDirect(childFqn);
+         if ((isMove || isActivation) && recursive)
+         {
+            // load data for children as well!
+            child.setInternalState(loader.get(child.getFqn()));
+            child.setDataLoaded(true);
+         }
+
+         if (recursive)
+         {
+            loadChildren(child.getFqn(), child, true, isMove, ctxt);
+         }
+      }
+      lock(fqn, recursive ? LockType.WRITE : LockType.READ, true, ctxt);// recursive=true: lock entire subtree
+      node.setChildrenLoaded(true);
+   }
+
+   private boolean mustLoad(NodeSPI n, Object key, boolean allKeys)
+   {
+      if (n == null)
+      {
+         if (trace) log.trace("must load, node null");
+         return true;
+      }
+
+      // check this first!!!
+      if (!n.isValid() && configuration.getNodeLockingScheme().isVersionedScheme())
+      {
+         // attempt to load again; this only happens if we have tombstones lying around, or we are using invalidation.
+         if (trace) log.trace("loading again from cache loader since in-memory node is marked as invalid");
+         return true;
+      }
+
+      // JBCACHE-1172 Skip single-key optimization if request needs all keys
+      if (!allKeys)
+      {
+         // if we are not looking for a specific key don't bother loading!
+         if (key == null)
+         {
+            if (trace) log.trace("don't load, key requested is null");
+            return false;
+         }
+         if (n.getKeysDirect().contains(key))
+         {
+            if (trace) log.trace("don't load, already have necessary key in memory");
+            return false;
+         }
+      }
+      if (!n.isDataLoaded())
+      {
+         if (trace) log.trace("must Load, uninitialized");
+         return true;
+      }
+      return false;
+   }
+
+   public long getCacheLoaderLoads()
+   {
+      return cacheLoads;
+   }
+
+   public long getCacheLoaderMisses()
+   {
+      return cacheMisses;
+   }
+
+   @Override
+   public void resetStatistics()
+   {
+      cacheLoads = 0;
+      cacheMisses = 0;
+   }
+
+   @Override
+   public Map<String, Object> dumpStatistics()
+   {
+      Map<String, Object> retval = new HashMap<String, Object>();
+      retval.put("CacheLoaderLoads", cacheLoads);
+      retval.put("CacheLoaderMisses", cacheMisses);
+      return retval;
+   }
+
+   protected void lock(Fqn fqn, LockType lockType, boolean recursive, InvocationContext ctx) throws Throwable
+   {
+      if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC) return;
+
+      if (recursive)
+         lockManager.lockAllAndRecord(fqn, lockType, ctx);
+      else
+         lockManager.lockAndRecord(fqn, lockType, ctx);
+   }
+
+   /**
+    * Returns true if the FQN or parent was removed during the current
+    * transaction.
+    * This is O(N) WRT to the number of modifications so far.
+    */
+   private boolean wasRemovedInTx(Fqn fqn, InvocationContext ctx)
+   {
+      TransactionContext transactionContext = ctx.getTransactionContext();
+      if (transactionContext == null) return false;
+
+      for (WriteCommand txCacheCommand : transactionContext.getModifications())
+      {
+         if (txCacheCommand instanceof RemoveNodeCommand && fqn.isChildOrEquals(txCacheCommand.getFqn())) return true;
+      }
+      return false;
+   }
+
+   /**
+    * Loads a node from disk; if it exists creates parent TreeNodes.
+    * If it doesn't exist on disk but in memory, clears the
+    * uninitialized flag, otherwise returns null.
+    */
+   private NodeSPI loadNode(InvocationContext ctx, Fqn fqn, NodeSPI n, TransactionContext transactionContext) throws Exception
+   {
+      if (trace) log.trace("loadNode " + fqn);
+      Map nodeData = loadData(fqn);
+      if (nodeData != null)
+      {
+         if (trace) log.trace("Node data is not null, loading");
+
+         notifier.notifyNodeLoaded(fqn, true, Collections.emptyMap(), ctx);
+         if (isActivation)
+         {
+            notifier.notifyNodeActivated(fqn, true, Collections.emptyMap(), ctx);
+         }
+
+         n = createNodes(fqn, transactionContext);
+//         n.clearDataDirect();
+         n.setInternalState(nodeData);
+
+         // set this node as valid?
+         if (usingVersionedInvalidation) n.setValid(true, false);
+
+         notifier.notifyNodeLoaded(fqn, false, nodeData, ctx);
+         if (isActivation)
+         {
+            notifier.notifyNodeActivated(fqn, false, nodeData, ctx);
+         }
+      }
+      if (n != null && !n.isDataLoaded())
+      {
+         if (trace) log.trace("Setting dataLoaded to true");
+         n.setDataLoaded(true);
+      }
+      return n;
+   }
+
+   /**
+    * Creates a new memory node in preparation for storage.
+    */
+   private NodeSPI createTempNode(Fqn fqn, TransactionContext transactionContext) throws Exception
+   {
+      NodeSPI n = createNodes(fqn, transactionContext);
+      n.setDataLoaded(false);
+      if (trace)
+      {
+         log.trace("createTempNode n " + n);
+      }
+      return n;
+   }
+
+   @SuppressWarnings("unchecked")
+   private NodeSPI createNodes(Fqn fqn, TransactionContext transactionContext) throws Exception
+   {
+      Object[] results = dataContainer.createNodes(fqn);
+      List<NodeSPI> createdNodes = (List<NodeSPI>) results[0];
+
+      NodeSPI lastCreated = null;
+      for (NodeSPI node : createdNodes)
+      {
+         node.setDataLoaded(false);
+         if (transactionContext != null)
+         {
+            transactionContext.addDummyNodeCreatedByCacheLoader(node.getFqn());
+         }
+         lastCreated = node;
+      }
+
+      // mark the leaf node as data loaded since that is what we are doing in this interceptor.
+      if (lastCreated != null) lastCreated.setDataLoaded(true);
+
+      // regardless of whether the last node was created, return it.
+      return (NodeSPI) results[1];
+   }
+
+   private Map loadData(Fqn fqn) throws Exception
+   {
+
+      Map nodeData = loader.get(fqn);
+      boolean nodeExists = (nodeData != null);
+      if (trace) log.trace("nodeExists " + nodeExists);
+
+      if (getStatisticsEnabled())
+      {
+         if (nodeExists)
+         {
+            cacheLoads++;
+         }
+         else
+         {
+            cacheMisses++;
+         }
+      }
+      return nodeData;
+   }
+
+}
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -3,6 +3,7 @@
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.NodeFactory;
+import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.VisitableCommand;
 import org.jboss.cache.commands.read.ExistsCommand;
 import org.jboss.cache.commands.read.GetChildrenNamesCommand;
@@ -31,7 +32,10 @@
 import org.jboss.cache.mvcc.MVCCNodeHelper;
 import org.jboss.cache.mvcc.ReadCommittedNode;
 
+import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Interceptor to implement <a href="http://wiki.jboss.org/wiki/JBossCacheMVCC">MVCC</a> functionality.
@@ -115,12 +119,44 @@
       ctx.getOptionOverrides().setLockAcquisitionTimeout(0);
       if (command.isRecursive())
       {
-         List<Fqn> fqnsToEvict = helper.wrapNodesForWriting(ctx, command.getFqn());
+         List<Fqn> fqnsToEvict;
+         if (command.getFqn().isRoot())
+         {
+            // special treatment - deal with all of root's kids instead.
+            Map<Object, NodeSPI> children = dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+            if (children != null && !children.isEmpty())
+            {
+               fqnsToEvict = new LinkedList<Fqn>();
+               for (NodeSPI child : children.values())
+                  fqnsToEvict.addAll(helper.wrapNodesForWriting(ctx, child.getFqn()));
+            }
+            else
+            {
+               fqnsToEvict = Collections.emptyList();
+            }
+         }
+         else
+         {
+            fqnsToEvict = helper.wrapNodesForWriting(ctx, command.getFqn());
+         }
+
          command.setNodesToEvict(fqnsToEvict);
       }
       else
       {
-         helper.wrapNodeForWriting(ctx, command.getFqn(), true, false, false, true, true);
+         if (command.getFqn().isRoot())
+         {
+            Map<Object, NodeSPI> children = dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+            if (children != null && !children.isEmpty())
+            {
+               for (NodeSPI child : children.values())
+                  helper.wrapNodeForWriting(ctx, child.getFqn(), true, false, false, true, true);
+            }
+         }
+         else
+         {
+            helper.wrapNodeForWriting(ctx, command.getFqn(), true, false, false, true, true);
+         }
       }
 
       return invokeNextInterceptor(ctx, command);
@@ -131,7 +167,7 @@
    {
       // this should be handled the same as a recursive evict command.
       ctx.getOptionOverrides().setLockAcquisitionTimeout(0);
-      helper.wrapNodesForWriting(ctx, command.getFqn());
+      if (!command.getFqn().isRoot()) helper.wrapNodesForWriting(ctx, command.getFqn());
       return invokeNextInterceptor(ctx, command);
    }
 

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,6 +1,5 @@
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.write.EvictCommand;
@@ -31,13 +30,11 @@
 
    protected CacheLoader loader;
    private Notifier notifier;
-   private DataContainer dataContainer;
 
    @Inject
-   public void setDependencies(Notifier notifier, DataContainer dataContainer, CacheLoaderManager loaderManager)
+   public void setDependencies(Notifier notifier, CacheLoaderManager loaderManager)
    {
       this.notifier = notifier;
-      this.dataContainer = dataContainer;
       this.loader = loaderManager.getCacheLoader();
    }
 
@@ -51,7 +48,7 @@
    {
       if (command.isRecursive())
       {
-         List<Fqn> fqnsToEvict = dataContainer.getNodesForEviction(command.getFqn(), true);
+         List<Fqn> fqnsToEvict = command.getNodesToEvict();
          if (fqnsToEvict != null)
          {
             for (Fqn f : fqnsToEvict)
@@ -74,7 +71,7 @@
       {
          // evict method local doesn't hold attributes therefore we have
          // to get them manually
-         Map attributes = getNodeAttributes(fqn);
+         Map attributes = getNodeAttributes(ctx, fqn);
          // notify listeners that this node is about to be passivated
          notifier.notifyNodePassivated(fqn, true, attributes, ctx);
          if (trace) log.trace("Passivating " + fqn);
@@ -113,13 +110,13 @@
    /**
     * Returns attributes for a node.
     */
-   private Map getNodeAttributes(Fqn fqn) throws NodeNotLoadedException
+   private Map getNodeAttributes(InvocationContext ctx, Fqn fqn) throws NodeNotLoadedException
    {
       if (fqn == null)
       {
          throw new NodeNotLoadedException();
       }
-      NodeSPI n = dataContainer.peek(fqn, true, false);
+      NodeSPI n = ctx.lookUpNode(fqn);
 
       if (n != null)
       {

Modified: core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/loader/AbstractCacheLoader.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -308,7 +308,7 @@
                _move(m.getFqn(), m.getFqn2());
                break;
             default:
-               throw new CacheException("Unknown modificatiobn " + m.getType());
+               throw new CacheException("Unknown modification " + m.getType());
          }
       }
    }

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -91,31 +91,35 @@
     *
     * @param ctx current invocation context
     * @param fqn fqn to fetch and wrap
+    * @return read committed node, or null if one is not found.
     * @throws InterruptedException if write locks are forced and the lock manager is interrupted.
     */
-   public void wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws InterruptedException
+   public ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws InterruptedException
    {
-      wrapNodeForReading(ctx, fqn, ctx.getOptionOverrides().isForceWriteLock());
+      return wrapNodeForReading(ctx, fqn, ctx.getOptionOverrides().isForceWriteLock());
    }
 
-   private void wrapNodeForReading(InvocationContext ctx, Fqn f, boolean writeLockForced) throws InterruptedException
+   private ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn f, boolean writeLockForced) throws InterruptedException
    {
+      NodeSPI n;
       if (writeLockForced)
       {
          if (trace) log.trace("Forcing lock on reading node " + f);
-         wrapNodeForWriting(ctx, f, true, false, false, false, false);
+         return wrapNodeForWriting(ctx, f, true, false, false, false, false);
       }
-      else if (ctx.lookUpNode(f) == null)
+      else if ((n = ctx.lookUpNode(f)) == null)
       {
          if (trace) log.trace("Node " + f + " is not in context, fetching from container.");
          // simple implementation.  Peek the node, wrap it, put wrapped node in the context.
          InternalNode node = dataContainer.peekInternalNode(f, false);
          ReadCommittedNode wrapped = nodeFactory.createMvccNode(node);
          if (wrapped != null) ctx.putLookedUpNode(f, wrapped);
+         return wrapped;
       }
       else
       {
          if (trace) log.trace("Node " + f + " is already in context.");
+         return (ReadCommittedNode) n;
       }
    }
 

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -37,6 +37,8 @@
 
    public void copyNodeForUpdate(DataContainer container, boolean allowWriteSkew, InvocationContext ctx, NodeFactory nodeFactory)
    {
+      if (changed) return; // already copied
+
       changed = true;
       backup = node;
       node = backup.copy();
@@ -51,7 +53,7 @@
       {
          Fqn fqn = getFqn();
          if (trace)
-            log.trace("Updating node [" + fqn + "].  deleted=" + isDeleted() + " valid=" + isValid() + " changed" + isChanged() + " created=" + created);
+            log.trace("Updating node [" + fqn + "].  deleted=" + isDeleted() + " valid=" + isValid() + " changed=" + isChanged() + " created=" + created);
 
          // check if node has been deleted.
          if (deleted)

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -26,6 +26,8 @@
    @Override
    public void copyNodeForUpdate(DataContainer container, boolean allowWriteSkew, InvocationContext ctx, NodeFactory nodeFactory)
    {
+      if (changed) return; // already copied
+
       Fqn fqn = getFqn();
 
       // mark node as changed.

Modified: core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/main/java/org/jboss/cache/transaction/PessimisticTransactionContext.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -42,7 +42,6 @@
 {
 
    private static final Log log = LogFactory.getLog(PessimisticTransactionContext.class);
-   private static final boolean trace = log.isTraceEnabled();
 
    /**
     * Local transaction

Modified: core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/NodeReplicatedMoveTest.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -11,7 +11,6 @@
 import org.jboss.cache.DefaultCacheFactory;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.Node;
-import org.jboss.cache.NodeNotExistsException;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.config.Configuration;
 import org.jboss.cache.config.Configuration.CacheMode;
@@ -142,7 +141,7 @@
          cache1.move(B, A);// should throw an NPE
          if (!isOptimistic()) assert false : "Should throw an exception!";
       }
-      catch (NodeNotExistsException expected)
+      catch (Exception expected)
       {
          if (isOptimistic()) assert false : "Should not have thrown an exception!";
       }

Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/CacheLoaderTest.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,8 +1,14 @@
 package org.jboss.cache.api.mvcc.read_committed;
 
+import org.jboss.cache.api.mvcc.LockAssert;
 import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
 import org.jboss.cache.loader.DummyInMemoryCacheLoaderTest;
 import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
 @Test(groups = {"functional", "mvcc"})
@@ -15,4 +21,12 @@
       cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
       cache.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
    }
+
+   @AfterMethod
+   public void postTest()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+      LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+   }
 }

Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,10 +1,16 @@
 package org.jboss.cache.api.mvcc.read_committed;
 
+import org.jboss.cache.api.mvcc.LockAssert;
 import org.jboss.cache.config.CacheLoaderConfig;
 import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
 import org.jboss.cache.loader.DummySharedInMemoryCacheLoader;
 import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
 import org.jboss.cache.passivation.PassivationTestsBase;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
 @Test(groups = {"functional", "mvcc"})
@@ -19,4 +25,12 @@
       clc.setPassivation(true);
       cache.getConfiguration().setCacheLoaderConfig(clc);
    }
+
+   @AfterMethod
+   public void postTest()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+      LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+   }
 }

Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/CacheLoaderTest.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,8 +1,14 @@
 package org.jboss.cache.api.mvcc.repeatable_read;
 
+import org.jboss.cache.api.mvcc.LockAssert;
 import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
 import org.jboss.cache.loader.DummyInMemoryCacheLoaderTest;
 import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
 @Test(groups = {"functional", "mvcc"})
@@ -15,4 +21,12 @@
       cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
       cache.getConfiguration().setIsolationLevel(IsolationLevel.REPEATABLE_READ);
    }
+
+   @AfterMethod
+   public void postTest()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+      LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+   }
 }

Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/PassivationTest.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -1,10 +1,16 @@
 package org.jboss.cache.api.mvcc.repeatable_read;
 
+import org.jboss.cache.api.mvcc.LockAssert;
 import org.jboss.cache.config.CacheLoaderConfig;
 import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
 import org.jboss.cache.loader.DummySharedInMemoryCacheLoader;
 import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockManager;
 import org.jboss.cache.passivation.PassivationTestsBase;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.AfterMethod;
 import org.testng.annotations.Test;
 
 @Test(groups = {"functional", "mvcc"})
@@ -19,4 +25,12 @@
       clc.setPassivation(true);
       cache.getConfiguration().setCacheLoaderConfig(clc);
    }
+
+   @AfterMethod
+   public void postTest()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+
+      LockAssert.assertNoLocks(cr.getComponent(LockManager.class), cr.getComponent(InvocationContextContainer.class));
+   }
 }
\ No newline at end of file

Modified: core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/loader/CacheLoaderTestsBase.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -728,39 +728,32 @@
    public void testGetChildren12()
    {
       Set children;
-      try
-      {
-         cache.put("/a/b", "key", "val");
-         cache.put("/a/b/1", "key", "val");
-         cache.put("/a/b/2", "key", "val");
-         cache.put("/a/b/3", "key", "val");
-         children = cache.getNode("/a/b").getChildrenNames();
-         assertEquals(3, children.size());
+      cache.put("/a/b", "key", "val");
+      cache.put("/a/b/1", "key", "val");
+      cache.put("/a/b/2", "key", "val");
+      cache.put("/a/b/3", "key", "val");
+      children = cache.getNode("/a/b").getChildrenNames();
+      assertEquals(3, children.size());
 
-         cache.evict(Fqn.fromString("/a/b/3"));
-         cache.evict(Fqn.fromString("/a/b/2"));
-         // cache.evict(Fqn.fromString("/a/b/1"));
-         cache.evict(Fqn.fromString("/a/b"));
-         cache.evict(Fqn.fromString("/a"));
+      cache.evict(Fqn.fromString("/a/b/3"));
+      cache.evict(Fqn.fromString("/a/b/2"));
+      // cache.evict(Fqn.fromString("/a/b/1"));
+      cache.evict(Fqn.fromString("/a/b"));
+      cache.evict(Fqn.fromString("/a"));
 
-         NodeSPI n = (NodeSPI) cache.getNode("/a/b");
-         assert !n.isChildrenLoaded();
+      NodeSPI n = cache.getNode("/a/b");
+      assert !n.isChildrenLoaded();
 
-         children = cache.getNode("/a/b").getChildrenNames();
-         assertEquals(3, children.size());
+      children = cache.getNode("/a/b").getChildrenNames();
+      assertEquals(3, children.size());
 
-         cache.evict(Fqn.fromString("/a/b/3"));
-         cache.evict(Fqn.fromString("/a/b/2"));
-         // cache.evict(Fqn.fromString("/a/b/1"));
-         cache.evict(Fqn.fromString("/a/b"));
-         cache.evict(Fqn.fromString("/a"));
-         children = cache.getNode("/a/b").getChildrenNames();
-         assertEquals(3, children.size());
-      }
-      catch (Exception e)
-      {
-         fail(e.toString());
-      }
+      cache.evict(Fqn.fromString("/a/b/3"));
+      cache.evict(Fqn.fromString("/a/b/2"));
+      // cache.evict(Fqn.fromString("/a/b/1"));
+      cache.evict(Fqn.fromString("/a/b"));
+      cache.evict(Fqn.fromString("/a"));
+      children = cache.getNode("/a/b").getChildrenNames();
+      assertEquals(3, children.size());
    }
 
    public void testLoaderGetChildrenNames() throws Exception
@@ -1035,16 +1028,12 @@
       mgr.begin();
       Set children = cache.getNode("/a").getChildrenNames();
 
-      System.out.println("**** " + cache.getTransactionManager());
-
       assertEquals(3, children.size());
       assertTrue(children.contains("1"));
       assertTrue(children.contains("2"));
       assertTrue(children.contains("3"));
 
-      assertEquals(5, cache.getNumberOfLocksHeld());
       mgr.commit();
-
    }
 
 

Modified: core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java	2008-07-08 16:13:44 UTC (rev 6214)
+++ core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java	2008-07-08 16:27:15 UTC (rev 6215)
@@ -742,7 +742,6 @@
       assertTrue(children.contains("1"));
       assertTrue(children.contains("2"));
       assertTrue(children.contains("3"));
-      assertEquals(5, cache.getNumberOfLocksHeld());
       mgr.commit();
    }
 




More information about the jbosscache-commits mailing list