package org.infinispan.tx; import org.infinispan.Cache; import org.infinispan.config.Configuration; import org.infinispan.context.Flag; import org.infinispan.test.MultipleCacheManagersTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.infinispan.transaction.LockingMode; import org.infinispan.transaction.RemoteTransaction; import org.infinispan.transaction.TransactionTable; import org.infinispan.tx.recovery.RecoveryDummyTransactionManagerLookup; import org.infinispan.util.concurrent.IsolationLevel; import org.testng.annotations.Test; import javax.transaction.Transaction; import java.util.Collection; import static org.testng.Assert.assertEquals; @Test(groups = "functional", testName = "TransactionCleanupWithRecoveryTest") public class TransactionCleanupWithRecoveryTest extends MultipleCacheManagersTest { @Override protected void createCacheManagers() throws Throwable { Configuration cfg = new Configuration().fluent() .clustering().mode(Configuration.CacheMode.REPL_SYNC) .locking() .concurrencyLevel(10000).isolationLevel(IsolationLevel.REPEATABLE_READ) .lockAcquisitionTimeout(100L).useLockStriping(false).writeSkewCheck(true) .transaction() .lockingMode(LockingMode.PESSIMISTIC) .recovery() .transactionManagerLookup(new RecoveryDummyTransactionManagerLookup()) .build(); registerCacheManager(TestCacheManagerFactory.createClusteredCacheManager(cfg), TestCacheManagerFactory.createClusteredCacheManager(cfg)); } public void testCleanup() throws Exception { cache(0).put(1, "v1"); assertNoTx(); } public void testWithSilentFailure() throws Exception { Cache<Integer, String> c0 = cache(0), c1 = cache(1); c0.put(1, "v1"); assertNoTx(); tm(1).begin(); c1.put(1, "v2"); Transaction suspendedTx = tm(1).suspend(); try { Cache<Integer, String> silentC0 = c0.getAdvancedCache().withFlags( Flag.FAIL_SILENTLY, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT); tm(0).begin(); assert !silentC0.getAdvancedCache().lock(1); assert "v1".equals(silentC0.get(1)); tm(0).rollback(); } finally { tm(1).resume(suspendedTx); tm(1).commit(); } assertNoTx(); } private void assertNoTx() { final TransactionTable tt0 = TestingUtil.getTransactionTable(cache(0)); // Message to forget transactions is sent asynchronously eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { int localTxCount = tt0.getLocalTxCount(); int remoteTxCount = tt0.getRemoteTxCount(); return localTxCount == 0 && remoteTxCount == 0; } }); final TransactionTable tt1 = TestingUtil.getTransactionTable(cache(1)); eventually(new Condition() { @Override public boolean isSatisfied() throws Exception { int localTxCount = tt1.getLocalTxCount(); int remoteTxCount = tt1.getRemoteTxCount(); return localTxCount == 0 && remoteTxCount == 0; } }); } }