package org.infinispan.tx; import javax.transaction.Transaction; import org.infinispan.Cache; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; 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.TransactionMode; import org.infinispan.transaction.impl.TransactionTable; import org.infinispan.transaction.lookup.EmbeddedTransactionManagerLookup; import org.infinispan.util.concurrent.IsolationLevel; import org.testng.annotations.Test; @Test(groups = "functional", testName = "tx.TransactionCleanupWithRecoveryTest") public class TransactionCleanupWithRecoveryTest extends MultipleCacheManagersTest { @Override protected void createCacheManagers() { ConfigurationBuilder cfg = new ConfigurationBuilder(); cfg.clustering().cacheMode(CacheMode.REPL_SYNC) .locking() .concurrencyLevel(10000) .isolationLevel(IsolationLevel.REPEATABLE_READ) .lockAcquisitionTimeout(TestingUtil.shortTimeoutMillis()) .useLockStriping(false) .transaction() .transactionMode(TransactionMode.TRANSACTIONAL) .lockingMode(LockingMode.PESSIMISTIC) .transactionManagerLookup(new EmbeddedTransactionManagerLookup()) .recovery().enable(); 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(() -> { int localTxCount = tt0.getLocalTxCount(); int remoteTxCount = tt0.getRemoteTxCount(); return localTxCount == 0 && remoteTxCount == 0; }); final TransactionTable tt1 = TestingUtil.getTransactionTable(cache(1)); eventually(() -> { int localTxCount = tt1.getLocalTxCount(); int remoteTxCount = tt1.getRemoteTxCount(); return localTxCount == 0 && remoteTxCount == 0; }); } }