Package org.jboss.cache.api.mvcc

Source Code of org.jboss.cache.api.mvcc.LockTestBase

package org.jboss.cache.api.mvcc;

import org.jboss.cache.Cache;
import org.jboss.cache.Fqn;
import org.jboss.cache.UnitTestCacheFactory;
import org.jboss.cache.config.Configuration.CacheMode;
import org.jboss.cache.config.Configuration.NodeLockingScheme;
import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
import org.jboss.cache.invocation.InvocationContextContainer;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.lock.LockManager;
import org.jboss.cache.lock.TimeoutException;
import org.jboss.cache.transaction.DummyTransactionManagerLookup;
import org.jboss.cache.util.TestingUtil;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import java.util.Collections;

/**
* @author Manik Surtani (<a href="mailto:manik AT jboss DOT org">manik AT jboss DOT org</a>)
* @since 3.0
*/
@Test(groups = {"functional", "mvcc"})
public abstract class LockTestBase
{
   protected Fqn A = Fqn.fromString("/a");
   protected Fqn AB = Fqn.fromString("/a/b");
   protected Fqn ABC = Fqn.fromString("/a/b/c");
   protected Fqn ABCD = Fqn.fromString("/a/b/c/d");
   protected boolean repeatableRead = true;
   protected boolean lockParentForChildInsertRemove = false;

   protected class LockTestBaseTL {
      public Cache<String, String> cache;
      public TransactionManager tm;
      public LockManager lockManager;
      public InvocationContextContainer icc;
   }
  
   protected ThreadLocal<LockTestBaseTL> threadLocal = new ThreadLocal<LockTestBaseTL>();

   @BeforeMethod
   public void setUp()
   {
      LockTestBaseTL tl = new LockTestBaseTL();
     
      tl.cache = new UnitTestCacheFactory<String, String>().createCache(UnitTestCacheConfigurationFactory.createConfiguration(CacheMode.LOCAL), false);
      tl.cache.getConfiguration().setNodeLockingScheme(NodeLockingScheme.MVCC);
      tl.cache.getConfiguration().setTransactionManagerLookupClass(DummyTransactionManagerLookup.class.getName());
      tl.cache.getConfiguration().setIsolationLevel(repeatableRead ? IsolationLevel.REPEATABLE_READ : IsolationLevel.READ_COMMITTED);
      tl.cache.getConfiguration().setLockParentForChildInsertRemove(lockParentForChildInsertRemove);
      // reduce lock acquisition timeout so this doesn't take forever to run
      tl.cache.getConfiguration().setLockAcquisitionTimeout(200); // 200 ms
      tl.cache.start();
      tl.lockManager = TestingUtil.extractComponentRegistry(tl.cache).getComponent(LockManager.class);
      tl.icc = TestingUtil.extractComponentRegistry(tl.cache).getComponent(InvocationContextContainer.class);
      tl.tm = TestingUtil.extractComponentRegistry(tl.cache).getComponent(TransactionManager.class);     
      threadLocal.set(tl);
   }

   @AfterMethod
   public void tearDown()
   {
      LockTestBaseTL tl = threadLocal.get();
      TestingUtil.killCaches(tl.cache);
      threadLocal.set(null);
   }

   protected void assertLocked(Fqn fqn)
   {
      LockTestBaseTL tl = threadLocal.get();
      LockAssert.assertLocked(fqn, tl.lockManager, tl.icc);
   }

   protected void assertNotLocked(Fqn fqn)
   {
      LockTestBaseTL tl = threadLocal.get();
      LockAssert.assertNotLocked(fqn, tl.lockManager, tl.icc);
   }

   protected void assertNoLocks()
   {
      LockTestBaseTL tl = threadLocal.get();
      LockAssert.assertNoLocks(tl.lockManager, tl.icc);
   }

   public void testLocksOnPutKeyVal() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.tm.begin();
      tl.cache.put(AB, "k", "v");
      if (lockParentForChildInsertRemove)
         assertLocked(Fqn.ROOT);
      else
         assertNotLocked(Fqn.ROOT);
      assertLocked(A);
      assertLocked(AB);
      assertNotLocked(ABC);
      tl.tm.commit();

      assertNoLocks();

      tl.tm.begin();
      assert tl.cache.get(AB, "k").equals("v");
      assertNotLocked(Fqn.ROOT);
      assertNotLocked(A);
      assertNotLocked(AB);
      assertNotLocked(ABC);
      tl.tm.commit();

      assertNoLocks();

      tl.tm.begin();
      tl.cache.put(ABC, "k", "v");
      assertNotLocked(Fqn.ROOT);
      assertNotLocked(A);
      if (lockParentForChildInsertRemove)
         assertLocked(AB);
      else
         assertNotLocked(AB);
      assertLocked(ABC);
      tl.tm.commit();

      assertNoLocks();
   }

   public void testLocksOnPutData() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.tm.begin();
      tl.cache.put(AB, Collections.singletonMap("k", "v"));
      if (lockParentForChildInsertRemove)
         assertLocked(Fqn.ROOT);
      else
         assertNotLocked(Fqn.ROOT);
      assertLocked(A);
      assertLocked(AB);
      assertNotLocked(ABC);
      assert "v".equals(tl.cache.get(AB, "k"));
      tl.tm.commit();
      assert "v".equals(tl.cache.get(AB, "k"));
      assertNoLocks();

      tl.tm.begin();
      assert "v".equals(tl.cache.get(AB, "k"));
      assertNotLocked(Fqn.ROOT);
      assertNotLocked(A);
      assertNotLocked(AB);
      assertNotLocked(ABC);
      tl.tm.commit();

      assertNoLocks();

      tl.tm.begin();
      tl.cache.put(ABC, Collections.singletonMap("k", "v"));
      assertNotLocked(Fqn.ROOT);
      assertNotLocked(A);
      if (lockParentForChildInsertRemove)
         assertLocked(AB);
      else
         assertNotLocked(AB);
      assertLocked(ABC);
      tl.tm.commit();

      assertNoLocks();
   }

   public void testLocksOnRemoveNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      // init some data on a node
      tl.cache.put(AB, Collections.singletonMap("k", "v"));

      assert "v".equals(tl.cache.get(AB, "k"));

      tl.tm.begin();
      tl.cache.removeNode(AB);
      assertLocked(AB);
      if (lockParentForChildInsertRemove)
         assertLocked(A);
      else
         assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.getNode(AB) == null : "Should not exist";
      assertNoLocks();
   }

   public void testLocksOnEvictNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      // init some data on a node
      tl.cache.put(AB, Collections.singletonMap("k", "v"));

      assert "v".equals(tl.cache.get(AB, "k"));

      tl.tm.begin();
      tl.cache.evict(AB);
      assertLocked(AB);
      if (lockParentForChildInsertRemove)
         assertLocked(A);
      else
         assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.getNode(AB) == null : "Should not exist";
      assertNoLocks();
   }

   public void testLocksOnEvictRecursiveNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      // init some data on a node
      tl.cache.put(AB, Collections.singletonMap("k", "v"));
      tl.cache.put(ABC, Collections.singletonMap("k", "v"));
      tl.cache.put(ABCD, Collections.singletonMap("k", "v"));

      assert "v".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));
      assert "v".equals(tl.cache.get(ABCD, "k"));

      tl.tm.begin();
      tl.cache.evict(AB, true);
      assertLocked(AB);
      assertLocked(ABC);
      assertLocked(ABCD);
      if (lockParentForChildInsertRemove)
         assertLocked(A);
      else
         assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.getNode(AB) == null : "Should not exist";
      assertNoLocks();
   }

   public void testLocksOnRemoveNonexistentNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      assert tl.cache.getNode(AB) == null : "Should not exist";

      tl.tm.begin();
      tl.cache.removeNode(AB);
      assertLocked(AB);
      if (lockParentForChildInsertRemove)
         assertLocked(A);
      else
         assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.getNode(AB) == null : "Should not exist";
      assertNoLocks();
   }

   public void testLocksOnEvictNonexistentNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      assert tl.cache.getNode(AB) == null : "Should not exist";

      tl.tm.begin();
      tl.cache.evict(AB);
      assertLocked(AB);
      if (lockParentForChildInsertRemove)
         assertLocked(A);
      else
         assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.getNode(AB) == null : "Should not exist";
      assertNoLocks();
   }

   public void testLocksOnRemoveData() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      // init some data on a node
      tl.cache.put(AB, "k", "v");
      tl.cache.put(AB, "k2", "v2");

      assert "v".equals(tl.cache.get(AB, "k"));
      assert "v2".equals(tl.cache.get(AB, "k2"));

      // remove
      tl.tm.begin();
      Object x = tl.cache.remove(AB, "k");
      assert x.equals("v");
      assertLocked(AB);
      assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.get(AB, "k") == null : "Should not exist";
      assert "v2".equals(tl.cache.get(AB, "k2"));
      assertNoLocks();

      // clearData
      tl.tm.begin();
      tl.cache.clearData(AB);
      assertLocked(AB);
      assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();

      assert tl.cache.get(AB, "k") == null : "Should not exist";
      assert tl.cache.get(AB, "k2") == null : "Should not exist";
      assertNoLocks();

      // nonexistent key
      assert tl.cache.get(AB, "k3") == null : "Should not exist";
      tl.tm.begin();
      tl.cache.remove(AB, "k3");
      assertLocked(AB);
      assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assertNoLocks();
   }

   public void testLocksOnRemoveDataNonExistentNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      assert tl.cache.getNode(AB) == null : "Should not exist";

      tl.tm.begin();
      tl.cache.remove(AB, "k");
      assertNotLocked(AB);
      assertNotLocked(A);
      assertNotLocked(Fqn.ROOT);
      tl.tm.commit();
      assert tl.cache.getNode(AB) == null : "Should not exist";
   }

   public void testReadMethods() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      tl.tm.begin();
      assert "v".equals(tl.cache.get(AB, "k"));
      assertNoLocks();
      tl.tm.commit();
      assertNoLocks();

      tl.tm.begin();
      assert tl.cache.getData(AB).containsKey("k");
      assertNoLocks();
      tl.tm.commit();
      assertNoLocks();

      tl.tm.begin();
      assert tl.cache.getKeys(AB).contains("k");
      assertNoLocks();
      tl.tm.commit();
      assertNoLocks();

      tl.tm.begin();
      assert tl.cache.getNode(AB) != null;
      assertNoLocks();
      tl.tm.commit();
      assertNoLocks();

      tl.tm.begin();
      assert tl.cache.getNode(A) != null;
      assert !(tl.cache.getNode(A).getChildrenNames().isEmpty());
      assert tl.cache.getNode(A).getChildrenNames().contains(AB.getLastElement());
      assertNoLocks();
      tl.tm.commit();
      assertNoLocks();
   }

   public void testWriteDoesntBlockRead() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      // start a write.
      tl.tm.begin();
      tl.cache.put(AB, "k2", "v2");
      assertLocked(AB);
      Transaction write = tl.tm.suspend();

      // now start a read and confirm that the write doesn't block it.
      tl.tm.begin();
      assert "v".equals(tl.cache.get(AB, "k"));
      assert null == tl.cache.get(AB, "k2") : "Should not see uncommitted changes";
      Transaction read = tl.tm.suspend();

      // commit the write
      tl.tm.resume(write);
      tl.tm.commit();

      assertNoLocks();

      tl.tm.resume(read);
      if (repeatableRead)
         assert null == tl.cache.get(AB, "k2") : "Should have repeatable read";
      else
         assert "v2".equals(tl.cache.get(AB, "k2")) : "Read committed should see committed changes";
      tl.tm.commit();
      assertNoLocks();
   }

   public void testWriteDoesntBlockReadNonexistent() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      // start a write.
      tl.tm.begin();
      tl.cache.put(AB, "k", "v");
      assertLocked(AB);
      Transaction write = tl.tm.suspend();

      // now start a read and confirm that the write doesn't block it.
      tl.tm.begin();
      assert null == tl.cache.get(AB, "k") : "Should not see uncommitted changes";
      assert null == tl.cache.getNode(AB);
      Transaction read = tl.tm.suspend();

      // commit the write
      tl.tm.resume(write);
      tl.tm.commit();

      assertNoLocks();

      tl.tm.resume(read);
      if (repeatableRead)
      {
         assert null == tl.cache.get(AB, "k") : "Should have repeatable read";
         assert null == tl.cache.getNode(AB);
      }
      else
      {
         assert "v".equals(tl.cache.get(AB, "k")) : "Read committed should see committed changes";
         assert null != tl.cache.getNode(AB);
      }
      tl.tm.commit();
      assertNoLocks();
   }

   public void testConcurrentWriters() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.tm.begin();
      tl.cache.put(AB, "k", "v");
      Transaction t1 = tl.tm.suspend();

      tl.tm.begin();
      try
      {
         tl.cache.put(AB, "k", "v");
         assert false : "Should fail lock acquisition";
      }
      catch (TimeoutException expected)
      {
//         expected.printStackTrace();  // for debugging
      }
      tl.tm.commit();
      tl.tm.resume(t1);
      tl.tm.commit();
      assertNoLocks();
   }

   public void testRollbacks() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");
      tl.tm.begin();
      assert "v".equals(tl.cache.get(AB, "k"));
      Transaction reader = tl.tm.suspend();

      tl.tm.begin();
      tl.cache.put(AB, "k", "v2");
      tl.tm.rollback();

      tl.tm.resume(reader);
      assert "v".equals(tl.cache.get(AB, "k")) : "Expecting 'v' but was " + tl.cache.get(AB, "k");
      tl.tm.commit();

      // even after commit
      assert "v".equals(tl.cache.get(AB, "k"));
      assertNoLocks();
   }

   public void testRollbacksOnNullNode() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.tm.begin();
      assert null == tl.cache.get(AB, "k");
      assert null == tl.cache.getNode(AB);
      Transaction reader = tl.tm.suspend();

      tl.tm.begin();
      tl.cache.put(AB, "k", "v");
      assert null != tl.cache.getNode(AB);
      assert "v".equals(tl.cache.get(AB, "k"));
      tl.tm.rollback();

      tl.tm.resume(reader);
      assert null == tl.cache.get(AB, "k") : "Expecting null but was " + tl.cache.get(AB, "k");
      assert null == tl.cache.getNode(AB);
      tl.tm.commit();

      // even after commit
      assert null == tl.cache.get(AB, "k");
      assert null == tl.cache.getNode(AB);
      assertNoLocks();
   }

   public void testPhantomChildren() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");
      assert tl.cache.getNode(AB).getChildren().size() == 0;
      assert tl.cache.getNode(A).getChildren().size() == 1;

      tl.tm.begin();
      tl.cache.put(ABC, "k", "v");
      assert tl.cache.getRoot().hasChild(ABC);
      assert tl.cache.getNode(ABC) != null;
      assert tl.cache.getNode(AB).getChild(ABC.getLastElement()) != null;
      assert tl.cache.getNode(AB).getChildren().size() == 1;
      Transaction t = tl.tm.suspend();


      assert tl.cache.getNode(ABC) == null;
      assert tl.cache.getNode(AB).getChild(ABC.getLastElement()) == null;
      assert tl.cache.getNode(AB).getChildren().size() == 0;

      tl.tm.resume(t);
      assert tl.cache.getRoot().hasChild(ABC);
      assert tl.cache.getNode(ABC) != null;
      tl.tm.commit();

      assert tl.cache.getNode(ABC) != null;
      assert tl.cache.getNode(AB).getChild(ABC.getLastElement()) != null;
      assert tl.cache.getNode(AB).getChildren().size() == 1;
   }

   public void testChildCount() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");
      assert tl.cache.getNode(AB).getChildren().size() == 0;
      assert tl.cache.getNode(A).getChildren().size() == 1;

      tl.tm.begin();
      assert tl.cache.getNode(AB).getChildren().size() == 0;
      assert tl.cache.getNode(A).getChildren().size() == 1;
      tl.cache.removeNode(AB);
      assert tl.cache.getNode(A).getChildren().size() == 0;
      assert tl.cache.getNode(A).hasChild(AB.getLastElement()) == false;
      assert tl.cache.getNode(AB) == null;
      Transaction t = tl.tm.suspend();


      assert tl.cache.getNode(AB) != null;
      assert tl.cache.getNode(A).getChild(AB.getLastElement()) != null;
      assert tl.cache.getNode(A).getChildren().size() == 1;

      tl.tm.resume(t);
      assert tl.cache.getNode(A).getChildren().size() == 0;
      assert tl.cache.getNode(A).hasChild(AB.getLastElement()) == false;
      assert tl.cache.getNode(AB) == null;
      tl.tm.commit();

      assert tl.cache.getNode(A).getChildren().size() == 0;
      assert tl.cache.getNode(A).hasChild(AB.getLastElement()) == false;
      assert tl.cache.getNode(AB) == null;
   }

   public void testOverwritingOnInsert() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      tl.tm.begin();
      tl.cache.put(ABC, "k", "v");
      assert "v".equals(tl.cache.get(ABC, "k"));
      assert "v".equals(tl.cache.get(AB, "k"));
      Transaction t1 = tl.tm.suspend();

      tl.tm.begin();
      tl.cache.put(AB, "k", "v2");
      assert "v2".equals(tl.cache.get(AB, "k"));
      assert null == tl.cache.get(ABC, "k");
      Transaction t2 = tl.tm.suspend();

      tl.tm.resume(t1);
      t1.commit();

      assert "v".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));

      tl.tm.resume(t2);
      t2.commit();

      assert "v2".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));
   }

   public void testOverwritingOnInsert2() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      tl.tm.begin();
      tl.cache.put(AB, "k", "v2");
      assert "v2".equals(tl.cache.get(AB, "k"));
      assert null == tl.cache.get(ABC, "k");
      Transaction t1 = tl.tm.suspend();

      tl.tm.begin();
      tl.cache.put(ABC, "k", "v");
      assert "v".equals(tl.cache.get(ABC, "k"));
      assert "v".equals(tl.cache.get(AB, "k"));
      Transaction t2 = tl.tm.suspend();

      tl.tm.resume(t1);
      t1.commit();

      assert "v2".equals(tl.cache.get(AB, "k"));
      assert null == tl.cache.get(ABC, "k");

      tl.tm.resume(t2);
      t2.commit();

      assert "v2".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));
   }

   public void testOverwritingOnInsert3() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      tl.tm.begin();
      tl.cache.put(AB, "k", "v2");
      assert "v2".equals(tl.cache.get(AB, "k"));
      assert null == tl.cache.get(ABC, "k");
      Transaction t1 = tl.tm.suspend();

      tl.tm.begin();
      tl.cache.put(ABC, "k", "v");
      assert "v".equals(tl.cache.get(ABC, "k"));
      assert "v".equals(tl.cache.get(AB, "k"));
      tl.tm.commit();

      assert "v".equals(tl.cache.get(ABC, "k"));
      assert "v".equals(tl.cache.get(AB, "k"));

      tl.tm.resume(t1);
      t1.commit();

      assert "v2".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));
   }

   public void testConcurrentInsertRemove1() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      tl.tm.begin();
      tl.cache.put(ABC, "k", "v");
      assert "v".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));
      Transaction t1 = tl.tm.suspend();

      tl.tm.begin();
      tl.cache.removeNode(AB);
      assert null == tl.cache.get(ABC, "k");
      assert null == tl.cache.get(AB, "k");
      tl.tm.commit();

      assert null == tl.cache.get(ABC, "k");
      assert null == tl.cache.get(AB, "k");

      tl.tm.resume(t1);
      t1.commit();

      assert null == tl.cache.get(ABC, "k");
      assert null == tl.cache.get(AB, "k");
   }

   public void testConcurrentInsertRemove2() throws Exception
   {
      LockTestBaseTL tl = threadLocal.get();
      tl.cache.put(AB, "k", "v");

      tl.tm.begin();
      tl.cache.removeNode(AB);
      assert null == tl.cache.get(ABC, "k");
      assert null == tl.cache.get(AB, "k");
      Transaction t1 = tl.tm.suspend();

      tl.tm.begin();
      assert "v".equals(tl.cache.get(AB, "k"));
      tl.cache.put(ABC, "k", "v");
      assert "v".equals(tl.cache.get(ABC, "k"));
      tl.tm.commit();

      assert "v".equals(tl.cache.get(AB, "k"));
      assert "v".equals(tl.cache.get(ABC, "k"));

      tl.tm.resume(t1);
      t1.commit();

      assert null == tl.cache.get(ABC, "k");
      assert null == tl.cache.get(AB, "k");
   }
}
TOP

Related Classes of org.jboss.cache.api.mvcc.LockTestBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.