[jbosscache-commits] JBoss Cache SVN: r6414 - in core/trunk/src: main/java/org/jboss/cache/commands and 23 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Mon Jul 28 06:56:30 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-07-28 06:56:29 -0400 (Mon, 28 Jul 2008)
New Revision: 6414

Added:
   core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java
   core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java
   core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java
Removed:
   core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
   core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java
   core/trunk/src/main/java/org/jboss/cache/DataContainer.java
   core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
   core/trunk/src/main/java/org/jboss/cache/InternalNode.java
   core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
   core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
   core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
   core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
   core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java
   core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
   core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java
   core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
   core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
   core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java
   core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java
   core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java
   core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.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/optimistic/WorkspaceNode.java
   core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java
   core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java
   core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java
   core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java
   core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java
   core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java
   core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java
   core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java
   core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java
   core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java
Log:
Whole bunch of performance enhancements and bug fixes

Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNode.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -5,7 +5,13 @@
 
 import static org.jboss.cache.AbstractNode.NodeFlags.REMOVED;
 import static org.jboss.cache.AbstractNode.NodeFlags.RESIDENT;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.lock.IdentityLock;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
 
+import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentMap;
 
 /**
@@ -15,7 +21,8 @@
  */
 public abstract class AbstractNode<K, V>
 {
-   protected volatile ConcurrentMap<Object, Node<K, V>> children;
+   protected volatile ConcurrentMap children; // purposefully NOT genericized yet, since UnversionedNode and PessimisticUnversionedNode will both store different types.
+
    protected Fqn fqn;
    /**
     * Flags placed on the node.  Replaces older 'boolean' flags.
@@ -133,36 +140,38 @@
       return isFlagSet(REMOVED);
    }
 
+   public void setResident(boolean resident)
+   {
+      setFlag(RESIDENT, resident);
+   }
+
    public void setRemoved(boolean marker)
    {
       markAsRemoved(marker, false);
    }
 
-   public void markAsRemoved(boolean marker, boolean recursive)
+   public abstract void markAsRemoved(boolean marker, boolean recursive);
+
+   public boolean isResident()
    {
-      setFlag(REMOVED, marker);
+      return isFlagSet(RESIDENT);
+   }
 
-      if (recursive && children != null)
-      {
-         synchronized (this)
-         {
-            for (Node<?, ?> child : children.values())
-            {
-               ((NodeSPI) child).markAsDeleted(marker, true);
-            }
-         }
-      }
+   @SuppressWarnings("deprecation")
+   public IdentityLock getLock()
+   {
+      throw new UnsupportedOperationException("Not supported in this implementation!");
    }
 
-   public void setResident(boolean resident)
+   // versioning
+   public void setVersion(DataVersion version)
    {
-      setFlag(RESIDENT, resident);
+      throw new UnsupportedOperationException("Versioning not supported");
    }
 
-
-   public boolean isResident()
+   public DataVersion getVersion()
    {
-      return isFlagSet(RESIDENT);
+      throw new UnsupportedOperationException("Versioning not supported");
    }
 
    @Override
@@ -181,4 +190,126 @@
    {
       return fqn.hashCode();
    }
+
+   // ----- default no-op impls of child manipulation methods
+
+   public InternalNode<K, V> getChild(Fqn f)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public InternalNode<K, V> getChild(Object childName)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public Set<InternalNode<K, V>> getChildren()
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public Set<InternalNode<K, V>> getChildren(boolean includeMarkedForRemoval)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public Map<Object, InternalNode<K, V>> getChildrenMap()
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public void addChild(Object nodeName, InternalNode<K, V> nodeToAdd)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public void addChild(InternalNode<K, V> child)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public InternalNode<K, V> addChild(Fqn f)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public InternalNode<K, V> addChild(Fqn f, boolean notify)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public InternalNode<K, V> addChild(Object o, boolean notify)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>> children)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext ctx)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public NodeSPI<K, V> getChildDirect(Fqn fqn)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public NodeSPI<K, V> getChildDirect(Object childName)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public Set<NodeSPI<K, V>> getChildrenDirect()
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public Map<Object, Node<K, V>> getChildrenMapDirect()
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public void addChildDirect(Object nodeName, Node<K, V> nodeToAdd)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public void addChildDirect(NodeSPI<K, V> child)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public NodeSPI<K, V> addChildDirect(Fqn f)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public NodeSPI<K, V> addChildDirect(Object o, boolean notify)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
+
+   public NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx)
+   {
+      throw new UnsupportedOperationException("Not supported in " + getClass().getSimpleName());
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNodeFactory.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -85,6 +85,11 @@
       return initializeNodeInvocationDelegate(internal);
    }
 
+   public InternalNode<K, V> createInternalNode(Fqn fqn)
+   {
+      throw new UnsupportedOperationException("Unsupported in this implementation (" + getClass().getSimpleName() + ")!");
+   }
+
    public NodeSPI<K, V> createNode(Object childName, NodeSPI<K, V> parent)
    {
       UnversionedNode<K, V> internal = createInternalNode(childName, Fqn.fromRelativeElements(parent.getFqn(), childName), parent, null);
@@ -111,7 +116,7 @@
       return createNode(Fqn.ROOT, null);
    }
 
-   public NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V> internalNode, boolean wrapWithNodeReference)
+   private NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V> internalNode, boolean wrapWithNodeReference)
    {
       if (wrapWithNodeReference)
          throw new UnsupportedOperationException("wrapWithNodeReferences is not supported in this impl!");
@@ -121,7 +126,7 @@
       return nid;
    }
 
-   public NodeSPI<K, V> createAndRegister(Fqn fqn, NodeSPI<K, V> parent, InvocationContext ctx, boolean attachToParent)
+   public InternalNode<K, V> createAndRegister(Fqn fqn, InternalNode<K, V> parent, InvocationContext ctx, boolean attachToParent)
    {
       throw new UnsupportedOperationException("Unsupported in this implementation (" + getClass().getSimpleName() + ")!");
    }

Modified: core/trunk/src/main/java/org/jboss/cache/DataContainer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -34,7 +34,9 @@
     *
     * @param fqn Fully qualified name for the corresponding node.
     * @return Node referenced by the given Fqn, or null if the node cannot be found or if there is an exception.
+    * @deprecated Note that this only supports legacy locking schemes (OL and PL) and will be removed when those schemes are removed.
     */
+   @Deprecated
    NodeSPI peek(Fqn fqn);
 
    /**
@@ -43,7 +45,9 @@
     * @param fqn                 Fqn to find
     * @param includeDeletedNodes if true, deleted nodes are considered
     * @return the node, if found, or null otherwise.
+    * @deprecated Note that this only supports legacy locking schemes (OL and PL) and will be removed when those schemes are removed.
     */
+   @Deprecated
    NodeSPI peek(Fqn fqn, boolean includeDeletedNodes);
 
    /**
@@ -54,7 +58,9 @@
     * @param includeDeletedNodes if true, deleted nodes are also considered
     * @param includeInvalidNodes if true, invalid nodes are also considered
     * @return the node, if found, or null otherwise.
+    * @deprecated Note that this only supports legacy locking schemes (OL and PL) and will be removed when those schemes are removed.
     */
+   @Deprecated
    NodeSPI peek(Fqn fqn, boolean includeDeletedNodes, boolean includeInvalidNodes);
 
    /**
@@ -188,5 +194,12 @@
     *
     * @param nodeInvocationDelegate
     */
-   void setRoot(NodeSPI nodeInvocationDelegate);
+   // TODO: 3.0.0: FIx this so that it can take in a NodeSPI for OL/PL and an InternalNode for MVCC
+   void setRoot(Object nodeInvocationDelegate);
+
+   /**
+    * @param fqn fqn to check
+    * @return true if the node exists and is marked as resident, false otherwise.
+    */
+   boolean isResident(Fqn fqn);
 }

Modified: core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -3,6 +3,8 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.NonVolatile;
 import org.jboss.cache.factories.annotations.Start;
@@ -33,7 +35,8 @@
    /**
     * Root node.
     */
-   private volatile NodeSPI root;
+   private volatile NodeInvocationDelegate root;
+   private volatile InternalNode rootInternal;
 
    /**
     * Set<Fqn> of Fqns of the topmost node of internal regions that should
@@ -43,9 +46,11 @@
    private NodeFactory nodeFactory;
    private LockManager lockManager;
    private BuddyFqnTransformer buddyFqnTransformer;
+   private Configuration config;
+   private boolean usingMvcc;
 
    @Inject
-   public void injectDependencies(NodeFactory nodeFactory, LockManager lockManager, BuddyFqnTransformer transformer)
+   public void injectDependencies(NodeFactory nodeFactory, LockManager lockManager, BuddyFqnTransformer transformer, Configuration configuration)
    {
       setDependencies(nodeFactory, lockManager);
 
@@ -55,6 +60,7 @@
       //TODO - remove setDependencies method at this point
       createRootNode();
       this.buddyFqnTransformer = transformer;
+      config = configuration;
    }
 
    public void setDependencies(NodeFactory nodeFactory, LockManager lockManager)
@@ -66,29 +72,42 @@
    @Start(priority = 12)
    public void createRootNode()
    {
-      if (trace) log.trace("Starting data container");
+      usingMvcc = config != null && config.getNodeLockingScheme() == NodeLockingScheme.MVCC;
+      if (trace) log.trace("Starting data container.  Using MVCC? " + usingMvcc);
       // create a new root temporarily.
       NodeSPI tempRoot = nodeFactory.createRootNode();
       // if we don't already have a root or the new (temp) root is of a different class (optimistic vs pessimistic) to
       // the current root, then we use the new one.
 
-      Class currentRootType = root == null ? null : ((NodeInvocationDelegate) root).getDelegationTarget().getClass();
-      Class tempRootType = ((NodeInvocationDelegate) tempRoot).getDelegationTarget().getClass();
+      Class currentRootType = root == null ? null : root.getDelegationTarget().getClass();
+      Class tempRootType = tempRoot.getDelegationTarget().getClass();
 
       if (!tempRootType.equals(currentRootType))
       {
          if (trace) log.trace("Setting root node to an instance of " + tempRootType);
          setRoot(tempRoot);
       }
-      root.setChildrenLoaded(true);
+
+      if (usingMvcc && rootInternal == null) setRoot(root); // sets the "internal root"
+
+      if (root != null) root.setChildrenLoaded(true);
+      if (rootInternal != null) rootInternal.setChildrenLoaded(true);
    }
 
    @Stop(priority = 100)
    public void stop()
    {
       // empty in-memory state
-      root.clearDataDirect();
-      root.removeChildrenDirect();
+      if (root != null)
+      {
+         root.clearDataDirect();
+         root.removeChildrenDirect();
+      }
+      else if (rootInternal != null)
+      {
+         rootInternal.clear();
+         rootInternal.removeChildren();
+      }
    }
 
    public NodeSPI getRoot()
@@ -101,13 +120,42 @@
     *
     * @param root node
     */
-   public void setRoot(NodeSPI root)
+   public void setRoot(Object root)
    {
-      if (root == null || !root.getFqn().isRoot())
-         throw new CacheException("Attempting to set an invalid node [" + root + "] as a root node!");
-      this.root = root;
+      if (root == null) throw new CacheException("Attempting to set an invalid node [" + root + "] as a root node!");
+      // Mega-Ugh!
+      if (usingMvcc && root instanceof InternalNode)
+      {
+         if (log.isDebugEnabled()) log.debug("Setting rootInternal to " + root);
+         rootInternal = (InternalNode) root;
+         this.root = null;
+      }
+      else
+      {
+         this.root = (NodeInvocationDelegate) root;
+         if (usingMvcc)
+         {
+            if (log.isDebugEnabled()) log.debug("Setting rootInternal to " + this.root.getDelegationTarget());
+            rootInternal = this.root.getDelegationTarget();
+            this.root = null;
+         }
+      }
    }
 
+   public boolean isResident(Fqn fqn)
+   {
+      if (usingMvcc)
+      {
+         InternalNode in = peekInternalNode(fqn, false);
+         return in != null && in.isResident();
+      }
+      else
+      {
+         NodeSPI<?, ?> nodeSPI = peek(fqn, false, false);
+         return nodeSPI != null && nodeSPI.isResident();
+      }
+   }
+
    public void registerInternalFqn(Fqn fqn)
    {
       internalFqns.add(fqn);
@@ -150,15 +198,23 @@
 
    public boolean exists(Fqn fqn)
    {
-      return peek(fqn, false, false) != null;
+      return usingMvcc ? peekInternalNode(fqn, false) != null : peek(fqn, false, false) != null;
    }
 
    public boolean hasChildren(Fqn fqn)
    {
       if (fqn == null) return false;
 
-      NodeSPI n = peek(fqn);
-      return n != null && n.hasChildrenDirect();
+      if (usingMvcc)
+      {
+         InternalNode in = peekInternalNode(fqn, false);
+         return in != null && in.hasChildren();
+      }
+      else
+      {
+         NodeSPI n = peek(fqn);
+         return n != null && n.hasChildrenDirect();
+      }
    }
 
    public List<NodeData> buildNodeData(List<NodeData> list, NodeSPI node, boolean mapSafe)
@@ -175,31 +231,62 @@
    public List<Fqn> getNodesForEviction(Fqn fqn, boolean recursive)
    {
       List<Fqn> result = new ArrayList<Fqn>();
-      NodeSPI node = peek(fqn, false);
-      if (recursive)
+      if (usingMvcc)
       {
-         if (node != null) recursiveAddEvictionNodes(node, result);
+         InternalNode node = peekInternalNode(fqn, false);
+         if (recursive)
+         {
+            if (node != null) recursiveAddEvictionNodes(node, result);
+         }
+         else
+         {
+            if (node == null)
+            {
+               result.add(fqn);
+               return result;
+            }
+            if (fqn.isRoot())
+            {
+               for (Object childName : node.getChildrenNames())
+               {
+                  if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn, childName));
+               }
+            }
+            else if (!node.isResident())
+            {
+               result.add(fqn);
+            }
+         }
+         return result;
       }
       else
       {
-         if (node == null)
+         NodeSPI node = peek(fqn, false);
+         if (recursive)
          {
-            result.add(fqn);
-            return result;
+            if (node != null) recursiveAddEvictionNodes(node, result);
          }
-         if (fqn.isRoot())
+         else
          {
-            for (Object childName : node.getChildrenNamesDirect())
+            if (node == null)
             {
-               if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn, childName));
+               result.add(fqn);
+               return result;
             }
+            if (fqn.isRoot())
+            {
+               for (Object childName : node.getChildrenNamesDirect())
+               {
+                  if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn, childName));
+               }
+            }
+            else if (!node.isResident())
+            {
+               result.add(fqn);
+            }
          }
-         else if (!node.isResident())
-         {
-            result.add(fqn);
-         }
+         return result;
       }
-      return result;
    }
 
    private void recursiveAddEvictionNodes(NodeSPI<?, ?> node, List<Fqn> result)
@@ -215,6 +302,19 @@
       }
    }
 
+   private void recursiveAddEvictionNodes(InternalNode<?, ?> node, List<Fqn> result)
+   {
+      for (InternalNode child : node.getChildren())
+      {
+         recursiveAddEvictionNodes(child, result);
+      }
+      Fqn fqn = node.getFqn();
+      if (!fqn.isRoot() && !node.isResident())
+      {
+         result.add(fqn);
+      }
+   }
+
    @Override
    public String toString()
    {
@@ -306,7 +406,10 @@
    public String printDetails()
    {
       StringBuilder sb = new StringBuilder();
-      root.printDetails(sb, 0);
+      if (root == null)
+         rootInternal.printDetails(sb, 0);
+      else
+         root.printDetails(sb, 0);
       sb.append("\n");
       return sb.toString();
    }
@@ -324,7 +427,7 @@
 
    public int getNumberOfAttributes(Fqn fqn)
    {
-      return numAttributes(peek(fqn));
+      return usingMvcc ? numAttributes(peekInternalNode(fqn, false)) : numAttributes(peek(fqn));
    }
 
    private int numAttributes(NodeSPI n)
@@ -338,13 +441,71 @@
       return count;
    }
 
+   private int numAttributes(InternalNode n)
+   {
+      int count = 0;
+      for (Object child : n.getChildren())
+      {
+         count += numAttributes((NodeSPI) child);
+      }
+      count += n.getData().size();
+      return count;
+   }
+
    public int getNumberOfAttributes()
    {
-      return numAttributes(root);
+      return usingMvcc ? numAttributes(rootInternal) : numAttributes(root);
    }
 
    public boolean removeFromDataStructure(Fqn f, boolean skipMarkerCheck)
    {
+      return usingMvcc ? removeMvcc(f, skipMarkerCheck) : removeLegacy(f, skipMarkerCheck);
+   }
+
+   private boolean removeMvcc(Fqn f, boolean skipMarkerCheck)
+   {
+      InternalNode n = peekInternalNode(f, true);
+      if (n == null)
+      {
+         return false;
+      }
+
+      if (trace) log.trace("Performing a real remove for node " + f + ", marked for removal.");
+      if (skipMarkerCheck || n.isRemoved())
+      {
+         if (n.getFqn().isRoot())
+         {
+            // do not actually delete; just remove deletion marker
+            n.setRemoved(true);
+
+            // mark the node to be removed (and all children) as invalid so anyone holding a direct reference to it will
+            // be aware that it is no longer valid.
+            n.setValid(false, true);
+            n.setValid(true, false);
+
+            // but now remove all children, since the call has been to remove("/")
+            n.removeChildren();
+            return true;
+         }
+         else
+         {
+            // mark the node to be removed (and all children) as invalid so anyone holding a direct reference to it will
+            // be aware that it is no longer valid.
+            n.setValid(false, true);
+            InternalNode parent = peekInternalNode(f.getParent(), true);
+            return parent.removeChild(n.getFqn().getLastElement());
+         }
+      }
+      else
+      {
+         if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked for removal as expected, not removing!");
+         return false;
+      }
+   }
+
+
+   private boolean removeLegacy(Fqn f, boolean skipMarkerCheck)
+   {
       NodeSPI n = peek(f, true);
       if (n == null)
       {
@@ -395,23 +556,29 @@
 
    public boolean evict(Fqn fqn)
    {
-      if (peek(fqn, false, true) == null) return true;
+      if (!exists(fqn)) return true;
       if (hasChildren(fqn))
       {
          if (trace)
             log.trace("removing DATA as node has children: evict(" + fqn + ")");
-         removeData(fqn);
+         if (usingMvcc)
+            removeData(fqn);
+         else
+            removeDataLegacy(fqn);
          return false;
       }
       else
       {
          if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
-         removeNode(fqn);
+         if (usingMvcc)
+            removeNode(fqn);
+         else
+            removeNodeLegacy(fqn);
          return true;
       }
    }
 
-   private void removeNode(Fqn fqn)
+   private void removeNodeLegacy(Fqn fqn)
    {
       NodeSPI targetNode = peek(fqn, false, true);
       if (targetNode == null) return;
@@ -424,8 +591,21 @@
       }
    }
 
-   private void removeData(Fqn fqn)
+   private void removeNode(Fqn fqn)
    {
+      InternalNode targetNode = peekInternalNode(fqn, true);
+      if (targetNode == null) return;
+      InternalNode parentNode = peekInternalNode(fqn.getParent(), true);
+      targetNode.setValid(false, false);
+      if (parentNode != null)
+      {
+         parentNode.removeChild(fqn.getLastElement());
+         parentNode.setChildrenLoaded(false);
+      }
+   }
+
+   private void removeDataLegacy(Fqn fqn)
+   {
       NodeSPI n = peek(fqn);
       if (n == null)
       {
@@ -436,6 +616,18 @@
       n.setDataLoaded(false);
    }
 
+   private void removeData(Fqn fqn)
+   {
+      InternalNode n = peekInternalNode(fqn, false);
+      if (n == null)
+      {
+         log.warn("node " + fqn + " not found");
+         return;
+      }
+      n.clear();
+      n.setDataLoaded(false);
+   }
+
    public Object[] createNodes(Fqn fqn)
    {
       List<NodeSPI> result = new ArrayList<NodeSPI>(fqn.size());
@@ -465,12 +657,25 @@
       return new Object[]{result, n};
    }
 
-   public InternalNode peekInternalNode(Fqn f, boolean includeInvalidNodes)
+   public InternalNode peekInternalNode(Fqn fqn, boolean includeInvalidNodes)
    {
-      // Yuck!
-      NodeSPI nodeSPI = peek(f, false, includeInvalidNodes);
-      if (nodeSPI == null) return null;
-      return ((NodeInvocationDelegate) nodeSPI).getDelegationTarget();
+      if (fqn == null || fqn.size() == 0) return rootInternal;
+      InternalNode n = rootInternal;
+      int fqnSize = fqn.size();
+      for (int i = 0; i < fqnSize; i++)
+      {
+         Object obj = fqn.get(i);
+         n = n.getChild(obj);
+         if (n == null)
+         {
+            return null;
+         }
+         else if (!includeInvalidNodes && !n.isValid())
+         {
+            return null;
+         }
+      }
+      return n;
    }
 
    public void setBuddyFqnTransformer(BuddyFqnTransformer buddyFqnTransformer)

Modified: core/trunk/src/main/java/org/jboss/cache/InternalNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InternalNode.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/InternalNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,11 +1,13 @@
 package org.jboss.cache;
 
+import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.lock.NodeLock;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.transaction.GlobalTransaction;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * An internal node interface, that represents nodes that directly form the tree structure in the cache.  This is as opposed
@@ -57,36 +59,78 @@
 
    boolean hasChildren();
 
-   NodeSPI<K, V> getChild(Fqn fqn);
+   // ***************** Old legacy methods that assume that the child map maintained contains NodeSPIs. These are still retained to support Optimistic and Pessimistic Locking ***************
 
-   NodeSPI<K, V> getChild(Object childName);
+   @Deprecated
+   NodeSPI<K, V> getChildDirect(Fqn fqn);
 
-   Set<NodeSPI<K, V>> getChildren();
+   @Deprecated
+   NodeSPI<K, V> getChildDirect(Object childName);
 
-   Set<NodeSPI<K, V>> getChildren(boolean includeMarkedForRemoval);
+   @Deprecated
+   Set<NodeSPI<K, V>> getChildrenDirect();
 
+   @Deprecated
+   Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval);
+
+   @Deprecated
+   Map<Object, Node<K, V>> getChildrenMapDirect();
+
+   @Deprecated
+   void setChildrenMapDirect(Map<Object, Node<K, V>> children);
+
+   @Deprecated
+   void addChildDirect(Object nodeName, Node<K, V> nodeToAdd);
+
+   @Deprecated
+   void addChildDirect(NodeSPI<K, V> child);
+
+   @Deprecated
+   NodeSPI<K, V> addChildDirect(Fqn f);
+
+   @Deprecated
+   NodeSPI<K, V> addChildDirect(Fqn f, boolean notify);
+
+   @Deprecated
+   NodeSPI<K, V> addChildDirect(Object o, boolean notify);
+
    /**
     * @deprecated should use the {@link org.jboss.cache.NodeFactory} instead.
     */
    @Deprecated
    NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx);
 
-   Set<Object> getChildrenNames();
+   // ***************** End old legacy methods.  See new versions below, which are supported by MVCC. *********************************
 
-   Map<Object, Node<K, V>> getChildrenMap();
+   InternalNode<K, V> getChild(Fqn f);
 
-   void setChildrenMap(Map<Object, Node<K, V>> children);
+   InternalNode<K, V> getChild(Object childName);
 
-   void addChild(NodeSPI<K, V> child);
+   Set<InternalNode<K, V>> getChildren();
 
-   void addChild(Object nodeName, Node<K, V> nodeToAdd);
+   Set<InternalNode<K, V>> getChildren(boolean includeMarkedForRemoval);
 
-   NodeSPI<K, V> addChild(Fqn f);
+   ConcurrentMap<Object, InternalNode<K, V>> getChildrenMap();
 
-   NodeSPI<K, V> addChild(Fqn f, boolean notify);
+   void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>> children);
 
-   NodeSPI<K, V> addChild(Object o, boolean notify);
+   void addChild(Object nodeName, InternalNode<K, V> nodeToAdd);
 
+   void addChild(InternalNode<K, V> child);
+
+   InternalNode<K, V> addChild(Fqn f);
+
+   InternalNode<K, V> addChild(Fqn f, boolean notify);
+
+   InternalNode<K, V> addChild(Object o, boolean notify);
+
+   InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext ctx);
+
+   // *****************End new methods *****************
+
+
+   Set<Object> getChildrenNames();
+
    void removeChildren();
 
    boolean removeChild(Object childName);

Modified: core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeFactory.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/NodeFactory.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -77,9 +77,16 @@
     * @param attachToParent if true, the node is registered in the parent's child map.  If false, it is not.
     * @return a new node, or the existing node if one existed.
     */
-   NodeSPI<K, V> createAndRegister(Fqn fqn, NodeSPI<K, V> parent, InvocationContext ctx, boolean attachToParent);
+   InternalNode<K, V> createAndRegister(Fqn fqn, InternalNode<K, V> parent, InvocationContext ctx, boolean attachToParent);
 
    NodeSPI<K, V> createRootNode();
 
-   NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V> internalNode, boolean wrapWithNodeReference);
+   /**
+    * Creates an internal node.  Similar to {@link #createNode(Fqn, NodeSPI)} except that the resultant node is not wrapped
+    * in a {@link org.jboss.cache.invocation.NodeInvocationDelegate}.
+    *
+    * @param childFqn
+    * @return
+    */
+   InternalNode<K, V> createInternalNode(Fqn childFqn);
 }

Modified: core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeSPI.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/NodeSPI.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -7,6 +7,7 @@
 package org.jboss.cache;
 
 import net.jcip.annotations.NotThreadSafe;
+import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.lock.NodeLock;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.transaction.GlobalTransaction;
@@ -496,4 +497,67 @@
     * @since 2.1.0
     */
    void setValid(boolean valid, boolean recursive);
+
+   /**
+    * @return true if the node is a null marker node.  Only used with MVCC.
+    */
+   boolean isNullNode();
+
+   /**
+    * Marks a node for updating.  Internally, this creates a copy of the delegate and performs any checks necessary to
+    * maintain isolation level.
+    * <p/>
+    * Only used with MVCC.
+    *
+    * @param ctx            invocation context
+    * @param container      data container
+    * @param nodeFactory    node factory for creating new nodes/copies.
+    * @param writeSkewCheck if true, and the node supports write skew checking, nodes are tested for write skews.
+    */
+   void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory, boolean writeSkewCheck);
+
+   /**
+    * Commits any updates made on this node to the underlying data structure, making it visible to all other transactions.
+    * <p/>
+    * Only used with MVCC.
+    *
+    * @param ctx         invocation context
+    * @param container   data container
+    * @param nodeFactory node factory
+    */
+   void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory);
+
+   /**
+    * Only used with MVCC.
+    * <p/>
+    *
+    * @return true if this node has been marked for update, false otherwise.
+    */
+   boolean isChanged();
+
+   /**
+    * Only used with MVCC.
+    * <p/>
+    *
+    * @return true if this node has been newly created in the current scope.
+    */
+   boolean isCreated();
+
+   InternalNode getDelegationTarget();
+
+   /**
+    * Sets the created flag on a node.
+    * <p/>
+    * Only used with MVCC.
+    *
+    * @param created flag
+    */
+   void setCreated(boolean created);
+
+   /**
+    * Rolls back any changes made to a node.
+    * <p/>
+    * Only used with MVCC.
+    */
+   void rollbackUpdate();
 }

Modified: core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/PessimisticUnversionedNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,13 +1,20 @@
 package org.jboss.cache;
 
+import static org.jboss.cache.AbstractNode.NodeFlags.VALID;
 import org.jboss.cache.commands.write.CreateNodeCommand;
 import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.lock.IdentityLock;
 import org.jboss.cache.lock.LockStrategyFactory;
+import org.jboss.cache.marshall.MarshalledValue;
 import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.util.ImmutableSetCopy;
 
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * UnversionedNode specific to pessimistic locking, with legacy code.
@@ -38,8 +45,19 @@
          this.data = new HashMap<K, V>();
 
       setLockForChildInsertRemove(cache != null && cache.getConfiguration() != null && cache.getConfiguration().isLockParentForChildInsertRemove());
+
+
    }
 
+   /**
+    * @return a genericized version of the child map.
+    */
+   @SuppressWarnings("unchecked")
+   private ConcurrentMap<Object, Node<K, V>> children()
+   {
+      return children;
+   }
+
    // ------ lock-per-node paradigm
 
    public void injectLockStrategyFactory(LockStrategyFactory lockStrategyFactory)
@@ -94,22 +112,21 @@
    // ------ legacy addChild methods that used a lot of implicit locks.
 
    @Override
-   public void addChild(NodeSPI<K, V> child)
+   public void addChildDirect(NodeSPI<K, V> child)
    {
       Fqn childFqn = child.getFqn();
       if (childFqn.isDirectChildOf(fqn))
       {
          synchronized (this)
          {
-            children.put(child.getFqn().getLastElement(), child);
+            children().put(child.getFqn().getLastElement(), child);
          }
       }
       else
          throw new CacheException("Attempting to add a child [" + child.getFqn() + "] to [" + getFqn() + "].  Can only add direct children.");
    }
 
-   @Override
-   protected NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx, boolean createIfNotExists, boolean notify)
+   private NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx, boolean createIfNotExists, boolean notify)
    {
       NodeSPI<K, V> child;
       if (childName == null)
@@ -117,7 +134,7 @@
          throw new IllegalArgumentException("null child name");
       }
 
-      child = (NodeSPI<K, V>) children.get(childName);
+      child = (NodeSPI<K, V>) children().get(childName);
       InvocationContext ctx = cache.getInvocationContext();
       if (createIfNotExists && child == null)
       {
@@ -133,12 +150,12 @@
          {
             // check again to see if the child exists
             // after acquiring exclusive lock
-            child = (NodeSPI<K, V>) children.get(childName);
+            child = (NodeSPI<K, V>) children().get(childName);
             if (child == null)
             {
                if (notify) cache.getNotifier().notifyNodeCreated(childFqn, true, ctx);
                child = newChild;
-               children.put(childName, child);
+               children().put(childName, child);
             }
          }
 
@@ -156,6 +173,218 @@
          }
       }
       return child;
+   }
 
+   @Override
+   public NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
+   {
+      if (f.size() == 1)
+      {
+         GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
+         return getOrCreateChild(f.getLastElement(), gtx, true, notify);
+      }
+      else
+      {
+         throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
+      }
    }
+
+   @Override
+   public NodeSPI<K, V> addChildDirect(Object o, boolean notify)
+   {
+      GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
+      return getOrCreateChild(o, gtx, true, notify);
+   }
+
+   @Override
+   public NodeSPI<K, V> getChildDirect(Fqn fqn)
+   {
+      if (fqn.size() == 1)
+      {
+         return getChildDirect(fqn.getLastElement());
+      }
+      else
+      {
+         NodeSPI<K, V> currentNode = delegate;
+         for (int i = 0; i < fqn.size(); i++)
+         {
+            Object nextChildName = fqn.get(i);
+            currentNode = currentNode.getChildDirect(nextChildName);
+            if (currentNode == null) return null;
+         }
+         return currentNode;
+      }
+   }
+
+   @Override
+   public NodeSPI<K, V> getChildDirect(Object childName)
+   {
+      if (childName == null) return null;
+      return (NodeSPI<K, V>) children().get(childName);
+   }
+
+   @Override
+   public Set<NodeSPI<K, V>> getChildrenDirect()
+   {
+      // strip out deleted child nodes...
+      if (children == null || children.size() == 0) return Collections.emptySet();
+
+      Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
+      for (Node<K, V> n : children().values())
+      {
+         NodeSPI<K, V> spi = (NodeSPI<K, V>) n;
+         if (!spi.isDeleted()) exclDeleted.add(spi);
+      }
+      exclDeleted = Collections.unmodifiableSet(exclDeleted);
+      return exclDeleted;
+   }
+
+   @Override
+   public Map<Object, Node<K, V>> getChildrenMapDirect()
+   {
+      return children();
+   }
+
+   @Override
+   public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
+   {
+      if (children == null)
+         this.children = null;
+      else
+      {
+         this.children.clear();
+         this.children().putAll(children);
+      }
+   }
+
+   @Override
+   public void addChildDirect(Object nodeName, Node<K, V> nodeToAdd)
+   {
+      if (nodeName != null)
+      {
+         children().put(nodeName, nodeToAdd);
+      }
+   }
+
+   @SuppressWarnings("unchecked")
+   @Override
+   public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
+   {
+      if (includeMarkedForRemoval)
+      {
+         if (children != null && !children.isEmpty())
+         {
+            return new ImmutableSetCopy(children.values());
+         }
+         else
+         {
+            return Collections.emptySet();
+         }
+      }
+      else
+      {
+         return getChildrenDirect();
+      }
+   }
+
+   @Override
+   public NodeSPI<K, V> addChildDirect(Fqn f)
+   {
+      return addChildDirect(f, true);
+   }
+
+   @Override
+   public NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx)
+   {
+      return getOrCreateChild(childName, gtx, true, true);
+   }
+
+   @Override
+   public void markAsRemoved(boolean marker, boolean recursive)
+   {
+      setFlag(NodeFlags.REMOVED, marker);
+
+      if (recursive && children != null)
+      {
+         synchronized (this)
+         {
+            for (Node<?, ?> child : children().values())
+            {
+               ((NodeSPI) child).markAsDeleted(marker, true);
+            }
+         }
+      }
+   }
+
+   @Override
+   public void setValid(boolean valid, boolean recursive)
+   {
+      setFlag(VALID, valid);
+
+      if (trace) log.trace("Marking node " + getFqn() + " as " + (valid ? "" : "in") + "valid");
+      if (recursive)
+      {
+         for (Node<K, V> child : children().values())
+         {
+            ((NodeSPI<K, V>) child).setValid(valid, recursive);
+         }
+      }
+   }
+
+   @Override
+   public void setFqn(Fqn fqn)
+   {
+      if (trace)
+      {
+         log.trace(getFqn() + " set FQN " + fqn);
+      }
+      this.fqn = fqn;
+
+      if (children == null)
+      {
+         return;
+      }
+
+      // invoke children
+      for (Map.Entry<Object, ? extends Node<K, V>> me : children().entrySet())
+      {
+         NodeSPI<K, V> n = (NodeSPI<K, V>) me.getValue();
+         Fqn cfqn = Fqn.fromRelativeElements(fqn, me.getKey());
+         n.setFqn(cfqn);
+      }
+   }
+
+   @Override
+   public void releaseObjectReferences(boolean recursive)
+   {
+      if (recursive && children != null)
+      {
+         for (Node<K, V> child : children().values())
+         {
+            child.releaseObjectReferences(recursive);
+         }
+      }
+
+      if (data != null)
+      {
+         for (K key : data.keySet())
+         {
+            // get the key first, before attempting to serialize stuff since data.get() may deserialize the key if doing
+            // a hashcode() or equals().
+
+            Object value = data.get(key);
+            if (key instanceof MarshalledValue)
+            {
+               ((MarshalledValue) key).compact(true, true);
+            }
+
+            if (value instanceof MarshalledValue)
+            {
+               ((MarshalledValue) value).compact(true, true);
+            }
+
+         }
+      }
+   }
+
 }

Modified: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -10,6 +10,7 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.commands.ReplicableCommand;
 import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
 import org.jboss.cache.config.RuntimeConfig;
 import org.jboss.cache.factories.ComponentRegistry;
 import org.jboss.cache.factories.annotations.Inject;
@@ -328,6 +329,7 @@
    }
 
 
+   @Deprecated
    private void removeLocksForDeadMembers(NodeSPI node, List deadMembers)
    {
       Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
@@ -344,7 +346,7 @@
       for (GlobalTransaction deadOwner : deadOwners)
       {
          boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
-         boolean broken = LockUtil.breakTransactionLock(node, lockManager, deadOwner, localTx, txTable, txManager);
+         boolean broken = LockUtil.breakTransactionLock(node.getFqn(), lockManager, deadOwner, localTx, txTable, txManager);
 
          if (broken && trace) log.trace("Broke lock for node " + node.getFqn() + " held by " + deadOwner);
       }
@@ -356,6 +358,31 @@
       }
    }
 
+
+   /**
+    * Only used with MVCC.
+    */
+   private void removeLocksForDeadMembers(InternalNode<?, ?> node, List deadMembers)
+   {
+      Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
+      Object owner = lockManager.getWriteOwner(node.getFqn());
+
+      if (isLockOwnerDead(owner, deadMembers)) deadOwners.add((GlobalTransaction) owner);
+
+      // MVCC won't have any read locks.
+
+      for (GlobalTransaction deadOwner : deadOwners)
+      {
+         boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
+         boolean broken = LockUtil.breakTransactionLock(node.getFqn(), lockManager, deadOwner, localTx, txTable, txManager);
+
+         if (broken && trace) log.trace("Broke lock for node " + node.getFqn() + " held by " + deadOwner);
+      }
+
+      // Recursively unlock children
+      for (InternalNode child : node.getChildren()) removeLocksForDeadMembers(child, deadMembers);
+   }
+
    private boolean isLockOwnerDead(Object owner, List deadMembers)
    {
       boolean result = false;
@@ -590,7 +617,20 @@
                   // and roll back any tx and break any locks
                   List<Address> removed = new ArrayList<Address>(members);
                   removed.removeAll(newMembers);
-                  removeLocksForDeadMembers(spi.getRoot(), removed);
+                  NodeSPI root = spi.getRoot();
+                  if (root != null)
+                  {
+                     // UGH!!!  What a shameless hack!
+                     if (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+                     {
+
+                        removeLocksForDeadMembers(root.getDelegationTarget(), removed);
+                     }
+                     else
+                     {
+                        removeLocksForDeadMembers(root, removed);
+                     }
+                  }
                }
 
                members = new ArrayList<Address>(newMembers); // defensive copy.

Modified: core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/RegionManagerImpl.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -337,19 +337,11 @@
    private void activateRegion(Fqn fqn, boolean suppressRegionNotEmptyException)
    {
       // Check whether the node already exists and has data
-      Node subtreeRoot = cache.peek(fqn, false, false);
+      Node subtreeRoot = cache.getNode(fqn); // NOTE this used to be a peek!
 
-      /*
-       * Commented out on Nov 16,2006 Manik&Vladimir
-       *
-       * if (!(cache.isNodeEmpty(subtreeRoot)))
-      {
-         throw new RegionNotEmptyException("Node " + subtreeRoot.getFqn() + " already exists and is not empty");
-      }*/
-
       if (isActivatingDeactivating(fqn))
       {
-         throw new CacheException("Region " + subtreeRoot.getFqn() + " is already being activated/deactivated");
+         throw new CacheException("Region " + fqn + " is already being activated/deactivated");
       }
 
       if (log.isDebugEnabled())

Modified: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -12,10 +12,7 @@
 import org.jboss.cache.commands.CommandsFactory;
 import org.jboss.cache.commands.write.CreateNodeCommand;
 import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.lock.IdentityLock;
 import org.jboss.cache.marshall.MarshalledValue;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.util.ImmutableSetCopy;
 import org.jboss.cache.util.concurrent.SelfInitializingConcurrentHashMap;
 
@@ -25,6 +22,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * Basic data node class.  Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
@@ -42,11 +40,6 @@
    protected static final boolean trace = log.isTraceEnabled();
 
    /**
-    * A reference of the CacheImpl instance.
-    */
-//   transient CacheSPI<K, V> cache;
-
-   /**
     * Map of general data keys to values.
     */
    protected HashMap<K, V> data;
@@ -81,15 +74,16 @@
       this.cache = cache;
       setLockForChildInsertRemove(lockForChildInsertRemove);
       this.fqn = fqn;
+
       // if this is a root node, create the child map.
       if (fqn.isRoot())
       {
-         children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
+         children = new ConcurrentHashMap<Object, InternalNode<K, V>>(64, .5f, 16);
       }
       else
       {
          // this always needs to be initialized.  The actual cost of the ConcurrentHashMap, however, is deferred.
-         children = new SelfInitializingConcurrentHashMap<Object, Node<K, V>>();
+         children = new SelfInitializingConcurrentHashMap<Object, InternalNode<K, V>>();
       }
    }
 
@@ -164,12 +158,6 @@
       return data == null ? null : data.get(key);
    }
 
-   @SuppressWarnings("deprecation")
-   public IdentityLock getLock()
-   {
-      throw new UnsupportedOperationException("Not supported in this implementation!");
-   }
-
    public Map<K, V> getData()
    {
       if (data == null) return Collections.emptyMap();
@@ -182,27 +170,146 @@
       return data.put(key, value);
    }
 
-   public NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx)
+   @Override
+   public InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext ctx)
    {
-      return getOrCreateChild(childName, gtx, true, true);
+      return getOrCreateChild(childName, ctx, true, true);
    }
 
-   protected NodeSPI<K, V> getOrCreateChild(Object childName, GlobalTransaction gtx, boolean createIfNotExists, boolean notify)
+   @Override
+   public InternalNode<K, V> getChild(Fqn f)
    {
-      NodeSPI<K, V> child;
-      if (childName == null)
+      if (fqn.size() == 1)
       {
-         throw new IllegalArgumentException("null child name");
+         return getChild(fqn.getLastElement());
       }
+      else
+      {
+         InternalNode<K, V> currentNode = this;
+         for (int i = 0; i < fqn.size(); i++)
+         {
+            Object nextChildName = fqn.get(i);
+            currentNode = currentNode.getChild(nextChildName);
+            if (currentNode == null) return null;
+         }
+         return currentNode;
+      }
+   }
 
-      child = (NodeSPI<K, V>) children.get(childName);
-      InvocationContext ctx = cache.getInvocationContext();
+   @Override
+   public InternalNode<K, V> getChild(Object childName)
+   {
+      if (childName == null) return null;
+      return children().get(childName);
+   }
+
+   @Override
+   public Set<InternalNode<K, V>> getChildren()
+   {
+      // strip out deleted child nodes...
+      if (children.isEmpty()) return Collections.emptySet();
+
+      Set<InternalNode<K, V>> exclDeleted = new HashSet<InternalNode<K, V>>();
+      for (InternalNode<K, V> n : children().values())
+      {
+         if (!n.isRemoved()) exclDeleted.add(n);
+      }
+      exclDeleted = Collections.unmodifiableSet(exclDeleted);
+      return exclDeleted;
+   }
+
+   @Override
+   public Set<InternalNode<K, V>> getChildren(boolean includeMarkedForRemoval)
+   {
+      if (includeMarkedForRemoval)
+      {
+         if (!children.isEmpty())
+         {
+            return new ImmutableSetCopy<InternalNode<K, V>>(children().values());
+         }
+         else
+         {
+            return Collections.emptySet();
+         }
+      }
+      else
+      {
+         return getChildren();
+      }
+   }
+
+   @Override
+   public ConcurrentMap<Object, InternalNode<K, V>> getChildrenMap()
+   {
+      return children();
+   }
+
+   @Override
+   public void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>> children)
+   {
+      this.children = children;
+   }
+
+   @Override
+   public void addChild(Object nodeName, InternalNode<K, V> nodeToAdd)
+   {
+      if (nodeName != null)
+      {
+         children().put(nodeName, nodeToAdd);
+      }
+   }
+
+   @Override
+   public void addChild(InternalNode<K, V> child)
+   {
+      Fqn childFqn = child.getFqn();
+      if (childFqn.isDirectChildOf(fqn))
+      {
+         children().put(childFqn.getLastElement(), child);
+      }
+      else
+      {
+         throw new CacheException("Attempting to add a child [" + childFqn + "] to [" + fqn + "].  Can only add direct children.");
+      }
+   }
+
+   public InternalNode<K, V> addChild(Fqn f)
+   {
+      return addChild(f, true);
+   }
+
+   @Override
+   public InternalNode<K, V> addChild(Fqn f, boolean notify)
+   {
+      if (f.size() == 1)
+      {
+         return getOrCreateChild(f.getLastElement(), cache.getInvocationContext(), true, notify);
+      }
+      else
+      {
+         throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
+      }
+   }
+
+   @Override
+   public InternalNode<K, V> addChild(Object o, boolean notify)
+   {
+      return getOrCreateChild(o, cache.getInvocationContext(), true, notify);
+   }
+
+   private InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext ctx, boolean createIfNotExists, boolean notify)
+   {
+      InternalNode<K, V> child;
+      if (childName == null) throw new IllegalArgumentException("null child name");
+
+      child = children().get(childName);
+
       if (createIfNotExists && child == null)
       {
          Fqn childFqn = Fqn.fromRelativeElements(fqn, childName);
-         NodeSPI<K, V> newChild = nodeFactory.createNode(childFqn, delegate);
+         InternalNode<K, V> newChild = nodeFactory.createInternalNode(childFqn);
 
-         child = (NodeSPI<K, V>) children.putIfAbsent(childName, newChild);
+         child = children().putIfAbsent(childName, newChild);
 
          if (child == null)
          {
@@ -211,7 +318,7 @@
 
             if (trace) log.trace("created child: fqn=" + childFqn);
 
-            if (gtx != null)
+            if (ctx.getTransactionContext() != null)
             {
                CreateNodeCommand createNodeCommand = commandsFactory.buildCreateNodeCommand(childFqn);
                ctx.getTransactionContext().addModification(createNodeCommand);
@@ -298,7 +405,7 @@
             sb.append("]");
          }
       }
-      if (children != null && !children.isEmpty())
+      if (!children.isEmpty())
       {
          if (trace)
          {
@@ -337,71 +444,14 @@
       return sb.toString();
    }
 
-   public void addChild(NodeSPI<K, V> child)
-   {
-      Fqn childFqn = child.getFqn();
-      if (childFqn.isDirectChildOf(fqn))
-      {
-         children.put(childFqn.getLastElement(), child);
-      }
-      else
-      {
-         throw new CacheException("Attempting to add a child [" + childFqn + "] to [" + fqn + "].  Can only add direct children.");
-      }
-   }
-
-   public NodeSPI<K, V> addChild(Fqn f)
-   {
-      return addChild(f, true);
-   }
-
-   public NodeSPI<K, V> addChild(Fqn f, boolean notify)
-   {
-      if (f.size() == 1)
-      {
-         GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
-         return getOrCreateChild(f.getLastElement(), gtx, true, notify);
-      }
-      else
-      {
-         throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
-      }
-
-   }
-
-   public NodeSPI<K, V> addChild(Object childName, boolean notify)
-   {
-      GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
-      return getOrCreateChild(childName, gtx, true, notify);
-   }
-
    public void clear()
    {
       if (data != null) data.clear();
    }
 
-   public NodeSPI<K, V> getChild(Fqn fqn)
-   {
-      if (fqn.size() == 1)
-      {
-         return getChild(fqn.getLastElement());
-      }
-      else
-      {
-         NodeSPI<K, V> currentNode = delegate;
-         for (int i = 0; i < fqn.size(); i++)
-         {
-            Object nextChildName = fqn.get(i);
-            currentNode = currentNode.getChildDirect(nextChildName);
-            if (currentNode == null) return null;
-         }
-         return currentNode;
-      }
-   }
-
    public Set<Object> getChildrenNames()
    {
-      return children == null ? Collections.emptySet() : new HashSet<Object>(children.keySet());
+      return children.isEmpty() ? Collections.emptySet() : new ImmutableSetCopy<Object>(children.keySet());
    }
 
    public Set<K> getKeys()
@@ -415,7 +465,7 @@
 
    public boolean removeChild(Object childName)
    {
-      return children != null && children.remove(childName) != null;
+      return children.remove(childName) != null;
    }
 
    public boolean removeChild(Fqn f)
@@ -426,27 +476,11 @@
       }
       else
       {
-         NodeSPI<K, V> child = getChild(f);
+         NodeSPI<K, V> child = getChildDirect(f);
          return child != null && child.getParentDirect().removeChildDirect(f.getLastElement());
       }
    }
 
-   public Map<Object, Node<K, V>> getChildrenMap()
-   {
-      return children;
-   }
-
-   public void setChildrenMap(Map<Object, Node<K, V>> children)
-   {
-      if (children == null)
-         this.children = null;
-      else
-      {
-         this.children.clear();
-         this.children.putAll(children);
-      }
-   }
-
    public void putAll(Map<K, V> data)
    {
       if (data != null)
@@ -458,24 +492,17 @@
 
    public void removeChildren()
    {
-      if (children != null)
-      {
-         children.clear();
-      }
-      children = null;
+      children.clear();
    }
 
-   // versioning
-
-   public void setVersion(DataVersion
-         version)
+   public void markAsRemoved(boolean marker, boolean recursive)
    {
-      throw new UnsupportedOperationException("Versioning not supported");
-   }
+      setFlag(REMOVED, marker);
 
-   public DataVersion getVersion()
-   {
-      throw new UnsupportedOperationException("Versioning not supported");
+      if (recursive)
+      {
+         for (InternalNode<K, V> child : children().values()) child.markAsRemoved(marker, true);
+      }
    }
 
    private void printIndent(StringBuilder sb, int indent)
@@ -489,14 +516,6 @@
       }
    }
 
-   public void addChild(Object childName, Node<K, V> n)
-   {
-      if (childName != null)
-      {
-         children.put(childName, n);
-      }
-   }
-
    /**
     * Returns the name of this node.
     */
@@ -513,66 +532,20 @@
       }
       this.fqn = fqn;
 
-      if (children == null)
-      {
-         return;
-      }
-
       // invoke children
-      for (Map.Entry<Object, ? extends Node<K, V>> me : children.entrySet())
+      for (Map.Entry<Object, InternalNode<K, V>> me : children().entrySet())
       {
-         NodeSPI<K, V> n = (NodeSPI<K, V>) me.getValue();
+         InternalNode<K, V> n = me.getValue();
          Fqn cfqn = Fqn.fromRelativeElements(fqn, me.getKey());
          n.setFqn(cfqn);
       }
    }
 
-   public NodeSPI<K, V> getChild(Object childName)
-   {
-      if (childName == null) return null;
-      return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
-   }
-
-   public Set<NodeSPI<K, V>> getChildren()
-   {
-      // strip out deleted child nodes...
-      if (children == null || children.size() == 0) return Collections.emptySet();
-
-      Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
-      for (Node<K, V> n : children.values())
-      {
-         NodeSPI<K, V> spi = (NodeSPI<K, V>) n;
-         if (!spi.isDeleted()) exclDeleted.add(spi);
-      }
-      exclDeleted = Collections.unmodifiableSet(exclDeleted);
-      return exclDeleted;
-   }
-
    public boolean hasChildren()
    {
-      return children != null && children.size() != 0;
+      return !children.isEmpty();
    }
 
-   @SuppressWarnings("unchecked")
-   public Set<NodeSPI<K, V>> getChildren(boolean includeMarkedForRemoval)
-   {
-      if (includeMarkedForRemoval)
-      {
-         if (children != null && !children.isEmpty())
-         {
-            return new ImmutableSetCopy(children.values());
-         }
-         else
-         {
-            return Collections.emptySet();
-         }
-      }
-      else
-      {
-         return getChildren();
-      }
-   }
-
    /**
     * Adds details of the node into a map as strings.
     */
@@ -587,14 +560,7 @@
       sb.append(fqn.getLastElement());
       sb.append("  ");
       sb.append(data);
-      if (children != null)
-      {
-         for (Node<K, V> n : children.values())
-         {
-            sb.append("\n");
-            ((NodeSPI<K, V>) n).printDetails(sb, indent);
-         }
-      }
+      sb.append(children);
    }
 
    /**
@@ -625,9 +591,9 @@
       if (trace) log.trace("Marking node " + getFqn() + " as " + (valid ? "" : "in") + "valid");
       if (recursive)
       {
-         for (Node<K, V> child : children.values())
+         for (InternalNode<K, V> child : children().values())
          {
-            ((NodeSPI<K, V>) child).setValid(valid, recursive);
+            child.setValid(valid, recursive);
          }
       }
    }
@@ -685,9 +651,9 @@
 
    public void releaseObjectReferences(boolean recursive)
    {
-      if (recursive && children != null)
+      if (recursive)
       {
-         for (Node<?, ?> child : children.values())
+         for (InternalNode<K, V> child : children().values())
          {
             child.releaseObjectReferences(recursive);
          }
@@ -714,4 +680,13 @@
          }
       }
    }
+
+   /**
+    * @return genericized version of the child map
+    */
+   @SuppressWarnings("unchecked")
+   private ConcurrentMap<Object, InternalNode<K, V>> children()
+   {
+      return children;
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/OptimisticCommandsFactoryImpl.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,10 +1,12 @@
 package org.jboss.cache.commands;
 
 import org.jboss.cache.Fqn;
+import org.jboss.cache.commands.legacy.read.LegacyGravitateDataCommand;
 import org.jboss.cache.commands.legacy.write.LegacyEvictCommand;
+import org.jboss.cache.commands.legacy.write.VersionedInvalidateCommand;
+import org.jboss.cache.commands.read.GravitateDataCommand;
 import org.jboss.cache.commands.write.EvictCommand;
 import org.jboss.cache.commands.write.InvalidateCommand;
-import org.jboss.cache.commands.write.VersionedInvalidateCommand;
 
 /**
  * Extends the default commands factory impl for optimistic locking.
@@ -32,12 +34,27 @@
    }
 
    @Override
+   public GravitateDataCommand buildGravitateDataCommand(Fqn fqn, Boolean searchSubtrees)
+   {
+      LegacyGravitateDataCommand command = new LegacyGravitateDataCommand(fqn, searchSubtrees, rpcManager.getLocalAddress());
+      command.initialize(dataContainer, cacheSpi, buddyFqnTransformer);
+      return command;
+   }
+
+   @Override
    public ReplicableCommand fromStream(int id, Object[] parameters)
    {
       ReplicableCommand command;
       boolean skipSetParams = false;
       switch (id)
       {
+         case GravitateDataCommand.METHOD_ID:
+         {
+            LegacyGravitateDataCommand returnValue = new LegacyGravitateDataCommand(rpcManager.getLocalAddress());
+            returnValue.initialize(dataContainer, cacheSpi, buddyFqnTransformer);
+            command = returnValue;
+            break;
+         }
          case InvalidateCommand.METHOD_ID:
          {
             VersionedInvalidateCommand returnValue = new VersionedInvalidateCommand(null);

Added: core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/LegacyGravitateDataCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,39 @@
+package org.jboss.cache.commands.legacy.read;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.commands.read.GravitateDataCommand;
+import org.jgroups.Address;
+
+import java.util.Set;
+
+/**
+ * Legacy version that uses old data container peeks
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 3.0
+ */
+public class LegacyGravitateDataCommand extends GravitateDataCommand
+{
+   public LegacyGravitateDataCommand(Fqn fqn, boolean searchSubtrees, Address localAddress)
+   {
+      super(fqn, searchSubtrees, localAddress);
+   }
+
+   public LegacyGravitateDataCommand(Address localAddress)
+   {
+      super(localAddress);
+   }
+
+   /**
+    * @return a Set of child node names that hang directly off the backup tree root, or null if the backup tree root doesn't exist.
+    */
+   @Override
+   protected Set<Object> getBackupRoots()
+   {
+      NodeSPI backupSubtree = dataContainer.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+      if (backupSubtree == null) return null;
+      return backupSubtree.getChildrenNamesDirect();
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/legacy/read/PessGetChildrenNamesCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,12 +1,15 @@
 package org.jboss.cache.commands.legacy.read;
 
 import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.read.GetChildrenNamesCommand;
 import org.jboss.cache.invocation.InvocationContext;
 
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 public class PessGetChildrenNamesCommand extends GetChildrenNamesCommand
@@ -20,8 +23,26 @@
       super(fqn);
    }
 
-   protected Set<Object> getCorrectedChildNames(Collection<NodeSPI<?, ?>> children, InvocationContext ctx)
+   /**
+    * Retrieves the names of children for a specific Fqn.
+    *
+    * @param ctx invocation context
+    * @return a Set<Object> of child names, for a given Fqn, or null if the Fqn refers to a node that does not exist.
+    */
+   @SuppressWarnings("unchecked")
+   @Override
+   public Object perform(InvocationContext ctx)
    {
+      NodeSPI<?, ?> n = fqn == null ? null : ctx.lookUpNode(fqn);
+      if (n == null || n.isDeleted()) return null;
+      Map<Object, ? extends Node<?, ?>> childrenMap = n.getChildrenMapDirect();
+      Collection<NodeSPI<?, ?>> children = (Collection<NodeSPI<?, ?>>) ((childrenMap == null || childrenMap.isEmpty()) ? Collections.emptySet() : childrenMap.values());
+
+      return getCorrectedChildNames(children, ctx);
+   }
+
+   private Set<Object> getCorrectedChildNames(Collection<NodeSPI<?, ?>> children, InvocationContext ctx)
+   {
       // prune deleted children - JBCACHE-1136
       Set<Object> childNames = new HashSet<Object>();
       for (NodeSPI child : children)

Modified: core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/LegacyEvictCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -36,4 +36,38 @@
       return dataContainer.getNodesForEviction(fqn, true);
    }
 
+   @Override
+   protected boolean evictNode(Fqn fqn, InvocationContext ctx, NodeSPI node)
+   {
+      notifier.notifyNodeEvicted(fqn, true, ctx);
+      try
+      {
+         if (node == null) return true;
+         if (node.hasChildrenDirect() || fqn.isRoot())
+         {
+            if (trace) log.trace("removing DATA as node has children: evict(" + fqn + ")");
+            node.clearDataDirect();
+            node.setDataLoaded(false);
+            return false;
+         }
+         else
+         {
+            if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
+            NodeSPI parentNode = lookupForEviction(ctx, fqn.getParent());
+
+            if (parentNode != null)
+            {
+               parentNode.removeChildDirect(fqn.getLastElement());
+               parentNode.setChildrenLoaded(false);
+            }
+            node.setValid(false, false);
+            node.markAsDeleted(true);
+            return true;
+         }
+      }
+      finally
+      {
+         notifier.notifyNodeEvicted(fqn, false, ctx);
+      }
+   }
 }

Copied: core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java (from rev 6358, core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,182 @@
+package org.jboss.cache.commands.legacy.write;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.VersionedDataCommand;
+import org.jboss.cache.commands.write.InvalidateCommand;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DataVersioningException;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+
+/**
+ * Behaves like {@link org.jboss.cache.commands.write.InvalidateCommand}. Also, potentially throws a cache exception if
+ * data versioning is used and the node in memory has a newer data version than what is passed in.
+ * <p/>
+ * Finally, the data version of the in-memory node is updated to the version being evicted to prevent versions
+ * going out of sync.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class VersionedInvalidateCommand extends InvalidateCommand implements VersionedDataCommand
+{
+   private static final Log log = LogFactory.getLog(VersionedInvalidateCommand.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   /*
+     dependencies
+    */
+   private TransactionManager transactionManager;
+
+   /**
+    * Params.
+    */
+   protected GlobalTransaction globalTransaction;
+   private DataVersion dataVersion;
+
+   public VersionedInvalidateCommand(Fqn fqn)
+   {
+      super(fqn);
+   }
+
+   public VersionedInvalidateCommand()
+   {
+   }
+
+   public void initialize(TransactionManager txManager)
+   {
+      this.transactionManager = txManager;
+   }
+
+   @Override
+   public Object perform(InvocationContext ctx)
+   {
+      NodeSPI node = enforceNodeLoading();
+      if (trace) log.trace("Invalidating fqn:" + fqn);
+      if (node == null)
+      {
+         // check if a tombstone already exists
+         NodeSPI nodeSPI = dataContainer.peek(fqn, true, true);
+         if (nodeSPI == null)
+         {
+            if (dataVersion == null)
+            {
+               if (trace)
+                  log.trace("Would have created a tombstone since the node doesn't exist, but the version to invalidate is null and hence cannot create a tombstone!");
+               return null;
+            }
+            createTombstone(ctx);
+            nodeSPI = (NodeSPI) dataContainer.getRoot().getChild(fqn);
+         }
+         node = nodeSPI;
+      }
+      else if (node.getVersion() == null)
+      {
+         throw new NullPointerException("Node " + node.getFqn() + " has a null data version, and is of type " + node.getClass().getSimpleName() + ".  This command expects versioned nodes.");
+      }
+      else
+      if (dataVersion != null && node.getVersion().newerThan(dataVersion)) // dataVersion *could* be null if the invalidate was triggered by removing a node that did not exist in the first place.
+      {
+         String errMsg = new StringBuilder("Node found, but version is not equal to or less than the expected [").append(dataVersion).append("].  Is [").append(node.getVersion()).append("] instead!").toString();
+         log.warn(errMsg);
+         throw new DataVersioningException(errMsg);
+      }
+
+      removeData(node, ctx);
+      invalidateNode(node);
+      node.setVersion(dataVersion);
+      return null;
+   }
+
+   protected void createTombstone(InvocationContext ctx)
+   {
+      if (trace)
+         log.trace("Node doesn't exist; creating a tombstone with data version " + dataVersion);
+      // create the node we need.
+      Option o = ctx.getOptionOverrides();
+      boolean origCacheModeLocal = o.isCacheModeLocal();
+      o.setCacheModeLocal(true);
+      o.setDataVersion(dataVersion);
+      // if we are in a tx this call should happen outside of any tx
+      try
+      {
+         Transaction suspended = null;
+         if (transactionManager != null)
+         {
+            suspended = transactionManager.suspend();
+         }
+         spi.put(fqn, Collections.emptyMap());
+         if (suspended != null) transactionManager.resume(suspended);
+         ctx.getOptionOverrides().setCacheModeLocal(origCacheModeLocal);
+      }
+      catch (Exception e)
+      {
+         log.error("Unable to create tombstone!", e);
+      }
+   }
+
+   protected void removeData(NodeSPI n, InvocationContext ctx) throws CacheException
+   {
+      notifier.notifyNodeEvicted(fqn, true, ctx);
+      n.clearDataDirect();
+      n.setDataLoaded(false);
+      notifier.notifyNodeEvicted(fqn, false, ctx);
+   }
+
+   public DataVersion getDataVersion()
+   {
+      return dataVersion;
+   }
+
+   public void setDataVersion(DataVersion dataVersion)
+   {
+      this.dataVersion = dataVersion;
+   }
+
+   public GlobalTransaction getGlobalTransaction()
+   {
+      return globalTransaction;
+   }
+
+   public void setGlobalTransaction(GlobalTransaction gtx)
+   {
+      this.globalTransaction = gtx;
+   }
+
+   public boolean isVersioned()
+   {
+      return dataVersion != null;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "OptimisticInvalidateCommand{" +
+            "dataVersion=" + dataVersion +
+            " ,fqn=" + fqn +
+            '}';
+   }
+
+   @Override
+   public Object[] getParameters()
+   {
+      return new Object[]{fqn, dataVersion};
+   }
+
+   @Override
+   public void setParameters(int commandId, Object[] args)
+   {
+      fqn = (Fqn) args[0];
+      dataVersion = (DataVersion) args[1];
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -3,7 +3,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.invocation.InvocationContext;
@@ -48,10 +48,10 @@
    @SuppressWarnings("unchecked")
    public Object perform(InvocationContext ctx)
    {
-      NodeSPI<?, ?> n = fqn == null ? null : ctx.lookUpNode(fqn);
+      ReadCommittedNode n = (ReadCommittedNode) (fqn == null ? null : ctx.lookUpNode(fqn));
       if (n == null || n.isDeleted()) return null;
-      Map<Object, ? extends Node<?, ?>> childrenMap = n.getChildrenMapDirect();
-      Collection<NodeSPI<?, ?>> children = (Collection<NodeSPI<?, ?>>) ((childrenMap == null || childrenMap.isEmpty()) ? Collections.emptySet() : childrenMap.values());
+      Map<Object, InternalNode<?, ?>> childrenMap = n.getDelegationTarget().getChildrenMap();
+      Collection<InternalNode> children = (Collection<InternalNode>) ((childrenMap == null || childrenMap.isEmpty()) ? Collections.emptySet() : childrenMap.values());
 
       return getCorrectedChildNames(children, ctx);
    }
@@ -64,11 +64,11 @@
     * @param ctx      invocation context
     * @return a set of valid children names.
     */
-   protected Set<Object> getCorrectedChildNames(Collection<NodeSPI<?, ?>> children, InvocationContext ctx)
+   private Set<Object> getCorrectedChildNames(Collection<InternalNode> children, InvocationContext ctx)
    {
       Set<Object> childNames = new HashSet<Object>();
 
-      for (NodeSPI realChild : children)
+      for (InternalNode realChild : children)
       {
          Fqn childFqn = realChild.getFqn();
          NodeSPI childNode = ctx.lookUpNode(childFqn);

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -5,6 +5,7 @@
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.Node;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
@@ -93,55 +94,53 @@
          if (actualNode == null && searchSubtrees)
          {
             log.trace("Looking at backup trees.");
-            NodeSPI backupSubtree = dataContainer.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
-            if (backupSubtree != null)
+
+            // need to loop through backupSubtree's children
+            Set allGroupNames = getBackupRoots();
+            if (allGroupNames != null)
             {
-               // need to loop through backupSubtree's children
-               Set allGroupNames = backupSubtree.getChildrenNamesDirect();
-               if (allGroupNames != null)
+               for (Object groupName : allGroupNames)
                {
-                  for (Object groupName : allGroupNames)
+                  // groupName is the name of a buddy group since all child names in this
+                  // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
+                  Fqn backupRoot = Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, (String) groupName);
+                  if (buddyFqnTransformer.isDeadBackupRoot(backupRoot))
                   {
-                     // groupName is the name of a buddy group since all child names in this
-                     // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
-                     Fqn backupRoot = Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, (String) groupName);
-                     if (buddyFqnTransformer.isDeadBackupRoot(backupRoot))
+                     Set<Integer> deadChildNames = new TreeSet<Integer>(spi.getChildrenNames(backupRoot));
+                     Integer[] elems = deadChildNames.toArray(new Integer[deadChildNames.size()]);
+
+                     // these are integers.  we need to start with the highest/most recent.
+                     for (int i = elems.length - 1; i > -1; i--)
                      {
-                        Set<Integer> deadChildNames = new TreeSet<Integer>(spi.getChildrenNames(backupRoot));
-                        Integer[] elems = deadChildNames.toArray(new Integer[deadChildNames.size()]);
+                        Integer versionOfDefunctData = elems[i];
+                        backupNodeFqn = Fqn.fromRelativeFqn(Fqn.fromRelativeElements(backupRoot, versionOfDefunctData), fqn);
 
-                        // these are integers.  we need to start with the highest/most recent.
-                        for (int i = elems.length - 1; i > -1; i--)
-                        {
-                           Integer versionOfDefunctData = elems[i];
-                           backupNodeFqn = Fqn.fromRelativeFqn(Fqn.fromRelativeElements(backupRoot, versionOfDefunctData), fqn);
-
-                           // use a get() call into the cache to make sure cache loading takes place.
-                           ctx.getOptionOverrides().setSkipDataGravitation(true);
-                           actualNode = spi.peek(backupNodeFqn, false);
-                           ctx.getOptionOverrides().setSkipDataGravitation(false);
-
-                           // break out of the inner loop searching through the dead node's various backups
-                           if (actualNode != null) break;
-                        }
-                     }
-                     else
-                     {
-                        backupNodeFqn = Fqn.fromRelativeFqn(backupRoot, fqn);
                         // use a get() call into the cache to make sure cache loading takes place.
                         ctx.getOptionOverrides().setSkipDataGravitation(true);
-                        actualNode = spi.getNode(backupNodeFqn);
+                        actualNode = spi.peek(backupNodeFqn, false);
                         ctx.getOptionOverrides().setSkipDataGravitation(false);
+
+                        // break out of the inner loop searching through the dead node's various backups
+                        if (actualNode != null) break;
                      }
+                  }
+                  else
+                  {
+                     backupNodeFqn = Fqn.fromRelativeFqn(backupRoot, fqn);
+                     // use a get() call into the cache to make sure cache loading takes place.
+                     ctx.getOptionOverrides().setSkipDataGravitation(true);
+                     actualNode = spi.getNode(backupNodeFqn);
+                     ctx.getOptionOverrides().setSkipDataGravitation(false);
+                  }
 
-                     if (trace)
-                        log.trace("Looking for " + backupNodeFqn + ". Search result: " + actualNode);
+                  if (trace)
+                     log.trace("Looking for " + backupNodeFqn + ". Search result: " + actualNode);
 
-                     // break out of outer loop searching through all available backups.
-                     if (actualNode != null) break;
-                  }
+                  // break out of outer loop searching through all available backups.
+                  if (actualNode != null) break;
                }
             }
+
          }
 
          if (actualNode == null)
@@ -174,6 +173,16 @@
       }
    }
 
+   /**
+    * @return a Set of child node names that hang directly off the backup tree root, or null if the backup tree root doesn't exist.
+    */
+   protected Set<Object> getBackupRoots()
+   {
+      InternalNode backupSubtree = dataContainer.peekInternalNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, false);
+      if (backupSubtree == null) return null;
+      return backupSubtree.getChildrenNames();
+   }
+
    public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
    {
       return visitor.visitGravitateDataCommand(ctx, this);

Modified: core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -4,7 +4,6 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
 import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
 import org.jboss.cache.buddyreplication.BuddyManager;
 import org.jboss.cache.commands.CommandsFactory;
@@ -88,20 +87,18 @@
                // if this is a DIRECT child of a DEAD buddy backup region, then remove the empty dead region structural node.
                if (buddyFqnTransformer.isDeadBackupFqn(backup) && buddyFqnTransformer.isDeadBackupRoot(backup.getAncestor(backup.size() - 2)))
                {
-                  NodeSPI deadBackupRoot = dataContainer.peek(backup.getParent(), false); // ctx.lookUpNode(backup.getParent());
-                  if (deadBackupRoot.getChildrenMapDirect().isEmpty())
+                  Fqn deadBackupRootFqn = backup.getParent();
+                  if (!dataContainer.hasChildren(deadBackupRootFqn))
                   {
-                     if (trace) log.trace("Removing dead backup region " + deadBackupRoot.getFqn());
-                     executeRemove(gtx, deadBackupRoot.getFqn());
+                     if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
+                     executeRemove(gtx, deadBackupRootFqn);
 
                      // now check the grand parent and see if we are free of versions
-
-//                     deadBackupRoot = ctx.lookUpNode(deadBackupRoot.getFqn().getParent());
-                     deadBackupRoot = dataContainer.peek(deadBackupRoot.getFqn().getParent(), false);
-                     if (deadBackupRoot.getChildrenMapDirect().isEmpty())
+                     deadBackupRootFqn = deadBackupRootFqn.getParent();
+                     if (!dataContainer.hasChildren(deadBackupRootFqn))
                      {
-                        if (trace) log.trace("Removing dead backup region " + deadBackupRoot.getFqn());
-                        executeRemove(gtx, deadBackupRoot.getFqn());
+                        if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
+                        executeRemove(gtx, deadBackupRootFqn);
                      }
                   }
                }

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -4,10 +4,12 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.commands.read.AbstractDataCommand;
 import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.mvcc.ReadCommittedNode;
 import org.jboss.cache.notifications.Notifier;
 
 import java.util.Collection;
@@ -28,8 +30,8 @@
    private boolean recursive = false;
 
    protected Notifier notifier;
-   private static final Log log = LogFactory.getLog(EvictCommand.class);
-   private static final boolean trace = log.isTraceEnabled();
+   protected static final Log log = LogFactory.getLog(EvictCommand.class);
+   protected static final boolean trace = log.isTraceEnabled();
    private List<Fqn> nodesToEvict;
 
    public EvictCommand(Fqn fqn)
@@ -102,7 +104,7 @@
       return nodesToEvict;
    }
 
-   boolean evictNode(Fqn fqn, InvocationContext ctx, NodeSPI node)
+   protected boolean evictNode(Fqn fqn, InvocationContext ctx, NodeSPI node)
    {
       notifier.notifyNodeEvicted(fqn, true, ctx);
       try
@@ -118,15 +120,17 @@
          else
          {
             if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
-            NodeSPI parentNode = lookupInAllScopes(ctx, fqn.getParent());
+            InternalNode parentNode = lookupInAllScopes(ctx, fqn.getParent());
 
             if (parentNode != null)
             {
-               parentNode.removeChildDirect(fqn.getLastElement());
+               parentNode.removeChild(fqn.getLastElement());
                parentNode.setChildrenLoaded(false);
             }
             node.setValid(false, false);
             node.markAsDeleted(true);
+            node.setDataLoaded(false);
+            node.getDelegationTarget().clear();
             return true;
          }
       }
@@ -136,14 +140,14 @@
       }
    }
 
-   private NodeSPI lookupInAllScopes(InvocationContext ctx, Fqn fqn)
+   private InternalNode lookupInAllScopes(InvocationContext ctx, Fqn fqn)
    {
-      NodeSPI nodeSPI = lookupForEviction(ctx, fqn);
+      ReadCommittedNode nodeSPI = (ReadCommittedNode) lookupForEviction(ctx, fqn);
       if (nodeSPI == null)
       {
-         nodeSPI = dataContainer.peek(fqn);
+         return dataContainer.peekInternalNode(fqn, true);
       }
-      return nodeSPI;
+      return nodeSPI.getDelegationTarget();
    }
 
    protected NodeSPI lookupForEviction(InvocationContext ctx, Fqn fqn)

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -4,6 +4,7 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.commands.WriteCommand;
@@ -67,7 +68,7 @@
     */
    public Object perform(InvocationContext ctx)
    {
-      if (to.isDirectChildOf(fqn))
+      if (fqn.isDirectChildOf(to))
       {
          if (log.isDebugEnabled()) log.debug("Attempting to move " + fqn + " onto itself.  Nothing to do.");
          return null;
@@ -99,10 +100,10 @@
    {
       if (trace) log.trace("Moving " + oldNode.getFqn() + " to " + newNode.getFqn());
       // start deep.
-      Map<Object, NodeSPI> children = oldNode.getChildrenMapDirect();
+      Map<Object, InternalNode> children = oldNode.getDelegationTarget().getChildrenMap();
       if (children != null && !children.isEmpty())
       {
-         for (NodeSPI child : children.values())
+         for (InternalNode child : children.values())
          {
             Fqn childFqn = child.getFqn();
             Fqn newChildFqn = childFqn.replaceAncestor(oldNode.getFqn(), newNode.getFqn());
@@ -111,7 +112,7 @@
       }
 
       // now swap the data for the current node.
-      newNode.putAllDirect(oldNode.getDataDirect());
+      newNode.getDelegationTarget().putAll(oldNode.getDelegationTarget().getData());
       oldNode.markAsDeleted(true);
    }
 

Deleted: core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/VersionedInvalidateCommand.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,181 +0,0 @@
-package org.jboss.cache.commands.write;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.CacheException;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
-import org.jboss.cache.commands.VersionedDataCommand;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.optimistic.DataVersioningException;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.util.Collections;
-
-/**
- * Behaves like {@link org.jboss.cache.commands.write.InvalidateCommand}. Also, potentially throws a cache exception if
- * data versioning is used and the node in memory has a newer data version than what is passed in.
- * <p/>
- * Finally, the data version of the in-memory node is updated to the version being evicted to prevent versions
- * going out of sync.
- * <p/>
- *
- * @author Mircea.Markus at jboss.com
- * @since 2.2
- */
-public class VersionedInvalidateCommand extends InvalidateCommand implements VersionedDataCommand
-{
-   private static final Log log = LogFactory.getLog(VersionedInvalidateCommand.class);
-   private static final boolean trace = log.isTraceEnabled();
-
-   /*
-     dependencies
-    */
-   private TransactionManager transactionManager;
-
-   /**
-    * Params.
-    */
-   protected GlobalTransaction globalTransaction;
-   private DataVersion dataVersion;
-
-   public VersionedInvalidateCommand(Fqn fqn)
-   {
-      super(fqn);
-   }
-
-   public VersionedInvalidateCommand()
-   {
-   }
-
-   public void initialize(TransactionManager txManager)
-   {
-      this.transactionManager = txManager;
-   }
-
-   @Override
-   public Object perform(InvocationContext ctx)
-   {
-      NodeSPI node = enforceNodeLoading();
-      if (trace) log.trace("Invalidating fqn:" + fqn);
-      if (node == null)
-      {
-         // check if a tombstone already exists
-         NodeSPI nodeSPI = dataContainer.peek(fqn, true, true);
-         if (nodeSPI == null)
-         {
-            if (dataVersion == null)
-            {
-               if (trace)
-                  log.trace("Would have created a tombstone since the node doesn't exist, but the version to invalidate is null and hence cannot create a tombstone!");
-               return null;
-            }
-            createTombstone(ctx);
-            nodeSPI = (NodeSPI) dataContainer.getRoot().getChild(fqn);
-         }
-         node = nodeSPI;
-      }
-      else if (node.getVersion() == null)
-      {
-         throw new NullPointerException("Node " + node.getFqn() + " has a null data version, and is of type " + node.getClass().getSimpleName() + ".  This command expects versioned nodes.");
-      }
-      else
-      if (dataVersion != null && node.getVersion().newerThan(dataVersion)) // dataVersion *could* be null if the invalidate was triggered by removing a node that did not exist in the first place.
-      {
-         String errMsg = new StringBuilder("Node found, but version is not equal to or less than the expected [").append(dataVersion).append("].  Is [").append(node.getVersion()).append("] instead!").toString();
-         log.warn(errMsg);
-         throw new DataVersioningException(errMsg);
-      }
-
-      removeData(node, ctx);
-      invalidateNode(node);
-      node.setVersion(dataVersion);
-      return null;
-   }
-
-   protected void createTombstone(InvocationContext ctx)
-   {
-      if (trace)
-         log.trace("Node doesn't exist; creating a tombstone with data version " + dataVersion);
-      // create the node we need.
-      Option o = ctx.getOptionOverrides();
-      boolean origCacheModeLocal = o.isCacheModeLocal();
-      o.setCacheModeLocal(true);
-      o.setDataVersion(dataVersion);
-      // if we are in a tx this call should happen outside of any tx
-      try
-      {
-         Transaction suspended = null;
-         if (transactionManager != null)
-         {
-            suspended = transactionManager.suspend();
-         }
-         spi.put(fqn, Collections.emptyMap());
-         if (suspended != null) transactionManager.resume(suspended);
-         ctx.getOptionOverrides().setCacheModeLocal(origCacheModeLocal);
-      }
-      catch (Exception e)
-      {
-         log.error("Unable to create tombstone!", e);
-      }
-   }
-
-   protected void removeData(NodeSPI n, InvocationContext ctx) throws CacheException
-   {
-      notifier.notifyNodeEvicted(fqn, true, ctx);
-      n.clearDataDirect();
-      n.setDataLoaded(false);
-      notifier.notifyNodeEvicted(fqn, false, ctx);
-   }
-
-   public DataVersion getDataVersion()
-   {
-      return dataVersion;
-   }
-
-   public void setDataVersion(DataVersion dataVersion)
-   {
-      this.dataVersion = dataVersion;
-   }
-
-   public GlobalTransaction getGlobalTransaction()
-   {
-      return globalTransaction;
-   }
-
-   public void setGlobalTransaction(GlobalTransaction gtx)
-   {
-      this.globalTransaction = gtx;
-   }
-
-   public boolean isVersioned()
-   {
-      return dataVersion != null;
-   }
-
-   @Override
-   public String toString()
-   {
-      return "OptimisticInvalidateCommand{" +
-            "dataVersion=" + dataVersion +
-            " ,fqn=" + fqn +
-            '}';
-   }
-
-   @Override
-   public Object[] getParameters()
-   {
-      return new Object[]{fqn, dataVersion};
-   }
-
-   @Override
-   public void setParameters(int commandId, Object[] args)
-   {
-      fqn = (Fqn) args[0];
-      dataVersion = (DataVersion) args[1];
-   }
-}

Modified: core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/factories/ComponentRegistry.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -177,6 +177,7 @@
       s.add(ContextMetaFactory.class);
       s.add(NodeMetaFactory.class);
       s.add(StateTransferManagerFactory.class);
+      s.add(StateTransferFactory.class);
       s.add(RegionManagerFactory.class);
       s.add(NodeMetaFactory.class);
       s.add(CommandsMetaFactory.class);

Copied: core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java (from rev 6358, core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,55 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache.factories;
+
+import org.jboss.cache.factories.annotations.DefaultFactoryFor;
+import org.jboss.cache.statetransfer.DefaultStateTransferGenerator;
+import org.jboss.cache.statetransfer.DefaultStateTransferIntegrator;
+import org.jboss.cache.statetransfer.LegacyStateTransferGenerator;
+import org.jboss.cache.statetransfer.LegacyStateTransferIntegrator;
+import org.jboss.cache.statetransfer.StateTransferGenerator;
+import org.jboss.cache.statetransfer.StateTransferIntegrator;
+
+/**
+ * Factory class able to create {@link org.jboss.cache.statetransfer.StateTransferGenerator} and
+ * {@link org.jboss.cache.statetransfer.StateTransferIntegrator} instances.
+ * <p/>
+ * Updated in 3.0.0 to extend ComponentFactory, etc.
+ * <p/>
+ *
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @author Manik Surtani
+ * @version $Revision$
+ */
+ at DefaultFactoryFor(classes = {StateTransferGenerator.class, StateTransferIntegrator.class})
+public class StateTransferFactory extends ComponentFactory
+{
+   protected <T> T construct(Class<T> componentType)
+   {
+
+      if (componentType.equals(StateTransferIntegrator.class))
+      {
+         switch (configuration.getNodeLockingScheme())
+         {
+            case MVCC:
+               return (T) new DefaultStateTransferIntegrator();
+            default:
+               return (T) new LegacyStateTransferIntegrator();
+         }
+      }
+      else
+      {
+         switch (configuration.getNodeLockingScheme())
+         {
+            case MVCC:
+               return (T) new DefaultStateTransferGenerator();
+            default:
+               return (T) new LegacyStateTransferGenerator();
+         }
+      }
+   }
+}


Property changes on: core/trunk/src/main/java/org/jboss/cache/factories/StateTransferFactory.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,8 +1,8 @@
 package org.jboss.cache.interceptors;
 
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 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;
@@ -95,7 +95,7 @@
    public Object visitGetChildrenNamesCommand(InvocationContext ctx, GetChildrenNamesCommand command) throws Throwable
    {
       Object returnValue = super.visitGetChildrenNamesCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -103,7 +103,7 @@
    public Object visitGetKeysCommand(InvocationContext ctx, GetKeysCommand command) throws Throwable
    {
       Object returnValue = super.visitGetKeysCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -111,7 +111,7 @@
    public Object visitGetNodeCommand(InvocationContext ctx, GetNodeCommand command) throws Throwable
    {
       Object returnValue = super.visitGetNodeCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -119,7 +119,7 @@
    public Object visitGetKeyValueCommand(InvocationContext ctx, GetKeyValueCommand command) throws Throwable
    {
       Object returnValue = super.visitGetKeyValueCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -133,7 +133,7 @@
    public Object visitPutKeyValueCommand(InvocationContext ctx, PutKeyValueCommand command) throws Throwable
    {
       Object returnValue = super.visitPutKeyValueCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -141,7 +141,7 @@
    public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
    {
       Object returnValue = super.visitPutDataMapCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -149,7 +149,7 @@
    public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
    {
       Object returnValue = super.visitRemoveKeyCommand(ctx, command);
-      removeNodeFromCacheLoader(ctx, command.getFqn());
+      removeNodeFromCacheLoader(command.getFqn());
       return returnValue;
    }
 
@@ -160,8 +160,8 @@
       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());
+      removeNodeFromCacheLoader(command.getFqn().getParent());
+      removeNodeFromCacheLoader(command.getTo());
       return returnValue;
    }
 
@@ -172,13 +172,13 @@
     * 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
+   private void removeNodeFromCacheLoader(Fqn fqn) throws Throwable
    {
-      NodeSPI n;
-      if (((n = dataContainer.peek(fqn, true, false)) != null) && n.isDataLoaded() && loader.exists(fqn))
+      InternalNode n;
+      if (((n = dataContainer.peekInternalNode(fqn, true)) != null) && n.isDataLoaded() && loader.exists(fqn))
       {
          // node not null and attributes have been loaded?
-         if (!n.getChildrenDirect().isEmpty())
+         if (n.hasChildren())
          {
             boolean result = childrenLoaded(n);
             if (result)
@@ -195,13 +195,13 @@
       }
    }
 
-   private static boolean childrenLoaded(NodeSPI<?, ?> node)
+   private static boolean childrenLoaded(InternalNode<?, ?> node)
    {
       if (!node.isChildrenLoaded())
       {
          return false;
       }
-      for (NodeSPI child : node.getChildrenDirect())
+      for (InternalNode child : node.getChildren())
       {
          if (!child.isDataLoaded())
          {
@@ -342,24 +342,24 @@
       private void handlePutCommand(InvocationContext ctx, Fqn fqn)
             throws Exception
       {
-         if (fqn != null && dataContainer.peek(fqn, false, false) != null && loader.exists(fqn))
+         if (fqn != null && dataContainer.exists(fqn) && loader.exists(fqn))
          {
-            NodeSPI n = dataContainer.peek(fqn, true, false);// don't load
+            InternalNode n = dataContainer.peekInternalNode(fqn, true);// 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)
+               if (n.hasChildren() && result)
                {
                   // children have been loaded, remove the node
-                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
                   txActs++;
                }
                // doesn't have children, check the cache loader
                else if (loaderNoChildren(fqn))
                {
-                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getDataDirect());
+                  addRemoveMod(ctx, cacheLoaderModifications, fqn, n.getData());
                   txActs++;
                }
             }

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -3,6 +3,7 @@
 import org.jboss.cache.CacheException;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.read.GetChildrenNamesCommand;
 import org.jboss.cache.commands.read.GetDataMapCommand;
@@ -155,8 +156,7 @@
       if (fqn != null)
       {
          loadIfNeeded(ctx, fqn, null, false, false, false, false, false, true, true);
-         NodeSPI n = dataContainer.peek(fqn, true, true);
-         loadChildren(fqn, n, false, false, ctx);
+         loadChildren(fqn, dataContainer.peekInternalNode(fqn, true), false, false, ctx);
       }
       return invokeNextInterceptor(ctx, command);
    }
@@ -266,7 +266,8 @@
             if (n == null && loader.exists(fqn))
             {
                // 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.
+               n = helper.wrapNodeForWriting(ctx, fqn, true, true, true, false, false);
+               n.setDataLoaded(false);
             }
             if (!bypassLoadingData)
             {
@@ -276,9 +277,9 @@
       }
 
       // The complete list of children aren't known without loading them
-      if (recursive)
+      if (recursive && n != null)
       {
-         loadChildren(fqn, n, recursive, isMove, ctx);
+         loadChildren(fqn, n.getDelegationTarget(), recursive, isMove, ctx);
       }
    }
 
@@ -288,7 +289,7 @@
     * @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
+   private void loadChildren(Fqn fqn, InternalNode node, boolean recursive, boolean isMove, InvocationContext ctxt) throws Throwable
    {
 
       if (node != null && node.isChildrenLoaded())
@@ -320,7 +321,7 @@
          {
             if (useCacheStore)
             {
-               node.removeChildrenDirect();//getChildrenMapDirect().clear();
+               node.removeChildren();
             }
             node.setChildrenLoaded(true);
          }
@@ -330,7 +331,8 @@
       // Create if node had not been created already
       if (node == null)
       {
-         node = helper.wrapNodeForWriting(ctxt, fqn, true, true, true, false, false);
+         NodeSPI temp = helper.wrapNodeForWriting(ctxt, fqn, true, true, true, false, false);
+         node = temp.getDelegationTarget();
       }
 
       // Create one DataNode per child, mark as UNINITIALIZED
@@ -340,6 +342,7 @@
 
          // create child if it didn't exist
          NodeSPI child = helper.wrapNodeForWriting(ctxt, childFqn, true, true, true, false, false);
+         if (child.isCreated()) child.setDataLoaded(false);
          if ((isMove || isActivation) && recursive)
          {
             // load data for children as well!
@@ -349,7 +352,7 @@
 
          if (recursive)
          {
-            loadChildren(child.getFqn(), child, true, isMove, ctxt);
+            loadChildren(child.getFqn(), child.getDelegationTarget(), true, isMove, ctxt);
          }
       }
       node.setChildrenLoaded(true);

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -160,7 +160,7 @@
          }
          else
          {
-            if (dataContainer.peek(command.getFqn(), false, false) == null)
+            if (!dataContainer.exists(command.getFqn()))
             {
                // gravitation is necessary.
 

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -9,7 +9,6 @@
 
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
 import org.jboss.cache.Region;
 import org.jboss.cache.RegionManager;
 import org.jboss.cache.commands.read.GetDataMapCommand;
@@ -237,12 +236,8 @@
          return;
       }
 
-      NodeSPI<?, ?> nodeSPI = dataContainer.peek(event.getFqn(), false, false);
       //we do not trigger eviction events for resident nodes
-      if (nodeSPI != null && nodeSPI.isResident())
-      {
-         return;
-      }
+      if (dataContainer.isResident(event.getFqn())) return;
 
       region.putNodeEvent(event);
 

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -11,6 +11,7 @@
 import org.jboss.cache.commands.CommandsFactory;
 import org.jboss.cache.commands.VisitableCommand;
 import org.jboss.cache.commands.WriteCommand;
+import org.jboss.cache.commands.legacy.write.VersionedInvalidateCommand;
 import org.jboss.cache.commands.tx.CommitCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
@@ -23,7 +24,6 @@
 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.commands.write.VersionedInvalidateCommand;
 import org.jboss.cache.config.Configuration.NodeLockingScheme;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.factories.annotations.Inject;

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -2,6 +2,7 @@
 
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeFactory;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.VisitableCommand;
@@ -30,7 +31,6 @@
 import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.lock.LockManager;
 import org.jboss.cache.mvcc.MVCCNodeHelper;
-import org.jboss.cache.mvcc.ReadCommittedNode;
 
 import java.util.Collections;
 import java.util.LinkedList;
@@ -130,11 +130,11 @@
       if (command.getFqn().isRoot())
       {
          // special treatment - deal with all of root's kids instead.
-         Map<Object, NodeSPI> children = dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+         Map<Object, InternalNode> children = dataContainer.peekInternalNode(Fqn.ROOT, false).getChildrenMap();
          if (children != null && !children.isEmpty())
          {
             fqnsToEvict = new LinkedList<Fqn>();
-            for (NodeSPI child : children.values())
+            for (InternalNode child : children.values())
                fqnsToEvict.addAll(helper.wrapNodesForWriting(ctx, child.getFqn()));
          }
          else
@@ -155,7 +155,7 @@
    {
       if (command.getFqn().isRoot())
       {
-         Map<Object, NodeSPI> children = dataContainer.peek(Fqn.ROOT).getChildrenMapDirect();
+         Map<Object, NodeSPI> children = dataContainer.peekInternalNode(Fqn.ROOT, false).getChildrenMap();
          if (children != null && !children.isEmpty())
          {
             for (NodeSPI child : children.values())
@@ -329,7 +329,7 @@
             {
                Fqn f = it.previous();
                // for each of these, swap refs
-               ReadCommittedNode rcn = (ReadCommittedNode) ctx.lookUpNode(f);
+               NodeSPI rcn = ctx.lookUpNode(f);
                if (rcn != null) rcn.commitUpdate(ctx, dataContainer, nodeFactory); // could be null with read-committed
                // and then unlock
                if (trace) log.trace("Releasing lock on [" + f + "] for thread " + owner);
@@ -363,7 +363,7 @@
             while (it.hasPrevious())
             {
                Fqn f = it.previous();
-               ReadCommittedNode rcn = (ReadCommittedNode) ctx.lookUpNode(f);
+               NodeSPI rcn = ctx.lookUpNode(f);
                if (rcn != null) // could be null with read-committed
                {
                   if (commit)

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -30,12 +30,14 @@
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.NonVolatile;
 import org.jboss.cache.interceptors.base.CommandInterceptor;
 import org.jboss.cache.loader.CacheLoaderManager;
 import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.mvcc.MVCCNodeHelper;
 import org.jboss.cache.notifications.Notifier;
 import org.jboss.cache.statetransfer.StateTransferManager;
 import org.jboss.cache.transaction.GlobalTransaction;
@@ -74,12 +76,13 @@
    private Marshaller marshaller;
    private DataContainer dataContainer;
    private CommandsFactory commandsFactory;
+   private MVCCNodeHelper mvccHelper;
 
    @Inject
    public void initialize(StateTransferManager stateTransferManager, CacheLoaderManager cacheLoaderManager, Notifier notifier,
                           TransactionManager transactionManager, BuddyManager buddyManager, TransactionTable transactionTable,
                           RPCManager rpcManager, RegionManager regionManager, Marshaller marshaller,
-                          CommandsFactory commandsFactory, DataContainer dataContainer)
+                          CommandsFactory commandsFactory, DataContainer dataContainer, MVCCNodeHelper mvccHelper)
    {
       this.stateTransferManager = stateTransferManager;
       this.cacheLoaderManager = cacheLoaderManager;
@@ -92,6 +95,7 @@
       this.marshaller = marshaller;
       this.dataContainer = dataContainer;
       this.commandsFactory = commandsFactory;
+      this.mvccHelper = mvccHelper;
    }
 
    private void reset()
@@ -248,15 +252,37 @@
    @SuppressWarnings("unchecked")
    public NodeSPI<K, V> peek(Fqn fqn, boolean includeDeletedNodes, boolean includeInvalidNodes)
    {
-      return (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes, includeInvalidNodes);
+      // TODO: clean this up somehow!  Anyway, this method should NOT be used outside of testing frameworks.
+      return (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+            ? mvccPeek(fqn)
+            : (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes, includeInvalidNodes);
    }
 
    @SuppressWarnings("unchecked")
    public NodeSPI<K, V> peek(Fqn fqn, boolean includeDeletedNodes)
    {
-      return (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes);
+      // TODO: clean this up somehow!  Anyway, this method should NOT be used outside of testing frameworks.
+      return (configuration.getNodeLockingScheme() == NodeLockingScheme.MVCC)
+            ? mvccPeek(fqn)
+            : (NodeSPI<K, V>) dataContainer.peek(fqn, includeDeletedNodes);
    }
 
+   @SuppressWarnings("unchecked")
+   private NodeSPI<K, V> mvccPeek(Fqn f)
+   {
+      NodeSPI<K, V> n;
+      try
+      {
+         n = mvccHelper.wrapNodeForReading(getInvocationContext(), f);
+      }
+      catch (InterruptedException e)
+      {
+         throw new CacheException(e);
+      }
+      if (n == null || n.isNullNode()) return null;
+      return n;
+   }
+
    public void addCacheListener(Object listener)
    {
       notifier.addCacheListener(listener);

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/NodeInvocationDelegate.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -4,9 +4,11 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.CacheException;
 import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InternalNode;
 import org.jboss.cache.Node;
+import org.jboss.cache.NodeFactory;
 import org.jboss.cache.NodeNotValidException;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.config.Option;
@@ -71,12 +73,12 @@
 
    public Map<Object, Node<K, V>> getChildrenMapDirect()
    {
-      return node.getChildrenMap();
+      return node.getChildrenMapDirect();
    }
 
    public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
    {
-      node.setChildrenMap(children);
+      node.setChildrenMapDirect(children);
    }
 
    public NodeSPI<K, V> getOrCreateChild(Object name, GlobalTransaction tx)
@@ -112,7 +114,7 @@
 
    public void addChild(Object nodeName, Node<K, V> nodeToAdd)
    {
-      node.addChild(nodeName, nodeToAdd);
+      node.addChildDirect(nodeName, nodeToAdd);
    }
 
    public void printDetails(StringBuilder sb, int indent)
@@ -137,7 +139,7 @@
 
    public Set<NodeSPI<K, V>> getChildrenDirect()
    {
-      return node.getChildren();
+      return node.getChildrenDirect();
    }
 
    public void removeChildrenDirect()
@@ -147,37 +149,37 @@
 
    public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedAsDeleted)
    {
-      return node.getChildren(includeMarkedAsDeleted);
+      return node.getChildrenDirect(includeMarkedAsDeleted);
    }
 
    public NodeSPI<K, V> getChildDirect(Object childName)
    {
-      return node.getChild(childName);
+      return node.getChildDirect(childName);
    }
 
    public NodeSPI<K, V> addChildDirect(Fqn childName)
    {
-      return node.addChild(childName);
+      return node.addChildDirect(childName);
    }
 
    public NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
    {
-      return node.addChild(f, notify);
+      return node.addChildDirect(f, notify);
    }
 
    public NodeSPI<K, V> addChildDirect(Object childName, boolean notify)
    {
-      return node.addChild(childName, notify);
+      return node.addChildDirect(childName, notify);
    }
 
    public void addChildDirect(NodeSPI<K, V> child)
    {
-      node.addChild(child);
+      node.addChildDirect(child);
    }
 
    public NodeSPI<K, V> getChildDirect(Fqn childName)
    {
-      return node.getChild(childName);
+      return node.getChildDirect(childName);
    }
 
    public boolean removeChildDirect(Fqn fqn)
@@ -516,4 +518,41 @@
    {
       return (node != null ? node.hashCode() : 0);
    }
+
+   // -------------- NO OP methods so that subclasses can work.  Specifically for MVCC, todo: rethink once we drop PL/OL support -----------
+   public boolean isNullNode()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory, boolean writeSkewCheck)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public boolean isChanged()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public boolean isCreated()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void setCreated(boolean b)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void rollbackUpdate()
+   {
+      throw new UnsupportedOperationException();
+   }
+
 }

Modified: core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/lock/LockUtil.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -28,7 +28,7 @@
       int STATUS_BROKEN = Integer.MIN_VALUE;
    }
 
-   public static boolean breakTransactionLock(NodeSPI node,
+   public static boolean breakTransactionLock(Fqn fqn,
                                               LockManager lockManager,
                                               GlobalTransaction gtx,
                                               boolean localTx,
@@ -38,9 +38,9 @@
       int tryCount = 0;
       int lastStatus = TransactionLockStatus.STATUS_BROKEN;
 
-      while (!broken && lockManager.ownsLock(node.getFqn(), gtx))
+      while (!broken && lockManager.ownsLock(fqn, gtx))
       {
-         int status = breakTransactionLock(gtx, node, lockManager, tx_table, tm, localTx, lastStatus, tryCount);
+         int status = breakTransactionLock(gtx, fqn, lockManager, tx_table, tm, localTx, lastStatus, tryCount);
          if (status == TransactionLockStatus.STATUS_BROKEN)
          {
             broken = true;
@@ -82,7 +82,7 @@
     *         if the lock held by gtx was forcibly broken.
     */
    private static int breakTransactionLock(GlobalTransaction gtx,
-                                           NodeSPI node, LockManager lockManager,
+                                           Fqn fqn, LockManager lockManager,
                                            TransactionTable transactionTable,
                                            TransactionManager tm,
                                            boolean localTx,
@@ -131,7 +131,7 @@
                   {
                      // Something is wrong; our initial rollback call
                      // didn't generate a valid state change; just force it
-                     lockManager.unlock(node.getFqn(), gtx);
+                     lockManager.unlock(fqn, gtx);
                      status = TransactionLockStatus.STATUS_BROKEN;
                   }
                   break;
@@ -148,7 +148,7 @@
                case Status.STATUS_COMMITTED:
                case Status.STATUS_ROLLEDBACK:
                case Status.STATUS_NO_TRANSACTION:
-                  lockManager.unlock(node.getFqn(), gtx);
+                  lockManager.unlock(fqn, gtx);
                   status = TransactionLockStatus.STATUS_BROKEN;
                   break;
 
@@ -180,14 +180,14 @@
 
                   // fall through and release
                default:
-                  lockManager.unlock(node.getFqn(), gtx);
+                  lockManager.unlock(fqn, gtx);
                   status = TransactionLockStatus.STATUS_BROKEN;
             }
          }
          catch (Exception e)
          {
             log.error("Exception breaking locks held by " + gtx, e);
-            lockManager.unlock(node.getFqn(), gtx);
+            lockManager.unlock(fqn, gtx);
             status = TransactionLockStatus.STATUS_BROKEN;
          }
       }
@@ -195,10 +195,10 @@
       {
          // Race condition; globalTransaction was cleared from txTable.
          // Just double check if globalTransaction still holds a lock
-         if (lockManager.ownsLock(node.getFqn(), gtx))
+         if (lockManager.ownsLock(fqn, gtx))
          {
             // perhaps we should throw an exception?
-            lockManager.unlock(node.getFqn(), gtx);
+            lockManager.unlock(fqn, gtx);
             status = TransactionLockStatus.STATUS_BROKEN;
          }
       }

Modified: core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/lock/MVCCLockManager.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -6,6 +6,7 @@
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.Node;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.factories.annotations.Inject;
@@ -21,6 +22,7 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.ListIterator;
+import java.util.Map;
 import java.util.Set;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import java.util.concurrent.locks.Lock;
@@ -134,7 +136,7 @@
       }
    }
 
-   protected boolean lockRecursively(Node<?, ?> node, long timeoutMillis, boolean excludeInternalFqns, InvocationContext ctx) throws InterruptedException
+   private boolean lockRecursively(InternalNode node, long timeoutMillis, boolean excludeInternalFqns, InvocationContext ctx) throws InterruptedException
    {
       if (excludeInternalFqns && internalFqns.contains(node.getFqn()))
          return true; // this will stop the recursion from proceeding down this subtree.
@@ -148,19 +150,17 @@
 
       // need to recursively walk through the node's children and acquire locks.  This needs to happen using API methods
       // since any cache loading will need to happen.
-      Set<? extends Node<?, ?>> children = node.getChildren();
+      //Set<InternalNode> children = node.getChildren();
+      Map<Object, InternalNode> children = node.getChildrenMap();
       try
       {
-         if (children != null)
+         for (InternalNode child : children.values())
          {
-            for (Node child : children)
+            locked = lockRecursively(child, timeoutMillis, excludeInternalFqns, ctx);
+            if (!locked)
             {
-               locked = lockRecursively(child, timeoutMillis, excludeInternalFqns, ctx);
-               if (!locked)
-               {
-                  needToUnlock = true;
-                  break;
-               }
+               needToUnlock = true;
+               break;
             }
          }
       }
@@ -168,7 +168,7 @@
       {
          if (needToUnlock)
          {
-            for (Node child : children)
+            for (InternalNode child : children.values())
             {
                Fqn childFqn = child.getFqn();
                unlock(childFqn, null);
@@ -184,30 +184,30 @@
    public boolean lockAll(NodeSPI node, LockType lockType, Object owner) throws InterruptedException
    {
       if (lockType == READ) return true; // we don't support read locks. TODO: enforce this with an assertion
-      return lockRecursively(node, lockAcquisitionTimeout, false, null);
+      return lockRecursively(node.getDelegationTarget(), lockAcquisitionTimeout, false, null);
    }
 
    public boolean lockAll(NodeSPI node, LockType lockType, Object owner, long timeout) throws InterruptedException
    {
       if (lockType == READ) return true; // we don't support read locks. TODO: enforce this with an assertion
-      return lockRecursively(node, timeout, false, null);
+      return lockRecursively(node.getDelegationTarget(), timeout, false, null);
    }
 
    public boolean lockAll(NodeSPI node, LockType lockType, Object owner, long timeout, boolean excludeInternalFqns) throws InterruptedException
    {
       if (lockType == READ) return true; // we don't support read locks. TODO: enforce this with an assertion
-      return lockRecursively(node, timeout, excludeInternalFqns, null);
+      return lockRecursively(node.getDelegationTarget(), timeout, excludeInternalFqns, null);
    }
 
    public boolean lockAllAndRecord(NodeSPI node, LockType lockType, InvocationContext ctx) throws InterruptedException
    {
       if (lockType == READ) return true; // we don't support read locks. TODO: enforce this with an assertion
-      return lockRecursively(node, ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout), false, ctx);
+      return lockRecursively(node.getDelegationTarget(), ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout), false, ctx);
    }
 
    public boolean lockAllAndRecord(Fqn fqn, LockType lockType, InvocationContext ctx) throws InterruptedException
    {
-      return lockAllAndRecord(dataContainer.peek(fqn, false), lockType, ctx);
+      return lockRecursively(dataContainer.peekInternalNode(fqn, false), ctx.getLockAcquisitionTimeout(lockAcquisitionTimeout), false, ctx);
    }
 
    public void unlockAll(NodeSPI<?, ?> node, Object owner)

Modified: core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/lock/NodeBasedLockManager.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -17,8 +17,10 @@
 /**
  * @author Mircea.Markus at jboss.com
  * @since 2.2
+ * @deprecated since this is specific to legacy locking schemes
  */
 @SuppressWarnings("deprecation")
+ at Deprecated
 public class NodeBasedLockManager extends AbstractLockManager
 {
    private static final Log log = LogFactory.getLog(NodeBasedLockManager.class);

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeFactory.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -58,31 +58,46 @@
       return rcn;
    }
 
-   private NodeSPI<K, V> initializeNodeInvocationDelegate(UnversionedNode<K, V> internal)
+//   private NodeSPI<K, V> initializeNodeInvocationDelegate(UnversionedNode<K, V> internal)
+//   {
+//      internal.injectDependencies(cache, commandsFactory, this);
+//
+//      // always assume that new nodes do not have data loaded
+//      internal.setDataLoaded(false);
+//      NodeSPI<K, V> nid = createNodeInvocationDelegate(internal, !useRepeatableRead);
+//
+//      // back reference
+//      internal.setDelegate(nid);
+//      return nid;
+//   }
+
+   @Override
+   public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data)
    {
-      internal.injectDependencies(cache, commandsFactory, this);
+//      UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn, cache, lockChildForInsertRemove, data);
+//      return initializeNodeInvocationDelegate(internal);
+      throw new UnsupportedOperationException();
+   }
 
-      // always assume that new nodes do not have data loaded
-      internal.setDataLoaded(false);
-      NodeSPI<K, V> nid = createNodeInvocationDelegate(internal, !useRepeatableRead);
-
-      // back reference
-      internal.setDelegate(nid);
-      return nid;
+   @Override
+   public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent)
+   {
+//      UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn, cache, lockChildForInsertRemove);
+//      return initializeNodeInvocationDelegate(internal);
+      throw new UnsupportedOperationException();
    }
 
    @Override
-   public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data)
+   public NodeSPI<K, V> createRootNode()
    {
-      UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn, cache, lockChildForInsertRemove, data);
-      return initializeNodeInvocationDelegate(internal);
+      return createWrappedNode(createInternalNode(Fqn.ROOT));
    }
 
    @Override
-   public NodeSPI<K, V> createNode(Fqn fqn, NodeSPI<K, V> parent)
+   public InternalNode<K, V> createInternalNode(Fqn fqn)
    {
-      UnversionedNode<K, V> internal = new UnversionedNode<K, V>(fqn, cache, lockChildForInsertRemove);
-      return initializeNodeInvocationDelegate(internal);
+      UnversionedNode<K, V> un = new UnversionedNode<K, V>(fqn, cache, lockChildForInsertRemove);
+      return useRepeatableRead ? un : new NodeReference<K, V>(un);
    }
 
    @Override
@@ -97,30 +112,30 @@
       return createNode(Fqn.fromRelativeElements(parent.getFqn(), childName), parent);
    }
 
-   @Override
-   public NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V> internalNode, boolean wrapWithNodeReference)
-   {
-      if (wrapWithNodeReference && internalNode instanceof NodeReference)
-         throw new IllegalArgumentException("Cannot wrap a NodeReference with a NodeReference!");
-      if (wrapWithNodeReference && useRepeatableRead)
-         throw new IllegalArgumentException("Cannot use NodeReferences with RepeatableRead!");
-      if (wrapWithNodeReference) internalNode = new NodeReference<K, V>(internalNode);
-      return super.createNodeInvocationDelegate(internalNode, false);
-   }
+//   @Override
+//   protected NodeSPI<K, V> createNodeInvocationDelegate(InternalNode<K, V> internalNode, boolean wrapWithNodeReference)
+//   {
+//      if (wrapWithNodeReference && internalNode instanceof NodeReference)
+//         throw new IllegalArgumentException("Cannot wrap a NodeReference with a NodeReference!");
+//      if (wrapWithNodeReference && useRepeatableRead)
+//         throw new IllegalArgumentException("Cannot use NodeReferences with RepeatableRead!");
+//      if (wrapWithNodeReference) internalNode = new NodeReference<K, V>(internalNode);
+//      return super.createNodeInvocationDelegate(internalNode, false);
+//   }
 
    @Override
-   public NodeSPI<K, V> createAndRegister(Fqn fqn, NodeSPI<K, V> parent, InvocationContext ctx, boolean attachToParent)
+   public InternalNode<K, V> createAndRegister(Fqn fqn, InternalNode<K, V> parent, InvocationContext ctx, boolean attachToParent)
    {
-      NodeSPI<K, V> child;
+      InternalNode<K, V> child;
       if (fqn == null) throw new IllegalArgumentException("null child fqn");
 
-      child = dataContainer.peek(fqn, false);
+      child = dataContainer.peekInternalNode(fqn, false);
 
       if (child == null)
       {
          cache.getNotifier().notifyNodeCreated(fqn, true, ctx);
-         NodeSPI<K, V> newChild = createNode(fqn, parent);
-         if (attachToParent) parent.addChildDirect(newChild);
+         InternalNode<K, V> newChild = createInternalNode(fqn);
+         if (attachToParent) parent.addChild(newChild);
          // addChild actually succeeded!
          child = newChild;
 

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/MVCCNodeHelper.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -13,8 +13,6 @@
 import org.jboss.cache.factories.annotations.NonVolatile;
 import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.invocation.NodeInvocationDelegate;
-import org.jboss.cache.lock.IsolationLevel;
 import org.jboss.cache.lock.LockManager;
 import static org.jboss.cache.lock.LockType.WRITE;
 import org.jboss.cache.lock.TimeoutException;
@@ -95,12 +93,12 @@
     * @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 ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws InterruptedException
+   public NodeSPI wrapNodeForReading(InvocationContext ctx, Fqn fqn) throws InterruptedException
    {
       return wrapNodeForReading(ctx, fqn, ctx.getOptionOverrides().isForceWriteLock());
    }
 
-   private ReadCommittedNode wrapNodeForReading(InvocationContext ctx, Fqn f, boolean writeLockForced) throws InterruptedException
+   private NodeSPI wrapNodeForReading(InvocationContext ctx, Fqn f, boolean writeLockForced) throws InterruptedException
    {
       NodeSPI n;
       if (writeLockForced)
@@ -120,7 +118,7 @@
       else
       {
          if (trace) log.trace("Node " + f + " is already in context.");
-         return (ReadCommittedNode) n;
+         return n;
       }
    }
 
@@ -166,10 +164,10 @@
     * @param force               if true, will force the write lock even if the node is null.
     * @return a wrapped node, or null.
     */
-   public ReadCommittedNode wrapNodeForWriting(InvocationContext context, Fqn fqn, boolean lockForWriting, boolean createIfAbsent, boolean includeInvalidNodes, boolean forRemoval, boolean force) throws InterruptedException
+   public NodeSPI wrapNodeForWriting(InvocationContext context, Fqn fqn, boolean lockForWriting, boolean createIfAbsent, boolean includeInvalidNodes, boolean forRemoval, boolean force) throws InterruptedException
    {
       Fqn parentFqn = null;
-      ReadCommittedNode n = (ReadCommittedNode) context.lookUpNode(fqn);
+      NodeSPI n = context.lookUpNode(fqn);
       if (createIfAbsent && n != null && n.isNullNode()) n = null;
       if (n != null) // exists in context!  Just acquire lock if needed, and wrap.
       {
@@ -209,7 +207,7 @@
             parentFqn = fqn.getParent();
             NodeSPI parent = wrapNodeForWriting(context, parentFqn, false, createIfAbsent, false, false, false);
             // do we need to lock the parent to create children?
-            boolean parentLockNeeded = isParentLockNeeded(parent);
+            boolean parentLockNeeded = isParentLockNeeded(parent.getDelegationTarget());
             // get a lock on the parent.
             if (parentLockNeeded && acquireLock(context, parentFqn))
             {
@@ -219,13 +217,12 @@
 
             // now to lock and create the node.  Lock first to prevent concurrent creation!
             acquireLock(context, fqn);
-//            NodeSPI temp = nodeFactory.createAndRegister(fqn, null, context, false);
+            in = nodeFactory.createAndRegister(fqn, null, context, false);
 
-            NodeSPI temp = parent.getOrCreateChild(fqn.getLastElement(), context.getGlobalTransaction());
-            parent.removeChildDirect(fqn.getLastElement());
+//            NodeSPI temp = parent.getOrCreateChild(fqn.getLastElement(), context.getGlobalTransaction());
+//            parent.removeChildDirect(fqn.getLastElement());
+//            in = ((NodeInvocationDelegate) temp).getDelegationTarget();
 
-
-            in = ((NodeInvocationDelegate) temp).getDelegationTarget();
             n = nodeFactory.createWrappedNode(in);
             n.setCreated(true);
             context.putLookedUpNode(fqn, n);
@@ -280,19 +277,21 @@
          if (parentLockNeeded && (needToCopyNode || needToCopyParent))
          {
             ReadCommittedNode parent = (ReadCommittedNode) ctx.lookUpNode(parentFqn);
-            parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node.getDelegationTarget(), configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
+            parent.getDelegationTarget().addChild(node.getDelegationTarget());
+
+//            parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node.getDelegationTarget(), configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
          }
 
          // now deal with children.
-         Map childMap = node.getChildrenMapDirect();
+//         Map childMap = node.getChildrenMapDirect();
+         Map<Object, InternalNode<?, ?>> childMap = node.getDelegationTarget().getChildrenMap();
          List<Fqn> fqnsToBeRemoved = new LinkedList<Fqn>();
          fqnsToBeRemoved.add(fqn);
          if (childMap == null || childMap.isEmpty()) return fqnsToBeRemoved;
 
-         for (Object n : childMap.values())
+         for (InternalNode n : childMap.values())
          {
-            NodeSPI child = (NodeSPI) n;
-            lockForWritingRecursive(child.getFqn(), ctx, fqnsToBeRemoved);
+            lockForWritingRecursive(n.getFqn(), ctx, fqnsToBeRemoved);
          }
 
          return fqnsToBeRemoved;
@@ -307,17 +306,25 @@
       if (fqnList != null) fqnList.add(fqn);
 
       // now wrap and add to the context
-      ReadCommittedNode rcn = wrapNodeForWriting(ctx, fqn, true, false, true, false, false);
+      NodeSPI rcn = wrapNodeForWriting(ctx, fqn, true, false, true, false, false);
       if (rcn != null)
       {
          rcn.markForUpdate(ctx, dataContainer, nodeFactory, writeSkewCheck);
-         ReadCommittedNode parent = (ReadCommittedNode) ctx.lookUpNode(fqn.getParent());
-         parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(rcn.getDelegationTarget(), configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
 
-         Map<Object, NodeSPI> children = rcn.getChildrenMapDirect();
+         // Why is this necessary again?!?? - Manik, 24Jul08
+
+//         NodeSPI parent = ctx.lookUpNode(fqn.getParent());
+//         parent.getDelegationTarget().addChild(rcn.getDelegationTarget());
+
+         // yukky logic.
+
+//         parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(rcn.getDelegationTarget(), configuration.getIsolationLevel() == IsolationLevel.READ_COMMITTED));
+
+//         Map<Object, NodeSPI> children = rcn.getChildrenMapDirect();
+         Map<Object, InternalNode<?, ?>> children = rcn.getDelegationTarget().getChildrenMap();
          if (children != null)
          {
-            for (NodeSPI child : children.values())
+            for (InternalNode child : children.values())
             {
                lockForWritingRecursive(child.getFqn(), ctx, fqnList);
             }
@@ -341,15 +348,15 @@
       }
    }
 
-   private boolean isParentLockNeeded(NodeSPI parent)
+   private boolean isParentLockNeeded(InternalNode parent)
    {
       return lockParentForChildInsertRemove || (parent != null && parent.isLockForChildInsertRemove());
    }
 
    private boolean isParentLockNeeded(Fqn parent, InvocationContext ctx)
    {
-      NodeSPI parentNode = ctx.lookUpNode(parent);
-      if (parentNode == null) parentNode = dataContainer.peek(parent, true, true);
-      return isParentLockNeeded(parentNode);
+      ReadCommittedNode parentNodeTmp = (ReadCommittedNode) ctx.lookUpNode(parent);
+      InternalNode in = parentNodeTmp == null ? dataContainer.peekInternalNode(parent, true) : parentNodeTmp.getDelegationTarget();
+      return isParentLockNeeded(in);
    }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -6,12 +6,14 @@
 import org.jboss.cache.InternalNode;
 import org.jboss.cache.Node;
 import org.jboss.cache.NodeSPI;
+import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.lock.NodeLock;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.transaction.GlobalTransaction;
 
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
 
 /**
  * A node reference that delegates all calls to a different {@link org.jboss.cache.InternalNode}.  Simple indirection
@@ -40,7 +42,7 @@
    /**
     * @return the InternalNode being delegated to.
     */
-   public InternalNode<K, V> getDelegate()
+   public final InternalNode<K, V> getDelegate()
    {
       return delegate;
    }
@@ -50,259 +52,319 @@
     *
     * @param delegate node to delegate to.
     */
-   public void setDelegate(InternalNode<K, V> delegate)
+   public final void setDelegate(InternalNode<K, V> delegate)
    {
       this.delegate = delegate;
    }
 
-   public NodeSPI<K, V> getParent()
+   public final NodeSPI<K, V> getParent()
    {
       return delegate.getParent();
    }
 
-   public CacheSPI<K, V> getCache()
+   public final CacheSPI<K, V> getCache()
    {
       return delegate.getCache();
    }
 
-   public boolean isChildrenLoaded()
+   public final boolean isChildrenLoaded()
    {
       return delegate.isChildrenLoaded();
    }
 
-   public void setChildrenLoaded(boolean flag)
+   public final void setChildrenLoaded(boolean flag)
    {
       delegate.setChildrenLoaded(flag);
    }
 
-   public V get(K key)
+   public final V get(K key)
    {
       return delegate.get(key);
    }
 
-   public Map<K, V> getData()
+   public final Map<K, V> getData()
    {
       return delegate.getData();
    }
 
-   public V put(K key, V value)
+   public final V put(K key, V value)
    {
       return delegate.put(key, value);
    }
 
-   public NodeSPI<K, V> getOrCreateChild(Object child_name, GlobalTransaction gtx)
+   public final NodeSPI<K, V> getOrCreateChild(Object child_name, GlobalTransaction gtx)
    {
       return delegate.getOrCreateChild(child_name, gtx);
    }
 
-   public V remove(K key)
+   public final InternalNode<K, V> getChild(Fqn f)
    {
-      return delegate.remove(key);
+      return delegate.getChild(f);
    }
 
-   public void addChild(NodeSPI child)
+   public final InternalNode<K, V> getChild(Object childName)
    {
+      return delegate.getChild(childName);
+   }
+
+   public final Set<InternalNode<K, V>> getChildren()
+   {
+      return delegate.getChildren();
+   }
+
+   public final Set<InternalNode<K, V>> getChildren(boolean includeMarkedForRemoval)
+   {
+      return delegate.getChildren(includeMarkedForRemoval);
+   }
+
+   public final ConcurrentMap<Object, InternalNode<K, V>> getChildrenMap()
+   {
+      return delegate.getChildrenMap();
+   }
+
+   public final void setChildrenMap(ConcurrentMap<Object, InternalNode<K, V>> children)
+   {
+      delegate.setChildrenMap(children);
+   }
+
+   public final void addChild(Object nodeName, InternalNode<K, V> nodeToAdd)
+   {
+      delegate.addChild(nodeName, nodeToAdd);
+   }
+
+   public final void addChild(InternalNode<K, V> child)
+   {
       delegate.addChild(child);
    }
 
-   public NodeSPI<K, V> addChild(Fqn f)
+   public final InternalNode<K, V> addChild(Fqn f)
    {
       return delegate.addChild(f);
    }
 
-   public NodeSPI<K, V> addChild(Fqn f, boolean notify)
+   public final InternalNode<K, V> addChild(Fqn f, boolean notify)
    {
       return delegate.addChild(f, notify);
    }
 
-   public NodeSPI<K, V> addChild(Object o, boolean notify)
+   public final InternalNode<K, V> addChild(Object o, boolean notify)
    {
       return delegate.addChild(o, notify);
    }
 
-   public void clear()
+   public final InternalNode<K, V> getOrCreateChild(Object childName, InvocationContext ctx)
    {
+      return delegate.getOrCreateChild(childName, ctx);
+   }
+
+   public final V remove(K key)
+   {
+      return delegate.remove(key);
+   }
+
+   public final NodeSPI<K, V> addChildDirect(Fqn f)
+   {
+      return delegate.addChildDirect(f);
+   }
+
+   public final NodeSPI<K, V> addChildDirect(Fqn f, boolean notify)
+   {
+      return delegate.addChildDirect(f, notify);
+   }
+
+   public final NodeSPI<K, V> addChildDirect(Object o, boolean notify)
+   {
+      return delegate.addChildDirect(o, notify);
+   }
+
+   public final void clear()
+   {
       delegate.clear();
    }
 
-   public NodeSPI<K, V> getChild(Fqn fqn)
+   public final NodeSPI<K, V> getChildDirect(Fqn fqn)
    {
-      return delegate.getChild(fqn);
+      return delegate.getChildDirect(fqn);
    }
 
-   public Set<Object> getChildrenNames()
+   public final Set<Object> getChildrenNames()
    {
       return delegate.getChildrenNames();
    }
 
-   public Set<K> getKeys()
+   public final Set<K> getKeys()
    {
       return delegate.getKeys();
    }
 
-   public boolean removeChild(Object childName)
+   public final void setInternalState(Map<K, V> state)
    {
+      delegate.setInternalState(state);
+   }
+
+   public final boolean removeChild(Object childName)
+   {
       return delegate.removeChild(childName);
    }
 
-   public boolean removeChild(Fqn f)
+   public final boolean removeChild(Fqn f)
    {
       return delegate.removeChild(f);
    }
 
-   public Map<Object, Node<K, V>> getChildrenMap()
+   public final Map<Object, Node<K, V>> getChildrenMapDirect()
    {
-      return delegate.getChildrenMap();
+      return delegate.getChildrenMapDirect();
    }
 
-   public void setChildrenMap(Map<Object, Node<K, V>> children)
+   public final void setChildrenMapDirect(Map<Object, Node<K, V>> children)
    {
-      delegate.setChildrenMap(children);
+      delegate.setChildrenMapDirect(children);
    }
 
-   public void putAll(Map<K, V> data)
+   public final void putAll(Map<K, V> data)
    {
       delegate.putAll(data);
    }
 
-   public void removeChildren()
+   public final void removeChildren()
    {
       delegate.removeChildren();
    }
 
-   public void setVersion(DataVersion version)
+   public final void setVersion(DataVersion version)
    {
       delegate.setVersion(version);
    }
 
-   public DataVersion getVersion()
+   public final DataVersion getVersion()
    {
       return delegate.getVersion();
    }
 
-   public Fqn getFqn()
+   public final Fqn getFqn()
    {
       return delegate.getFqn();
    }
 
-   public void setFqn(Fqn fqn)
+   public final void setFqn(Fqn fqn)
    {
       delegate.setFqn(fqn);
    }
 
-   public NodeSPI<K, V> getChild(Object childName)
+   public final NodeSPI<K, V> getChildDirect(Object childName)
    {
-      return delegate.getChild(childName);
+      return delegate.getChildDirect(childName);
    }
 
-   public Set<NodeSPI<K, V>> getChildren()
+   public final Set<NodeSPI<K, V>> getChildrenDirect()
    {
-      return delegate.getChildren();
+      return delegate.getChildrenDirect();
    }
 
-   public boolean hasChildren()
+   public final boolean hasChildren()
    {
       return delegate.hasChildren();
    }
 
-   public Set<NodeSPI<K, V>> getChildren(boolean includeMarkedForRemoval)
+   public final Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
    {
-      return delegate.getChildren(includeMarkedForRemoval);
+      return delegate.getChildrenDirect(includeMarkedForRemoval);
    }
 
-   public boolean isDataLoaded()
+   public final boolean isDataLoaded()
    {
       return delegate.isDataLoaded();
    }
 
-   public void setDataLoaded(boolean dataLoaded)
+   public final void setDataLoaded(boolean dataLoaded)
    {
       delegate.setDataLoaded(dataLoaded);
    }
 
-   public boolean isValid()
+   public final boolean isValid()
    {
       return delegate.isValid();
    }
 
-   public void setValid(boolean valid, boolean recursive)
+   public final void setValid(boolean valid, boolean recursive)
    {
       delegate.setValid(valid, recursive);
    }
 
-   public boolean isLockForChildInsertRemove()
+   public final boolean isLockForChildInsertRemove()
    {
       return delegate.isLockForChildInsertRemove();
    }
 
-   public void setLockForChildInsertRemove(boolean lockForChildInsertRemove)
+   public final void setLockForChildInsertRemove(boolean lockForChildInsertRemove)
    {
       delegate.setLockForChildInsertRemove(lockForChildInsertRemove);
    }
 
-   public void setInternalState(Map state)
+   public final Map getInternalState(boolean onlyInternalState)
    {
-      delegate.setInternalState(state);
-   }
-
-   public Map getInternalState(boolean onlyInternalState)
-   {
       return delegate.getInternalState(onlyInternalState);
    }
 
-   public void releaseObjectReferences(boolean recursive)
+   public final void releaseObjectReferences(boolean recursive)
    {
       delegate.releaseObjectReferences(recursive);
    }
 
-   public boolean isRemoved()
+   public final boolean isRemoved()
    {
       return delegate.isRemoved();
    }
 
-   public void setRemoved(boolean marker)
+   public final void setRemoved(boolean marker)
    {
       delegate.setRemoved(marker);
    }
 
-   public void markAsRemoved(boolean marker, boolean recursive)
+   public final void markAsRemoved(boolean marker, boolean recursive)
    {
       delegate.markAsRemoved(marker, recursive);
    }
 
-   public void setResident(boolean resident)
+   public final void setResident(boolean resident)
    {
       delegate.setResident(resident);
    }
 
-   public boolean isResident()
+   public final boolean isResident()
    {
       return delegate.isResident();
    }
 
-   public InternalNode<K, V> copy()
+   public final InternalNode<K, V> copy()
    {
       InternalNode<K, V> cloneDelegate = delegate.copy();
       return new NodeReference<K, V>(cloneDelegate);
    }
 
-   public NodeLock getLock()
+   public final NodeLock getLock()
    {
       return delegate.getLock();
    }
 
-   public void addChild(Object nodeName, Node<K, V> nodeToAdd)
+   public final void addChildDirect(Object nodeName, Node<K, V> nodeToAdd)
    {
-      delegate.addChild(nodeName, nodeToAdd);
+      delegate.addChildDirect(nodeName, nodeToAdd);
    }
 
-   public void printDetails(StringBuilder sb, int indent)
+   public final void addChildDirect(NodeSPI<K, V> child)
    {
+      delegate.addChildDirect(child);
+   }
+
+   public final void printDetails(StringBuilder sb, int indent)
+   {
       delegate.printDetails(sb, indent);
    }
 
    @Override
-   public String toString()
+   public final String toString()
    {
       return "NodeReference{" +
             "delegate=" + delegate +
@@ -310,7 +372,7 @@
    }
 
    @Override
-   public boolean equals(Object o)
+   public final boolean equals(Object o)
    {
       if (this == o) return true;
       if (o == null || getClass() != o.getClass()) return false;
@@ -323,7 +385,7 @@
    }
 
    @Override
-   public int hashCode()
+   public final int hashCode()
    {
       return (delegate != null ? delegate.hashCode() : 0);
    }

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/ReadCommittedNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -73,20 +73,13 @@
       flags &= ~flag.mask;
    }
 
+   @Override
    public boolean isNullNode()
    {
       return false;
    }
 
-   /**
-    * Marks a node for updating.  Internally, this creates a copy of the delegate and performs any checks necessary to
-    * maintain isolation level.
-    *
-    * @param ctx            invocation context
-    * @param container      data container
-    * @param nodeFactory    node factory for creating new nodes/copies.
-    * @param writeSkewCheck if true, and the node supports write skew checking, nodes are tested for write skews.
-    */
+   @Override
    public void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory, boolean writeSkewCheck)
    {
       if (isFlagSet(CHANGED)) return; // already copied
@@ -100,13 +93,7 @@
       }
    }
 
-   /**
-    * Commits any updates made on this node to the underlying data structure, making it visible to all other transactions.
-    *
-    * @param ctx         invocation context
-    * @param container   data container
-    * @param nodeFactory node factory
-    */
+   @Override
    public void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory)
    {
       if (isFlagSet(CHANGED))
@@ -120,8 +107,8 @@
          {
             if (!fqn.isRoot())
             {
-               NodeSPI parent = lookupParent(fqn, ctx, container);
-               parent.removeChildDirect(fqn.getLastElement());
+               InternalNode parent = lookupParent(fqn, ctx, container);
+               parent.removeChild(fqn.getLastElement());
                setValid(false, false);
                updateNode(ctx, container, nodeFactory);
             }
@@ -133,8 +120,9 @@
          else if (isFlagSet(CREATED))
          {
             // add newly created nodes to parents.
-            NodeSPI parent = lookupParent(fqn, ctx, container);
-            parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node, false));
+            InternalNode parent = lookupParent(fqn, ctx, container);
+//            parent.addChildDirect(nodeFactory.createNodeInvocationDelegate(node, false));
+            parent.addChild(node);
          }
          else
          {
@@ -161,15 +149,22 @@
     * @return Parent node, never null.
     * @throws NodeNotExistsException if the parent node cannot be found in any scope or data container.
     */
-   protected final NodeSPI lookupParent(Fqn fqn, InvocationContext ctx, DataContainer container) throws NodeNotExistsException
+   protected final InternalNode lookupParent(Fqn fqn, InvocationContext ctx, DataContainer container) throws NodeNotExistsException
    {
+      InternalNode retval;
       Fqn parentFqn = fqn.getParent();
       NodeSPI parent = ctx.lookUpNode(parentFqn);
-      if (parent != null) return parent;
-      parent = container.peek(parentFqn);
-      if (parent == null)
+      if (parent != null)
+      {
+         retval = parent.getDelegationTarget();
+      }
+      else
+      {
+         retval = container.peekInternalNode(parentFqn, false);
+      }
+      if (retval == null)
          throw new NodeNotExistsException("Node " + parentFqn + " cannot be found in any context or data container!");
-      return parent;
+      return retval;
    }
 
    /**
@@ -186,28 +181,26 @@
       node = backup;
    }
 
+   @Override
    public void rollbackUpdate()
    {
       node = backup;
       reset();
    }
 
-   /**
-    * @return true if this node has been marked for update, false otherwise.
-    */
+   @Override
    public boolean isChanged()
    {
       return isFlagSet(CHANGED);
    }
 
-   /**
-    * @return true if this node has been newly created in the current scope.
-    */
+   @Override
    public boolean isCreated()
    {
       return isFlagSet(CREATED);
    }
 
+   @Override
    public void setCreated(boolean created)
    {
       if (created)

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/RepeatableReadNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -6,9 +6,7 @@
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeFactory;
-import org.jboss.cache.NodeSPI;
 import org.jboss.cache.invocation.InvocationContext;
-import org.jboss.cache.invocation.NodeInvocationDelegate;
 import static org.jboss.cache.mvcc.ReadCommittedNode.Flags.CHANGED;
 import static org.jboss.cache.mvcc.ReadCommittedNode.Flags.DELETED;
 import org.jboss.cache.optimistic.DataVersioningException;
@@ -41,9 +39,9 @@
       if (writeSkewCheck)
       {
          // check for write skew.
-         NodeInvocationDelegate underlyingNode = (NodeInvocationDelegate) container.peek(fqn, false, true);  // even check for invalid nodes.  we should check tombstones too.
+         InternalNode underlyingNode = container.peekInternalNode(fqn, true);
 
-         if (underlyingNode != null && underlyingNode.getDelegationTarget() != node)
+         if (underlyingNode != null && underlyingNode != node)
          {
             String errormsg = new StringBuilder().append("Detected write skew on Fqn [").append(fqn).append("].  Another process has changed the node since we last read it!").toString();
             if (log.isWarnEnabled()) log.warn(errormsg + ".  Unable to copy node for update.");
@@ -61,12 +59,12 @@
    {
       if (getFqn().isRoot())
       {
-         dataContainer.setRoot(nf.createNodeInvocationDelegate(node, false));
+         dataContainer.setRoot(node);
       }
       else if (!isFlagSet(DELETED))
       {
-         NodeSPI parent = lookupParent(getFqn(), ctx, dataContainer);
-         parent.addChildDirect(nf.createNodeInvocationDelegate(node, false));
+         InternalNode parent = lookupParent(getFqn(), ctx, dataContainer);
+         parent.addChild(node);
       }
    }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNode.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -25,8 +25,10 @@
  * @author Steve Woodcock (<a href="mailto:stevew at jofti.com">stevew at jofti.com</a>)
  * @since 1.3.0
  */
-public interface WorkspaceNode<K, V> extends Node<K, V>
+public interface WorkspaceNode<K, V>// extends Node<K, V>
 {
+   Fqn getFqn();
+
    /**
     * Returns 2 Sets - a set of children added (first set) and a set of children removed.
     *
@@ -129,7 +131,7 @@
     * @param o node name
     * @return a child node
     */
-   NodeSPI<K, V> getChild(Object o);
+   NodeSPI<K, V> getChildDirect(Object o);
 
    /**
     * Overrides {@link Node#getChild(Fqn)} to return a {@link org.jboss.cache.NodeSPI} rather than a {@link org.jboss.cache.Node}
@@ -137,7 +139,7 @@
     * @param f node fqn
     * @return a child node
     */
-   NodeSPI<K, V> getChild(Fqn f);
+   NodeSPI<K, V> getChildDirect(Fqn f);
 
    /**
     * Adds a given WorkspaceNode to the current node's child map
@@ -173,4 +175,22 @@
    void setRemoved(boolean marker);
 
    void markAsRemoved(boolean marker, boolean recursive);
+
+   void clearData();
+
+   Map<K, V> getData();
+
+   V remove(K removeKey);
+
+   V get(K key);
+
+   Set<K> getKeys();
+
+   Set<Object> getChildrenNames();
+
+   boolean removeChild(Object nodeName);
+
+   void putAll(Map<K, V> data);
+
+   V put(K key, V value);
 }

Modified: core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/optimistic/WorkspaceNodeImpl.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -112,7 +112,19 @@
    @Override
    public void markAsRemoved(boolean marker, boolean recursive)
    {
-      super.markAsRemoved(marker, recursive);
+      setFlag(NodeFlags.REMOVED, marker);
+
+      if (recursive && children != null)
+      {
+         synchronized (this)
+         {
+            for (Object child : children.values())
+            {
+               ((NodeSPI) child).markAsDeleted(marker, true);
+            }
+         }
+      }
+
       if (marker)
       {
          if (childrenAdded != null) childrenAdded.clear();
@@ -255,23 +267,18 @@
       setFlag(VERSIONING_IMPLICIT, versioningImplicit);
    }
 
-   public NodeSPI<K, V> getChild(Object childName)
-   {
-      //see if in the the transaction map
-//      return optimisticChildNodeMap.get(childName);
-      throw new UnsupportedOperationException("This call should be intercepted by the optimisticNodeInterceptor and the child node should be retrieved from the workspace.");
-   }
-
    public NodeSPI<K, V> getNode()
    {
       return node;
    }
 
+   @Override
    public DataVersion getVersion()
    {
       return version;
    }
 
+   @Override
    public void setVersion(DataVersion version)
    {
       this.version = version;
@@ -339,10 +346,11 @@
       return getClass().getSimpleName() + " [ fqn=" + getFqn() + " " + sb + "ver=" + version + " " + (isVersioningImplicit() ? "implicit" : "explicit") + "]";
    }
 
-   public Node<K, V> addChild(Fqn f)
+   @Override
+   public NodeSPI<K, V> addChildDirect(Fqn f)
    {
       CacheSPI cache = getCache();
-      Node<K, V> newNode = this;
+      NodeSPI<K, V> newNode = null;
       GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
 
       if (f.size() == 1)
@@ -352,7 +360,7 @@
       else
       {
          // recursively create children
-         Node<K, V> currentParent = this;
+         NodeSPI<K, V> currentParent = this.getNode();
          for (Object o : f.peekElements())
          {
             if (currentParent instanceof WorkspaceNode)
@@ -367,7 +375,7 @@
                }
                else
                {
-                  newNode = ((NodeSPI<K, V>) currentParent).getOrCreateChild(o, gtx);
+                  newNode = currentParent.getOrCreateChild(o, gtx);
                }
             }
             currentParent = newNode;
@@ -422,16 +430,18 @@
       throw new UnsupportedOperationException();
    }
 
-   public NodeSPI<K, V> getChild(Fqn f)
+   @Override
+   public NodeSPI<K, V> getChildDirect(Fqn f)
    {
       if (f.size() > 1)
       {
          throw new UnsupportedOperationException("Workspace node does not support fetching indirect children");
       }
-      return getChild(f.getLastElement());
+      return getChildDirect(f.getLastElement());
    }
 
-   public Set<Node<K, V>> getChildren()
+   @Override
+   public Set getChildren()
    {
       throw new UnsupportedOperationException();
    }

Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -10,9 +10,11 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.Node;
-import org.jboss.cache.NodeSPI;
 import org.jboss.cache.Version;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.loader.CacheLoader;
 import org.jboss.cache.marshall.NodeData;
 import org.jboss.cache.marshall.NodeDataExceptionMarker;
@@ -35,16 +37,22 @@
 
    private Set<Fqn> internalFqns;
 
-   protected DefaultStateTransferGenerator(CacheSPI cache)
+   @Inject
+   public void inject(CacheSPI cache)
    {
       this.cache = cache;
+   }
+
+   @Start(priority = 18)
+   private void start()
+   {
       this.internalFqns = cache.getInternalFqns();
    }
 
-   public void generateState(ObjectOutputStream out, Node rootNode, boolean generateTransient,
+   public void generateState(ObjectOutputStream out, Object rootNode, boolean generateTransient,
                              boolean generatePersistent, boolean suppressErrors) throws Exception
    {
-      Fqn fqn = rootNode.getFqn();
+      Fqn fqn = getFqn(rootNode);
       try
       {
          cache.getMarshaller().objectToObjectStream(STATE_TRANSFER_VERSION, out);
@@ -55,8 +63,7 @@
             {
                log.trace("writing transient state for " + fqn);
             }
-            marshallTransientState((NodeSPI) rootNode, out);
-            delimitStream(out);
+            marshallTransientState((InternalNode) rootNode, out);
 
             if (log.isTraceEnabled())
             {
@@ -69,7 +76,6 @@
                log.trace("writing associated state");
             }
 
-            marshallAssociatedState(fqn, out);
             delimitStream(out);
 
             if (log.isTraceEnabled())
@@ -116,6 +122,13 @@
       }
    }
 
+   private Fqn getFqn(Object o)
+   {
+      if (o instanceof Node) return ((Node) o).getFqn();
+      if (o instanceof InternalNode) return ((InternalNode) o).getFqn();
+      throw new IllegalArgumentException();
+   }
+
    /**
     * Places a delimiter marker on the stream
     *
@@ -133,14 +146,14 @@
     * @param out
     * @throws Exception
     */
-   protected void marshallTransientState(NodeSPI node, ObjectOutputStream out) throws Exception
+   protected void marshallTransientState(InternalNode node, ObjectOutputStream out) throws Exception
    {
       List<NodeData> nodeData = new LinkedList<NodeData>();
       generateNodeDataList(node, nodeData);
       cache.getMarshaller().objectToObjectStream(nodeData, out, node.getFqn());
    }
 
-   protected void generateNodeDataList(NodeSPI<?, ?> node, List<NodeData> list) throws Exception
+   protected void generateNodeDataList(InternalNode<?, ?> node, List<NodeData> list) throws Exception
    {
       if (internalFqns.contains(node.getFqn()))
       {
@@ -165,14 +178,6 @@
       list.add(nd);
 
       // then visit the children
-      for (NodeSPI child : node.getChildrenDirect()) generateNodeDataList(child, list);
+      for (InternalNode child : node.getChildren()) generateNodeDataList(child, list);
    }
-
-   /**
-    * Does nothing in this base class; can be overridden in a subclass.
-    */
-   protected void marshallAssociatedState(Fqn fqn, ObjectOutputStream baos) throws Exception
-   {
-      // no-op in this base class      
-   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -11,13 +11,14 @@
 import org.jboss.cache.CacheException;
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeFactory;
-import org.jboss.cache.NodeSPI;
 import org.jboss.cache.Region;
 import org.jboss.cache.buddyreplication.BuddyManager;
 import org.jboss.cache.eviction.EvictedEventNode;
 import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.loader.CacheLoader;
 import org.jboss.cache.loader.CacheLoaderManager;
@@ -42,28 +43,34 @@
 
    private CacheSPI cache;
 
-   private Fqn targetFqn;
-
    private NodeFactory factory;
 
    private Set<Fqn> internalFqns;
 
-   public DefaultStateTransferIntegrator(Fqn targetFqn, CacheSPI<?, ?> cache, NodeFactory nodefactory)
+   @Inject
+   public void inject(CacheSPI<?, ?> cache, NodeFactory nodefactory)
    {
-      this.targetFqn = targetFqn;
       this.cache = cache;
       this.factory = nodefactory;
+   }
+
+   @Start(priority = 14)
+   public void start()
+   {
       this.internalFqns = cache.getInternalFqns();
    }
 
-   public void integrateState(ObjectInputStream ois, Node target) throws Exception
+   public void integrateState(ObjectInputStream ois, Object target, Fqn targetRoot) throws Exception
    {
-      integrateTransientState(ois, (NodeSPI) target);
+      // pop version from the stream first!
+      short version = (Short) cache.getMarshaller().objectFromObjectStream(ois);
+      log.info("Using version " + version);
+      integrateTransientState(ois, (InternalNode) target);
       integrateAssociatedState(ois);
-      integratePersistentState(ois);
+      integratePersistentState(ois, targetRoot);
    }
 
-   protected void integrateTransientState(ObjectInputStream in, NodeSPI target) throws Exception
+   protected void integrateTransientState(ObjectInputStream in, InternalNode target) throws Exception
    {
       boolean transientSet = false;
       try
@@ -92,11 +99,9 @@
       {
          if (!transientSet)
          {
-            target.clearDataDirect();
-            target.removeChildrenDirect();
+            target.clear();
+            target.removeChildren();
          }
-
-//         resetClassLoader(oldCL);
       }
    }
 
@@ -112,7 +117,7 @@
       cache.getMarshaller().objectFromObjectStream(in);
    }
 
-   protected void integratePersistentState(ObjectInputStream in) throws Exception
+   protected void integratePersistentState(ObjectInputStream in, Fqn targetFqn) throws Exception
    {
 
       CacheLoaderManager loaderManager = cache.getCacheLoaderManager();
@@ -169,66 +174,32 @@
       }
    }
 
-   protected NodeFactory getFactory()
-   {
-      return factory;
-   }
-
-   protected Fqn getTargetFqn()
-   {
-      return targetFqn;
-   }
-
    /**
     * Generates NodeAdded notifications for all nodes of the tree. This is
     * called whenever the tree is initially retrieved (state transfer)
     */
-   private void notifyAllNodesCreated(InvocationContext ctx, NodeSPI curr)
+   private void notifyAllNodesCreated(InvocationContext ctx, InternalNode curr)
    {
       if (curr == null) return;
       ctx.setOriginLocal(false);
       cache.getNotifier().notifyNodeCreated(curr.getFqn(), true, ctx);
       cache.getNotifier().notifyNodeCreated(curr.getFqn(), false, ctx);
       // AND notify that they have been modified!!
-      if (!curr.getKeysDirect().isEmpty())
+      if (!curr.getKeys().isEmpty())
       {
          cache.getNotifier().notifyNodeModified(curr.getFqn(), true, NodeModifiedEvent.ModificationType.PUT_MAP, Collections.emptyMap(), ctx);
-         cache.getNotifier().notifyNodeModified(curr.getFqn(), false, NodeModifiedEvent.ModificationType.PUT_MAP, curr.getDataDirect(), ctx);
+         cache.getNotifier().notifyNodeModified(curr.getFqn(), false, NodeModifiedEvent.ModificationType.PUT_MAP, curr.getData(), ctx);
       }
       ctx.setOriginLocal(true);
 
-      Set<NodeSPI> children = curr.getChildrenDirect();
-      for (NodeSPI n : children)
-      {
-         notifyAllNodesCreated(ctx, n);
-      }
+      Set<InternalNode> children = curr.getChildren();
+      for (InternalNode n : children) notifyAllNodesCreated(ctx, n);
    }
 
-   /*
-   private ClassLoader setClassLoader(ClassLoader newLoader)
+   private void integrateTransientState(InternalNode target, ObjectInputStream in) throws Exception
    {
-      ClassLoader oldClassLoader = null;
-      if (newLoader != null)
-      {
-         oldClassLoader = Thread.currentThread().getContextClassLoader();
-         Thread.currentThread().setContextClassLoader(newLoader);
-      }
-      return oldClassLoader;
-   }
+      target.removeChildren();
 
-   private void resetClassLoader(ClassLoader oldLoader)
-   {
-      if (oldLoader != null)
-      {
-         Thread.currentThread().setContextClassLoader(oldLoader);
-      }
-   }
-   */
-
-   private void integrateTransientState(NodeSPI target, ObjectInputStream in) throws Exception
-   {
-      target.removeChildrenDirect();
-
       List<NodeData> list = readNodesAsList(in);
       if (list != null)
       {
@@ -276,7 +247,7 @@
       return (List<NodeData>) obj;
    }
 
-   private NodeData integrateStateTransferChildren(NodeSPI parent, int offset, Iterator<NodeData> nodeDataIterator)
+   private NodeData integrateStateTransferChildren(InternalNode parent, int offset, Iterator<NodeData> nodeDataIterator)
          throws IOException, ClassNotFoundException
    {
       int parent_level = parent.getFqn().size();
@@ -305,10 +276,9 @@
 
          Map attrs = nd.getAttributes();
 
-         // We handle this NodeData.  Create a TreeNode and
-         // integrate its data
-         NodeSPI target = factory.createNode(fqn, parent, attrs);
-         parent.addChild(fqn.getLastElement(), target);
+         InternalNode internalTarget = factory.createInternalNode(fqn);
+         internalTarget.setInternalState(attrs);
+         parent.addChild(internalTarget);
 
          // JBCACHE-913
          Region region = cache.getRegion(fqn, false);
@@ -320,7 +290,7 @@
 
          // Recursively call, which will walk down the tree
          // and return the next NodeData that's a child of our parent
-         nd = integrateStateTransferChildren(target, offset, nodeDataIterator);
+         nd = integrateStateTransferChildren(internalTarget, offset, nodeDataIterator);
       }
       if (nd != null && nd.isExceptionMarker())
       {
@@ -331,15 +301,15 @@
       return null;
    }
 
-   private Set<Node> retainInternalNodes(Node target)
+   private Set<InternalNode> retainInternalNodes(InternalNode target)
    {
-      Set<Node> result = new HashSet<Node>();
+      Set<InternalNode> result = new HashSet<InternalNode>();
       Fqn targetFqn = target.getFqn();
       for (Fqn internalFqn : internalFqns)
       {
          if (internalFqn.isChildOf(targetFqn))
          {
-            Node internalNode = getInternalNode(target, internalFqn);
+            InternalNode internalNode = getInternalNode(target, internalFqn);
             if (internalNode != null)
             {
                result.add(internalNode);
@@ -350,11 +320,10 @@
       return result;
    }
 
-   private Node getInternalNode(Node parent, Fqn internalFqn)
+   private InternalNode getInternalNode(InternalNode parent, Fqn internalFqn)
    {
       Object name = internalFqn.get(parent.getFqn().size());
-      cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
-      Node result = parent.getChild(name);
+      InternalNode result = parent.getChild(name);
       if (result != null)
       {
          if (internalFqn.size() < result.getFqn().size())
@@ -366,11 +335,11 @@
       return result;
    }
 
-   private void integrateRetainedNodes(NodeSPI target)
+   private void integrateRetainedNodes(InternalNode target)
    {
-      Set<Node> retainedNodes = retainInternalNodes(target);
+      Set<InternalNode> retainedNodes = retainInternalNodes(target);
       Fqn rootFqn = target.getFqn();
-      for (Node retained : retainedNodes)
+      for (InternalNode retained : retainedNodes)
       {
          if (retained.getFqn().isChildOf(rootFqn))
          {
@@ -379,12 +348,12 @@
       }
    }
 
-   private void integrateRetainedNode(NodeSPI ancestor, Node descendant)
+   private void integrateRetainedNode(InternalNode ancestor, InternalNode descendant)
    {
       Fqn descFqn = descendant.getFqn();
       Fqn ancFqn = ancestor.getFqn();
       Object name = descFqn.get(ancFqn.size());
-      NodeSPI child = (NodeSPI) ancestor.getChild(name);
+      InternalNode child = ancestor.getChild(name);
       if (ancFqn.size() == descFqn.size() + 1)
       {
          if (child == null)
@@ -403,8 +372,11 @@
             // Missing level -- have to create empty node
             // This shouldn't really happen -- internal fqns should
             // be immediately under the root
-            child = factory.createNode(name, ancestor);
-            ancestor.addChild(name, child);
+//            child = factory.createInternalNode(name, ancestor);
+//            ancestor.addChild(name, child);
+
+            // since this shouldn't happen, deal with it. - Manik - Jul08
+            throw new NullPointerException("Child is null");
          }
 
          // Keep walking down the tree

Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferManager.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -11,6 +11,7 @@
 import org.jboss.cache.CacheException;
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.NodeFactory;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.RegionEmptyException;
@@ -43,14 +44,16 @@
    protected RegionManager regionManager;
    protected Configuration configuration;
    private CacheLoaderManager cacheLoaderManager;
-   private boolean fetchTransientState;
-   private boolean fetchPersistentState;
-   private long stateRetrievalTimeout;
+   boolean fetchTransientState;
+   boolean fetchPersistentState;
+   protected long stateRetrievalTimeout;
    private NodeFactory nodeFactory;
+   protected StateTransferIntegrator integrator;
+   protected StateTransferGenerator generator;
 
 
    @Inject
-   public void injectDependencies(CacheSPI cache, Marshaller marshaller, RegionManager regionManager, Configuration configuration, CacheLoaderManager cacheLoaderManager, NodeFactory nodeFactory)
+   public void injectDependencies(CacheSPI cache, Marshaller marshaller, RegionManager regionManager, Configuration configuration, CacheLoaderManager cacheLoaderManager, NodeFactory nodeFactory, StateTransferIntegrator integrator, StateTransferGenerator generator)
    {
       this.cache = cache;
       this.regionManager = regionManager;
@@ -58,6 +61,8 @@
       this.configuration = configuration;
       this.cacheLoaderManager = cacheLoaderManager;
       this.nodeFactory = nodeFactory;
+      this.integrator = integrator;
+      this.generator = generator;
    }
 
    @Start(priority = 19)
@@ -76,27 +81,18 @@
       if (canProvideState && (fetchPersistentState || fetchTransientState))
       {
          marshaller.objectToObjectStream(true, out);
-         StateTransferGenerator generator = getStateTransferGenerator();
          long startTime = System.currentTimeMillis();
-         NodeSPI rootNode = cache.peek(fqn, false, false);
+         InternalNode rootNode = cache.getRoot().getDelegationTarget();
 
-         try
-         {
-            if (log.isDebugEnabled())
-            {
-               log.debug("locking the " + fqn + " subtree to return the in-memory (transient) state");
-            }
-            acquireLocksForStateTransfer(rootNode, timeout, force);
-            generator.generateState(out, rootNode, fetchTransientState, fetchPersistentState, suppressErrors);
-            if (log.isDebugEnabled())
-            {
-               log.debug("Successfully generated state in " + (System.currentTimeMillis() - startTime) + " msec");
-            }
-         }
-         finally
-         {
-            releaseStateTransferLocks(rootNode);
-         }
+         // we don't need READ locks for MVCC based state transfer!
+
+         if (log.isDebugEnabled())
+            log.debug("locking the " + fqn + " subtree to return the in-memory (transient) state");
+
+         generator.generateState(out, rootNode, fetchTransientState, fetchPersistentState, suppressErrors);
+
+         if (log.isDebugEnabled())
+            log.debug("Successfully generated state in " + (System.currentTimeMillis() - startTime) + " msec");
       }
       else
       {
@@ -128,7 +124,8 @@
 
    public void setState(ObjectInputStream in, Fqn targetRoot) throws Exception
    {
-      NodeSPI target = cache.peek(targetRoot, false, false);
+      cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+      NodeSPI target = cache.getNode(targetRoot);
       if (target == null)
       {
          // Create the integration root, but do not replicate
@@ -137,7 +134,8 @@
          //needed for BR state transfers
          cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
          cache.put(targetRoot, null);
-         target = cache.peek(targetRoot, false, false);
+         cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+         target = cache.getNode(targetRoot);
       }
       Object o = marshaller.objectFromObjectStream(in);
       Boolean hasState = (Boolean) o;
@@ -166,69 +164,21 @@
     *                   persistent state (or null)
     * @param targetRoot node into which the state should be integrated
     */
-   private void setState(ObjectInputStream state, NodeSPI targetRoot) throws Exception
+   protected void setState(ObjectInputStream state, NodeSPI targetRoot) throws Exception
    {
       long startTime = System.currentTimeMillis();
+      /*
+       * Vladimir/Manik/Brian (Dec 7,2006)
+       *
+       * integrator.integrateState(in,targetRoot, cl) will call cache.put for each
+       * node read from stream. Having option override below allows nodes read
+       * to be directly stored into a tree since we bypass interceptor chain.
+       *
+       */
+      if (log.isDebugEnabled()) log.debug("starting state integration at node " + targetRoot);
+      integrator.integrateState(state, targetRoot.getDelegationTarget(), targetRoot.getFqn());
 
-      try
-      {
-         // Acquire a lock on the root node
-         acquireLocksForStateTransfer(targetRoot, stateRetrievalTimeout, true);
-
-         /*
-          * Vladimir/Manik/Brian (Dec 7,2006)
-          *
-          * integrator.integrateState(in,targetRoot, cl) will call cache.put for each
-          * node read from stream. Having option override below allows nodes read
-          * to be directly stored into a tree since we bypass interceptor chain.
-          *
-          */
-
-//         Option option = new Option();
-//         option.setBypassInterceptorChain(true);
-//         cache.getInvocationContext().setOptionOverrides(option);
-//
-         StateTransferIntegrator integrator = getStateTransferIntegrator(state, targetRoot.getFqn());
-         if (log.isDebugEnabled())
-         {
-            log.debug("starting state integration at node " + targetRoot);
-         }
-         integrator.integrateState(state, targetRoot);
-         if (log.isDebugEnabled())
-         {
-            log.debug("successfully integrated state in " + (System.currentTimeMillis() - startTime) + " msec");
-         }
-      }
-      finally
-      {
-         releaseStateTransferLocks(targetRoot);
-      }
+      if (log.isDebugEnabled())
+         log.debug("successfully integrated state in " + (System.currentTimeMillis() - startTime) + " msec");
    }
-
-
-   /**
-    * Acquires locks on a root node for an owner for state transfer.
-    */
-   protected void acquireLocksForStateTransfer(NodeSPI root, long timeout, boolean force) throws InterruptedException
-   {
-      // no op
-   }
-
-   /**
-    * Releases all state transfer locks acquired.
-    */
-   protected void releaseStateTransferLocks(NodeSPI root)
-   {
-      // no op
-   }
-
-   protected StateTransferGenerator getStateTransferGenerator()
-   {
-      return StateTransferFactory.getStateTransferGenerator(cache);
-   }
-
-   protected StateTransferIntegrator getStateTransferIntegrator(ObjectInputStream istream, Fqn fqn) throws Exception
-   {
-      return StateTransferFactory.getStateTransferIntegrator(istream, fqn, cache, nodeFactory);
-   }
 }

Copied: core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java (from rev 6358, core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferGenerator.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferGenerator.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,185 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache.statetransfer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
+import org.jboss.cache.Node;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.Version;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.marshall.NodeDataExceptionMarker;
+
+import java.io.ObjectOutputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+ at Deprecated
+public class LegacyStateTransferGenerator implements StateTransferGenerator
+{
+
+   public static final short STATE_TRANSFER_VERSION = Version.getVersionShort("2.0.0.GA");
+
+   private Log log = LogFactory.getLog(getClass().getName());
+
+   private CacheSPI cache;
+
+   private Set<Fqn> internalFqns;
+
+   @Inject
+   public void inject(CacheSPI cache)
+   {
+      this.cache = cache;
+   }
+
+   @Start(priority = 18)
+   private void start()
+   {
+      this.internalFqns = cache.getInternalFqns();
+   }
+
+   public void generateState(ObjectOutputStream out, Object rootNode, boolean generateTransient,
+                             boolean generatePersistent, boolean suppressErrors) throws Exception
+   {
+      Fqn fqn = getFqn(rootNode);
+      try
+      {
+         cache.getMarshaller().objectToObjectStream(STATE_TRANSFER_VERSION, out);
+         if (generateTransient)
+         {
+            //transient + marker
+            if (log.isTraceEnabled())
+            {
+               log.trace("writing transient state for " + fqn);
+            }
+            marshallTransientState((NodeSPI) rootNode, out);
+            delimitStream(out);
+
+            if (log.isTraceEnabled())
+            {
+               log.trace("transient state succesfully written");
+            }
+
+            //associated + marker
+            if (log.isTraceEnabled())
+            {
+               log.trace("writing associated state");
+            }
+
+            delimitStream(out);
+
+            if (log.isTraceEnabled())
+            {
+               log.trace("associated state succesfully written");
+            }
+
+         }
+         else
+         {
+            //we have to write two markers for transient and associated
+            delimitStream(out);
+            delimitStream(out);
+         }
+
+         CacheLoader cacheLoader = cache.getCacheLoaderManager() == null ? null : cache.getCacheLoaderManager().getCacheLoader();
+         if (cacheLoader != null && generatePersistent)
+         {
+            if (log.isTraceEnabled())
+            {
+               log.trace("writing persistent state for " + fqn + ",using " + cache.getCacheLoaderManager().getCacheLoader().getClass());
+            }
+
+            if (fqn.isRoot())
+            {
+               cacheLoader.loadEntireState(out);
+            }
+            else
+            {
+               cacheLoader.loadState(fqn, out);
+            }
+
+            if (log.isTraceEnabled())
+            {
+               log.trace("persistent state succesfully written");
+            }
+         }
+         delimitStream(out);
+      }
+      catch (Exception e)
+      {
+         cache.getMarshaller().objectToObjectStream(new NodeDataExceptionMarker(e, cache.getLocalAddress()), out);
+         throw e;
+      }
+   }
+
+   private Fqn getFqn(Object o)
+   {
+      if (o instanceof Node) return ((Node) o).getFqn();
+      if (o instanceof InternalNode) return ((InternalNode) o).getFqn();
+      throw new IllegalArgumentException();
+   }
+
+   /**
+    * Places a delimiter marker on the stream
+    *
+    * @param out stream
+    * @throws java.io.IOException if there are errs
+    */
+   protected void delimitStream(ObjectOutputStream out) throws Exception
+   {
+      cache.getMarshaller().objectToObjectStream(DefaultStateTransferManager.STREAMING_DELIMITER_NODE, out);
+   }
+
+   /**
+    * Do a preorder traversal: visit the node first, then the node's children
+    *
+    * @param out
+    * @throws Exception
+    */
+   protected void marshallTransientState(NodeSPI node, ObjectOutputStream out) throws Exception
+   {
+      List<NodeData> nodeData = new LinkedList<NodeData>();
+      generateNodeDataList(node, nodeData);
+      cache.getMarshaller().objectToObjectStream(nodeData, out, node.getFqn());
+   }
+
+   protected void generateNodeDataList(NodeSPI<?, ?> node, List<NodeData> list) throws Exception
+   {
+      if (internalFqns.contains(node.getFqn()))
+      {
+         return;
+      }
+
+      Map attrs;
+      NodeData nd;
+
+      // first handle the current node
+      attrs = node.getInternalState(false);
+
+      if (attrs.size() == 0)
+      {
+         nd = new NodeData(node.getFqn());
+      }
+      else
+      {
+         nd = new NodeData(node.getFqn(), attrs, true);
+      }
+
+      list.add(nd);
+
+      // then visit the children
+      for (NodeSPI child : node.getChildrenDirect()) generateNodeDataList(child, list);
+   }
+}
\ No newline at end of file

Copied: core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java (from rev 6358, core/trunk/src/main/java/org/jboss/cache/statetransfer/DefaultStateTransferIntegrator.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferIntegrator.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,383 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ * 
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache.statetransfer;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.NodeFactory;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.Region;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.eviction.EvictedEventNode;
+import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.invocation.InvocationContext;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.marshall.NodeDataExceptionMarker;
+import org.jboss.cache.marshall.NodeDataMarker;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+ at Deprecated
+public class LegacyStateTransferIntegrator implements StateTransferIntegrator
+{
+
+   private static final Log log = LogFactory.getLog(LegacyStateTransferIntegrator.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   private CacheSPI cache;
+
+   private NodeFactory factory;
+
+   private Set<Fqn> internalFqns;
+
+   @Inject
+   public void inject(CacheSPI<?, ?> cache, NodeFactory nodefactory)
+   {
+      this.cache = cache;
+      this.factory = nodefactory;
+   }
+
+   @Start(priority = 14)
+   public void start()
+   {
+      this.internalFqns = cache.getInternalFqns();
+   }
+
+   public void integrateState(ObjectInputStream ois, Object target, Fqn targetFqn) throws Exception
+   {
+      // pop version from the stream first!
+      short version = (Short) cache.getMarshaller().objectFromObjectStream(ois);
+      log.info("Using version " + version);
+      integrateTransientState(ois, (NodeSPI) target);
+      // read another marker for the dummy associated state
+      if (trace) log.trace("Reading marker for nonexistent associated state");
+      cache.getMarshaller().objectFromObjectStream(ois);
+      integratePersistentState(ois, targetFqn);
+   }
+
+   protected void integrateTransientState(ObjectInputStream in, NodeSPI target) throws Exception
+   {
+      boolean transientSet = false;
+      try
+      {
+         if (log.isTraceEnabled())
+         {
+            log.trace("integrating transient state for " + target);
+         }
+
+         integrateTransientState(target, in);
+
+         transientSet = true;
+
+         if (log.isTraceEnabled())
+         {
+            log.trace("transient state successfully integrated");
+         }
+
+         notifyAllNodesCreated(cache.getInvocationContext(), target);
+      }
+      catch (Exception e)
+      {
+         throw new CacheException(e);
+      }
+      finally
+      {
+         if (!transientSet)
+         {
+            target.clearDataDirect();
+            target.removeChildrenDirect();
+         }
+      }
+   }
+
+   protected void integratePersistentState(ObjectInputStream in, Fqn targetFqn) throws Exception
+   {
+      if (trace) log.trace("Reading persistent state from stream");
+      CacheLoaderManager loaderManager = cache.getCacheLoaderManager();
+      CacheLoader loader = loaderManager == null ? null : loaderManager.getCacheLoader();
+      if (loader == null)
+      {
+         if (log.isTraceEnabled())
+         {
+            log.trace("cache loader is null, will not attempt to integrate persistent state");
+         }
+      }
+      else
+      {
+
+         if (log.isTraceEnabled())
+         {
+            log.trace("integrating persistent state using " + loader.getClass().getName());
+         }
+
+         boolean persistentSet = false;
+         try
+         {
+            if (targetFqn.isRoot())
+            {
+               loader.storeEntireState(in);
+            }
+            else
+            {
+               loader.storeState(targetFqn, in);
+            }
+            persistentSet = true;
+         }
+         catch (ClassCastException cce)
+         {
+            log.error("Failed integrating persistent state. One of cacheloaders is not"
+                  + " adhering to state stream format. See JBCACHE-738.");
+            throw cce;
+         }
+         finally
+         {
+            if (!persistentSet)
+            {
+               log.warn("persistent state integration failed, removing all nodes from loader");
+               loader.remove(targetFqn);
+            }
+            else
+            {
+               if (log.isTraceEnabled())
+               {
+                  log.trace("persistent state integrated successfully");
+               }
+            }
+         }
+      }
+   }
+
+   /**
+    * Generates NodeAdded notifications for all nodes of the tree. This is
+    * called whenever the tree is initially retrieved (state transfer)
+    */
+   private void notifyAllNodesCreated(InvocationContext ctx, NodeSPI curr)
+   {
+      if (curr == null) return;
+      ctx.setOriginLocal(false);
+      cache.getNotifier().notifyNodeCreated(curr.getFqn(), true, ctx);
+      cache.getNotifier().notifyNodeCreated(curr.getFqn(), false, ctx);
+      // AND notify that they have been modified!!
+      if (!curr.getKeysDirect().isEmpty())
+      {
+         cache.getNotifier().notifyNodeModified(curr.getFqn(), true, NodeModifiedEvent.ModificationType.PUT_MAP, Collections.emptyMap(), ctx);
+         cache.getNotifier().notifyNodeModified(curr.getFqn(), false, NodeModifiedEvent.ModificationType.PUT_MAP, curr.getDataDirect(), ctx);
+      }
+      ctx.setOriginLocal(true);
+
+      Set<NodeSPI> children = curr.getChildrenDirect();
+      for (NodeSPI n : children)
+      {
+         notifyAllNodesCreated(ctx, n);
+      }
+   }
+
+   private void integrateTransientState(NodeSPI target, ObjectInputStream in) throws Exception
+   {
+      if (trace) log.trace("Reading transient state from stream");
+      target.removeChildrenDirect();
+
+      List<NodeData> list = readNodesAsList(in);
+      if (list != null)
+      {
+         // if the list was null we read an EOF marker!!  So don't bother popping it off the stack later.
+         Iterator<NodeData> nodeDataIterator = list.iterator();
+
+         // Read the first NodeData and integrate into our target
+         if (nodeDataIterator.hasNext())
+         {
+            NodeData nd = nodeDataIterator.next();
+
+            //are there any transient nodes at all?
+            if (nd != null && !nd.isMarker())
+            {
+               Map attributes = nd.getAttributes();
+
+               target.setInternalState(attributes);
+
+               // Check whether this is an integration into the buddy backup
+               // subtree
+               Fqn tferFqn = nd.getFqn();
+               Fqn tgtFqn = target.getFqn();
+               boolean move = tgtFqn.isChildOrEquals(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN)
+                     && !tferFqn.isChildOrEquals(tgtFqn);
+               // If it is an integration, calculate how many levels of offset
+               int offset = move ? tgtFqn.size() - tferFqn.size() : 0;
+
+               integrateStateTransferChildren(target, offset, nodeDataIterator);
+
+               integrateRetainedNodes(target);
+            }
+         }
+
+         // read marker off stack
+         if (trace) log.trace("Reading marker from stream");
+         cache.getMarshaller().objectFromObjectStream(in);
+      }
+   }
+
+   @SuppressWarnings("unchecked")
+   private List<NodeData> readNodesAsList(ObjectInputStream in) throws Exception
+   {
+      Object obj = cache.getMarshaller().objectFromObjectStream(in);
+      if (obj instanceof NodeDataMarker) return null;
+
+      return (List<NodeData>) obj;
+   }
+
+   private NodeData integrateStateTransferChildren(NodeSPI parent, int offset, Iterator<NodeData> nodeDataIterator)
+         throws IOException, ClassNotFoundException
+   {
+      int parent_level = parent.getFqn().size();
+      int target_level = parent_level + 1;
+      Fqn fqn;
+      int size;
+      NodeData nd = nodeDataIterator.hasNext() ? nodeDataIterator.next() : null;
+      while (nd != null && !nd.isMarker())
+      {
+         fqn = nd.getFqn();
+         // If we need to integrate into the buddy backup subtree,
+         // change the Fqn to fit under it
+         if (offset > 0)
+         {
+            fqn = Fqn.fromRelativeFqn(parent.getFqn().getAncestor(offset), fqn);
+         }
+         size = fqn.size();
+         if (size <= parent_level)
+         {
+            return nd;
+         }
+         else if (size > target_level)
+         {
+            throw new IllegalStateException("NodeData " + fqn + " is not a direct child of " + parent.getFqn());
+         }
+
+         Map attrs = nd.getAttributes();
+
+         // We handle this NodeData.  Create a TreeNode and
+         // integrate its data
+         NodeSPI target = factory.createNode(fqn, parent, attrs);
+         parent.addChild(fqn.getLastElement(), target);
+
+         // JBCACHE-913
+         Region region = cache.getRegion(fqn, false);
+         if (region != null && region.getEvictionPolicy() != null)
+         {
+            region.putNodeEvent(new EvictedEventNode(fqn, NodeEventType.ADD_NODE_EVENT,
+                  attrs == null ? 0 : attrs.size()));
+         }
+
+         // Recursively call, which will walk down the tree
+         // and return the next NodeData that's a child of our parent
+         nd = integrateStateTransferChildren(target, offset, nodeDataIterator);
+      }
+      if (nd != null && nd.isExceptionMarker())
+      {
+         NodeDataExceptionMarker ndem = (NodeDataExceptionMarker) nd;
+         throw new CacheException("State provider node " + ndem.getCacheNodeIdentity()
+               + " threw exception during loadState", ndem.getCause());
+      }
+      return null;
+   }
+
+   private Set<Node> retainInternalNodes(Node target)
+   {
+      Set<Node> result = new HashSet<Node>();
+      Fqn targetFqn = target.getFqn();
+      for (Fqn internalFqn : internalFqns)
+      {
+         if (internalFqn.isChildOf(targetFqn))
+         {
+            Node internalNode = getInternalNode(target, internalFqn);
+            if (internalNode != null)
+            {
+               result.add(internalNode);
+            }
+         }
+      }
+
+      return result;
+   }
+
+   private Node getInternalNode(Node parent, Fqn internalFqn)
+   {
+      Object name = internalFqn.get(parent.getFqn().size());
+      cache.getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+      Node result = parent.getChild(name);
+      if (result != null)
+      {
+         if (internalFqn.size() < result.getFqn().size())
+         {
+            // need to recursively walk down the tree
+            result = getInternalNode(result, internalFqn);
+         }
+      }
+      return result;
+   }
+
+   private void integrateRetainedNodes(NodeSPI target)
+   {
+      Set<Node> retainedNodes = retainInternalNodes(target);
+      Fqn rootFqn = target.getFqn();
+      for (Node retained : retainedNodes)
+      {
+         if (retained.getFqn().isChildOf(rootFqn))
+         {
+            integrateRetainedNode(target, retained);
+         }
+      }
+   }
+
+   private void integrateRetainedNode(NodeSPI ancestor, Node descendant)
+   {
+      Fqn descFqn = descendant.getFqn();
+      Fqn ancFqn = ancestor.getFqn();
+      Object name = descFqn.get(ancFqn.size());
+      NodeSPI child = (NodeSPI) ancestor.getChild(name);
+      if (ancFqn.size() == descFqn.size() + 1)
+      {
+         if (child == null)
+         {
+            ancestor.addChild(name, descendant);
+         }
+         else
+         {
+            log.warn("Received unexpected internal node " + descFqn + " in transferred state");
+         }
+      }
+      else
+      {
+         if (child == null)
+         {
+            // Missing level -- have to create empty node
+            // This shouldn't really happen -- internal fqns should
+            // be immediately under the root
+            child = factory.createNode(name, ancestor);
+            ancestor.addChild(name, child);
+         }
+
+         // Keep walking down the tree
+         integrateRetainedNode(child, descendant);
+      }
+   }
+}
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/LegacyStateTransferManager.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,17 +1,25 @@
 package org.jboss.cache.statetransfer;
 
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
 import org.jboss.cache.NodeSPI;
+import org.jboss.cache.RegionEmptyException;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.lock.LockManager;
 import static org.jboss.cache.lock.LockType.READ;
 import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.marshall.InactiveRegionException;
 
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
 /**
  * This is to support legacy locking schemes such as Pessimistic and Optimistic locking.
  *
  * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
  * @since 3.0
  */
+ at Deprecated
 public class LegacyStateTransferManager extends DefaultStateTransferManager
 {
    protected LockManager lockManager;
@@ -23,6 +31,109 @@
    }
 
    @Override
+   public void getState(ObjectOutputStream out, Fqn fqn, long timeout, boolean force, boolean suppressErrors) throws Exception
+   {
+      // can't give state for regions currently being activated/inactivated
+      boolean canProvideState = (!regionManager.isInactive(fqn) && cache.peek(fqn, false) != null);
+
+      if (canProvideState && (fetchPersistentState || fetchTransientState))
+      {
+         marshaller.objectToObjectStream(true, out);
+         long startTime = System.currentTimeMillis();
+         NodeSPI rootNode = cache.peek(fqn, false, false);
+
+         try
+         {
+            if (log.isDebugEnabled())
+            {
+               log.debug("locking the " + fqn + " subtree to return the in-memory (transient) state");
+            }
+            acquireLocksForStateTransfer(rootNode, timeout, force);
+            generator.generateState(out, rootNode, fetchTransientState, fetchPersistentState, suppressErrors);
+            if (log.isDebugEnabled())
+            {
+               log.debug("Successfully generated state in " + (System.currentTimeMillis() - startTime) + " msec");
+            }
+         }
+         finally
+         {
+            releaseStateTransferLocks(rootNode);
+         }
+      }
+      else
+      {
+         marshaller.objectToObjectStream(false, out);
+         Exception e = null;
+         if (!canProvideState)
+         {
+            String exceptionMessage = "Cache instance at " + cache.getLocalAddress() + " cannot provide state for fqn " + fqn + ".";
+
+            if (regionManager.isInactive(fqn))
+            {
+               exceptionMessage += " Region for fqn " + fqn + " is inactive.";
+               e = new InactiveRegionException(exceptionMessage);
+            }
+            // this is not really an exception.  Just provide empty state. The exception is just a signal.  Yes, lousy.  - JBCACHE-1349
+            if (cache.peek(fqn, false, false) == null)
+            {
+               e = new RegionEmptyException();
+            }
+         }
+         if (!fetchPersistentState && !fetchTransientState)
+         {
+            e = new CacheException("Cache instance at " + cache.getLocalAddress() + " is not configured to provide state");
+         }
+         marshaller.objectToObjectStream(e, out);
+         if (e != null) throw e;
+      }
+   }
+
+   /**
+    * Set the portion of the cache rooted in <code>targetRoot</code>
+    * to match the given state. Updates the contents of <code>targetRoot</code>
+    * to reflect those in <code>new_state</code>.
+    * <p/>
+    * <strong>NOTE:</strong> This method performs no locking of nodes; it
+    * is up to the caller to lock <code>targetRoot</code> before calling
+    * this method.
+    *
+    * @param state      a serialized byte[][] array where element 0 is the
+    *                   transient state (or null) , and element 1 is the
+    *                   persistent state (or null)
+    * @param targetRoot node into which the state should be integrated
+    */
+   protected void setState(ObjectInputStream state, NodeSPI targetRoot) throws Exception
+   {
+      long startTime = System.currentTimeMillis();
+
+      acquireLocksForStateTransfer(targetRoot, stateRetrievalTimeout, true);
+      /*
+       * Vladimir/Manik/Brian (Dec 7,2006)
+       *
+       * integrator.integrateState(in,targetRoot, cl) will call cache.put for each
+       * node read from stream. Having option override below allows nodes read
+       * to be directly stored into a tree since we bypass interceptor chain.
+       *
+       */
+      try
+      {
+         if (log.isDebugEnabled())
+         {
+            log.debug("starting state integration at node " + targetRoot);
+         }
+         integrator.integrateState(state, targetRoot, targetRoot.getFqn());
+         if (log.isDebugEnabled())
+         {
+            log.debug("successfully integrated state in " + (System.currentTimeMillis() - startTime) + " msec");
+         }
+      }
+      finally
+      {
+         releaseStateTransferLocks(targetRoot);
+      }
+   }
+
+
    protected void acquireLocksForStateTransfer(NodeSPI root, long timeout, boolean force) throws InterruptedException
    {
       try
@@ -44,7 +155,6 @@
       }
    }
 
-   @Override
    protected void releaseStateTransferLocks(NodeSPI root)
    {
       try

Deleted: core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferFactory.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,75 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- * 
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache.statetransfer;
-
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeFactory;
-import org.jboss.cache.Version;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-
-/**
- * Factory class able to create {@link StateTransferGenerator} and
- * {@link StateTransferIntegrator} instances.
- *
- * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
- * @version $Revision$
- */
-public abstract class StateTransferFactory
-{
-   private static final short RV_200 = Version.getVersionShort("2.0.0");
-
-   /**
-    * Gets the StateTransferGenerator able to handle the given cache instance.
-    *
-    * @param cache the cache
-    * @return the {@link StateTransferGenerator}
-    * @throws IllegalStateException if the cache's ReplicationVersion is < 2.0.0
-    */
-   public static StateTransferGenerator getStateTransferGenerator(CacheSPI cache)
-   {
-      short version = cache.getConfiguration().getReplicationVersion();
-
-      // Compiler won't let me use a switch
-
-      if (version < RV_200 && version > 0) // <= 0 is actually a version > 15.31.63
-         throw new IllegalStateException("State transfer with cache replication version < 2.0.0 not supported");
-      else
-         return new DefaultStateTransferGenerator(cache); // current default
-   }
-
-   public static StateTransferIntegrator getStateTransferIntegrator(ObjectInputStream in, Fqn fqn, CacheSPI cache, NodeFactory nodeFactory)
-         throws Exception
-   {
-      short version;
-      try
-      {
-         version = (Short) cache.getMarshaller().objectFromObjectStream(in);
-      }
-      catch (IOException io)
-      {
-         // something is wrong with this stream, close it
-         try
-         {
-            in.close();
-         }
-         catch (IOException ignored)
-         {
-         }
-         throw new IllegalStateException("Stream corrupted ", io);
-      }
-
-      // Compiler won't let me use a switch
-
-      if (version < RV_200 && version > 0) // <= 0 is actually a version > 15.31.63
-         throw new IllegalStateException("State transfer with cache replication version < 2.0.0 not supported");
-      else
-         return new DefaultStateTransferIntegrator(fqn, cache, nodeFactory); // current default
-   }
-}

Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferGenerator.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -6,8 +6,6 @@
  */
 package org.jboss.cache.statetransfer;
 
-import org.jboss.cache.Node;
-
 import java.io.ObjectOutputStream;
 
 /**
@@ -15,6 +13,6 @@
  */
 public interface StateTransferGenerator
 {
-   void generateState(ObjectOutputStream stream, Node rootNode, boolean generateTransient, boolean generatePersistent, boolean suppressErrors) throws Exception;
-
+   // TODO: rootNode is an Object to support both InternalNodes and NodeSPIs.
+   void generateState(ObjectOutputStream stream, Object rootNode, boolean generateTransient, boolean generatePersistent, boolean suppressErrors) throws Exception;
 }
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/statetransfer/StateTransferIntegrator.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -6,7 +6,7 @@
  */
 package org.jboss.cache.statetransfer;
 
-import org.jboss.cache.Node;
+import org.jboss.cache.Fqn;
 
 import java.io.ObjectInputStream;
 
@@ -15,7 +15,6 @@
  */
 public interface StateTransferIntegrator
 {
-
-   void integrateState(ObjectInputStream ois, Node target) throws Exception;
-
+   // TODO: target is an Object to support both InternalNodes and NodeSPIs.
+   void integrateState(ObjectInputStream ois, Object target, Fqn targetFqn) throws Exception;
 }
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/util/concurrent/SelfInitializingConcurrentHashMap.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,5 +1,7 @@
 package org.jboss.cache.util.concurrent;
 
+import org.jboss.cache.UnversionedNode;
+
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
@@ -16,6 +18,8 @@
  */
 public class SelfInitializingConcurrentHashMap<K, V> implements ConcurrentMap<K, V>
 {
+   static boolean DEBUG = false; // TODO remove this
+
    private volatile ConcurrentMap<K, V> delegate;
 //   private int initialCapacity = -1, concurrencyLevel = -1;
 //   private float loadFactor = -1;
@@ -82,6 +86,7 @@
 
    public final V put(K key, V value)
    {
+      if (DEBUG) if (value instanceof UnversionedNode) throw new RuntimeException();
       return getDelegate().put(key, value);
    }
 
@@ -97,16 +102,19 @@
 
    public final V putIfAbsent(K key, V value)
    {
+      if (DEBUG) if (value instanceof UnversionedNode) throw new RuntimeException();
       return getDelegate().putIfAbsent(key, value);
    }
 
    public final boolean replace(K key, V oldValue, V newValue)
    {
+      if (DEBUG) if (oldValue instanceof UnversionedNode) throw new RuntimeException();
       return getDelegate().replace(key, oldValue, newValue);
    }
 
    public final V replace(K key, V value)
    {
+      if (DEBUG) if (value instanceof UnversionedNode) throw new RuntimeException();
       return getDelegate().replace(key, value);
    }
 

Modified: core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/main/java/org/jboss/cache/util/reflect/ReflectionUtil.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -124,7 +124,7 @@
       }
       catch (Exception e)
       {
-         throw new CacheException("Unable to invoke method " + method + " on object instance " + instance +
+         throw new CacheException("Unable to invoke method " + method + " on object " + //instance +
                (parameters != null ? " with parameters " + Arrays.asList(parameters) : ""), e);
       }
    }

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/PassivationTest.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -21,7 +21,7 @@
    {
       cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
       cache.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
-      CacheLoaderConfig clc = getSingleCacheLoaderConfig("", DummySharedInMemoryCacheLoader.class.getName(), "", false, true, false);
+      CacheLoaderConfig clc = getSingleCacheLoaderConfig("", DummySharedInMemoryCacheLoader.class.getName(), "debug=true", false, true, false);
       clc.setPassivation(true);
       cache.getConfiguration().setCacheLoaderConfig(clc);
    }

Copied: core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java (from rev 6358, core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java)
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/legacy/write/VersionedInvalidateCommandTest.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,138 @@
+package org.jboss.cache.commands.legacy.write;
+
+import static org.easymock.EasyMock.createStrictControl;
+import static org.easymock.EasyMock.expect;
+import org.easymock.IMocksControl;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DataVersioningException;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+import org.testng.annotations.Test;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+
+/**
+ * tester class for {@link VersionedInvalidateCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class VersionedInvalidateCommandTest extends AbstractDataCommandTest
+{
+   DataVersion dataVersion;
+   VersionedInvalidateCommand command;
+   IMocksControl control;
+
+   Notifier notifier;
+   TransactionManager tmMock;
+
+   MockNodesFixture nodes;
+   CacheSPI spiMock;
+
+   protected void moreSetup()
+   {
+      control = createStrictControl();
+      notifier = control.createMock(Notifier.class);
+      container = control.createMock(DataContainer.class);
+      tmMock = control.createMock(TransactionManager.class);
+      spiMock = control.createMock(CacheSPI.class);
+      nodes = new MockNodesFixture();
+
+      command = new VersionedInvalidateCommand(testFqn);
+      dataVersion = new DefaultDataVersion(10);
+      command.setDataVersion(dataVersion);
+      command.initialize(spiMock, container, notifier);
+      command.initialize(tmMock);
+   }
+
+   public void testWithExistingNode()
+   {
+      nodes.adfNode.put("key", "value");
+      nodes.adfNode.setVersion(dataVersion);
+      nodes.adfNode.setDataLoaded(true);
+      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+      notifier.notifyNodeEvicted(testFqn, true, ctx);
+      notifier.notifyNodeEvicted(testFqn, false, ctx);
+
+      control.replay();
+      assert null == command.perform(ctx);
+      assert nodes.adfNode.getData().isEmpty();
+      assert !nodes.adfNode.isDataLoaded();
+      assert !nodes.adfNode.isValid();
+      assert nodes.adfNode.getVersion().equals(dataVersion);
+
+      control.verify();
+   }
+
+   public void testWithExistingNodeInvalidVersion()
+   {
+      nodes.adfNode.put("key", "value");
+      nodes.adfNode.setDataLoaded(true);
+      nodes.adfNode.setVersion(new DefaultDataVersion(100));
+      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+      control.replay();
+
+      try
+      {
+         command.perform(ctx);
+         assert false : "exception expected";
+      }
+      catch (DataVersioningException e)
+      {
+         //expected as there is a version mismatch
+      }
+      assert !nodes.adfNode.getData().isEmpty();
+      assert nodes.adfNode.isDataLoaded();
+      assert nodes.adfNode.isValid();
+      assert !dataVersion.equals(nodes.adfNode.getVersion());
+
+      control.verify();
+   }
+
+   public void testExistingTombstone()
+   {
+      nodes.adfNode.setValid(false, true);
+      nodes.adfNode.setVersion(dataVersion);
+      expect(spiMock.getNode(testFqn)).andReturn(null);
+      expect(container.peek(testFqn, true, true)).andReturn(nodes.adfNode);
+      notifier.notifyNodeEvicted(testFqn, true, ctx);
+      notifier.notifyNodeEvicted(testFqn, false, ctx);
+
+      control.replay();
+      assert null == command.perform(ctx);
+      assert nodes.adfNode.getData().isEmpty();
+      assert !nodes.adfNode.isDataLoaded();
+      assert !nodes.adfNode.isValid();
+      assert nodes.adfNode.getVersion().equals(dataVersion);
+      control.verify();
+   }
+
+   public void testCreateTombstone() throws Exception
+   {
+      Transaction tx = control.createMock(Transaction.class);
+      expect(tmMock.suspend()).andReturn(tx);
+      spiMock.put(testFqn, Collections.emptyMap());
+      tmMock.resume(tx);
+
+      control.replay();
+      command.createTombstone(ctx);
+      control.verify();
+   }
+
+   public void testCreateTombstoneNoTx() throws Exception
+   {
+      expect(tmMock.suspend()).andReturn(null);
+      spiMock.put(testFqn, Collections.EMPTY_MAP);
+
+      control.replay();
+      command.createTombstone(ctx);
+      control.verify();
+   }
+}

Deleted: core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/VersionedInvalidateCommandTest.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,138 +0,0 @@
-package org.jboss.cache.commands.write;
-
-import static org.easymock.EasyMock.createStrictControl;
-import static org.easymock.EasyMock.expect;
-import org.easymock.IMocksControl;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.commands.read.AbstractDataCommandTest;
-import org.jboss.cache.mock.MockNodesFixture;
-import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.optimistic.DataVersioningException;
-import org.jboss.cache.optimistic.DefaultDataVersion;
-import org.testng.annotations.Test;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.util.Collections;
-
-/**
- * tester class for {@link VersionedInvalidateCommand}.
- *
- * @author Mircea.Markus at jboss.com
- * @since 2.2
- */
- at Test(groups = "unit")
-public class VersionedInvalidateCommandTest extends AbstractDataCommandTest
-{
-   DataVersion dataVersion;
-   VersionedInvalidateCommand command;
-   IMocksControl control;
-
-   Notifier notifier;
-   TransactionManager tmMock;
-
-   MockNodesFixture nodes;
-   CacheSPI spiMock;
-
-   protected void moreSetup()
-   {
-      control = createStrictControl();
-      notifier = control.createMock(Notifier.class);
-      container = control.createMock(DataContainer.class);
-      tmMock = control.createMock(TransactionManager.class);
-      spiMock = control.createMock(CacheSPI.class);
-      nodes = new MockNodesFixture();
-
-      command = new VersionedInvalidateCommand(testFqn);
-      dataVersion = new DefaultDataVersion(10);
-      command.setDataVersion(dataVersion);
-      command.initialize(spiMock, container, notifier);
-      command.initialize(tmMock);
-   }
-
-   public void testWithExistingNode()
-   {
-      nodes.adfNode.put("key", "value");
-      nodes.adfNode.setVersion(dataVersion);
-      nodes.adfNode.setDataLoaded(true);
-      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
-      notifier.notifyNodeEvicted(testFqn, true, ctx);
-      notifier.notifyNodeEvicted(testFqn, false, ctx);
-
-      control.replay();
-      assert null == command.perform(ctx);
-      assert nodes.adfNode.getData().isEmpty();
-      assert !nodes.adfNode.isDataLoaded();
-      assert !nodes.adfNode.isValid();
-      assert nodes.adfNode.getVersion().equals(dataVersion);
-
-      control.verify();
-   }
-
-   public void testWithExistingNodeInvalidVersion()
-   {
-      nodes.adfNode.put("key", "value");
-      nodes.adfNode.setDataLoaded(true);
-      nodes.adfNode.setVersion(new DefaultDataVersion(100));
-      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
-      control.replay();
-
-      try
-      {
-         command.perform(ctx);
-         assert false : "exception expected";
-      }
-      catch (DataVersioningException e)
-      {
-         //expected as there is a version mismatch
-      }
-      assert !nodes.adfNode.getData().isEmpty();
-      assert nodes.adfNode.isDataLoaded();
-      assert nodes.adfNode.isValid();
-      assert !dataVersion.equals(nodes.adfNode.getVersion());
-
-      control.verify();
-   }
-
-   public void testExistingTombstone()
-   {
-      nodes.adfNode.setValid(false, true);
-      nodes.adfNode.setVersion(dataVersion);
-      expect(spiMock.getNode(testFqn)).andReturn(null);
-      expect(container.peek(testFqn, true, true)).andReturn(nodes.adfNode);
-      notifier.notifyNodeEvicted(testFqn, true, ctx);
-      notifier.notifyNodeEvicted(testFqn, false, ctx);
-
-      control.replay();
-      assert null == command.perform(ctx);
-      assert nodes.adfNode.getData().isEmpty();
-      assert !nodes.adfNode.isDataLoaded();
-      assert !nodes.adfNode.isValid();
-      assert nodes.adfNode.getVersion().equals(dataVersion);
-      control.verify();
-   }
-
-   public void testCreateTumbstone() throws Exception
-   {
-      Transaction tx = control.createMock(Transaction.class);
-      expect(tmMock.suspend()).andReturn(tx);
-      spiMock.put(testFqn, Collections.emptyMap());
-      tmMock.resume(tx);
-
-      control.replay();
-      command.createTombstone(ctx);
-      control.verify();
-   }
-
-   public void testCreateTumbstoneNoTx() throws Exception
-   {
-      expect(tmMock.suspend()).andReturn(null);
-      spiMock.put(testFqn, Collections.EMPTY_MAP);
-
-      control.replay();
-      command.createTombstone(ctx);
-      control.verify();
-   }
-}

Modified: core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -1,9 +1,13 @@
 package org.jboss.cache.mock;
 
 import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InternalNode;
 import org.jboss.cache.Node;
+import org.jboss.cache.NodeFactory;
 import org.jboss.cache.NodeSPI;
+import org.jboss.cache.invocation.InvocationContext;
 import org.jboss.cache.lock.NodeLock;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.transaction.GlobalTransaction;
@@ -292,6 +296,46 @@
       }
    }
 
+   public boolean isNullNode()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void markForUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory, boolean writeSkewCheck)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void commitUpdate(InvocationContext ctx, DataContainer container, NodeFactory nodeFactory)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public boolean isChanged()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public boolean isCreated()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public InternalNode getDelegationTarget()
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void setCreated(boolean created)
+   {
+      throw new UnsupportedOperationException();
+   }
+
+   public void rollbackUpdate()
+   {
+      throw new UnsupportedOperationException();
+   }
+
    public Set getChildren()
    {
       return getChildrenDirect();

Modified: core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/optimistic/NodeInterceptorRemoveNodeTest.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -8,7 +8,6 @@
 
 import org.jboss.cache.CacheSPI;
 import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
 import org.jboss.cache.commands.tx.CommitCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.interceptors.CallInterceptor;
@@ -251,8 +250,8 @@
 
       TransactionWorkspace workspace = entry.getTransactionWorkSpace();
 
-      Node one = workspace.getNode(Fqn.fromString("/one"));
-      Node two = workspace.getNode(Fqn.fromString("/one/two"));
+      WorkspaceNode one = workspace.getNode(Fqn.fromString("/one"));
+      WorkspaceNode two = workspace.getNode(Fqn.fromString("/one/two"));
 
 
       cache.removeNode("/one");
@@ -311,8 +310,8 @@
 
       TransactionWorkspace workspace = entry.getTransactionWorkSpace();
 
-      Node one = workspace.getNode(Fqn.fromString("/one"));
-      Node two = workspace.getNode(Fqn.fromString("/one/two"));
+      WorkspaceNode one = workspace.getNode(Fqn.fromString("/one"));
+      WorkspaceNode two = workspace.getNode(Fqn.fromString("/one/two"));
 
 
       cache.removeNode("/one");

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-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/passivation/PassivationTestsBase.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -68,6 +68,7 @@
    @AfterMethod(alwaysRun = true)
    public void tearDown() throws Exception
    {
+      log.info("**** TEARING DOWN ****");
       loader.remove(Fqn.ROOT);
       TestingUtil.killCaches(cache);
    }
@@ -342,19 +343,12 @@
 
    public void testGetChildren4()
    {
-      try
+      if (!cache.exists("/a/b/c"))
       {
-         if (!cache.exists("/a/b/c"))
-         {
-            cache.put("/a/b/c", null);
-         }
-         Set children = cache.getChildrenNames((Fqn) null);// get "null* node children names
-         assertTrue(children.isEmpty());
+         cache.put("/a/b/c", null);
       }
-      catch (Exception e)
-      {
-         fail(e.toString());
-      }
+      Set children = cache.getChildrenNames((Fqn) null);// get "null* node children names
+      assertTrue(children.isEmpty());
    }
 
 
@@ -417,6 +411,7 @@
       cache.evict(Fqn.fromString("/a/2"));// passivate node
       cache.evict(Fqn.fromString("/a/3"));// passivate node
       cache.evict(Fqn.fromString("/a"));// passivate node
+      assert !exists("/a");
       assertTrue(loader.exists(Fqn.fromString("/a")));
       addDelay();
       Object val = cache.get("/a", "test");// load node's attributes but not children

Added: core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/profiling/MemoryFootprintTest.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -0,0 +1,40 @@
+package org.jboss.cache.profiling;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.lock.IsolationLevel;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+
+ at Test(groups = "profiling")
+public class MemoryFootprintTest
+{
+   int numFqns = 100000;
+
+   public void testLocal() throws IOException
+   {
+      Cache<String, String> c = new DefaultCacheFactory<String, String>().createCache(false);
+      c.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
+      c.getConfiguration().setIsolationLevel(IsolationLevel.READ_COMMITTED);
+//      c.getConfiguration().setIsolationLevel(IsolationLevel.REPEATABLE_READ);
+      c.start();
+
+      for (int i = 100000; i < 100000 + numFqns; i++)
+      {
+         String key = "keyX" + i;
+         String value = "valX" + i;
+         Fqn fqn = Fqn.fromElements(i);
+         c.put(fqn, key, value);
+      }
+
+      System.out.println("Hit enter when done");
+      System.in.read();
+
+      c.stop();
+   }
+
+
+}

Modified: core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/statetransfer/StateTransferTestBase.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -345,7 +345,7 @@
          try
          {
             stopCache(caches.get(cacheID));
-            TestingUtil.sleepThread(1500);
+//            TestingUtil.sleepThread(1500);
             File file = new File(getTempLocation(cacheID));
             cleanFile(file);
          }
@@ -354,6 +354,13 @@
             // errors in teardown should not fail test
          }
       }
+
+      // repeat.  Make sure everything is properly STOPPED!!!
+
+      for (Cache c : caches.values())
+      {
+         TestingUtil.killCaches(c);
+      }
    }
 
    protected void stopCache(Cache cache)

Modified: core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/util/ImmutableListCopyTest.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -141,4 +141,14 @@
       while (li.hasPrevious()) assert li.previous() == number--;
       assert number == 0;
    }
+
+   public void testSubLists()
+   {
+      List<Integer> ints = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
+      List<Integer> list = new ImmutableListCopy<Integer>(ints);
+
+      assert ints.subList(2, 5).equals(list.subList(2, 5));
+      assert ints.subList(1, 9).equals(list.subList(1, 9));
+      assert ints.subList(0, 1).equals(list.subList(0, 1));
+   }
 }

Modified: core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java	2008-07-28 10:29:41 UTC (rev 6413)
+++ core/trunk/src/test/java/org/jboss/cache/util/TestingUtil.java	2008-07-28 10:56:29 UTC (rev 6414)
@@ -421,37 +421,44 @@
    {
       for (Cache c : caches)
       {
-         if (c != null && c.getCacheStatus() == CacheStatus.STARTED)
+         try
          {
-            CacheSPI spi = (CacheSPI) c;
-            if (spi.getTransactionManager() != null)
+            if (c != null && c.getCacheStatus() == CacheStatus.STARTED)
             {
-               try
+               CacheSPI spi = (CacheSPI) c;
+               if (spi.getTransactionManager() != null)
                {
-                  spi.getTransactionManager().rollback();
+                  try
+                  {
+                     spi.getTransactionManager().rollback();
+                  }
+                  catch (Exception e)
+                  {
+                     // don't care
+                  }
                }
-               catch (Exception e)
+
+               CacheLoaderManager clm = spi.getCacheLoaderManager();
+               CacheLoader cl = clm == null ? null : clm.getCacheLoader();
+               if (cl != null)
                {
-                  // don't care
+                  try
+                  {
+                     cl.remove(Fqn.ROOT);
+                  }
+                  catch (Exception e)
+                  {
+                     // don't care
+                  }
                }
-            }
 
-            CacheLoaderManager clm = spi.getCacheLoaderManager();
-            CacheLoader cl = clm == null ? null : clm.getCacheLoader();
-            if (cl != null)
-            {
-               try
-               {
-                  cl.remove(Fqn.ROOT);
-               }
-               catch (Exception e)
-               {
-                  // don't care
-               }
+               spi.stop();
+               spi.destroy();
             }
+         }
+         catch (Throwable t)
+         {
 
-            spi.stop();
-            spi.destroy();
          }
       }
    }




More information about the jbosscache-commits mailing list