package org.infinispan.distribution.groups; import java.util.Map; import javax.transaction.HeuristicMixedException; import javax.transaction.HeuristicRollbackException; import javax.transaction.NotSupportedException; import javax.transaction.RollbackException; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; import org.infinispan.configuration.cache.ConfigurationBuilder; import org.infinispan.transaction.TransactionProtocol; import org.infinispan.util.concurrent.IsolationLevel; import org.testng.AssertJUnit; import org.testng.annotations.Test; /** * It tests the grouping advanced interface for transactional caches. * * @author Pedro Ruivo * @since 7.0 */ @Test(groups = "functional", testName = "distribution.groups.TransactionalGetGroupKeysTest") public class TransactionalGetGroupKeysTest extends GetGroupKeysTest { @Override public Object[] factory() { return new Object[] { new TransactionalGetGroupKeysTest(TestCacheFactory.PRIMARY_OWNER).totalOrder(false).isolationLevel(IsolationLevel.READ_COMMITTED), new TransactionalGetGroupKeysTest(TestCacheFactory.PRIMARY_OWNER).totalOrder(true).isolationLevel(IsolationLevel.READ_COMMITTED), new TransactionalGetGroupKeysTest(TestCacheFactory.BACKUP_OWNER).totalOrder(false).isolationLevel(IsolationLevel.READ_COMMITTED), new TransactionalGetGroupKeysTest(TestCacheFactory.BACKUP_OWNER).totalOrder(true).isolationLevel(IsolationLevel.READ_COMMITTED), new TransactionalGetGroupKeysTest(TestCacheFactory.NON_OWNER).totalOrder(false).isolationLevel(IsolationLevel.READ_COMMITTED), new TransactionalGetGroupKeysTest(TestCacheFactory.NON_OWNER).totalOrder(true).isolationLevel(IsolationLevel.READ_COMMITTED), }; } public TransactionalGetGroupKeysTest() { this(null); } protected TransactionalGetGroupKeysTest(TestCacheFactory factory) { super(true, factory); } public void testGetGroupsInTransaction() throws SystemException, NotSupportedException, HeuristicRollbackException, HeuristicMixedException, RollbackException { final TestCache testCache = createTestCacheAndReset(GROUP, this.caches()); initCache(testCache.primaryOwner); final TransactionManager tm = tm(testCache.testCache); tm.begin(); testCache.testCache.put(key(10), value(10)); testCache.testCache.put(key(11), value(11)); Map<GroupKey, String> groupKeySet = testCache.testCache.getGroup(GROUP); Map<GroupKey, String> expectedGroupSet = createMap(0, 12); tm.commit(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); groupKeySet = testCache.testCache.getGroup(GROUP); expectedGroupSet = createMap(0, 12); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); } public void testGetGroupsWithConcurrentPut() throws Exception { final TestCache testCache = createTestCacheAndReset(GROUP, this.caches()); initCache(testCache.primaryOwner); final TransactionManager tm = tm(testCache.testCache); tm.begin(); testCache.testCache.put(key(10), value(10)); testCache.testCache.put(key(11), value(11)); Map<GroupKey, String> groupKeySet = testCache.testCache.getGroup(GROUP); Map<GroupKey, String> expectedGroupSet = createMap(0, 12); final Transaction tx = tm.suspend(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); testCache.primaryOwner.put(key(12), value(12)); expectedGroupSet.put(key(12), value(12)); tm.resume(tx); groupKeySet = testCache.testCache.getGroup(GROUP); tm.commit(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); groupKeySet = testCache.testCache.getGroup(GROUP); expectedGroupSet = createMap(0, 13); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); } public void testGetGroupsWithConcurrentRemove() throws Exception { final TestCache testCache = createTestCacheAndReset(GROUP, this.caches()); initCache(testCache.primaryOwner); final TransactionManager tm = tm(testCache.testCache); tm.begin(); testCache.testCache.put(key(10), value(10)); testCache.testCache.put(key(11), value(11)); Map<GroupKey, String> groupKeySet = testCache.testCache.getGroup(GROUP); Map<GroupKey, String> expectedGroupSet = createMap(0, 12); final Transaction tx = tm.suspend(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); testCache.primaryOwner.remove(key(1)); tm.resume(tx); groupKeySet = testCache.testCache.getGroup(GROUP); tm.commit(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); groupKeySet = testCache.testCache.getGroup(GROUP); expectedGroupSet.remove(key(1)); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); } public void testGetGroupsWithConcurrentReplace() throws Exception { final TestCache testCache = createTestCacheAndReset(GROUP, this.caches()); initCache(testCache.primaryOwner); final TransactionManager tm = tm(testCache.testCache); tm.begin(); testCache.testCache.put(key(10), value(10)); testCache.testCache.put(key(11), value(11)); Map<GroupKey, String> groupKeySet = testCache.testCache.getGroup(GROUP); Map<GroupKey, String> expectedGroupSet = createMap(0, 12); final Transaction tx = tm.suspend(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); testCache.primaryOwner.put(key(1), value(-1)); if (isolationLevel == IsolationLevel.READ_COMMITTED) { //in ReadCommitted the entries are not wrapped (for read). So the changes are made immediately visible. expectedGroupSet.put(key(1), value(-1)); // GetKeysInGroupCommand will be always replicated to owner nodes and will return all entries, including // those we already have in context. With RC, the context gets overwritten by these updated values. // If we ran regular testCache.get(key(1)), it would still return just v1 (we wouldn't fetch remote value) } tm.resume(tx); groupKeySet = testCache.testCache.getGroup(GROUP); tm.commit(); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); groupKeySet = testCache.testCache.getGroup(GROUP); expectedGroupSet.put(key(1), value(-1)); AssertJUnit.assertEquals(expectedGroupSet, groupKeySet); } @Override protected ConfigurationBuilder amendConfiguration(ConfigurationBuilder builder) { super.amendConfiguration(builder); builder.locking().isolationLevel(isolationLevel); builder.transaction().transactionProtocol(totalOrder ? TransactionProtocol.TOTAL_ORDER : TransactionProtocol.DEFAULT); builder.transaction().recovery().disable(); return builder; } }