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

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Mon Jul 7 15:38:22 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-07-07 15:38:22 -0400 (Mon, 07 Jul 2008)
New Revision: 6193

Added:
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeMoveMvccTestBase.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/Cache.java
   core/trunk/src/main/java/org/jboss/cache/Fqn.java
   core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/PessMoveCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java
   core/trunk/src/test/java/org/jboss/cache/FqnTest.java
   core/trunk/src/test/java/org/jboss/cache/api/NodeMoveAPITest.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/NodeMoveMvccTest.java
   core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/NodeMoveMvccTest.java
   core/trunk/src/test/java/org/jboss/cache/api/optimistic/NodeMoveOptimisticTest.java
Log:
Improved various mvcc move implementation

Modified: core/trunk/src/main/java/org/jboss/cache/Cache.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Cache.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/main/java/org/jboss/cache/Cache.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -419,6 +419,13 @@
     * /a/e
     * </pre>
     * No-op if the node to be moved is the root node.
+    * <p/>
+    * <b>Note</b>: As of 3.0.0 and when using MVCC locking, more specific behaviour is defined as follows:
+    * <ul>
+    * <li>A no-op if the node is moved unto itself.  E.g., <tt>move(fqn, fqn.getParent())</tt> will not do anything.</li>
+    * <li>If a target node does not exist it will be created silently, to be more consistent with other APIs such as <tt>put()</tt> on a nonexistent node.</li>
+    * <li>If the source node does not exist this is a no-op, to be more consistent with other APIs such as <tt>get()</tt> on a nonexistent node.</li>
+    * </ul>
     *
     * @param nodeToMove the Fqn of the node to move.
     * @param newParent  new location under which to attach the node being moved.

Modified: core/trunk/src/main/java/org/jboss/cache/Fqn.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Fqn.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/main/java/org/jboss/cache/Fqn.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -670,4 +670,18 @@
    {
       return FqnComparator.INSTANCE.compare(this, Fqn);
    }
+
+   /**
+    * Creates a new Fqn whose ancestor has been replaced with the new ancestor passed in.
+    *
+    * @param newAncestor
+    * @return a new Fqn
+    */
+   public Fqn replaceAncestor(Fqn oldAncestor, Fqn newAncestor)
+   {
+      if (!isChildOf(oldAncestor))
+         throw new IllegalArgumentException("Old ancestor must be an ancestor of the current Fqn!");
+      Fqn subFqn = this.getSubFqn(oldAncestor.size(), size());
+      return Fqn.fromRelativeFqn(newAncestor, subFqn);
+   }
 }
\ No newline at end of file

Modified: core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/PessMoveCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/PessMoveCommand.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/main/java/org/jboss/cache/commands/legacy/write/PessMoveCommand.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -1,8 +1,11 @@
 package org.jboss.cache.commands.legacy.write;
 
 import org.jboss.cache.Fqn;
+import org.jboss.cache.NodeNotExistsException;
+import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.legacy.ReversibleCommand;
 import org.jboss.cache.commands.write.MoveCommand;
+import org.jboss.cache.invocation.InvocationContext;
 
 /**
  * A version of {@link org.jboss.cache.commands.write.MoveCommand} which can be rolled back, for use with
@@ -22,6 +25,65 @@
       super(from, to);
    }
 
+   /**
+    * Moves a node, from <tt>fqn</tt> to <tt>to</tt>, and returns null.
+    *
+    * @param ctx invocation context
+    * @return null
+    */
+   @Override
+   public Object perform(InvocationContext ctx)
+   {
+      move(fqn, to, false, ctx);
+      return null;
+   }
+
+   private void adjustFqn(NodeSPI node, Fqn newBase)
+   {
+      Fqn newFqn = Fqn.fromRelativeElements(newBase, node.getFqn().getLastElement());
+      node.setFqn(newFqn);
+   }
+
+   private void move(Fqn toMoveFqn, Fqn newParentFqn, boolean skipNotifications, InvocationContext ctx)
+   {
+      // the actual move algorithm.
+      // ctx *could* be null if this is a rollback!!!  Sucks big time.
+      NodeSPI newParent = ctx == null ? dataContainer.peek(newParentFqn) : ctx.lookUpNode(newParentFqn);
+      if (newParent == null || newParent.isDeleted())
+      {
+         throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
+      }
+
+      // ctx *could* be null if this is a rollback!!!  Sucks big time.
+      NodeSPI node = ctx == null ? dataContainer.peek(toMoveFqn) : ctx.lookUpNode(toMoveFqn);
+
+      if (node == null || node.isDeleted())
+      {
+         throw new NodeNotExistsException("Node " + toMoveFqn + " does not exist when attempting to move node!!");
+      }
+
+      if (trace) log.trace("Moving " + fqn + " to sit under " + to);
+
+      NodeSPI oldParent = node.getParentDirect();
+      Object nodeName = toMoveFqn.getLastElement();
+
+      // now that we have the parent and target nodes:
+      // first correct the pointers at the pruning point
+      oldParent.removeChildDirect(nodeName);
+      newParent.addChild(nodeName, node);
+      // parent pointer is calculated on the fly using Fqns.
+
+      // notify
+      if (!skipNotifications)
+         notifier.notifyNodeMoved(toMoveFqn, Fqn.fromRelativeElements(newParentFqn, toMoveFqn.getLastElement()), true, ctx);
+
+      // now adjust Fqns of node and all children.
+      adjustFqn(node, newParent.getFqn());
+
+      if (!skipNotifications)
+         notifier.notifyNodeMoved(toMoveFqn, Fqn.fromRelativeElements(newParentFqn, toMoveFqn.getLastElement()), false, ctx);
+   }
+
    public void rollback()
    {
       move(Fqn.fromRelativeElements(to, fqn.getLastElement()), fqn.getParent(), true, null);

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-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -4,7 +4,6 @@
 import org.apache.commons.logging.LogFactory;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeNotExistsException;
 import org.jboss.cache.NodeSPI;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.commands.WriteCommand;
@@ -13,21 +12,22 @@
 import org.jboss.cache.notifications.Notifier;
 import org.jboss.cache.transaction.GlobalTransaction;
 
+import java.util.Map;
+
 /**
  * Implements functionality defined by {@link org.jboss.cache.Cache#move(org.jboss.cache.Fqn, org.jboss.cache.Fqn)}
  *
  * @author Mircea.Markus at jboss.com
  * @since 2.2
  */
-// TODO: 2.2.0: Make sure this is properly intercepted, i.e., locked and loaded!!
 public class MoveCommand extends AbstractDataCommand implements WriteCommand
 {
    public static final int METHOD_ID = 36;
-   private static final Log log = LogFactory.getLog(MoveCommand.class);
-   private static final boolean trace = log.isTraceEnabled();
+   protected static final Log log = LogFactory.getLog(MoveCommand.class);
+   protected static final boolean trace = log.isTraceEnabled();
 
    /* dependencies */
-   private Notifier notifier;
+   protected Notifier notifier;
 
    /* params */
    protected Fqn to;
@@ -67,59 +67,57 @@
     */
    public Object perform(InvocationContext ctx)
    {
-      move(fqn, to, false, ctx);
-      return null;
-   }
-
-   private void adjustFqn(NodeSPI node, Fqn newBase)
-   {
-      Fqn newFqn = Fqn.fromRelativeElements(newBase, node.getFqn().getLastElement());
-      node.setFqn(newFqn);
-   }
-
-   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
-   {
-      return visitor.visitMoveCommand(ctx, this);
-   }
-
-   protected void move(Fqn toMoveFqn, Fqn newParentFqn, boolean skipNotifications, InvocationContext ctx)
-   {
-      // the actual move algorithm.
-      // ctx *could* be null if this is a rollback!!!  Sucks big time.
-      NodeSPI newParent = ctx == null ? dataContainer.peek(newParentFqn) : ctx.lookUpNode(newParentFqn);
-      if (newParent == null || newParent.isDeleted())
+      if (to.equals(fqn.getParent()))
       {
-         throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
+         if (log.isDebugEnabled()) log.debug("Attempting to move " + fqn + " onto itself.  Nothing to do.");
+         return null;
       }
 
-      // ctx *could* be null if this is a rollback!!!  Sucks big time.
-      NodeSPI node = ctx == null ? dataContainer.peek(toMoveFqn) : ctx.lookUpNode(toMoveFqn);
+      NodeSPI node = ctx.lookUpNode(fqn);
 
       if (node == null || node.isDeleted())
       {
-         throw new NodeNotExistsException("Node " + toMoveFqn + " does not exist when attempting to move node!!");
+         if (trace) log.trace("Node " + fqn + " does not exist when attempting to move node!  Not doing anything.");
+         return null;
       }
 
       if (trace) log.trace("Moving " + fqn + " to sit under " + to);
 
-      NodeSPI oldParent = node.getParentDirect();
-      Object nodeName = toMoveFqn.getLastElement();
+      // the actual move algorithm.
+      NodeSPI newNode = ctx.lookUpNode(Fqn.fromRelativeElements(to, fqn.getLastElement()));
+      Fqn newNodeFqn = newNode.getFqn();
 
-      // now that we have the parent and target nodes:
-      // first correct the pointers at the pruning point
-      oldParent.removeChildDirect(nodeName);
-      newParent.addChild(nodeName, node);
-      // parent pointer is calculated on the fly using Fqns.
+      // at this stage all child node objects we need have been created and are available in the ctx.
+      // we just need to mark old ones as deleted, new ones as created, and move data across.
+      notifier.notifyNodeMoved(fqn, newNodeFqn, true, ctx);
+      moveRecursively(node, newNode, ctx);
+      notifier.notifyNodeMoved(fqn, newNodeFqn, false, ctx);
+      return null;
+   }
 
-      // notify
-      if (!skipNotifications)
-         notifier.notifyNodeMoved(toMoveFqn, Fqn.fromRelativeElements(newParentFqn, toMoveFqn.getLastElement()), true, ctx);
+   private void moveRecursively(NodeSPI oldNode, NodeSPI newNode, InvocationContext ctx)
+   {
+      if (trace) log.trace("Moving " + oldNode.getFqn() + " to " + newNode.getFqn());
+      // start deep.
+      Map<Object, NodeSPI> children = oldNode.getChildrenMapDirect();
+      if (children != null && !children.isEmpty())
+      {
+         for (NodeSPI child : children.values())
+         {
+            Fqn childFqn = child.getFqn();
+            Fqn newChildFqn = childFqn.replaceAncestor(oldNode.getFqn(), newNode.getFqn());
+            moveRecursively(ctx.lookUpNode(childFqn), ctx.lookUpNode(newChildFqn), ctx);
+         }
+      }
 
-      // now adjust Fqns of node and all children.
-      adjustFqn(node, newParent.getFqn());
+      // now swap the data for the current node.
+      newNode.putAllDirect(oldNode.getDataDirect());
+      oldNode.markAsDeleted(true);
+   }
 
-      if (!skipNotifications)
-         notifier.notifyNodeMoved(toMoveFqn, Fqn.fromRelativeElements(newParentFqn, toMoveFqn.getLastElement()), false, ctx);
+   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
+   {
+      return visitor.visitMoveCommand(ctx, this);
    }
 
    public Fqn getTo()

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-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/MVCCLockingInterceptor.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -298,16 +298,23 @@
    {
       // nodes we need to get WLs for:
       // node we are moving FROM (and it's parent and children.)  Same as removeNode.
-      List<Fqn> children = addNodeAndParentForRemoval(ctx, command.getFqn(), true);
+      List<Fqn> nodeAndChildren = addNodeAndParentForRemoval(ctx, command.getFqn(), true);
 
+      Fqn newParent = command.getTo();
+      Fqn oldParent = command.getFqn().getParent();
+
       // now lock the new parent.
-      getWrappedNode(ctx, command.getTo(), true, true, false);
+      getWrappedNode(ctx, newParent, true, true, false);
 
-      // the children list contains all child nodes, including the node itself.
-      // now obtain locks on the new places these children will occupy.
-      for (Fqn f : children)
+      if (!oldParent.equals(newParent) && nodeAndChildren != null)
       {
-         getWrappedNode(ctx, Fqn.fromRelativeFqn(command.getTo(), f), true, true, true);
+         // the nodeAndChildren list contains all child nodes, including the node itself.
+         // now obtain locks on the new places these new nodes will occupy.
+         for (Fqn f : nodeAndChildren)
+         {
+            Fqn newChildFqn = f.replaceAncestor(oldParent, newParent);
+            getWrappedNode(ctx, newChildFqn, true, true, true);
+         }
       }
 
       // now pass up the chain.

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-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/main/java/org/jboss/cache/mvcc/NodeReference.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -294,4 +294,23 @@
             "delegate=" + delegate +
             '}';
    }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      NodeReference that = (NodeReference) o;
+
+      if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return (delegate != null ? delegate.hashCode() : 0);
+   }
 }

Modified: core/trunk/src/test/java/org/jboss/cache/FqnTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/FqnTest.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/test/java/org/jboss/cache/FqnTest.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -432,6 +432,24 @@
       System.out.println("-- " + msg);
    }
 
+   public void testReplacingDirectAncestor()
+   {
+      Fqn fqn = Fqn.fromString("/a/b/c");
+      Fqn newParent = Fqn.fromString("/hot/dog");
+      Fqn expectedNewChild = Fqn.fromString("/hot/dog/c");
+
+      assert expectedNewChild.equals(fqn.replaceAncestor(fqn.getParent(), newParent));
+   }
+
+   public void testReplacingindirectAncestor()
+   {
+      Fqn fqn = Fqn.fromString("/a/b/c");
+      Fqn newParent = Fqn.fromString("/hot/dog");
+      Fqn expectedNewChild = Fqn.fromString("/hot/dog/b/c");
+
+      assert expectedNewChild.equals(fqn.replaceAncestor(fqn.getParent().getParent(), newParent));
+   }
+
    public void testDifferentFactories()
    {
       Fqn[] fqns = new Fqn[7];

Modified: core/trunk/src/test/java/org/jboss/cache/api/NodeMoveAPITest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/NodeMoveAPITest.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/test/java/org/jboss/cache/api/NodeMoveAPITest.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -69,7 +69,6 @@
       // to be overridden
    }
 
-   @Test(groups = {"functional"})
    public void testBasicMove()
    {
       nodeA = rootNode.addChild(A);
@@ -134,7 +133,6 @@
       return (Node<Object, Object>) node;
    }
 
-   @Test(groups = {"functional"})
    public void testMoveWithChildren()
    {
       nodeA = rootNode.addChild(A);
@@ -203,7 +201,6 @@
       assertEquals(nodeD, nodeE.getParent());
    }
 
-   @Test(groups = {"functional"})
    public void testTxCommit() throws Exception
    {
       nodeA = rootNode.addChild(A);
@@ -231,7 +228,6 @@
       assertTrue(nodeA.getChildren().isEmpty());
    }
 
-   @Test(groups = {"functional"})
    public void testTxRollback() throws Exception
    {
       nodeA = rootNode.addChild(A);
@@ -248,7 +244,7 @@
       cache.move(nodeB.getFqn(), Fqn.ROOT);
 
       // need to think of a way to test the same with optimistically locked nodes
-      if (!isOptimistic())
+      if (nodeLockingScheme == NodeLockingScheme.PESSIMISTIC)
       {
          assertEquals(rootNode, nodeA.getParent());
          assertEquals(rootNode, nodeB.getParent());
@@ -270,25 +266,21 @@
       assertEquals(nodeB, nodeA.getChildren().iterator().next());
    }
 
-   @Test(groups = {"functional"})
    public void testWithCacheloaders() throws Exception
    {
       doCacheLoaderTest(false, false);
    }
 
-   @Test(groups = {"functional"})
    public void testWithPassivation() throws Exception
    {
       doCacheLoaderTest(true, false);
    }
 
-   @Test(groups = {"functional"})
    public void testWithCacheloadersTx() throws Exception
    {
       doCacheLoaderTest(false, true);
    }
 
-   @Test(groups = {"functional"})
    public void testWithPassivationTx() throws Exception
    {
       doCacheLoaderTest(true, true);
@@ -296,7 +288,6 @@
 
    protected void doCacheLoaderTest(boolean pasv, boolean useTx) throws Exception
    {
-//      cache.stop();
       cache.destroy();
       cache.getConfiguration().setCacheLoaderConfig(getSingleCacheLoaderConfig(pasv, "/", DummyInMemoryCacheLoader.class.getName(), null, false, false, false, false));
       cache.start();
@@ -372,27 +363,26 @@
 
    }
 
-   @Test(groups = {"functional"})
    public void testLocksDeepMove() throws Exception
    {
       nodeA = rootNode.addChild(A);
       nodeB = nodeA.addChild(B);
       nodeD = nodeB.addChild(D);
       nodeC = rootNode.addChild(C);
+      nodeE = nodeC.addChild(E);
       assertEquals(0, cache.getNumberOfLocksHeld());
       tm.begin();
 
       cache.move(nodeC.getFqn(), nodeB.getFqn());
-      //       nodeC should have a RL, nodeA should have a RL, nodeB should have a WL, nodeD should have a WL
 
-      assertEquals("ROOT should have a RL, nodeC should have a RL, nodeA should have a RL, nodeB should have a WL, nodeD should have a WL", 5, cache.getNumberOfLocksHeld());
+      checkLocksDeep();
 
+
       tm.commit();
 
       assertEquals(0, cache.getNumberOfLocksHeld());
    }
 
-   @Test(groups = {"functional"})
    public void testLocks() throws Exception
    {
       nodeA = rootNode.addChild(A);
@@ -414,17 +404,18 @@
       assertEquals("ROOT should have a RL, nodeC should have a RL, nodeA should have a RL, nodeB should have a WL", 4, cache.getNumberOfLocksHeld());
    }
 
+   protected void checkLocksDeep()
+   {
+      assertEquals("ROOT should have a RL, nodeC should have a RL, nodeA should have a RL, nodeB should have a WL, nodeD should have a WL", 6, cache.getNumberOfLocksHeld());
+   }
+
    protected void assertNoLocks()
    {
       assertEquals(0, cache.getNumberOfLocksHeld());
    }
 
-   @Test(groups = {"functional"})
    public void testConcurrency() throws InterruptedException
    {
-      // FIXME: investigate intermittent failure when in isOptimistic() mode.
-      if (isOptimistic()) return;
-
       final int N = 3;// number of threads
       final int loops = 1 << 6;// number of loops
       // tests a tree structure as such:
@@ -536,7 +527,6 @@
       assertFalse("Should have only found y once", found_y_again);
    }
 
-   @Test(groups = {"functional"})
    public void testMoveInSamePlace()
    {
       final Fqn<String> FQN_X = Fqn.fromString("/x");
@@ -546,6 +536,8 @@
       assertEquals(aNode.getChildren().size(), 1);
       cache.move(xNode.getFqn(), aNode.getFqn());
       assertEquals(aNode.getChildren().size(), 1);
+
+      assert 0 == cache.getNumberOfLocksHeld();
    }
 
    protected CacheLoaderConfig getSingleCacheLoaderConfig(boolean passivation, String preload, String cacheloaderClass, String properties, boolean async, boolean fetchPersistentState, boolean shared, boolean purgeOnStartup) throws Exception
@@ -569,6 +561,6 @@
 
    protected boolean isOptimistic()
    {
-      return nodeLockingScheme == NodeLockingScheme.OPTIMISTIC;
+      return false;
    }
 }

Added: core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeMoveMvccTestBase.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeMoveMvccTestBase.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/NodeMoveMvccTestBase.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -0,0 +1,104 @@
+package org.jboss.cache.api.mvcc;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.api.NodeMoveAPITest;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.factories.ComponentRegistry;
+import org.jboss.cache.invocation.InvocationContextContainer;
+import org.jboss.cache.lock.LockManager;
+import org.jboss.cache.util.TestingUtil;
+import org.testng.annotations.Test;
+
+ at Test(groups = {"functional", "mvcc"})
+public abstract class NodeMoveMvccTestBase extends NodeMoveAPITest
+{
+   Fqn A_B = Fqn.fromRelativeFqn(A, B);
+   Fqn A_B_C = Fqn.fromRelativeFqn(A_B, C);
+   Fqn A_B_C_E = Fqn.fromRelativeFqn(A_B_C, E);
+   Fqn A_B_D = Fqn.fromRelativeFqn(A_B, D);
+   Fqn C_E = Fqn.fromRelativeFqn(C, E);
+   Fqn D_B = Fqn.fromRelativeFqn(D, B);
+   Fqn D_B_C = Fqn.fromRelativeFqn(D_B, C);
+
+
+   public NodeMoveMvccTestBase()
+   {
+      nodeLockingScheme = NodeLockingScheme.MVCC;
+   }
+
+   @Override
+   protected void checkLocks()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+      LockManager lm = cr.getComponent(LockManager.class);
+      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
+
+      LockAssert.assertNotLocked(A, lm, icc);
+      LockAssert.assertNotLocked(Fqn.ROOT, lm, icc);
+      LockAssert.assertLocked(C, lm, icc);
+      LockAssert.assertLocked(A_B, lm, icc);
+      LockAssert.assertLocked(A_B_C, lm, icc);
+   }
+
+   @Override
+   protected void checkLocksDeep()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+      LockManager lm = cr.getComponent(LockManager.class);
+      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
+
+      LockAssert.assertNotLocked(A, lm, icc);
+      LockAssert.assertNotLocked(Fqn.ROOT, lm, icc);
+      LockAssert.assertNotLocked(A_B_D, lm, icc);
+
+      // /a/b, /c, /c/e, /a/b/c and /a/b/c/e should all be locked.
+      LockAssert.assertLocked(A_B, lm, icc);
+      LockAssert.assertLocked(C, lm, icc);
+      LockAssert.assertLocked(C_E, lm, icc);
+      LockAssert.assertLocked(A_B_C, lm, icc);
+      LockAssert.assertLocked(A_B_C_E, lm, icc);
+   }
+
+   @Override
+   protected void assertNoLocks()
+   {
+      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
+      LockManager lm = cr.getComponent(LockManager.class);
+      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
+      LockAssert.assertNoLocks(lm, icc);
+   }
+
+   public void testNonexistentSource()
+   {
+      cache.put(A_B_C, "k", "v");
+      assert "v".equals(cache.get(A_B_C, "k"));
+      assert 1 == cache.getNode(A_B).getChildren().size();
+      assert cache.getNode(A_B).getChildrenNames().contains(C.getLastElement());
+      assert !cache.getNode(A_B).getChildrenNames().contains(D.getLastElement());
+
+      cache.move(D, A_B);
+
+      assert "v".equals(cache.get(A_B_C, "k"));
+      assert 1 == cache.getNode(A_B).getChildren().size();
+      assert cache.getNode(A_B).getChildrenNames().contains(C.getLastElement());
+      assert !cache.getNode(A_B).getChildrenNames().contains(D.getLastElement());
+   }
+
+   public void testNonexistentTarget()
+   {
+      cache.put(A_B_C, "k", "v");
+      assert "v".equals(cache.get(A_B_C, "k"));
+      assert 1 == cache.getNode(A_B).getChildren().size();
+      assert cache.getNode(A_B).getChildrenNames().contains(C.getLastElement());
+      assert null == cache.getNode(D);
+
+      cache.move(A_B, D);
+
+      assert null == cache.getNode(A_B_C);
+      assert null == cache.getNode(A_B);
+      assert null != cache.getNode(D);
+      assert null != cache.getNode(D_B);
+      assert null != cache.getNode(D_B_C);
+      assert "v".equals(cache.get(D_B_C, "k"));
+   }
+}

Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/NodeMoveMvccTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/NodeMoveMvccTest.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/read_committed/NodeMoveMvccTest.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -6,52 +6,17 @@
  */
 package org.jboss.cache.api.mvcc.read_committed;
 
-import org.jboss.cache.Fqn;
-import org.jboss.cache.api.NodeMoveAPITest;
-import org.jboss.cache.api.mvcc.LockAssert;
+import org.jboss.cache.api.mvcc.NodeMoveMvccTestBase;
 import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.Configuration.NodeLockingScheme;
-import org.jboss.cache.factories.ComponentRegistry;
-import org.jboss.cache.invocation.InvocationContextContainer;
 import org.jboss.cache.lock.IsolationLevel;
-import org.jboss.cache.lock.LockManager;
-import org.jboss.cache.util.TestingUtil;
 import org.testng.annotations.Test;
 
 @Test(groups = {"functional", "mvcc"})
-public class NodeMoveMvccTest extends NodeMoveAPITest
+public class NodeMoveMvccTest extends NodeMoveMvccTestBase
 {
-   public NodeMoveMvccTest()
-   {
-      nodeLockingScheme = NodeLockingScheme.MVCC;
-   }
-
    @Override
    protected void configure(Configuration c)
    {
       c.setIsolationLevel(IsolationLevel.READ_COMMITTED);
    }
-
-   @Override
-   protected void checkLocks()
-   {
-      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
-      LockManager lm = cr.getComponent(LockManager.class);
-      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
-
-      LockAssert.assertNotLocked(A, lm, icc);
-      LockAssert.assertLocked(Fqn.ROOT, lm, icc);
-      LockAssert.assertLocked(C, lm, icc);
-      LockAssert.assertLocked(Fqn.fromRelativeFqn(A, B), lm, icc);
-      LockAssert.assertLocked(Fqn.fromRelativeFqn(B, C), lm, icc);
-   }
-
-   @Override
-   protected void assertNoLocks()
-   {
-      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
-      LockManager lm = cr.getComponent(LockManager.class);
-      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
-      LockAssert.assertNoLocks(lm, icc);
-   }
 }
\ No newline at end of file

Modified: core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/NodeMoveMvccTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/NodeMoveMvccTest.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/test/java/org/jboss/cache/api/mvcc/repeatable_read/NodeMoveMvccTest.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -6,52 +6,17 @@
  */
 package org.jboss.cache.api.mvcc.repeatable_read;
 
-import org.jboss.cache.Fqn;
-import org.jboss.cache.api.NodeMoveAPITest;
-import org.jboss.cache.api.mvcc.LockAssert;
+import org.jboss.cache.api.mvcc.NodeMoveMvccTestBase;
 import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.Configuration.NodeLockingScheme;
-import org.jboss.cache.factories.ComponentRegistry;
-import org.jboss.cache.invocation.InvocationContextContainer;
 import org.jboss.cache.lock.IsolationLevel;
-import org.jboss.cache.lock.LockManager;
-import org.jboss.cache.util.TestingUtil;
 import org.testng.annotations.Test;
 
 @Test(groups = {"functional", "mvcc"})
-public class NodeMoveMvccTest extends NodeMoveAPITest
+public class NodeMoveMvccTest extends NodeMoveMvccTestBase
 {
-   public NodeMoveMvccTest()
-   {
-      nodeLockingScheme = NodeLockingScheme.MVCC;
-   }
-
    @Override
    protected void configure(Configuration c)
    {
       c.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
    }
-
-   @Override
-   protected void checkLocks()
-   {
-      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
-      LockManager lm = cr.getComponent(LockManager.class);
-      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
-
-      LockAssert.assertNotLocked(A, lm, icc);
-      LockAssert.assertLocked(Fqn.ROOT, lm, icc);
-      LockAssert.assertLocked(C, lm, icc);
-      LockAssert.assertLocked(Fqn.fromRelativeFqn(A, B), lm, icc);
-      LockAssert.assertLocked(Fqn.fromRelativeFqn(Fqn.fromRelativeFqn(A, B), C), lm, icc);
-   }
-
-   @Override
-   protected void assertNoLocks()
-   {
-      ComponentRegistry cr = TestingUtil.extractComponentRegistry(cache);
-      LockManager lm = cr.getComponent(LockManager.class);
-      InvocationContextContainer icc = cr.getComponent(InvocationContextContainer.class);
-      LockAssert.assertNoLocks(lm, icc);
-   }
 }

Modified: core/trunk/src/test/java/org/jboss/cache/api/optimistic/NodeMoveOptimisticTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/api/optimistic/NodeMoveOptimisticTest.java	2008-07-07 19:34:48 UTC (rev 6192)
+++ core/trunk/src/test/java/org/jboss/cache/api/optimistic/NodeMoveOptimisticTest.java	2008-07-07 19:38:22 UTC (rev 6193)
@@ -18,13 +18,27 @@
       nodeLockingScheme = NodeLockingScheme.OPTIMISTIC;
    }
 
+   @Override
+   protected boolean isOptimistic()
+   {
+      return true;
+   }
+
+   @Override
    public void testLocks()
    {
       // no op
    }
 
+   @Override
    public void testLocksDeepMove()
    {
       // no op
    }
+
+   @Override
+   public void testConcurrency()
+   {
+      // no op
+   }
 }




More information about the jbosscache-commits mailing list