/* * JBoss, Home of Professional Open Source * Copyright 2010 Red Hat Inc. and/or its affiliates and other * contributors as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a full listing of * individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.infinispan.tx.exception; import org.infinispan.config.Configuration; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.test.SingleCacheManagerTest; import org.infinispan.test.TestingUtil; import org.infinispan.test.fwk.TestCacheManagerFactory; import org.infinispan.transaction.LockingMode; import org.infinispan.transaction.TransactionTable; import org.infinispan.util.concurrent.TimeoutException; import org.infinispan.util.concurrent.locks.LockManager; import org.testng.annotations.Test; import javax.transaction.Status; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import java.util.HashMap; import java.util.Map; import static org.testng.Assert.assertEquals; /** * Tester for https://jira.jboss.org/browse/ISPN-629. * * @author Mircea.Markus@jboss.com * @since 4.2 */ @Test(testName = "tx.TxAndTimeoutExceptionTest", groups = "functional") public class TxAndTimeoutExceptionTest extends SingleCacheManagerTest { @Override protected EmbeddedCacheManager createCacheManager() throws Exception { Configuration config = getDefaultStandaloneConfig(true); config.fluent().transaction().lockingMode(LockingMode.PESSIMISTIC); config.setUseLockStriping(false); config.setLockAcquisitionTimeout(1000); EmbeddedCacheManager cm = TestCacheManagerFactory.createCacheManager(config); cache = cm.getCache(); return cm; } public void testPutTimeoutsInTx() throws Exception { assertExpectedBehavior(new CacheOperation() { @Override public void execute() { cache.put("k1", "v2222"); } }); } public void testRemoveTimeoutsInTx() throws Exception { assertExpectedBehavior(new CacheOperation() { @Override public void execute() { cache.remove("k1"); } }); } public void testClearTimeoutsInTx() throws Exception { cache.put("k1", "value"); assertExpectedBehavior(new CacheOperation() { @Override public void execute() { cache.clear(); } }); } public void testReplaceTimeoutsInTx() throws Exception { assertExpectedBehavior(new CacheOperation() { @Override public void execute() { cache.replace("k1", "newValue"); } }); } public void testPutAllTimeoutsInTx() throws Exception { assertExpectedBehavior(new CacheOperation() { @Override public void execute() { Map toAdd = new HashMap(); toAdd.put("k1", "v22222"); cache.putAll(toAdd); } }); } private void assertExpectedBehavior(CacheOperation op) throws Exception { LockManager lm = TestingUtil.extractLockManager(cache); TransactionTable txTable = TestingUtil.getTransactionTable(cache); TransactionManager tm = cache.getAdvancedCache().getTransactionManager(); tm.begin(); cache.put("k1", "v1"); Transaction k1LockOwner = tm.suspend(); assert lm.isLocked("k1"); assertEquals(1, txTable.getLocalTxCount()); tm.begin(); cache.put("k2", "v2"); assert lm.isLocked("k2"); assertEquals(2, txTable.getLocalTxCount()); assert tm.getTransaction() != null; try { op.execute(); assert false : "Timeout exception expected"; } catch (TimeoutException e) { //expected } //make sure that locks acquired by that tx were released even before the transaction is rolled back, the tx object //was marked for rollback Transaction transaction = tm.getTransaction(); assert transaction != null; assert transaction.getStatus() == Status.STATUS_MARKED_ROLLBACK; assert !lm.isLocked("k2"); assert lm.isLocked("k1"); try { cache.put("k3", "v3"); assert false; } catch (IllegalStateException e) { //expected } assertEquals(txTable.getLocalTxCount(), 2); //now the TM is expected to rollback the tx tm.rollback(); assertEquals(txTable.getLocalTxCount(), 1); tm.resume(k1LockOwner); tm.commit(); //now test that the other tx works as expected assertEquals(0, txTable.getLocalTxCount()); assertEquals(cache.get("k1"), "v1"); assert !lm.isLocked("k1"); assertEquals(txTable.getLocalTxCount(), 0); } public interface CacheOperation { public abstract void execute(); } }