package org.infinispan.lock; import static org.testng.AssertJUnit.assertTrue; import java.util.Map; import org.infinispan.Cache; import org.infinispan.commands.ReplicableCommand; import org.infinispan.commands.control.LockControlCommand; import org.infinispan.configuration.cache.CacheMode; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.distribution.MagicKey; import org.infinispan.remoting.responses.Response; import org.infinispan.remoting.rpc.RpcManager; import org.infinispan.remoting.transport.Address; import org.infinispan.test.MultipleCacheManagersTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.CleanupAfterMethod; import org.infinispan.transaction.LockingMode; import org.infinispan.util.AbstractControlledRpcManager; import org.infinispan.util.concurrent.IsolationLevel; import org.infinispan.util.concurrent.TimeoutException; import org.testng.annotations.Test; /** * Test the failures after lock acquired for Pessimistic transactional caches. * * @author Pedro Ruivo * @since 6.0 */ @Test(groups = "functional", testName = "lock.PessimistTxFailureAfterLockingTest") @CleanupAfterMethod public class PessimistTxFailureAfterLockingTest extends MultipleCacheManagersTest { /** * ISPN-3556 */ public void testReplyLostWithImplicitLocking() throws Exception { doTest(false); } /** * ISPN-3556 */ public void testReplyLostWithExplicitLocking() throws Exception { doTest(true); } private void doTest(boolean explicitLocking) throws Exception { final Object key = new MagicKey(cache(1), cache(2)); replaceRpcManagerInCache(cache(0)); boolean failed = false; tm(0).begin(); try { if (explicitLocking) { cache(0).getAdvancedCache().lock(key); } else { cache(0).put(key, "value"); } } catch (Exception e) { failed = true; //expected } tm(0).rollback(); assertTrue("Expected an exception", failed); assertNoTransactions(); assertEventuallyNotLocked(cache(1), key); } @Override protected void createCacheManagers() throws Throwable { ConfigurationBuilder builder = getDefaultClusteredCacheConfig(CacheMode.DIST_SYNC, true); builder.locking() .isolationLevel(IsolationLevel.READ_COMMITTED); //read committed is enough builder.transaction() .lockingMode(LockingMode.PESSIMISTIC); builder.clustering().hash() .numOwners(2); createClusteredCaches(3, builder); } private void replaceRpcManagerInCache(Cache cache) { RpcManager rpcManager = TestingUtil.extractComponent(cache, RpcManager.class); TestControllerRpcManager testControllerRpcManager = new TestControllerRpcManager(rpcManager); TestingUtil.replaceComponent(cache, RpcManager.class, testControllerRpcManager, true); } /** * this RpcManager simulates a reply lost from LockControlCommand by throwing a TimeoutException. However, it is * expected the command to acquire the remote lock. */ private class TestControllerRpcManager extends AbstractControlledRpcManager { public TestControllerRpcManager(RpcManager realOne) { super(realOne); } @Override protected Map<Address, Response> afterInvokeRemotely(ReplicableCommand command, Map<Address, Response> responseMap, Object argument) { if (command instanceof LockControlCommand) { throw new TimeoutException("Exception expected!"); } return responseMap; } } }