public void testTxRollbackThroughConcurrentWrite() throws Exception
{
TreeCache cache = createCacheWithListener();
Set keys;
DummyTransactionManager mgr = DummyTransactionManager.getInstance();
if (mgr.getTransaction() != null) mgr.rollback();
assertNull(mgr.getTransaction());
// first put in a value
mgr.begin();
assertEquals(0, cache.getTransactionTable().getNumGlobalTransactions());
assertEquals(0, cache.getTransactionTable().getNumLocalTransactions());
cache.put("/one/two", "key1", "val1");
mgr.commit();
keys = cache.getKeys("/one/two");
System.out.println("keys after TX #1: " + keys);
assertEquals(1, keys.size());
// First TX
mgr.begin();
Transaction tx = mgr.getTransaction();
cache.put("/one/two", "key2", "val2"); // version for this is 1
// start another
mgr.suspend();
// Second TX
mgr.begin();
cache.put("/one/two", "key3", "val3");
mgr.commit(); // now version is 2, attrs are key1 and key3
// assert we can see this outside the existing tx
keys = cache.getKeys("/one/two");
System.out.println("keys after TX #3 committed: " + keys);
assertEquals(2, keys.size());
// resume the suspended one
mgr.resume(tx);
// assert we can't see the change from tx2 as we already touched the node
keys = cache.getKeys("/one/two");
System.out.println("keys after TX #2 resumed (in private workspace of TX #2): " + keys);
assertEquals(2, keys.size()); // we will see key1 and key2, but *not* key3
// this will fail as our workspace has version 1, whereas cache has 2; TX will be rolled back
try
{
mgr.commit();
fail("TX should fail as other TX incremented version number");
}
catch (RollbackException rollback_ex)
{
System.out.println("TX was rolled back because the other TX committed first and incremented version ID." +