[jboss-cvs] JBossCache/tests/functional/org/jboss/cache/transaction ...
Manik Surtani
msurtani at jboss.com
Wed Dec 6 07:46:53 EST 2006
User: msurtani
Date: 06/12/06 07:46:53
Modified: tests/functional/org/jboss/cache/transaction
TransactionTest.java
Log:
Partially brought in tests for JBCACHE-875 and JBCACHE-871
Revision Changes Path
1.18 +281 -86 JBossCache/tests/functional/org/jboss/cache/transaction/TransactionTest.java
(In the diff below, changes in quantity of whitespace are not shown.)
Index: TransactionTest.java
===================================================================
RCS file: /cvsroot/jboss/JBossCache/tests/functional/org/jboss/cache/transaction/TransactionTest.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -b -r1.17 -r1.18
--- TransactionTest.java 20 Nov 2006 03:53:57 -0000 1.17
+++ TransactionTest.java 6 Dec 2006 12:46:53 -0000 1.18
@@ -15,9 +15,10 @@
import org.jboss.cache.DataNode;
import org.jboss.cache.Fqn;
import org.jboss.cache.GlobalTransaction;
+import org.jboss.cache.NodeImpl;
import org.jboss.cache.TreeCache;
+import org.jboss.cache.lock.IdentityLock;
import org.jboss.cache.lock.IsolationLevel;
-import org.jboss.cache.lock.NodeLock;
import javax.naming.Context;
import javax.naming.InitialContext;
@@ -37,7 +38,7 @@
* Tests transactional access to a local TreeCache.
* Note: we use DummpyTranasctionManager to replace jta
*
- * @version $Id: TransactionTest.java,v 1.17 2006/11/20 03:53:57 genman Exp $
+ * @version $Id: TransactionTest.java,v 1.18 2006/12/06 12:46:53 msurtani Exp $
*/
public class TransactionTest extends TestCase
{
@@ -152,27 +153,40 @@
}
- public void testRollbackTx()
+ public void testGetAfterRemovalRollback() throws Exception
{
- try
- {
- cache.put("/a/b/c", "age", new Integer(38));
- assertNotNull(cache.get("/a/b/c", "age"));
+ cache.put("/a/b", null);
+ assertTrue(cache.exists("/a/b"));
tx.begin();
- cache.remove("/a/b/c");
+ cache.remove("/a/b");
+ assertFalse(cache.exists("/a/b"));
tx.rollback();
-
- // This test is done outside the TX, it wouldn't work if someone else
- // modified "age". This works because we're the only TX running.
- assertNotNull(cache.get("/a/b/c", "age"));
+ assertTrue(cache.exists("/a/b"));
+ assertEquals(0, cache.getNumberOfLocksHeld());
+ // new tx in new thread
+ Thread th = new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ cache.getTransactionManager().begin();
+ assertNotNull(cache.get("/a/b"));
+ cache.getTransactionManager().rollback();
}
- catch (Throwable t)
+ catch (Exception e)
{
- t.printStackTrace();
- fail(t.toString());
+ e.printStackTrace();
+ fail("Caught exception");
}
}
+ };
+ th.start();
+ th.join();
+
+ assertEquals(0, cache.getNumberOfLocksHeld());
+ }
public void testRollbackTx2()
{
@@ -360,109 +374,288 @@
}
- public void testNodeDeletionRollback3()
+ public void testNodeCreation() throws Exception
+ {
+ GlobalTransaction gtx;
+ cache.put("/a/b", null);
+ tx.begin();
+ gtx = cache.getCurrentTransaction();
+ cache.put("/a/b/c", null);
+ assertLocked(gtx, "/a", false);
+ assertLocked(gtx, "/a/b", true);
+ assertLocked(gtx, "/a/b/c", true);
+ System.out.println("locks: " + cache.printLockInfo());
+ }
+
+
+ public void testNodeCreation2() throws Exception
+ {
+ GlobalTransaction gtx;
+ tx.begin();
+ gtx = cache.getCurrentTransaction();
+ cache.put("/a/b/c", null);
+ assertLocked(gtx, "/a", true);
+ assertLocked(gtx, "/a/b", true);
+ assertLocked(gtx, "/a/b/c", true);
+ System.out.println("locks: " + cache.printLockInfo());
+ }
+
+
+ public void testNodeRemoval()
{
GlobalTransaction gtx;
try
{
+ cache.put("/a/b/c", null);
+ tx.begin();
+ gtx = cache.getCurrentTransaction();
+ cache.remove("/a/b/c"); // need to remove the node, not just the data in the node.
+ assertLocked(gtx, "/a", false);
+ assertLocked(gtx, "/a/b", true);
+ assertLocked(gtx, "/a/b/c", true);
+ System.out.println("locks: " + cache.printLockInfo());
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace();
+ fail(t.toString());
+ }
+ }
+
+
+ public void testNodeRemoval2()
+ {
+ GlobalTransaction gtx;
+ try
+ {
+ cache.put("/a/b/c", null);
+ tx.begin();
+ gtx = cache.getCurrentTransaction();
+ cache.remove("/a/b"); // need to remove the node, not just the data in the node.
+ assertLocked(gtx, "/a", true);
+ assertLocked(gtx, "/a/b", true);
+ assertLocked(gtx, "/a/b/c", true);
+ System.out.println("locks: " + cache.printLockInfo());
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace();
+ fail(t.toString());
+ }
+ }
+
+ public void testIntermediateNodeCreationOnWrite() throws Exception
+ {
+ cache.put("/a", null);
+ tx.begin();
+ cache.put("/a/b/c", null);
+ // expecting WLs on /a, /a/b and /a/b/c.
+ GlobalTransaction gtx = cache.getCurrentTransaction();
+ assertLocked(gtx, "/a", true);
+ assertLocked(gtx, "/a/b", true);
+ assertLocked(gtx, "/a/b/c", true);
+ tx.rollback();
+
+ }
+
+ public void testIntermediateNodeCreationOnRead() throws Exception
+ {
+ cache.put("/a", null);
+ tx.begin();
+ cache.get("/a/b/c");
+
+ // expecting RLs on /, /a
+ // /a/b, /a/b/c should NOT be created!
+ GlobalTransaction gtx = cache.getCurrentTransaction();
+ assertLocked(gtx, "/", false);
+ assertLocked(gtx, "/a", false);
+ assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b")));
+ assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c")));
+ tx.rollback();
+ assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b")));
+ assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c")));
+
+ }
+
+
+ public void testIntermediateNodeCreationOnRemove() throws Exception
+ {
+ cache.put("/a", null);
+ tx.begin();
+ cache.remove("/a/b/c");
+
+ // expecting RLs on /, /a
+ // /a/b, /a/b/c should NOT be created!
+ GlobalTransaction gtx = cache.getCurrentTransaction();
+ assertLocked(gtx, "/", false);
+ assertLocked(gtx, "/a", false);
+ assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b")));
+ assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c")));
+ tx.rollback();
+ assertNull("/a/b should not exist", cache.peek(Fqn.fromString("/a/b")));
+ assertNull("/a/b/c should not exist", cache.peek(Fqn.fromString("/a/b/c")));
+
+ }
+
+
+ public void testNodeDeletionRollback3() throws Exception
+ {
+ GlobalTransaction gtx;
+ cache.put("/a/b/c1", null);
+
tx.begin();
gtx = cache.getCurrentTransaction();
cache.put("/a/b/c1", null);
- checkLock(gtx, "/a", false);
- checkLock(gtx, "/a/b", false);
- checkLock(gtx, "/a/b/c1", true);
+ assertLocked(gtx, "/a", false);
+ assertLocked(gtx, "/a/b", false);
+ assertLocked(gtx, "/a/b/c1", true);
cache.put("/a/b/c2", null);
- checkLock(gtx, "/a/b/c2", true);
+ assertLocked(gtx, "/a/b", true);
+ assertLocked(gtx, "/a/b/c2", true);
cache.put("/a/b/c3", null);
cache.put("/a/b/c1/one", null);
- checkLock(gtx, "/a/b/c1", true);
- checkLock(gtx, "/a/b/c1/one", true);
+ assertLocked(gtx, "/a/b/c1", true);
+ assertLocked(gtx, "/a/b/c1/one", true);
cache.put("/a/b/c1/two", null);
cache.put("/a/b/c1/one/1", null);
- checkLock(gtx, "/a/b/c1", true);
- checkLock(gtx, "/a/b/c1/one", true);
- checkLock(gtx, "/a/b/c1/one/1", true);
+ assertLocked(gtx, "/a/b/c1", true);
+ assertLocked(gtx, "/a/b/c1/one", true);
+ assertLocked(gtx, "/a/b/c1/one/1", true);
cache.put("/a/b/c1/two/2/3/4", null);
- checkLock(gtx, "/a/b/c1", true);
- checkLock(gtx, "/a/b/c1/two", true);
- checkLock(gtx, "/a/b/c1/two/2", false);
- checkLock(gtx, "/a/b/c1/two/2/3", false);
- checkLock(gtx, "/a/b/c1/two/2/3/4", true);
+ assertLocked(gtx, "/a/b/c1", true);
+ assertLocked(gtx, "/a/b/c1/two", true);
+ assertLocked(gtx, "/a/b/c1/two/2", true);
+ assertLocked(gtx, "/a/b/c1/two/2/3", true);
+ assertLocked(gtx, "/a/b/c1/two/2/3/4", true);
System.out.println("locks: " + cache.printLockInfo());
cache.remove("/a/b");
tx.rollback();
- assertNull(cache.getChildrenNames("/a/b"));
- }
- catch (Throwable t)
- {
- t.printStackTrace();
- fail(t.toString());
- }
+ assertTrue(cache.getChildrenNames("/a/b/c1").isEmpty());
+ Set cn = cache.getChildrenNames("/a/b");
+ assertEquals(1, cn.size());
+ assertEquals("c1", cn.iterator().next());
}
- public void testDoubleLocks()
- {
- try
+ public void testDoubleLocks() throws Exception
{
tx.begin();
+ GlobalTransaction gtx = cache.getCurrentTransaction();
cache.put("/a/b/c", null);
cache.put("/a/b/c", null);
- DataNode n = cache.get("/a");
- NodeLock lock = n.getNodeSPI().getLock();
+ NodeImpl n = cache.get("/a");
+ IdentityLock lock = n.getLock();
int num = lock.getReaderOwners().size();
- assertEquals(1, num);
+ assertEquals(0, num);
+ // make sure this is write locked.
+ assertLocked(gtx, "/a", true);
n = cache.get("/a/b");
- lock = n.getNodeSPI().getLock();
+ lock = n.getLock();
num = lock.getReaderOwners().size();
- assertEquals(1, num);
- // added this here since we had stale gtxs lurking about. - Manik, 02Jan06
+ assertEquals(0, num);
+ // make sure this is write locked.
+ assertLocked(gtx, "/a/b", true);
+
+ n = cache.get("/a/b/c");
+ lock = n.getLock();
+ num = lock.getReaderOwners().size();
+ assertEquals(0, num);
+ // make sure this is write locked.
+ assertLocked(gtx, "/a/b/c", true);
+
tx.rollback();
- }
- catch (Throwable t)
- {
- t.printStackTrace();
- fail(t.toString());
- }
+ assertEquals(0, cache.getNumberOfLocksHeld());
}
- private void checkLock(Object owner, String fqn, boolean write_locked) throws Exception
+ private void assertLocked(Object owner, String fqn, boolean write_locked) throws Exception
{
- DataNode n = cache.get(fqn);
- NodeLock lock = n.getNodeSPI().getLock();
+ NodeImpl n = cache.get(fqn);
+ IdentityLock lock = n.getLock();
if (owner == null)
- {
owner = Thread.currentThread();
+ assertTrue("node " + fqn + " is not locked", lock.isLocked());
+ if (write_locked)
+ {
+ assertTrue("node " + fqn + " is not write-locked" + (lock.isReadLocked() ? " but is read-locked instead!" : "!"), lock.isWriteLocked());
}
- if (lock.isLocked() == false)
+ else
{
- throw new Exception("node " + fqn + " is not locked");
+ assertTrue("node " + fqn + " is not read-locked" + (lock.isWriteLocked() ? " but is write-locked instead!" : "!"), lock.isReadLocked());
}
- if (write_locked)
+ assertTrue("owner " + owner + "is not owner", lock.isOwner(owner));
+ }
+
+ public void testConcurrentNodeAccessOnRemovalWithTx() throws Exception
{
- if (lock.isWriteLocked() == false)
+ cache.put("/a/b/c", null);
+ tx.begin();
+ cache.remove("/a/b/c");
+ // this node should now be locked.
+ Transaction t = cache.getTransactionManager().suspend();
+ Transaction t2 = null;
+ try
{
- throw new Exception("node " + fqn + " is not write-locked");
+ System.out.println(cache.printLockInfo());
+ // start a new tx
+ cache.getTransactionManager().begin();
+ t2 = cache.getTransactionManager().getTransaction();
+ cache.get("/a/b/c"); // should fail
+ t2.commit();
+ fail("Should not be able to get a hold of /a/b/c until the deleting tx completes");
}
+ catch (Exception e)
+ {
+ // expected
+ t2.commit();
}
- else
+
+ cache.getTransactionManager().resume(t);
+ tx.rollback();
+
+ assertNotNull(cache.get("/a/b/c"));
+ assertEquals(0, cache.getNumberOfLocksHeld());
+ }
+
+ public void testConcurrentNodeAccessOnRemovalWithoutTx() throws Exception
+ {
+ cache.put("/a/b/c", null);
+ tx.begin();
+ cache.remove("/a/b/c");
+ // this node should now be locked.
+ Transaction t = cache.getTransactionManager().suspend();
+ Thread th = new Thread()
{
- if (lock.isReadLocked() == false)
+ public void run()
{
- throw new Exception("node " + fqn + " is not read-locked");
- }
+ try
+ {
+ System.out.println(cache.printLockInfo());
+ cache.get("/a/b/c"); // should fail
+
+ fail("Should not be able to get a hold of /a/b/c until the deleting tx completes");
}
- if (lock.isOwner(owner) == false)
+ catch (Exception e)
{
- throw new Exception("owner " + owner + "is not owner");
+ // expected
+ }
}
+ };
+
+ th.start();
+ th.join();
+
+ cache.getTransactionManager().resume(t);
+ tx.rollback();
+
+ assertNotNull(cache.get("/a/b/c"));
+ assertEquals(0, cache.getNumberOfLocksHeld());
}
@@ -480,7 +673,9 @@
tx.begin();
cache.remove("/a/b/c");
System.out.println("locks held (after removing /a/b/c): \n" + cache.printLockInfo());
- assertEquals(2, cache.getNumberOfLocksHeld());
+ // this used to test for 2 locks held. After the fixes for JBCACHE-875 however, 2 more locks are acquired - for the root node as well as the deleted node.
+ // and since we would lock all children of the deleted node as well, we have 10 locks here.
+ assertEquals(10, cache.getNumberOfLocksHeld());
tx.commit();
System.out.println("locks held (after committing /a/b/c): \n" + cache.printLockInfo());
assertEquals(0, cache.getNumberOfLocksHeld());
@@ -502,7 +697,7 @@
System.out.println("locks held (before removing /a/b/c): \n" + cache.printLockInfo());
cache.remove("/a/b/c");
System.out.println("locks held (after removing /a/b/c): \n" + cache.printLockInfo());
- assertEquals(2, cache.getNumberOfLocksHeld());
+ assertEquals(10, cache.getNumberOfLocksHeld());
tx.rollback();
System.out.println("locks held (after rollback): \n" + cache.printLockInfo());
assertEquals(0, cache.getNumberOfLocksHeld());
More information about the jboss-cvs-commits
mailing list