private void runAssertion(CacheOperation operation) throws NotSupportedException, SystemException, HeuristicMixedException, HeuristicRollbackException, InvalidTransactionException, RollbackException { txStatus.reset(); tm.begin(); cache(1).put("k1", "v1"); Transaction k1LockOwner = tm.suspend(); assert lm1.isLocked("k1"); assertEquals(1, txTable1.getLocalTxCount()); tm.begin(); cache(0).put("k2", "v2"); assert lm0.isLocked("k2"); assert !lm1.isLocked("k2"); operation.execute(); assertEquals(1, txTable1.getLocalTxCount()); assertEquals(1, txTable0.getLocalTxCount()); try { tm.commit(); assert false; } catch (RollbackException re) { // expected } assert txStatus.teReceived; assert txStatus.isTxInTableAfterTeOnPrepare; // expect 1 as k1 is locked by the other tx assertEquals( txStatus.numLocksAfterTeOnPrepare, 1, "This would make sure that locks are being released quickly, not waiting for a remote rollback to happen"); assertEquals(0, txTable0.getLocalTxCount()); assertEquals(1, txTable1.getLocalTxCount()); log.trace("Right before second commit"); tm.resume(k1LockOwner); tm.commit(); assertEquals("v1", cache(0).get("k1")); assertEquals("v1", cache(1).get("k1")); assertEquals(0, txTable1.getLocalTxCount()); assertEquals(0, txTable1.getLocalTxCount()); assertEquals(0, lm0.getNumberOfLocksHeld()); assertEquals(0, lm1.getNumberOfLocksHeld()); }
/** * Verifies the cache doesn't contain any lock * * @param cache */ public static void assertNoLocks(Cache<?, ?> cache) { LockManager lm = TestingUtil.extractLockManager(cache); for (Object key : cache.keySet()) assert !lm.isLocked(key); }
public void testCommitDoesntWriteAfterRollback() throws Exception { // Start a tx on A: put(k, v1), owners(k) = [B (primary) and C (backup)] // Block the commit on C so that it times out // Wait for the rollback command to be executed on B and C, and for the tx to end // Check that locks are released on B // Start another transaction on A: put(k, v2) with the same key // Check that the new transaction writes successfully // Allow the commit to proceed on C // Check that k=v2 everywhere StateSequencer sequencer = new StateSequencer(); sequencer.logicalThread( "tx1", "tx1:begin", "tx1:block_commit_on_backup", "tx1:after_rollback_on_primary", "tx1:after_rollback_on_backup", "tx1:resume_commit_on_backup", "tx1:after_commit_on_backup", "tx1:check"); sequencer.logicalThread("tx2", "tx2:begin", "tx2:end"); sequencer.order( "tx1:after_rollback_on_backup", "tx2:begin", "tx2:end", "tx1:resume_commit_on_backup"); advanceOnInterceptor( sequencer, cache(2), StateTransferInterceptor.class, matchCommand(CommitCommand.class).matchCount(0).build()) .before("tx1:block_commit_on_backup", "tx1:resume_commit_on_backup") .after("tx1:after_commit_on_backup"); advanceOnInterceptor( sequencer, cache(1), StateTransferInterceptor.class, matchCommand(RollbackCommand.class).build()) .after("tx1:after_rollback_on_primary"); advanceOnInterceptor( sequencer, cache(2), StateTransferInterceptor.class, matchCommand(RollbackCommand.class).build()) .after("tx1:after_rollback_on_backup"); assertEquals( Arrays.asList(address(1), address(2)), advancedCache(0).getDistributionManager().locate(TEST_KEY)); sequencer.advance("tx1:begin"); tm(0).begin(); cache(0).put(TEST_KEY, TX1_VALUE); try { tm(0).commit(); } catch (RollbackException e) { log.debugf("Commit timed out as expected", e); } sequencer.advance("tx2:begin"); LockManager lockManager1 = TestingUtil.extractLockManager(cache(1)); assertFalse(lockManager1.isLocked(TEST_KEY)); tm(0).begin(); cache(0).put(TEST_KEY, TX2_VALUE); tm(0).commit(); checkValue(); sequencer.advance("tx2:end"); sequencer.advance("tx1:check"); checkValue(); }