Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  package org.infinispan.api.tree;
  
 
 
 import java.util.Set;
 
 import static org.testng.AssertJUnit.*;

Exercises and tests the new move() api.

Author(s):
Manik Surtani
 
 @Test(groups = "functional", testName = "api.tree.BaseNodeMoveAPITest")
 public abstract class BaseNodeMoveAPITest extends SingleCacheManagerTest {
    protected final Log log = LogFactory.getLog(getClass());
 
    protected static final Fqn A = Fqn.fromString("/a"), B = Fqn.fromString("/b"), C = Fqn.fromString("/c"), D = Fqn.fromString("/d"), E = Fqn.fromString("/e");
    static final Fqn A_B = Fqn.fromRelativeFqn();
    static final Fqn A_B_C = Fqn.fromRelativeFqn();
    static final Fqn A_B_C_E = Fqn.fromRelativeFqn();
    static final Fqn C_E = Fqn.fromRelativeFqn();
    static final Fqn D_B = Fqn.fromRelativeFqn();
    static final Fqn D_B_C = Fqn.fromRelativeFqn();
    protected static final Object k = "key"vA = "valueA"vB = "valueB"vC = "valueC"vD = "valueD"vE = "valueE";
 
 
    protected EmbeddedCacheManager createCacheManager() throws Exception {
       EmbeddedCacheManager cm = TestCacheManagerFactory.createCacheManager();
        = cm.getCache("test");
        = TestingUtil.extractComponent(TransactionManager.class);
        = new TreeCacheImpl<ObjectObject>();
        = TestingUtil.extractComponent(DataContainer.class);
       return cm;
    }

   
Various subclasses will provide a suitable cache configuration builder.
 
    protected abstract ConfigurationBuilder createConfigurationBuilder();
 
    public void testBasicMove() {
       Node<ObjectObjectrootNode = .getRoot();
 
       Node<ObjectObjectnodeA = rootNode.addChild();
       nodeA.put();
       Node<ObjectObjectnodeB = rootNode.addChild();
       nodeB.put();
       Node<ObjectObjectnodeC = nodeA.addChild();
       nodeC.put();
       /*
         /a/c
         /b
       */
 
       assertTrue(rootNode.hasChild());
       assertTrue(rootNode.hasChild());
       assertFalse(rootNode.hasChild());
       assertTrue(nodeA.hasChild());
 
       // test data
       assertEquals("" + nodeAnodeA.get());
       assertEquals(nodeB.get());
       assertEquals(nodeC.get());
 
       // parentage
       assertEquals(nodeAnodeC.getParent());
 
      .info("BEFORE MOVE " + );
      // move
      .move(nodeC.getFqn(), nodeB.getFqn());
      // re-fetch nodeC
      nodeC = .getNode(Fqn.fromRelativeFqn(nodeB.getFqn(), ));
      .info("POST MOVE " + );
      .info("HC " + nodeC + " " + Util.hexIdHashCode(nodeC));
      Node x = .getRoot().getChild(Fqn.fromString("b/c"));
      .info("HC " + x + " " + Util.hexIdHashCode(x));
      /*
         /a
         /b/c
      */
      assertEquals("NODE C " + nodeC"/b/c"nodeC.getFqn().toString());
      assertTrue(rootNode.hasChild());
      assertTrue(rootNode.hasChild());
      assertFalse(rootNode.hasChild());
      assertFalse(nodeA.hasChild());
      assertTrue(nodeB.hasChild());
      // test data
      assertEquals(nodeA.get());
      assertEquals(nodeB.get());
      assertEquals(nodeC.get());
      // parentage
      assertEquals("B is parent of C: " + nodeBnodeBnodeC.getParent());
   }
   @SuppressWarnings("unchecked")
   private Node<ObjectObjectgenericize(Node node) {
      return (Node<ObjectObject>) node;
   }
   public void testMoveWithChildren() {
      Node<ObjectObjectrootNode = .getRoot();
      Node<ObjectObjectnodeA = rootNode.addChild();
      nodeA.put();
      Node<ObjectObjectnodeB = rootNode.addChild();
      nodeB.put();
      Node<ObjectObjectnodeC = nodeA.addChild();
      nodeC.put();
      Node<ObjectObjectnodeD = nodeC.addChild();
      nodeD.put();
      Node<ObjectObjectnodeE = nodeD.addChild();
      nodeE.put();
      assertTrue(rootNode.hasChild());
      assertTrue(rootNode.hasChild());
      assertFalse(rootNode.hasChild());
      assertTrue(nodeA.hasChild());
      assertTrue(nodeC.hasChild());
      assertTrue(nodeD.hasChild());
      // test data
      assertEquals(nodeA.get());
      assertEquals(nodeB.get());
      assertEquals(nodeC.get());
      assertEquals(nodeD.get());
      assertEquals(nodeE.get());
      // parentage
      assertEquals(rootNodenodeA.getParent());
      assertEquals(rootNodenodeB.getParent());
      assertEquals(nodeAnodeC.getParent());
      assertEquals(nodeCnodeD.getParent());
      assertEquals(nodeDnodeE.getParent());
      // move
      .info("move " + nodeC + " to " + nodeB);
      .move(nodeC.getFqn(), nodeB.getFqn());
      //log.debugf("nodeB " + nodeB);
      //log.debugf("nodeC " + nodeC);
      // child nodes will need refreshing, since existing pointers will be stale.
      nodeC = nodeB.getChild();
      nodeD = nodeC.getChild();
      nodeE = nodeD.getChild();
      assertTrue(rootNode.hasChild());
      assertTrue(rootNode.hasChild());
      assertFalse(rootNode.hasChild());
      assertFalse(nodeA.hasChild());
      assertTrue(nodeB.hasChild());
      assertTrue(nodeC.hasChild());
      assertTrue(nodeD.hasChild());
      // test data
      assertEquals(nodeA.get());
      assertEquals(nodeB.get());
      assertEquals(nodeC.get());
      assertEquals(nodeD.get());
      assertEquals(nodeE.get());
      // parentage
      assertEquals(rootNodenodeA.getParent());
      assertEquals(rootNodenodeB.getParent());
      assertEquals(nodeBnodeC.getParent());
      assertEquals(nodeCnodeD.getParent());
      assertEquals(nodeDnodeE.getParent());
   }
   public void testTxCommit() throws Exception {
      Node<ObjectObjectrootNode = .getRoot();
      Node<ObjectObjectnodeA = rootNode.addChild();
      Node<ObjectObjectnodeB = nodeA.addChild();
      assertEquals(rootNodenodeA.getParent());
      assertEquals(nodeAnodeB.getParent());
      assertEquals(nodeArootNode.getChildren().iterator().next());
      assertEquals(nodeBnodeA.getChildren().iterator().next());
      .begin();
      .debugf("Before: " + TreeStructureSupport.printTree(true));
      // move node B up to hang off the root
      .move(nodeB.getFqn(), .);
      .debugf("After: " + TreeStructureSupport.printTree(true));
      .commit();
      .debugf("Committed: " + TreeStructureSupport.printTree(true));
      nodeB = rootNode.getChild();
      assertEquals(rootNodenodeA.getParent());
      assertEquals(rootNodenodeB.getParent());
      assertTrue(rootNode.getChildren().contains(nodeA));
      assertTrue(rootNode.getChildren().contains(nodeB));
      assertTrue(nodeA.getChildren().isEmpty());
   }
   public void testTxRollback() throws Exception {
      Node<ObjectObjectrootNode = .getRoot();
      Node<ObjectObjectnodeA = rootNode.addChild();
      Node<ObjectObjectnodeB = nodeA.addChild();
      assertEquals(rootNodenodeA.getParent());
      assertEquals(nodeAnodeB.getParent());
      assertEquals(nodeArootNode.getChildren().iterator().next());
      assertEquals(nodeBnodeA.getChildren().iterator().next());
      .begin();
      // move node B up to hang off the root
      .debugf("Before: " + TreeStructureSupport.printTree(true));
      .move(nodeB.getFqn(), .);
      .debugf("After: " + TreeStructureSupport.printTree(true));
      .rollback();
      .debugf("Rolled back: " + TreeStructureSupport.printTree(true));
      nodeA = rootNode.getChild();
      nodeB = nodeA.getChild();
      // should revert
      assertEquals(rootNodenodeA.getParent());
      assertEquals(nodeAnodeB.getParent());
      assertEquals(nodeArootNode.getChildren().iterator().next());
      assertEquals(nodeBnodeA.getChildren().iterator().next());
   }
   public void testLocksDeepMove() throws Exception {
      Node<ObjectObjectrootNode = .getRoot();
      // Initial setup: /a/b/d, /c/e
      Node<ObjectObjectnodeA = rootNode.addChild();
      Node<ObjectObjectnodeB = nodeA.addChild();
      Node<ObjectObjectnodeD = nodeB.addChild();
      Node<ObjectObjectnodeC = rootNode.addChild();
      Node<ObjectObjectnodeE = nodeC.addChild();
      assertNoLocks();
      .begin();
      // Move /c -> /a/b, new setup: /a/b/d, /a/b/c/e
      .move(nodeC.getFqn(), nodeB.getFqn());
      // /a/b, /c, /c/e, /a/b/c and /a/b/c/e should all be locked.
      assertTrue(isNodeLocked(true));
      assertTrue(isNodeLocked(true));
      assertTrue(isNodeLocked(false));
      assertTrue(isNodeLocked(true));
      assertTrue(isNodeLocked(true));
      .commit();
      assertNoLocks();
   }
   public void testLocks() throws Exception {
      Node<ObjectObjectrootNode = .getRoot();
      // Initial setup: /a/b, /c
      Node<ObjectObjectnodeA = rootNode.addChild();
      Node<ObjectObjectnodeB = nodeA.addChild();
      Node<ObjectObjectnodeC = rootNode.addChild();
      assertNoLocks();
      .begin();
      // Move /c -> /a/b/c
      .move(nodeC.getFqn(), nodeB.getFqn());
      assertTrue(isNodeLocked(true));
      assertTrue(isNodeLocked(true));
      assertTrue(isNodeLocked(.false));
      assertTrue(isNodeLocked(false));
      .commit();
      assertNoLocks();
   }
   public void testConcurrentMoveSiblings() throws Exception {
      // tests a tree structure as such:
      // /a/x, a/y, /b, /c
      // N threads try to move /a/x from /a to /b and /a/y from /a to /c
      final int N = 5;
      final Fqn X = Fqn.fromString("/x"), Y = Fqn.fromString("/y");
      // set up the initial structure.
      Node<ObjectObjectrootNode = .getRoot();
      Node<ObjectObjectnodeA = rootNode.addChild();
      nodeA.addChild(X);
      nodeA.addChild(Y);
      Node<ObjectObjectnodeB = rootNode.addChild();
      Node<ObjectObjectnodeC = rootNode.addChild();
      Callable<Object>[] movers = new Callable[N];
      for (int i = 0; i < Ni++) {
         final Fqn source = Fqn.fromRelativeFqn(i % 2 == 0 ? X : Y);
         final Fqn dest = i % 2 == 0 ?  : ;
         movers[i] = new Callable<Object>() {
            public Object call() {
               try {
                  .move(sourcedest);
               } catch (Exception e) {
                  // expected on some of the threads, in optimistic mode
               }
               return null;
            }
         };
      }
      runConcurrently(movers);
      .info("Tree: " + TreeStructureSupport.printTree(true));
      assertNoLocks();
      // Any of the move operations may fail, so just check that each node exists in exactly one place
      assertTrue(nodeA.getChildrenNames().contains("x") ^ nodeB.getChildrenNames().contains("x"));
      assertTrue(nodeA.getChildrenNames().contains("y") ^ nodeC.getChildrenNames().contains("y"));
   }
   public void testConcurrentMoveToSameDest() throws Exception {
      // tests a tree structure as such:
      // /a/x, /b/y, /c
      // N threads try to move /a/x to /c and /b/y to /c at the same time
      final int N = 5;
      final Fqn X = Fqn.fromString("/x"), Y = Fqn.fromString("/y");
      // set up the initial structure.
      Node<ObjectObjectrootNode = .getRoot();
      Node<ObjectObjectnodeA = rootNode.addChild();
      nodeA.addChild(X);
      Node<ObjectObjectnodeB = rootNode.addChild();
      nodeB.addChild(Y);
      Node<ObjectObjectnodeC = rootNode.addChild();
      Callable<Object>[] movers = new Callable[N];
      for (int i = 0; i < Ni++) {
         final Fqn source = i % 2 == 0 ? Fqn.fromRelativeFqn(X) : Fqn.fromRelativeFqn(Y);
         movers[i] = new Callable<Object>() {
            public Object call() throws Exception {
               try {
                  .move(source);
               } catch (Exception e) {
                  // expected on some of the threads, in optimistic mode
               }
               return null;
            }
         };
      }
      runConcurrently(movers);
      .info("Tree: " + TreeStructureSupport.printTree(true));
      assertNoLocks();
      // Any of the move operations may fail, so just check that each node exists in exactly one place
      assertTrue(nodeA.getChildrenNames().contains("x") ^ nodeC.getChildrenNames().contains("x"));
      assertTrue(nodeB.getChildrenNames().contains("y") ^ nodeC.getChildrenNames().contains("y"));
   }
   public void testConcurrentMoveSameNode() throws Exception {
      // set up the initial structure
      // /a, /b, /c
      // one thread tries to move /c under /a, another tries to move /c under /b
      Node<ObjectObjectrootNode = .getRoot();
      final Fqn FQN_A = FQN_B = FQN_C = ;
      Node nodeA = rootNode.addChild(FQN_A);
      Node nodeB = rootNode.addChild(FQN_B);
      Node nodeC = rootNode.addChild(FQN_C);
      final CountDownLatch nodeReadLatch = new CountDownLatch(1);
      final CountDownLatch nodeMovedLatch = new CountDownLatch(1);
      // tries to move C under B right after another thread already moved C under A
      Callable<ObjectmoveCtoB = new Callable<Object>() {
         public Object call() throws Exception {
            tm().begin();
            try {
               // ensure we already 'see' node C in this tx. this is what actually triggers the issue.
               assertEquals(asSet("a""b""c"), .getRoot().getChildrenNames());
               assertEquals(Collections.emptySet(), .getNode(FQN_C).getChildrenNames());
               nodeReadLatch.countDown();
               nodeMovedLatch.await();
               .move(FQN_CFQN_B);
               tm().commit(); //this is expected to fail
               fail("Transaction should have failed");
            } catch (Exception e) {
               if (tm().getTransaction() != null) {
                  // the TX is most likely rolled back already, but we attempt a rollback just in case it isn't
                  try {
                     tm().rollback();
                  } catch (SystemException e1) {
                     .error("Failed to rollback"e1);
                  }
               }
            }
            return null;
         }
      };
      // moves C under A successfully
      Callable<ObjectmoveCtoA = new Callable<Object>() {
         public Object call() throws Exception {
            tm().begin();
            try {
               try {
                  nodeReadLatch.await();
                  .move(FQN_CFQN_A);
                  tm().commit();
               } finally {
                  nodeMovedLatch.countDown();
               }
            } catch (Exception e) {
               if (tm().getTransaction() != null) {
                  // the TX is most likely rolled back already, but we attempt a rollback just in case it isn't
                  try {
                     tm().rollback();
                  } catch (SystemException e1) {
                     .error("Failed to rollback"e1);
                  }
               }
               throw e;
            }
            return null;
         }
      };
      runConcurrently(moveCtoBmoveCtoA);
      .trace("Tree: " + TreeStructureSupport.printTree(true));
      assertNoLocks();
      assertFalse(nodeC.isValid());
      assertEquals(asSet("a""b"), rootNode.getChildrenNames());
      assertEquals(asSet("c"), nodeA.getChildrenNames());
      assertEquals(Collections.emptySet(), nodeB.getChildrenNames());
   }
   public void testMoveInSamePlace() {
      Node<ObjectObjectrootNode = .getRoot();
      final Fqn FQN_X = Fqn.fromString("/x");
      // set up the initial structure.
      Node aNode = rootNode.addChild();
      Node xNode = aNode.addChild(FQN_X);
      assertEquals(aNode.getChildren().size(), 1);
      .debugf("Before: " + TreeStructureSupport.printTree(true));
      .move(xNode.getFqn(), aNode.getFqn());
      .debugf("After: " + TreeStructureSupport.printTree(true));
      assertNoLocks();
      assertEquals(aNode.getChildren().size(), 1);
   }

   
Looks up the CacheEntry stored in transactional context corresponding to this AtomicMap. If this AtomicMap has yet to be touched by the current transaction, this method will return a null.

Returns:
   protected CacheEntry lookupEntryFromCurrentTransaction(TransactionTable transactionTableTransactionManager transactionManagerObject key) {
      // Prior to 5.1, this used to happen by grabbing any InvocationContext in ThreadLocal.  Since ThreadLocals
      // can no longer be relied upon in 5.1, we need to grab the TransactionTable and check if an ongoing
      // transaction exists, peeking into transactional state instead.
      try {
         LocalTransaction localTransaction = transactionTable.getLocalTransaction(transactionManager.getTransaction());
         // The stored localTransaction could be null, if this is the first call in a transaction.  In which case
         // we know that there is no transactional state to refer to - i.e., no entries have been looked up as yet.
         return localTransaction == null ? null : localTransaction.lookupEntry(key);
      } catch (SystemException e) {
         return null;
      }
   }
   protected boolean isNodeLocked(Fqn fqnboolean includeData) {
      CacheEntry structure = lookupEntryFromCurrentTransaction(tttmnew NodeKey(fqn..));
      CacheEntry data = lookupEntryFromCurrentTransaction(tttmnew NodeKey(fqn..));
      return structure != null && data != null && structure.isChanged() && (!includeData || data.isChanged());
   }
   protected void assertNoLocks() {
      ComponentRegistry cr = TestingUtil.extractComponentRegistry();
      LockManager lm = cr.getComponent(LockManager.class);
      LockAssert.assertNoLocks(lm);
   }
   public void testNonexistentSource() {
      .put("k""v");
      assert "v".equals(.get("k"));
      assert 1 == .getNode().getChildren().size();
      .move();
      assert "v".equals(.get("k"));
      assert 1 == .getNode().getChildren().size();
   }
   public void testNonexistentTarget() {
      .put("k""v");
      assert "v".equals(.get("k"));
      assert 1 == .getNode().getChildren().size();
      assert null == .getNode();
      .debugf(TreeStructureSupport.printTree(true));
      .move();
      .debugf(TreeStructureSupport.printTree(true));
      assert null == .getNode();
      assert null == .getNode();
      assert null != .getNode();
      assert null != .getNode();
      assert null != .getNode();
      assert "v".equals(.get("k"));
   }
   
   private Set<ObjectasSet(Object... names) {
      return Util.asSet(names);
   }
New to GrepCode? Check out our FAQ X