package org.infinispan.tx; import java.util.concurrent.atomic.AtomicInteger; import javax.transaction.Transaction; import org.infinispan.commands.tx.CommitCommand; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.context.Flag; import org.infinispan.context.impl.TxInvocationContext; import org.infinispan.interceptors.base.BaseCustomInterceptor; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.test.SingleCacheManagerTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.CleanupAfterMethod; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.infinispan.transaction.LockingMode; import org.infinispan.transaction.impl.TransactionTable; import org.infinispan.transaction.xa.LocalXaTransaction; import org.testng.AssertJUnit; import org.testng.annotations.Test; /** * @author Mircea.Markus@jboss.com * @since 4.2 */ @Test (groups = "functional", testName = "tx.ReadOnlyTxTest") @CleanupAfterMethod public class ReadOnlyTxTest extends SingleCacheManagerTest { @Override protected EmbeddedCacheManager createCacheManager() throws Exception { ConfigurationBuilder configuration = getDefaultClusteredCacheConfig(CacheMode.LOCAL, true); configuration.transaction().lockingMode(LockingMode.PESSIMISTIC); configure(configuration); return TestCacheManagerFactory.createCacheManager(configuration); } protected void configure(ConfigurationBuilder builder) { builder.transaction().useSynchronization(false); } public void testSimpleReadOnlTx() throws Exception { tm().begin(); assert cache.get("k") == null; Transaction transaction = tm().suspend(); LocalXaTransaction localTransaction = (LocalXaTransaction) txTable().getLocalTransaction(transaction); assert localTransaction != null && localTransaction.isReadOnly(); } public void testNotROWhenHasWrites() throws Exception { tm().begin(); cache.put("k", "v"); assert TestingUtil.extractLockManager(cache).isLocked("k"); Transaction transaction = tm().suspend(); LocalXaTransaction localTransaction = (LocalXaTransaction) txTable().getLocalTransaction(transaction); assert localTransaction != null && !localTransaction.isReadOnly(); } public void testROWhenHasOnlyLocksAndReleasedProperly() throws Exception { cache.put("k", "v"); tm().begin(); cache.getAdvancedCache().withFlags(Flag.FORCE_WRITE_LOCK).get("k"); assert TestingUtil.extractLockManager(cache).isLocked("k"); Transaction transaction = tm().suspend(); LocalXaTransaction localTransaction = (LocalXaTransaction) txTable().getLocalTransaction(transaction); assert localTransaction != null && localTransaction.isReadOnly(); tm().resume(transaction); tm().commit(); assert !TestingUtil.extractLockManager(cache).isLocked("k"); } public void testSingleCommitCommand() throws Exception { cache.put("k", "v"); CommitCommandCounterInterceptor counterInterceptor = new CommitCommandCounterInterceptor(); cache.getAdvancedCache().addInterceptor(counterInterceptor, 0); try { tm().begin(); AssertJUnit.assertEquals("Wrong value for key k.", "v", cache.get("k")); tm().commit(); } finally { cache.getAdvancedCache().getAdvancedCache().removeInterceptor(counterInterceptor.getClass()); } AssertJUnit.assertEquals("Wrong number of CommitCommand.", numberCommitCommand(), counterInterceptor.counter.get()); } protected int numberCommitCommand() { //in this case, the transactions are committed in 1 phase due to pessimistic locking. return 0; } private TransactionTable txTable() { return TestingUtil.getTransactionTable(cache); } private class CommitCommandCounterInterceptor extends BaseCustomInterceptor { public final AtomicInteger counter = new AtomicInteger(0); @Override public Object visitCommitCommand(TxInvocationContext ctx, CommitCommand command) throws Throwable { counter.incrementAndGet(); return invokeNextInterceptor(ctx, command); } } }