HHH-11344 Testsuite speed-up
* reduce number of setups (@Before -> @BeforeClassOnce)
* remove sleeps related to JGroups flush (issue in a 6+ years old version)
* do not create new cache manager in CollectionRegionAccessStrategyTest#doPutFromLoadRemoveDoesNotProduceStaleDataInvalidation
* Share cache manager in some tests
* Replace system time with mocked time service where possible
* Replace sleeps with synchronization
* Disabled ConcurrentWriteTest.testMany (this is a stress test)
(cherry picked from commit a21706bf02
)
This commit is contained in:
parent
4cc22a679d
commit
4a6c46dd8e
|
@ -101,6 +101,8 @@ public class PutFromLoadValidator {
|
||||||
*/
|
*/
|
||||||
private final AdvancedCache cache;
|
private final AdvancedCache cache;
|
||||||
|
|
||||||
|
private final InfinispanRegionFactory regionFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injected interceptor
|
* Injected interceptor
|
||||||
*/
|
*/
|
||||||
|
@ -138,6 +140,7 @@ public class PutFromLoadValidator {
|
||||||
* @param cacheManager where to find a cache to store pending put information
|
* @param cacheManager where to find a cache to store pending put information
|
||||||
*/
|
*/
|
||||||
public PutFromLoadValidator(AdvancedCache cache, InfinispanRegionFactory regionFactory, EmbeddedCacheManager cacheManager) {
|
public PutFromLoadValidator(AdvancedCache cache, InfinispanRegionFactory regionFactory, EmbeddedCacheManager cacheManager) {
|
||||||
|
this.regionFactory = regionFactory;
|
||||||
Configuration cacheConfiguration = cache.getCacheConfiguration();
|
Configuration cacheConfiguration = cache.getCacheConfiguration();
|
||||||
Configuration pendingPutsConfiguration = regionFactory.getPendingPutsCacheConfiguration();
|
Configuration pendingPutsConfiguration = regionFactory.getPendingPutsCacheConfiguration();
|
||||||
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
|
||||||
|
@ -417,7 +420,7 @@ public class PutFromLoadValidator {
|
||||||
log.trace("Started invalidating region " + cache.getName());
|
log.trace("Started invalidating region " + cache.getName());
|
||||||
}
|
}
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
long now = System.currentTimeMillis();
|
long now = regionFactory.nextTimestamp();
|
||||||
// deny all puts until endInvalidatingRegion is called; at that time the region should be already
|
// deny all puts until endInvalidatingRegion is called; at that time the region should be already
|
||||||
// in INVALID state, therefore all new requests should be blocked and ongoing should fail by timestamp
|
// in INVALID state, therefore all new requests should be blocked and ongoing should fail by timestamp
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
|
@ -458,7 +461,7 @@ public class PutFromLoadValidator {
|
||||||
public void endInvalidatingRegion() {
|
public void endInvalidatingRegion() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (--regionInvalidations == 0) {
|
if (--regionInvalidations == 0) {
|
||||||
regionInvalidationTimestamp = System.currentTimeMillis();
|
regionInvalidationTimestamp = regionFactory.nextTimestamp();
|
||||||
if (trace) {
|
if (trace) {
|
||||||
log.tracef("Finished invalidating region %s at %d", cache.getName(), regionInvalidationTimestamp);
|
log.tracef("Finished invalidating region %s at %d", cache.getName(), regionInvalidationTimestamp);
|
||||||
}
|
}
|
||||||
|
@ -566,7 +569,7 @@ public class PutFromLoadValidator {
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
long now = System.currentTimeMillis();
|
long now = regionFactory.nextTimestamp();
|
||||||
pending.invalidate(now);
|
pending.invalidate(now);
|
||||||
pending.addInvalidator(lockOwner, valueForPFER, now);
|
pending.addInvalidator(lockOwner, valueForPFER, now);
|
||||||
}
|
}
|
||||||
|
@ -607,7 +610,7 @@ public class PutFromLoadValidator {
|
||||||
}
|
}
|
||||||
if (pending.acquireLock(60, TimeUnit.SECONDS)) {
|
if (pending.acquireLock(60, TimeUnit.SECONDS)) {
|
||||||
try {
|
try {
|
||||||
long now = System.currentTimeMillis();
|
long now = regionFactory.nextTimestamp();
|
||||||
pending.removeInvalidator(lockOwner, key, now, doPFER);
|
pending.removeInvalidator(lockOwner, key, now, doPFER);
|
||||||
// we can't remove the pending put yet because we wait for naked puts
|
// we can't remove the pending put yet because we wait for naked puts
|
||||||
// pendingPuts should be configured with maxIdle time so won't have memory leak
|
// pendingPuts should be configured with maxIdle time so won't have memory leak
|
||||||
|
@ -802,7 +805,8 @@ public class PutFromLoadValidator {
|
||||||
*/
|
*/
|
||||||
private void gc() {
|
private void gc() {
|
||||||
assert fullMap != null;
|
assert fullMap != null;
|
||||||
long now = System.currentTimeMillis();
|
long now = regionFactory.nextTimestamp();
|
||||||
|
log.tracef("Contains %d, doing GC at %d, expiration %d", size(), now, expirationPeriod);
|
||||||
for ( Iterator<PendingPut> it = fullMap.values().iterator(); it.hasNext(); ) {
|
for ( Iterator<PendingPut> it = fullMap.values().iterator(); it.hasNext(); ) {
|
||||||
PendingPut pp = it.next();
|
PendingPut pp = it.next();
|
||||||
if (pp.gc(now, expirationPeriod)) {
|
if (pp.gc(now, expirationPeriod)) {
|
||||||
|
|
|
@ -2,16 +2,15 @@ package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
|
import org.hibernate.cache.internal.CacheDataDescriptionImpl;
|
||||||
import org.hibernate.cache.spi.CacheDataDescription;
|
import org.hibernate.cache.spi.CacheDataDescription;
|
||||||
import org.hibernate.cache.spi.access.AccessType;
|
|
||||||
import org.hibernate.cache.spi.access.RegionAccessStrategy;
|
import org.hibernate.cache.spi.access.RegionAccessStrategy;
|
||||||
import org.hibernate.cache.spi.access.SoftLock;
|
import org.hibernate.cache.spi.access.SoftLock;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.internal.util.compare.ComparableComparator;
|
import org.hibernate.internal.util.compare.ComparableComparator;
|
||||||
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
|
||||||
import org.hibernate.test.cache.infinispan.util.TestingKeyFactory;
|
import org.hibernate.test.cache.infinispan.util.TestingKeyFactory;
|
||||||
import org.junit.After;
|
import org.hibernate.testing.AfterClassOnce;
|
||||||
import org.junit.Before;
|
import org.hibernate.testing.BeforeClassOnce;
|
||||||
import org.junit.Rule;
|
import org.infinispan.test.fwk.TestResourceTracker;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
@ -21,8 +20,6 @@ import static org.mockito.Mockito.mock;
|
||||||
* @author Radim Vansa <rvansa@redhat.com>
|
* @author Radim Vansa <rvansa@redhat.com>
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractExtraAPITest<S extends RegionAccessStrategy> extends AbstractNonFunctionalTest {
|
public abstract class AbstractExtraAPITest<S extends RegionAccessStrategy> extends AbstractNonFunctionalTest {
|
||||||
@Rule
|
|
||||||
public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup();
|
|
||||||
|
|
||||||
public static final String REGION_NAME = "test/com.foo.test";
|
public static final String REGION_NAME = "test/com.foo.test";
|
||||||
public static final Object KEY = TestingKeyFactory.generateCollectionCacheKey( "KEY" );
|
public static final Object KEY = TestingKeyFactory.generateCollectionCacheKey( "KEY" );
|
||||||
|
@ -33,24 +30,23 @@ public abstract class AbstractExtraAPITest<S extends RegionAccessStrategy> exten
|
||||||
protected S accessStrategy;
|
protected S accessStrategy;
|
||||||
protected NodeEnvironment environment;
|
protected NodeEnvironment environment;
|
||||||
|
|
||||||
@Before
|
@BeforeClassOnce
|
||||||
public final void prepareLocalAccessStrategy() throws Exception {
|
public final void prepareLocalAccessStrategy() throws Exception {
|
||||||
|
TestResourceTracker.testStarted(getClass().getSimpleName());
|
||||||
environment = new NodeEnvironment( createStandardServiceRegistryBuilder() );
|
environment = new NodeEnvironment( createStandardServiceRegistryBuilder() );
|
||||||
environment.prepare();
|
environment.prepare();
|
||||||
|
|
||||||
// Sleep a bit to avoid concurrent FLUSH problem
|
|
||||||
avoidConcurrentFlush();
|
|
||||||
|
|
||||||
accessStrategy = getAccessStrategy();
|
accessStrategy = getAccessStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract S getAccessStrategy();
|
protected abstract S getAccessStrategy();
|
||||||
|
|
||||||
@After
|
@AfterClassOnce
|
||||||
public final void releaseLocalAccessStrategy() throws Exception {
|
public final void releaseLocalAccessStrategy() throws Exception {
|
||||||
if ( environment != null ) {
|
if ( environment != null ) {
|
||||||
environment.release();
|
environment.release();
|
||||||
}
|
}
|
||||||
|
TestResourceTracker.testFinished(getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -7,36 +7,44 @@
|
||||||
package org.hibernate.test.cache.infinispan;
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.SessionFactory;
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.SharedSessionContract;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.boot.MetadataSources;
|
import org.hibernate.boot.MetadataSources;
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistry;
|
import org.hibernate.boot.registry.StandardServiceRegistry;
|
||||||
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
|
||||||
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
import org.hibernate.cache.infinispan.impl.BaseGeneralDataRegion;
|
import org.hibernate.cache.infinispan.impl.BaseGeneralDataRegion;
|
||||||
import org.hibernate.cache.infinispan.util.Caches;
|
import org.hibernate.cache.infinispan.impl.BaseRegion;
|
||||||
import org.hibernate.cache.spi.GeneralDataRegion;
|
import org.hibernate.cache.spi.GeneralDataRegion;
|
||||||
import org.hibernate.cache.spi.QueryResultsRegion;
|
import org.hibernate.cache.spi.QueryResultsRegion;
|
||||||
import org.hibernate.cache.spi.Region;
|
import org.hibernate.cache.spi.Region;
|
||||||
import org.hibernate.cache.spi.RegionFactory;
|
import org.hibernate.cache.spi.RegionFactory;
|
||||||
|
import org.hibernate.cache.spi.access.AccessType;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
import org.hibernate.cfg.AvailableSettings;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.ExpectingInterceptor;
|
||||||
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
import org.infinispan.AdvancedCache;
|
|
||||||
import org.jboss.logging.Logger;
|
import org.infinispan.commands.write.PutKeyValueCommand;
|
||||||
|
import org.infinispan.commands.write.RemoveCommand;
|
||||||
|
import org.infinispan.configuration.cache.CacheMode;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hibernate.test.cache.infinispan.util.CacheTestUtil.assertEqualsEventually;
|
import org.infinispan.AdvancedCache;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for tests of QueryResultsRegion and TimestampsRegion.
|
* Base class for tests of QueryResultsRegion and TimestampsRegion.
|
||||||
|
@ -45,14 +53,18 @@ import static org.junit.Assert.assertNull;
|
||||||
* @since 3.5
|
* @since 3.5
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTest {
|
public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTest {
|
||||||
private static final Logger log = Logger.getLogger( AbstractGeneralDataRegionTest.class );
|
|
||||||
|
|
||||||
protected static final String KEY = "Key";
|
protected static final String KEY = "Key";
|
||||||
|
|
||||||
protected static final String VALUE1 = "value1";
|
protected static final String VALUE1 = "value1";
|
||||||
protected static final String VALUE2 = "value2";
|
protected static final String VALUE2 = "value2";
|
||||||
protected static final String VALUE3 = "value3";
|
protected static final String VALUE3 = "value3";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Object[]> getCacheModeParameters() {
|
||||||
|
// the actual cache mode and access type is irrelevant for the general data regions
|
||||||
|
return Arrays.<Object[]>asList(new Object[]{ CacheMode.INVALIDATION_SYNC, AccessType.TRANSACTIONAL });
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void putInRegion(Region region, Object key, Object value) {
|
protected void putInRegion(Region region, Object key, Object value) {
|
||||||
((GeneralDataRegion) region).put(null, key, value );
|
((GeneralDataRegion) region).put(null, key, value );
|
||||||
|
@ -63,11 +75,6 @@ public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTe
|
||||||
((GeneralDataRegion) region).evict( key );
|
((GeneralDataRegion) region).evict( key );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEvict() throws Exception {
|
|
||||||
evictOrRemoveTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected interface SFRConsumer {
|
protected interface SFRConsumer {
|
||||||
void accept(List<SessionFactory> sessionFactories, List<GeneralDataRegion> regions) throws Exception;
|
void accept(List<SessionFactory> sessionFactories, List<GeneralDataRegion> regions) throws Exception;
|
||||||
}
|
}
|
||||||
|
@ -107,17 +114,28 @@ public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void evictOrRemoveTest() throws Exception {
|
@Test
|
||||||
|
public void testEvict() throws Exception {
|
||||||
withSessionFactoriesAndRegions(2, ((sessionFactories, regions) -> {
|
withSessionFactoriesAndRegions(2, ((sessionFactories, regions) -> {
|
||||||
GeneralDataRegion localRegion = regions.get(0);
|
GeneralDataRegion localRegion = regions.get(0);
|
||||||
GeneralDataRegion remoteRegion = regions.get(1);
|
GeneralDataRegion remoteRegion = regions.get(1);
|
||||||
SessionImplementor localSession = (SessionImplementor) sessionFactories.get(0).openSession();
|
SessionImplementor localSession = (SessionImplementor) sessionFactories.get(0).openSession();
|
||||||
SessionImplementor remoteSession = (SessionImplementor) sessionFactories.get(1).openSession();
|
SessionImplementor remoteSession = (SessionImplementor) sessionFactories.get(1).openSession();
|
||||||
|
AdvancedCache localCache = ((BaseRegion) localRegion).getCache();
|
||||||
|
AdvancedCache remoteCache = ((BaseRegion) remoteRegion).getCache();
|
||||||
try {
|
try {
|
||||||
assertNull("local is clean", localRegion.get(localSession, KEY));
|
assertNull("local is clean", localRegion.get(localSession, KEY));
|
||||||
assertNull("remote is clean", remoteRegion.get(remoteSession, KEY));
|
assertNull("remote is clean", remoteRegion.get(remoteSession, KEY));
|
||||||
|
|
||||||
Transaction tx = ((Session) localSession).getTransaction();
|
// If this node is backup owner, it will see the update once as originator and then when getting the value from primary
|
||||||
|
boolean isLocalNodeBackupOwner = localCache.getDistributionManager().locate(KEY).indexOf(localCache.getCacheManager().getAddress()) > 0;
|
||||||
|
CountDownLatch insertLatch = new CountDownLatch(isLocalNodeBackupOwner ? 3 : 2);
|
||||||
|
ExpectingInterceptor.get(localCache).when((ctx, cmd) -> cmd instanceof PutKeyValueCommand).countDown(insertLatch);
|
||||||
|
ExpectingInterceptor.get(remoteCache).when((ctx, cmd) -> cmd instanceof PutKeyValueCommand).countDown(
|
||||||
|
insertLatch
|
||||||
|
);
|
||||||
|
|
||||||
|
Transaction tx = ( (SharedSessionContract) localSession ).getTransaction();
|
||||||
tx.begin();
|
tx.begin();
|
||||||
try {
|
try {
|
||||||
localRegion.put(localSession, KEY, VALUE1);
|
localRegion.put(localSession, KEY, VALUE1);
|
||||||
|
@ -127,19 +145,24 @@ public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTe
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Callable<Object> getFromLocalRegion = () -> localRegion.get(localSession, KEY);
|
assertTrue(insertLatch.await(2, TimeUnit.SECONDS));
|
||||||
Callable<Object> getFromRemoteRegion = () -> remoteRegion.get(remoteSession, KEY);
|
assertEquals(VALUE1, localRegion.get(localSession, KEY));
|
||||||
|
assertEquals(VALUE1, remoteRegion.get(remoteSession, KEY));
|
||||||
|
|
||||||
assertEqualsEventually(VALUE1, getFromLocalRegion, 10, TimeUnit.SECONDS);
|
CountDownLatch removeLatch = new CountDownLatch(isLocalNodeBackupOwner ? 3 : 2);
|
||||||
assertEqualsEventually(VALUE1, getFromRemoteRegion, 10, TimeUnit.SECONDS);
|
ExpectingInterceptor.get(localCache).when((ctx, cmd) -> cmd instanceof RemoveCommand).countDown(removeLatch);
|
||||||
|
ExpectingInterceptor.get(remoteCache).when((ctx, cmd) -> cmd instanceof RemoveCommand).countDown(removeLatch);
|
||||||
|
|
||||||
regionEvict(localRegion);
|
regionEvict(localRegion);
|
||||||
|
|
||||||
assertEqualsEventually(null, getFromLocalRegion, 10, TimeUnit.SECONDS);
|
assertTrue(removeLatch.await(2, TimeUnit.SECONDS));
|
||||||
assertEqualsEventually(null, getFromRemoteRegion, 10, TimeUnit.SECONDS);
|
assertEquals(null, localRegion.get(localSession, KEY));
|
||||||
|
assertEquals(null, remoteRegion.get(remoteSession, KEY));
|
||||||
} finally {
|
} finally {
|
||||||
( (Session) localSession).close();
|
( (Session) localSession ).close();
|
||||||
( (Session) remoteSession).close();
|
( (Session) remoteSession ).close();
|
||||||
|
|
||||||
|
ExpectingInterceptor.cleanup(localCache, remoteCache);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -157,10 +180,6 @@ public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTe
|
||||||
* CollectionRegionAccessStrategy API.
|
* CollectionRegionAccessStrategy API.
|
||||||
*/
|
*/
|
||||||
public void testEvictAll() throws Exception {
|
public void testEvictAll() throws Exception {
|
||||||
evictOrRemoveAllTest( "entity" );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void evictOrRemoveAllTest(String configName) throws Exception {
|
|
||||||
withSessionFactoriesAndRegions(2, (sessionFactories, regions) -> {
|
withSessionFactoriesAndRegions(2, (sessionFactories, regions) -> {
|
||||||
GeneralDataRegion localRegion = regions.get(0);
|
GeneralDataRegion localRegion = regions.get(0);
|
||||||
GeneralDataRegion remoteRegion = regions.get(1);
|
GeneralDataRegion remoteRegion = regions.get(1);
|
||||||
|
@ -182,19 +201,11 @@ public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTe
|
||||||
localRegion.put(localSession, KEY, VALUE1);
|
localRegion.put(localSession, KEY, VALUE1);
|
||||||
assertEquals( VALUE1, localRegion.get(null, KEY ) );
|
assertEquals( VALUE1, localRegion.get(null, KEY ) );
|
||||||
|
|
||||||
// Allow async propagation
|
|
||||||
sleep( 250 );
|
|
||||||
|
|
||||||
remoteRegion.put(remoteSession, KEY, VALUE1);
|
remoteRegion.put(remoteSession, KEY, VALUE1);
|
||||||
assertEquals( VALUE1, remoteRegion.get(null, KEY ) );
|
assertEquals( VALUE1, remoteRegion.get(null, KEY ) );
|
||||||
|
|
||||||
// Allow async propagation
|
|
||||||
sleep( 250 );
|
|
||||||
|
|
||||||
localRegion.evictAll();
|
localRegion.evictAll();
|
||||||
|
|
||||||
// allow async propagation
|
|
||||||
sleep( 250 );
|
|
||||||
// This should re-establish the region root node in the optimistic case
|
// This should re-establish the region root node in the optimistic case
|
||||||
assertNull( localRegion.get(null, KEY ) );
|
assertNull( localRegion.get(null, KEY ) );
|
||||||
localKeys = localCache.keySet();
|
localKeys = localCache.keySet();
|
||||||
|
@ -210,8 +221,8 @@ public abstract class AbstractGeneralDataRegionTest extends AbstractRegionImplTe
|
||||||
assertEquals( "local is clean", null, localRegion.get(null, KEY ) );
|
assertEquals( "local is clean", null, localRegion.get(null, KEY ) );
|
||||||
assertEquals( "remote is clean", null, remoteRegion.get(null, KEY ) );
|
assertEquals( "remote is clean", null, remoteRegion.get(null, KEY ) );
|
||||||
} finally {
|
} finally {
|
||||||
( (Session) localSession).close();
|
( (Session) localSession ).close();
|
||||||
( (Session) remoteSession).close();
|
( (Session) remoteSession ).close();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -188,18 +188,6 @@ public abstract class AbstractNonFunctionalTest extends org.hibernate.testing.ju
|
||||||
return testSupport;
|
return testSupport;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sleep(long ms) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(ms);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
log.warn("Interrupted during sleep", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void avoidConcurrentFlush() {
|
|
||||||
testSupport.avoidConcurrentFlush();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() {
|
protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() {
|
||||||
final StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder(
|
final StandardServiceRegistryBuilder ssrb = CacheTestUtil.buildBaselineStandardServiceRegistryBuilder(
|
||||||
REGION_PREFIX, getRegionFactoryClass(), true, false, jtaPlatform);
|
REGION_PREFIX, getRegionFactoryClass(), true, false, jtaPlatform);
|
||||||
|
|
|
@ -12,7 +12,6 @@ import java.util.function.Predicate;
|
||||||
|
|
||||||
import javax.transaction.RollbackException;
|
import javax.transaction.RollbackException;
|
||||||
import javax.transaction.SystemException;
|
import javax.transaction.SystemException;
|
||||||
import javax.transaction.TransactionManager;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
|
@ -40,9 +39,11 @@ import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLoca
|
||||||
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransactionAccess;
|
import org.hibernate.resource.transaction.backend.jdbc.spi.JdbcResourceTransactionAccess;
|
||||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner;
|
import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
|
||||||
|
import org.hibernate.testing.AfterClassOnce;
|
||||||
|
import org.hibernate.testing.BeforeClassOnce;
|
||||||
import org.hibernate.test.cache.infinispan.util.BatchModeJtaPlatform;
|
import org.hibernate.test.cache.infinispan.util.BatchModeJtaPlatform;
|
||||||
import org.hibernate.test.cache.infinispan.util.BatchModeTransactionCoordinator;
|
import org.hibernate.test.cache.infinispan.util.BatchModeTransactionCoordinator;
|
||||||
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
|
||||||
import org.hibernate.test.cache.infinispan.util.ExpectingInterceptor;
|
import org.hibernate.test.cache.infinispan.util.ExpectingInterceptor;
|
||||||
import org.hibernate.test.cache.infinispan.util.JdbcResourceTransactionMock;
|
import org.hibernate.test.cache.infinispan.util.JdbcResourceTransactionMock;
|
||||||
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
|
@ -54,9 +55,9 @@ import org.hibernate.test.cache.infinispan.util.TestTimeService;
|
||||||
import org.infinispan.commands.write.InvalidateCommand;
|
import org.infinispan.commands.write.InvalidateCommand;
|
||||||
import org.infinispan.AdvancedCache;
|
import org.infinispan.AdvancedCache;
|
||||||
import org.infinispan.commands.write.PutKeyValueCommand;
|
import org.infinispan.commands.write.PutKeyValueCommand;
|
||||||
|
import org.infinispan.test.fwk.TestResourceTracker;
|
||||||
|
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -75,9 +76,6 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
extends AbstractNonFunctionalTest {
|
extends AbstractNonFunctionalTest {
|
||||||
protected final Logger log = Logger.getLogger(getClass());
|
protected final Logger log = Logger.getLogger(getClass());
|
||||||
|
|
||||||
@Rule
|
|
||||||
public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup();
|
|
||||||
|
|
||||||
public static final String REGION_NAME = "test/com.foo.test";
|
public static final String REGION_NAME = "test/com.foo.test";
|
||||||
public static final String KEY_BASE = "KEY";
|
public static final String KEY_BASE = "KEY";
|
||||||
public static final String VALUE1 = "VALUE1";
|
public static final String VALUE1 = "VALUE1";
|
||||||
|
@ -110,23 +108,21 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@BeforeClassOnce
|
||||||
public void prepareResources() throws Exception {
|
public void prepareResources() throws Exception {
|
||||||
|
TestResourceTracker.testStarted( getClass().getSimpleName() );
|
||||||
// to mimic exactly the old code results, both environments here are exactly the same...
|
// to mimic exactly the old code results, both environments here are exactly the same...
|
||||||
StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder();
|
StandardServiceRegistryBuilder ssrb = createStandardServiceRegistryBuilder();
|
||||||
localEnvironment = new NodeEnvironment( ssrb );
|
localEnvironment = new NodeEnvironment( ssrb );
|
||||||
localEnvironment.prepare();
|
localEnvironment.prepare();
|
||||||
|
|
||||||
localRegion = getRegion(localEnvironment);
|
localRegion = getRegion( localEnvironment );
|
||||||
localAccessStrategy = getAccessStrategy(localRegion);
|
localAccessStrategy = getAccessStrategy( localRegion );
|
||||||
|
|
||||||
transactional = Caches.isTransactionalCache(localRegion.getCache());
|
transactional = Caches.isTransactionalCache( localRegion.getCache() );
|
||||||
invalidation = Caches.isInvalidationCache(localRegion.getCache());
|
invalidation = Caches.isInvalidationCache( localRegion.getCache() );
|
||||||
synchronous = Caches.isSynchronousCache(localRegion.getCache());
|
synchronous = Caches.isSynchronousCache(localRegion.getCache());
|
||||||
|
|
||||||
// Sleep a bit to avoid concurrent FLUSH problem
|
|
||||||
avoidConcurrentFlush();
|
|
||||||
|
|
||||||
remoteEnvironment = new NodeEnvironment( ssrb );
|
remoteEnvironment = new NodeEnvironment( ssrb );
|
||||||
remoteEnvironment.prepare();
|
remoteEnvironment.prepare();
|
||||||
|
|
||||||
|
@ -136,6 +132,29 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
waitForClusterToForm(localRegion.getCache(), remoteRegion.getCache());
|
waitForClusterToForm(localRegion.getCache(), remoteRegion.getCache());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void cleanup() {
|
||||||
|
cleanup.forEach(Runnable::run);
|
||||||
|
cleanup.clear();
|
||||||
|
if (localRegion != null) localRegion.getCache().clear();
|
||||||
|
if (remoteRegion != null) remoteRegion.getCache().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClassOnce
|
||||||
|
public void releaseResources() throws Exception {
|
||||||
|
try {
|
||||||
|
if (localEnvironment != null) {
|
||||||
|
localEnvironment.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (remoteEnvironment != null) {
|
||||||
|
remoteEnvironment.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TestResourceTracker.testFinished(getClass().getSimpleName());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() {
|
protected StandardServiceRegistryBuilder createStandardServiceRegistryBuilder() {
|
||||||
StandardServiceRegistryBuilder ssrb = super.createStandardServiceRegistryBuilder();
|
StandardServiceRegistryBuilder ssrb = super.createStandardServiceRegistryBuilder();
|
||||||
|
@ -224,7 +243,7 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
node1.setDaemon(true);
|
node1.setDaemon(true);
|
||||||
node2.setDaemon( true );
|
node2.setDaemon( true );
|
||||||
|
|
||||||
CountDownLatch remoteUpdate = setupExpectAfterUpdate();
|
CountDownLatch remoteUpdate = expectAfterUpdate();
|
||||||
|
|
||||||
node1.start();
|
node1.start();
|
||||||
node2.start();
|
node2.start();
|
||||||
|
@ -248,11 +267,11 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CountDownLatch setupExpectAfterUpdate() {
|
protected CountDownLatch expectAfterUpdate() {
|
||||||
return setupExpectPutWithValue(value -> value instanceof FutureUpdate);
|
return expectPutWithValue( value -> value instanceof FutureUpdate );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CountDownLatch setupExpectPutWithValue(Predicate<Object> valuePredicate) {
|
protected CountDownLatch expectPutWithValue(Predicate<Object> valuePredicate) {
|
||||||
if (!isUsingInvalidation() && accessType != AccessType.NONSTRICT_READ_WRITE) {
|
if (!isUsingInvalidation() && accessType != AccessType.NONSTRICT_READ_WRITE) {
|
||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
ExpectingInterceptor.get(remoteRegion.getCache())
|
ExpectingInterceptor.get(remoteRegion.getCache())
|
||||||
|
@ -265,8 +284,8 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected CountDownLatch setupExpectPutFromLoad() {
|
protected CountDownLatch expectPutFromLoad() {
|
||||||
return setupExpectPutWithValue(value -> value instanceof TombstoneUpdate);
|
return expectPutWithValue(value -> value instanceof TombstoneUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract void doUpdate(S strategy, SessionImplementor session, Object key, Object value, Object version) throws RollbackException, SystemException;
|
protected abstract void doUpdate(S strategy, SessionImplementor session, Object key, Object value, Object version) throws RollbackException, SystemException;
|
||||||
|
@ -342,27 +361,6 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
TestingUtil.blockUntilViewsReceived(10000, Arrays.asList(caches));
|
TestingUtil.blockUntilViewsReceived(10000, Arrays.asList(caches));
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
|
||||||
public void cleanup() throws Exception {
|
|
||||||
for (Runnable runnable : cleanup) {
|
|
||||||
runnable.run();
|
|
||||||
}
|
|
||||||
cleanup.clear();
|
|
||||||
if (localRegion != null) localRegion.getCache().clear();
|
|
||||||
if (remoteRegion != null) remoteRegion.getCache().clear();
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (localEnvironment != null) {
|
|
||||||
localEnvironment.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (remoteEnvironment != null) {
|
|
||||||
remoteEnvironment.release();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean isTransactional() {
|
protected boolean isTransactional() {
|
||||||
return transactional;
|
return transactional;
|
||||||
}
|
}
|
||||||
|
@ -391,7 +389,7 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
SessionImplementor s3 = mockedSession();
|
SessionImplementor s3 = mockedSession();
|
||||||
localAccessStrategy.putFromLoad(s3, KEY, VALUE1, s3.getTimestamp(), 1);
|
localAccessStrategy.putFromLoad(s3, KEY, VALUE1, s3.getTimestamp(), 1);
|
||||||
SessionImplementor s5 = mockedSession();
|
SessionImplementor s5 = mockedSession();
|
||||||
remoteAccessStrategy.putFromLoad(s5, KEY, VALUE1, s5.getTimestamp(), new Integer(1));
|
remoteAccessStrategy.putFromLoad(s5, KEY, VALUE1, s5.getTimestamp(), 1);
|
||||||
|
|
||||||
// putFromLoad is applied on local node synchronously, but if there's a concurrent update
|
// putFromLoad is applied on local node synchronously, but if there's a concurrent update
|
||||||
// from the other node it can silently fail when acquiring the loc . Then we could try to read
|
// from the other node it can silently fail when acquiring the loc . Then we could try to read
|
||||||
|
@ -410,7 +408,7 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
localAccessStrategy.evict(KEY);
|
localAccessStrategy.evict(KEY);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
doRemove(localRegion.getTransactionManager(), localAccessStrategy, session, KEY);
|
doRemove(localAccessStrategy, session, KEY);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
@ -423,7 +421,7 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
assertEquals(0, remoteRegion.getCache().size());
|
assertEquals(0, remoteRegion.getCache().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void doRemove(TransactionManager tm, S strategy, SessionImplementor session, Object key) throws SystemException, RollbackException {
|
protected void doRemove(S strategy, SessionImplementor session, Object key) throws SystemException, RollbackException {
|
||||||
SoftLock softLock = strategy.lockItem(session, key, null);
|
SoftLock softLock = strategy.lockItem(session, key, null);
|
||||||
strategy.remove(session, key);
|
strategy.remove(session, key);
|
||||||
session.getTransactionCoordinator().getLocalSynchronizations().registerSynchronization(
|
session.getTransactionCoordinator().getLocalSynchronizations().registerSynchronization(
|
||||||
|
@ -493,7 +491,7 @@ public abstract class AbstractRegionAccessStrategyTest<R extends BaseRegion, S e
|
||||||
if (invalidation && !evict) {
|
if (invalidation && !evict) {
|
||||||
// removeAll causes transactional remove commands which trigger EndInvalidationCommands on the remote side
|
// removeAll causes transactional remove commands which trigger EndInvalidationCommands on the remote side
|
||||||
// if the cache is non-transactional, PutFromLoadValidator.registerRemoteInvalidations cannot find
|
// if the cache is non-transactional, PutFromLoadValidator.registerRemoteInvalidations cannot find
|
||||||
// current session nor register tx synchronization, so it falls back to simpe InvalidationCommand.
|
// current session nor register tx synchronization, so it falls back to simple InvalidationCommand.
|
||||||
endInvalidationLatch = new CountDownLatch(1);
|
endInvalidationLatch = new CountDownLatch(1);
|
||||||
if (transactional) {
|
if (transactional) {
|
||||||
PutFromLoadValidator originalValidator = PutFromLoadValidator.removeFromCache(remoteRegion.getCache());
|
PutFromLoadValidator originalValidator = PutFromLoadValidator.removeFromCache(remoteRegion.getCache());
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.test.cache.infinispan;
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
|
@ -30,6 +31,9 @@ import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
||||||
import org.hibernate.testing.ServiceRegistryBuilder;
|
import org.hibernate.testing.ServiceRegistryBuilder;
|
||||||
import org.infinispan.configuration.cache.ClusteringConfigurationBuilder;
|
import org.infinispan.configuration.cache.ClusteringConfigurationBuilder;
|
||||||
|
import org.infinispan.commons.util.FileLookupFactory;
|
||||||
|
import org.infinispan.configuration.parsing.ConfigurationBuilderHolder;
|
||||||
|
import org.infinispan.configuration.parsing.ParserRegistry;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -37,7 +41,6 @@ import org.infinispan.AdvancedCache;
|
||||||
import org.infinispan.configuration.cache.CacheMode;
|
import org.infinispan.configuration.cache.CacheMode;
|
||||||
import org.infinispan.configuration.cache.Configuration;
|
import org.infinispan.configuration.cache.Configuration;
|
||||||
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
||||||
import org.infinispan.configuration.global.GlobalConfigurationBuilder;
|
|
||||||
import org.infinispan.eviction.EvictionStrategy;
|
import org.infinispan.eviction.EvictionStrategy;
|
||||||
import org.infinispan.manager.DefaultCacheManager;
|
import org.infinispan.manager.DefaultCacheManager;
|
||||||
import org.infinispan.manager.EmbeddedCacheManager;
|
import org.infinispan.manager.EmbeddedCacheManager;
|
||||||
|
@ -298,7 +301,9 @@ public class InfinispanRegionFactoryTestCase {
|
||||||
public void testTimestampValidation() {
|
public void testTimestampValidation() {
|
||||||
final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache";
|
final String timestamps = "org.hibernate.cache.spi.UpdateTimestampsCache";
|
||||||
Properties p = createProperties();
|
Properties p = createProperties();
|
||||||
final DefaultCacheManager manager = new DefaultCacheManager(GlobalConfigurationBuilder.defaultClusteredBuilder().build());
|
InputStream configStream = FileLookupFactory.newInstance().lookupFile(InfinispanRegionFactory.DEF_INFINISPAN_CONFIG_RESOURCE, getClass().getClassLoader());
|
||||||
|
ConfigurationBuilderHolder cbh = new ParserRegistry().parse(configStream);
|
||||||
|
DefaultCacheManager manager = new DefaultCacheManager(cbh, true);
|
||||||
ConfigurationBuilder builder = new ConfigurationBuilder();
|
ConfigurationBuilder builder = new ConfigurationBuilder();
|
||||||
builder.clustering().cacheMode(CacheMode.INVALIDATION_SYNC);
|
builder.clustering().cacheMode(CacheMode.INVALIDATION_SYNC);
|
||||||
manager.defineConfiguration( DEF_TIMESTAMPS_RESOURCE, builder.build() );
|
manager.defineConfiguration( DEF_TIMESTAMPS_RESOURCE, builder.build() );
|
||||||
|
|
|
@ -9,6 +9,8 @@ package org.hibernate.test.cache.infinispan.access;
|
||||||
import javax.transaction.TransactionManager;
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
@ -25,22 +27,33 @@ import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
|
import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
|
||||||
import org.hibernate.cache.infinispan.util.InfinispanMessageLogger;
|
import org.hibernate.cache.infinispan.util.InfinispanMessageLogger;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestTimeService;
|
||||||
|
import org.hibernate.testing.AfterClassOnce;
|
||||||
|
import org.hibernate.testing.BeforeClassOnce;
|
||||||
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
|
import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
|
||||||
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
import org.hibernate.testing.junit4.CustomRunner;
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.infinispan.AdvancedCache;
|
||||||
|
import org.infinispan.test.fwk.TestResourceTracker;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.infinispan.configuration.cache.Configuration;
|
import org.infinispan.configuration.cache.Configuration;
|
||||||
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
import org.infinispan.configuration.cache.ConfigurationBuilder;
|
||||||
import org.infinispan.manager.EmbeddedCacheManager;
|
import org.infinispan.manager.EmbeddedCacheManager;
|
||||||
import org.infinispan.test.CacheManagerCallable;
|
|
||||||
import org.infinispan.test.fwk.TestCacheManagerFactory;
|
import org.infinispan.test.fwk.TestCacheManagerFactory;
|
||||||
import org.junit.After;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.infinispan.test.TestingUtil.withCacheManager;
|
import static org.infinispan.test.Exceptions.expectException;
|
||||||
import static org.infinispan.test.TestingUtil.withTx;
|
import static org.infinispan.test.TestingUtil.withTx;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
import static org.mockito.Mockito.doReturn;
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
@ -52,95 +65,97 @@ import static org.junit.Assert.*;
|
||||||
* @author Galder Zamarreño
|
* @author Galder Zamarreño
|
||||||
* @version $Revision: $
|
* @version $Revision: $
|
||||||
*/
|
*/
|
||||||
|
@RunWith(CustomRunner.class)
|
||||||
public class PutFromLoadValidatorUnitTest {
|
public class PutFromLoadValidatorUnitTest {
|
||||||
|
|
||||||
private static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog(
|
private static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog(
|
||||||
PutFromLoadValidatorUnitTest.class);
|
PutFromLoadValidatorUnitTest.class);
|
||||||
|
private static final TestTimeService TIME_SERVICE = new TestTimeService();
|
||||||
@Rule
|
|
||||||
public InfinispanTestingSetup infinispanTestIdentifier = new InfinispanTestingSetup();
|
|
||||||
|
|
||||||
private Object KEY1 = "KEY1";
|
private Object KEY1 = "KEY1";
|
||||||
|
|
||||||
private TransactionManager tm;
|
private TransactionManager tm;
|
||||||
|
private EmbeddedCacheManager cm;
|
||||||
|
private AdvancedCache<Object, Object> cache;
|
||||||
|
private List<Runnable> cleanup = new ArrayList<>();
|
||||||
|
|
||||||
@Before
|
@BeforeClassOnce
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
TestResourceTracker.testStarted(getClass().getSimpleName());
|
||||||
tm = DualNodeJtaTransactionManagerImpl.getInstance("test");
|
tm = DualNodeJtaTransactionManagerImpl.getInstance("test");
|
||||||
|
cm = TestCacheManagerFactory.createCacheManager(true);
|
||||||
|
cache = cm.getCache().getAdvancedCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClassOnce
|
||||||
|
public void stop() {
|
||||||
|
tm = null;
|
||||||
|
cm.stop();
|
||||||
|
TestResourceTracker.testFinished(getClass().getSimpleName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() throws Exception {
|
public void tearDown() throws Exception {
|
||||||
tm = null;
|
cleanup.forEach(Runnable::run);
|
||||||
|
cleanup.clear();
|
||||||
try {
|
try {
|
||||||
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
|
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
|
DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
|
||||||
}
|
}
|
||||||
}
|
cache.clear();
|
||||||
|
cm.getCache(cache.getName() + "-" + InfinispanRegionFactory.DEF_PENDING_PUTS_RESOURCE).clear();
|
||||||
private static EmbeddedCacheManager createCacheManager() {
|
|
||||||
EmbeddedCacheManager cacheManager = TestCacheManagerFactory.createCacheManager(false);
|
|
||||||
return cacheManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InfinispanRegionFactory regionFactory(EmbeddedCacheManager cm) {
|
private static InfinispanRegionFactory regionFactory(EmbeddedCacheManager cm) {
|
||||||
InfinispanRegionFactory regionFactory = new InfinispanRegionFactory();
|
Properties properties = new Properties();
|
||||||
|
properties.put(TestInfinispanRegionFactory.TIME_SERVICE, TIME_SERVICE);
|
||||||
|
InfinispanRegionFactory regionFactory = new TestInfinispanRegionFactory(properties);
|
||||||
regionFactory.setCacheManager(cm);
|
regionFactory.setCacheManager(cm);
|
||||||
regionFactory.start(CacheTestUtil.sfOptionsForStart(), new Properties());
|
regionFactory.start(CacheTestUtil.sfOptionsForStart(), properties);
|
||||||
return regionFactory;
|
return regionFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNakedPut() throws Exception {
|
public void testNakedPut() throws Exception {
|
||||||
nakedPutTest(false);
|
nakedPutTest( false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testNakedPutTransactional() throws Exception {
|
public void testNakedPutTransactional() throws Exception {
|
||||||
nakedPutTest(true);
|
nakedPutTest( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void nakedPutTest(final boolean transactional) throws Exception {
|
private void nakedPutTest(final boolean transactional) throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
exec( transactional, new NakedPut( testee, true ) );
|
||||||
public void call() {
|
|
||||||
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
|
||||||
exec(transactional, new NakedPut(testee, true));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPut() throws Exception {
|
public void testRegisteredPut() throws Exception {
|
||||||
registeredPutTest(false);
|
registeredPutTest( false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutTransactional() throws Exception {
|
public void testRegisteredPutTransactional() throws Exception {
|
||||||
registeredPutTest(true);
|
registeredPutTest( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registeredPutTest(final boolean transactional) throws Exception {
|
private void registeredPutTest(final boolean transactional) throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
exec(transactional, new RegularPut(testee));
|
||||||
public void call() {
|
|
||||||
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
|
||||||
exec(transactional, new RegularPut(testee));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNakedPutAfterKeyRemoval() throws Exception {
|
public void testNakedPutAfterKeyRemoval() throws Exception {
|
||||||
nakedPutAfterRemovalTest(false, false);
|
nakedPutAfterRemovalTest( false, false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testNakedPutAfterKeyRemovalTransactional() throws Exception {
|
public void testNakedPutAfterKeyRemovalTransactional() throws Exception {
|
||||||
nakedPutAfterRemovalTest(true, false);
|
nakedPutAfterRemovalTest( true, false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testNakedPutAfterRegionRemoval() throws Exception {
|
public void testNakedPutAfterRegionRemoval() throws Exception {
|
||||||
nakedPutAfterRemovalTest(false, true);
|
nakedPutAfterRemovalTest( false, true );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testNakedPutAfterRegionRemovalTransactional() throws Exception {
|
public void testNakedPutAfterRegionRemovalTransactional() throws Exception {
|
||||||
|
@ -149,30 +164,24 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
|
|
||||||
private void nakedPutAfterRemovalTest(final boolean transactional,
|
private void nakedPutAfterRemovalTest(final boolean transactional,
|
||||||
final boolean removeRegion) throws Exception {
|
final boolean removeRegion) throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
Invalidation invalidation = new Invalidation(testee, removeRegion);
|
||||||
public void call() {
|
// the naked put can succeed because it has txTimestamp after invalidation
|
||||||
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
NakedPut nakedPut = new NakedPut(testee, true);
|
||||||
Invalidation invalidation = new Invalidation(testee, removeRegion);
|
exec( transactional, invalidation, nakedPut );
|
||||||
// the naked put can succeed because it has txTimestamp after invalidation
|
|
||||||
NakedPut nakedPut = new NakedPut(testee, true);
|
|
||||||
exec(transactional, invalidation, nakedPut);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutAfterKeyRemoval() throws Exception {
|
public void testRegisteredPutAfterKeyRemoval() throws Exception {
|
||||||
registeredPutAfterRemovalTest(false, false);
|
registeredPutAfterRemovalTest( false, false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutAfterKeyRemovalTransactional() throws Exception {
|
public void testRegisteredPutAfterKeyRemovalTransactional() throws Exception {
|
||||||
registeredPutAfterRemovalTest(true, false);
|
registeredPutAfterRemovalTest( true, false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutAfterRegionRemoval() throws Exception {
|
public void testRegisteredPutAfterRegionRemoval() throws Exception {
|
||||||
registeredPutAfterRemovalTest(false, true);
|
registeredPutAfterRemovalTest( false, true );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutAfterRegionRemovalTransactional() throws Exception {
|
public void testRegisteredPutAfterRegionRemovalTransactional() throws Exception {
|
||||||
|
@ -181,28 +190,22 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
|
|
||||||
private void registeredPutAfterRemovalTest(final boolean transactional,
|
private void registeredPutAfterRemovalTest(final boolean transactional,
|
||||||
final boolean removeRegion) throws Exception {
|
final boolean removeRegion) throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
Invalidation invalidation = new Invalidation(testee, removeRegion);
|
||||||
public void call() {
|
RegularPut regularPut = new RegularPut(testee);
|
||||||
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
exec( transactional, invalidation, regularPut );
|
||||||
Invalidation invalidation = new Invalidation(testee, removeRegion);
|
|
||||||
RegularPut regularPut = new RegularPut(testee);
|
|
||||||
exec(transactional, invalidation, regularPut);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutWithInterveningKeyRemoval() throws Exception {
|
public void testRegisteredPutWithInterveningKeyRemoval() throws Exception {
|
||||||
registeredPutWithInterveningRemovalTest(false, false);
|
registeredPutWithInterveningRemovalTest( false, false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutWithInterveningKeyRemovalTransactional() throws Exception {
|
public void testRegisteredPutWithInterveningKeyRemovalTransactional() throws Exception {
|
||||||
registeredPutWithInterveningRemovalTest(true, false);
|
registeredPutWithInterveningRemovalTest( true, false );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutWithInterveningRegionRemoval() throws Exception {
|
public void testRegisteredPutWithInterveningRegionRemoval() throws Exception {
|
||||||
registeredPutWithInterveningRemovalTest(false, true);
|
registeredPutWithInterveningRemovalTest( false, true );
|
||||||
}
|
}
|
||||||
@Test
|
@Test
|
||||||
public void testRegisteredPutWithInterveningRegionRemovalTransactional() throws Exception {
|
public void testRegisteredPutWithInterveningRegionRemovalTransactional() throws Exception {
|
||||||
|
@ -212,121 +215,102 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
private void registeredPutWithInterveningRemovalTest(
|
private void registeredPutWithInterveningRemovalTest(
|
||||||
final boolean transactional, final boolean removeRegion)
|
final boolean transactional, final boolean removeRegion)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
try {
|
||||||
public void call() {
|
long txTimestamp = TIME_SERVICE.wallClockTime();
|
||||||
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
if (transactional) {
|
||||||
try {
|
tm.begin();
|
||||||
long txTimestamp = System.currentTimeMillis();
|
}
|
||||||
if (transactional) {
|
SessionImplementor session1 = mock(SessionImplementor.class);
|
||||||
tm.begin();
|
SessionImplementor session2 = mock(SessionImplementor.class);
|
||||||
}
|
testee.registerPendingPut(session1, KEY1, txTimestamp);
|
||||||
SessionImplementor session1 = mock(SessionImplementor.class);
|
if (removeRegion) {
|
||||||
SessionImplementor session2 = mock(SessionImplementor.class);
|
testee.beginInvalidatingRegion();
|
||||||
testee.registerPendingPut(session1, KEY1, txTimestamp);
|
} else {
|
||||||
if (removeRegion) {
|
testee.beginInvalidatingKey(session2, KEY1);
|
||||||
testee.beginInvalidatingRegion();
|
}
|
||||||
} else {
|
|
||||||
testee.beginInvalidatingKey(session2, KEY1);
|
|
||||||
}
|
|
||||||
|
|
||||||
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session1, KEY1, txTimestamp);
|
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session1, KEY1, txTimestamp);
|
||||||
try {
|
try {
|
||||||
assertNull(lock);
|
assertNull(lock);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (lock != null) {
|
if (lock != null) {
|
||||||
testee.releasePutFromLoadLock(KEY1, lock);
|
testee.releasePutFromLoadLock(KEY1, lock);
|
||||||
}
|
}
|
||||||
if (removeRegion) {
|
if (removeRegion) {
|
||||||
testee.endInvalidatingRegion();
|
testee.endInvalidatingRegion();
|
||||||
} else {
|
} else {
|
||||||
testee.endInvalidatingKey(session2, KEY1);
|
testee.endInvalidatingKey(session2, KEY1);
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleRegistrations() throws Exception {
|
public void testMultipleRegistrations() throws Exception {
|
||||||
multipleRegistrationtest(false);
|
multipleRegistrationtest( false );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultipleRegistrationsTransactional() throws Exception {
|
public void testMultipleRegistrationsTransactional() throws Exception {
|
||||||
multipleRegistrationtest(true);
|
multipleRegistrationtest( true );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void multipleRegistrationtest(final boolean transactional) throws Exception {
|
private void multipleRegistrationtest(final boolean transactional) throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
final PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
|
||||||
public void call() {
|
|
||||||
final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
|
||||||
|
|
||||||
final CountDownLatch registeredLatch = new CountDownLatch(3);
|
final CountDownLatch registeredLatch = new CountDownLatch(3);
|
||||||
final CountDownLatch finishedLatch = new CountDownLatch(3);
|
final CountDownLatch finishedLatch = new CountDownLatch(3);
|
||||||
final AtomicInteger success = new AtomicInteger();
|
final AtomicInteger success = new AtomicInteger();
|
||||||
|
|
||||||
Runnable r = new Runnable() {
|
Runnable r = () -> {
|
||||||
public void run() {
|
try {
|
||||||
try {
|
long txTimestamp = TIME_SERVICE.wallClockTime();
|
||||||
long txTimestamp = System.currentTimeMillis();
|
if (transactional) {
|
||||||
if (transactional) {
|
tm.begin();
|
||||||
tm.begin();
|
}
|
||||||
}
|
SessionImplementor session = mock (SessionImplementor.class);
|
||||||
SessionImplementor session = mock (SessionImplementor.class);
|
testee.registerPendingPut(session, KEY1, txTimestamp);
|
||||||
testee.registerPendingPut(session, KEY1, txTimestamp);
|
registeredLatch.countDown();
|
||||||
registeredLatch.countDown();
|
registeredLatch.await(5, TimeUnit.SECONDS);
|
||||||
registeredLatch.await(5, TimeUnit.SECONDS);
|
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp);
|
||||||
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp);
|
if (lock != null) {
|
||||||
if (lock != null) {
|
try {
|
||||||
try {
|
log.trace("Put from load lock acquired for key = " + KEY1);
|
||||||
log.trace("Put from load lock acquired for key = " + KEY1);
|
success.incrementAndGet();
|
||||||
success.incrementAndGet();
|
} finally {
|
||||||
} finally {
|
testee.releasePutFromLoadLock(KEY1, lock);
|
||||||
testee.releasePutFromLoadLock(KEY1, lock);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.trace("Unable to acquired putFromLoad lock for key = " + KEY1);
|
|
||||||
}
|
|
||||||
finishedLatch.countDown();
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
|
log.trace("Unable to acquired putFromLoad lock for key = " + KEY1);
|
||||||
ExecutorService executor = Executors.newFixedThreadPool(3);
|
|
||||||
|
|
||||||
// Start with a removal so the "isPutValid" calls will fail if
|
|
||||||
// any of the concurrent activity isn't handled properly
|
|
||||||
|
|
||||||
testee.beginInvalidatingRegion();
|
|
||||||
testee.endInvalidatingRegion();
|
|
||||||
try {
|
|
||||||
Thread.sleep(10);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
}
|
||||||
|
finishedLatch.countDown();
|
||||||
// Do the registration + isPutValid calls
|
} catch (Exception e) {
|
||||||
executor.execute(r);
|
e.printStackTrace();
|
||||||
executor.execute(r);
|
|
||||||
executor.execute(r);
|
|
||||||
|
|
||||||
try {
|
|
||||||
finishedLatch.await(5, TimeUnit.SECONDS);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals("All threads succeeded", 3, success.get());
|
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newFixedThreadPool(3);
|
||||||
|
cleanup.add(() -> executor.shutdownNow());
|
||||||
|
|
||||||
|
// Start with a removal so the "isPutValid" calls will fail if
|
||||||
|
// any of the concurrent activity isn't handled properly
|
||||||
|
|
||||||
|
testee.beginInvalidatingRegion();
|
||||||
|
testee.endInvalidatingRegion();
|
||||||
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
|
// Do the registration + isPutValid calls
|
||||||
|
executor.execute(r);
|
||||||
|
executor.execute(r);
|
||||||
|
executor.execute(r);
|
||||||
|
|
||||||
|
assertTrue(finishedLatch.await(5, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
assertEquals("All threads succeeded", 3, success.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -340,71 +324,55 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invalidationBlocksForInProgressPutTest(final boolean keyOnly) throws Exception {
|
private void invalidationBlocksForInProgressPutTest(final boolean keyOnly) throws Exception {
|
||||||
withCacheManager(new CacheManagerCallable(createCacheManager()) {
|
final PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory(cm));
|
||||||
@Override
|
final CountDownLatch removeLatch = new CountDownLatch(1);
|
||||||
public void call() {
|
final CountDownLatch pferLatch = new CountDownLatch(1);
|
||||||
final PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory(cm));
|
final AtomicReference<Object> cache = new AtomicReference<>("INITIAL");
|
||||||
final CountDownLatch removeLatch = new CountDownLatch(1);
|
|
||||||
final CountDownLatch pferLatch = new CountDownLatch(1);
|
|
||||||
final AtomicReference<Object> cache = new AtomicReference<Object>("INITIAL");
|
|
||||||
|
|
||||||
Callable<Boolean> pferCallable = new Callable<Boolean>() {
|
|
||||||
public Boolean call() throws Exception {
|
|
||||||
long txTimestamp = System.currentTimeMillis();
|
|
||||||
SessionImplementor session = mock (SessionImplementor.class);
|
|
||||||
testee.registerPendingPut(session, KEY1, txTimestamp);
|
|
||||||
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp);
|
|
||||||
if (lock != null) {
|
|
||||||
try {
|
|
||||||
removeLatch.countDown();
|
|
||||||
pferLatch.await();
|
|
||||||
cache.set("PFER");
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
testee.releasePutFromLoadLock(KEY1, lock);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Boolean.FALSE;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Callable<Void> invalidateCallable = new Callable<Void>() {
|
|
||||||
public Void call() throws Exception {
|
|
||||||
removeLatch.await();
|
|
||||||
if (keyOnly) {
|
|
||||||
SessionImplementor session = mock (SessionImplementor.class);
|
|
||||||
testee.beginInvalidatingKey(session, KEY1);
|
|
||||||
} else {
|
|
||||||
testee.beginInvalidatingRegion();
|
|
||||||
}
|
|
||||||
cache.set(null);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
|
||||||
Future<Boolean> pferFuture = executorService.submit(pferCallable);
|
|
||||||
Future<Void> invalidateFuture = executorService.submit(invalidateCallable);
|
|
||||||
|
|
||||||
|
Callable<Boolean> pferCallable = () -> {
|
||||||
|
long txTimestamp = TIME_SERVICE.wallClockTime();
|
||||||
|
SessionImplementor session = mock (SessionImplementor.class);
|
||||||
|
testee.registerPendingPut(session, KEY1, txTimestamp);
|
||||||
|
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp);
|
||||||
|
if (lock != null) {
|
||||||
try {
|
try {
|
||||||
try {
|
removeLatch.countDown();
|
||||||
invalidateFuture.get(1, TimeUnit.SECONDS);
|
pferLatch.await();
|
||||||
fail("invalidateFuture did not block");
|
cache.set("PFER");
|
||||||
}
|
return Boolean.TRUE;
|
||||||
catch (TimeoutException good) {}
|
}
|
||||||
|
finally {
|
||||||
pferLatch.countDown();
|
testee.releasePutFromLoadLock(KEY1, lock);
|
||||||
|
|
||||||
assertTrue(pferFuture.get(5, TimeUnit.SECONDS));
|
|
||||||
invalidateFuture.get(5, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
assertNull(cache.get());
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
return Boolean.FALSE;
|
||||||
|
};
|
||||||
|
|
||||||
|
Callable<Void> invalidateCallable = () -> {
|
||||||
|
removeLatch.await();
|
||||||
|
if (keyOnly) {
|
||||||
|
SessionImplementor session = mock (SessionImplementor.class);
|
||||||
|
testee.beginInvalidatingKey(session, KEY1);
|
||||||
|
} else {
|
||||||
|
testee.beginInvalidatingRegion();
|
||||||
|
}
|
||||||
|
cache.set(null);
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExecutorService executor = Executors.newCachedThreadPool();
|
||||||
|
cleanup.add(() -> executor.shutdownNow());
|
||||||
|
Future<Boolean> pferFuture = executor.submit(pferCallable);
|
||||||
|
Future<Void> invalidateFuture = executor.submit(invalidateCallable);
|
||||||
|
|
||||||
|
expectException(TimeoutException.class, () -> invalidateFuture.get(1, TimeUnit.SECONDS));
|
||||||
|
|
||||||
|
pferLatch.countDown();
|
||||||
|
|
||||||
|
assertTrue(pferFuture.get(5, TimeUnit.SECONDS));
|
||||||
|
invalidateFuture.get(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
assertNull(cache.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void exec(boolean transactional, Callable<?>... callables) {
|
protected void exec(boolean transactional, Callable<?>... callables) {
|
||||||
|
@ -449,7 +417,7 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
}
|
}
|
||||||
// if we go for the timestamp-based approach, invalidation in the same millisecond
|
// if we go for the timestamp-based approach, invalidation in the same millisecond
|
||||||
// as the registerPendingPut/acquirePutFromLoad lock results in failure.
|
// as the registerPendingPut/acquirePutFromLoad lock results in failure.
|
||||||
Thread.sleep(10);
|
TIME_SERVICE.advance(1);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +432,7 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
@Override
|
@Override
|
||||||
public Void call() throws Exception {
|
public Void call() throws Exception {
|
||||||
try {
|
try {
|
||||||
long txTimestamp = System.currentTimeMillis(); // this should be acquired before UserTransaction.begin()
|
long txTimestamp = TIME_SERVICE.wallClockTime(); // this should be acquired before UserTransaction.begin()
|
||||||
SessionImplementor session = mock (SessionImplementor.class);
|
SessionImplementor session = mock (SessionImplementor.class);
|
||||||
putFromLoadValidator.registerPendingPut(session, KEY1, txTimestamp);
|
putFromLoadValidator.registerPendingPut(session, KEY1, txTimestamp);
|
||||||
|
|
||||||
|
@ -495,7 +463,7 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
@Override
|
@Override
|
||||||
public Void call() throws Exception {
|
public Void call() throws Exception {
|
||||||
try {
|
try {
|
||||||
long txTimestamp = System.currentTimeMillis(); // this should be acquired before UserTransaction.begin()
|
long txTimestamp = TIME_SERVICE.wallClockTime(); // this should be acquired before UserTransaction.begin()
|
||||||
SessionImplementor session = mock (SessionImplementor.class);
|
SessionImplementor session = mock (SessionImplementor.class);
|
||||||
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp);
|
PutFromLoadValidator.Lock lock = testee.acquirePutFromLoadLock(session, KEY1, txTimestamp);
|
||||||
try {
|
try {
|
||||||
|
@ -520,59 +488,44 @@ public class PutFromLoadValidatorUnitTest {
|
||||||
@Test
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-9928")
|
@TestForIssue(jiraKey = "HHH-9928")
|
||||||
public void testGetForNullReleasePuts() {
|
public void testGetForNullReleasePuts() {
|
||||||
EmbeddedCacheManager cm = createCacheManager();
|
|
||||||
InfinispanRegionFactory tmp = new InfinispanRegionFactory();
|
|
||||||
tmp.setCacheManager(cm);
|
|
||||||
ConfigurationBuilder cb = new ConfigurationBuilder();
|
ConfigurationBuilder cb = new ConfigurationBuilder();
|
||||||
cb.simpleCache(true).expiration().maxIdle(500);
|
cb.simpleCache(true).expiration().maxIdle(500);
|
||||||
Configuration ppCfg = cb.build();
|
Configuration ppCfg = cb.build();
|
||||||
cm.defineConfiguration(InfinispanRegionFactory.DEF_PENDING_PUTS_RESOURCE, cb.build());
|
|
||||||
InfinispanRegionFactory regionFactory = mock(InfinispanRegionFactory.class);
|
InfinispanRegionFactory regionFactory = mock(InfinispanRegionFactory.class);
|
||||||
doReturn(ppCfg).when(regionFactory).getPendingPutsCacheConfiguration();
|
doReturn(ppCfg).when(regionFactory).getPendingPutsCacheConfiguration();
|
||||||
withCacheManager(new CacheManagerCallable(cm) {
|
doAnswer(invocation -> TIME_SERVICE.wallClockTime()).when(regionFactory).nextTimestamp();
|
||||||
@Override
|
|
||||||
public void call() {
|
PutFromLoadValidator testee = new PutFromLoadValidator(cache, regionFactory, cm);
|
||||||
PutFromLoadValidator testee = new PutFromLoadValidator(cm.getCache().getAdvancedCache(), regionFactory, cm);
|
|
||||||
long lastInsert = Long.MAX_VALUE;
|
for (int i = 0; i < 100; ++i) {
|
||||||
for (int i = 0; i < 100; ++i) {
|
try {
|
||||||
lastInsert = System.currentTimeMillis();
|
withTx(tm, () -> {
|
||||||
try {
|
SessionImplementor session = mock (SessionImplementor.class);
|
||||||
withTx(tm, new Callable<Object>() {
|
testee.registerPendingPut(session, KEY1, 0);
|
||||||
@Override
|
return null;
|
||||||
public Object call() throws Exception {
|
});
|
||||||
SessionImplementor session = mock (SessionImplementor.class);
|
TIME_SERVICE.advance(10);
|
||||||
testee.registerPendingPut(session, KEY1, 0);
|
} catch (Exception e) {
|
||||||
return null;
|
throw new RuntimeException(e);
|
||||||
}
|
|
||||||
});
|
|
||||||
Thread.sleep(10);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
String ppName = cm.getCache().getName() + "-" + InfinispanRegionFactory.DEF_PENDING_PUTS_RESOURCE;
|
|
||||||
Map ppCache = cm.getCache(ppName, false);
|
|
||||||
assertNotNull(ppCache);
|
|
||||||
Object pendingPutMap = ppCache.get(KEY1);
|
|
||||||
long end = System.currentTimeMillis();
|
|
||||||
if (end - lastInsert > 500) {
|
|
||||||
log.warn("Test took too long");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
assertNotNull(pendingPutMap);
|
|
||||||
int size;
|
|
||||||
try {
|
|
||||||
Method sizeMethod = pendingPutMap.getClass().getMethod("size");
|
|
||||||
sizeMethod.setAccessible(true);
|
|
||||||
size = (Integer) sizeMethod.invoke(pendingPutMap);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
// some of the pending puts need to be expired by now
|
|
||||||
assertTrue(size < 100);
|
|
||||||
// but some are still registered
|
|
||||||
assertTrue(size > 0);
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
String ppName = cm.getCache().getName() + "-" + InfinispanRegionFactory.DEF_PENDING_PUTS_RESOURCE;
|
||||||
|
Map ppCache = cm.getCache(ppName, false);
|
||||||
|
assertNotNull(ppCache);
|
||||||
|
Object pendingPutMap = ppCache.get(KEY1);
|
||||||
|
assertNotNull(pendingPutMap);
|
||||||
|
int size;
|
||||||
|
try {
|
||||||
|
Method sizeMethod = pendingPutMap.getClass().getMethod("size");
|
||||||
|
sizeMethod.setAccessible(true);
|
||||||
|
size = (Integer) sizeMethod.invoke(pendingPutMap);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
// some of the pending puts need to be expired by now
|
||||||
|
assertTrue(size < 100);
|
||||||
|
// but some are still registered
|
||||||
|
assertTrue(size > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,41 +95,41 @@ public class CollectionRegionAccessStrategyTest extends
|
||||||
}
|
}
|
||||||
}).when(mockValidator).acquirePutFromLoadLock(any(), any(), anyLong());
|
}).when(mockValidator).acquirePutFromLoadLock(any(), any(), anyLong());
|
||||||
PutFromLoadValidator.addToCache(localRegion.getCache(), mockValidator);
|
PutFromLoadValidator.addToCache(localRegion.getCache(), mockValidator);
|
||||||
|
cleanup.add(() -> {
|
||||||
try {
|
|
||||||
final AccessDelegate delegate = localRegion.getCache().getCacheConfiguration().transaction().transactionMode().isTransactional() ?
|
|
||||||
new TxInvalidationCacheAccessDelegate(localRegion, mockValidator) :
|
|
||||||
new NonTxInvalidationCacheAccessDelegate(localRegion, mockValidator);
|
|
||||||
|
|
||||||
ExecutorService executorService = Executors.newCachedThreadPool();
|
|
||||||
|
|
||||||
final String KEY = "k1";
|
|
||||||
Future<Void> pferFuture = executorService.submit(() -> {
|
|
||||||
SessionImplementor session = mockedSession();
|
|
||||||
delegate.putFromLoad(session, KEY, "v1", session.getTimestamp(), null);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
Future<Void> removeFuture = executorService.submit(() -> {
|
|
||||||
removeLatch.await();
|
|
||||||
SessionImplementor session = mockedSession();
|
|
||||||
withTx(localEnvironment, session, () -> {
|
|
||||||
delegate.remove(session, KEY);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
pferLatch.countDown();
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
|
|
||||||
pferFuture.get();
|
|
||||||
removeFuture.get();
|
|
||||||
|
|
||||||
assertFalse(localRegion.getCache().containsKey(KEY));
|
|
||||||
assertFalse(remoteRegion.getCache().containsKey(KEY));
|
|
||||||
} finally {
|
|
||||||
PutFromLoadValidator.removeFromCache(localRegion.getCache());
|
PutFromLoadValidator.removeFromCache(localRegion.getCache());
|
||||||
PutFromLoadValidator.addToCache(localRegion.getCache(), originalValidator);
|
PutFromLoadValidator.addToCache(localRegion.getCache(), originalValidator);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
final AccessDelegate delegate = localRegion.getCache().getCacheConfiguration().transaction().transactionMode().isTransactional() ?
|
||||||
|
new TxInvalidationCacheAccessDelegate(localRegion, mockValidator) :
|
||||||
|
new NonTxInvalidationCacheAccessDelegate(localRegion, mockValidator);
|
||||||
|
|
||||||
|
ExecutorService executorService = Executors.newCachedThreadPool();
|
||||||
|
cleanup.add(() -> executorService.shutdownNow());
|
||||||
|
|
||||||
|
final String KEY = "k1";
|
||||||
|
Future<Void> pferFuture = executorService.submit(() -> {
|
||||||
|
SessionImplementor session = mockedSession();
|
||||||
|
delegate.putFromLoad(session, KEY, "v1", session.getTimestamp(), null);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
Future<Void> removeFuture = executorService.submit(() -> {
|
||||||
|
removeLatch.await();
|
||||||
|
SessionImplementor session = mockedSession();
|
||||||
|
withTx(localEnvironment, session, () -> {
|
||||||
|
delegate.remove(session, KEY);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
pferLatch.countDown();
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
pferFuture.get();
|
||||||
|
removeFuture.get();
|
||||||
|
|
||||||
|
assertFalse(localRegion.getCache().containsKey(KEY));
|
||||||
|
assertFalse(remoteRegion.getCache().containsKey(KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class CollectionRegionImplTest extends AbstractEntityCollectionRegionTest
|
||||||
@Override
|
@Override
|
||||||
protected void putInRegion(Region region, Object key, Object value) {
|
protected void putInRegion(Region region, Object key, Object value) {
|
||||||
CollectionRegionAccessStrategy strategy = ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL);
|
CollectionRegionAccessStrategy strategy = ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL);
|
||||||
strategy.putFromLoad(null, key, value, System.currentTimeMillis(), new Integer(1));
|
strategy.putFromLoad(null, key, value, region.nextTimestamp(), new Integer(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class EntityRegionAccessStrategyTest extends
|
||||||
final CountDownLatch commitLatch = new CountDownLatch(1);
|
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||||
final CountDownLatch completionLatch = new CountDownLatch(2);
|
final CountDownLatch completionLatch = new CountDownLatch(2);
|
||||||
|
|
||||||
CountDownLatch asyncInsertLatch = setupExpectAfterUpdate();
|
CountDownLatch asyncInsertLatch = expectAfterUpdate();
|
||||||
|
|
||||||
Thread inserter = new Thread(() -> {
|
Thread inserter = new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -154,7 +154,7 @@ public class EntityRegionAccessStrategyTest extends
|
||||||
protected void putFromLoadTestReadOnly(boolean minimal) throws Exception {
|
protected void putFromLoadTestReadOnly(boolean minimal) throws Exception {
|
||||||
final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ );
|
final Object KEY = TestingKeyFactory.generateEntityCacheKey( KEY_BASE + testCount++ );
|
||||||
|
|
||||||
CountDownLatch remotePutFromLoadLatch = setupExpectPutFromLoad();
|
CountDownLatch remotePutFromLoadLatch = expectPutFromLoad();
|
||||||
|
|
||||||
SessionImplementor session = mockedSession();
|
SessionImplementor session = mockedSession();
|
||||||
withTx(localEnvironment, session, () -> {
|
withTx(localEnvironment, session, () -> {
|
||||||
|
@ -196,7 +196,7 @@ public class EntityRegionAccessStrategyTest extends
|
||||||
remoteAccessStrategy.putFromLoad(s2, KEY, VALUE1, s2.getTimestamp(), 1);
|
remoteAccessStrategy.putFromLoad(s2, KEY, VALUE1, s2.getTimestamp(), 1);
|
||||||
|
|
||||||
// both nodes are updated, we don't have to wait for any async replication of putFromLoad
|
// both nodes are updated, we don't have to wait for any async replication of putFromLoad
|
||||||
CountDownLatch asyncUpdateLatch = setupExpectAfterUpdate();
|
CountDownLatch asyncUpdateLatch = expectAfterUpdate();
|
||||||
|
|
||||||
final CountDownLatch readLatch = new CountDownLatch(1);
|
final CountDownLatch readLatch = new CountDownLatch(1);
|
||||||
final CountDownLatch commitLatch = new CountDownLatch(1);
|
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||||
|
|
|
@ -9,10 +9,14 @@ package org.hibernate.test.cache.infinispan.functional;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.boot.Metadata;
|
import org.hibernate.boot.Metadata;
|
||||||
import org.hibernate.boot.spi.MetadataImplementor;
|
import org.hibernate.boot.spi.MetadataImplementor;
|
||||||
|
import org.hibernate.cache.infinispan.util.FutureUpdate;
|
||||||
|
import org.hibernate.cache.infinispan.util.TombstoneUpdate;
|
||||||
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
|
import org.hibernate.cache.internal.SimpleCacheKeysFactory;
|
||||||
import org.hibernate.cache.spi.RegionFactory;
|
import org.hibernate.cache.spi.RegionFactory;
|
||||||
import org.hibernate.cache.spi.access.AccessType;
|
import org.hibernate.cache.spi.access.AccessType;
|
||||||
|
@ -29,16 +33,19 @@ import org.hibernate.resource.transaction.TransactionCoordinatorBuilder;
|
||||||
import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl;
|
import org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl;
|
||||||
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
|
import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.util.ExpectingInterceptor;
|
||||||
|
import org.hibernate.testing.BeforeClassOnce;
|
||||||
|
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
||||||
|
import org.hibernate.testing.junit4.CustomParameterized;
|
||||||
|
import org.hibernate.test.cache.infinispan.tm.JtaPlatformImpl;
|
||||||
import org.hibernate.test.cache.infinispan.tm.XaConnectionProvider;
|
import org.hibernate.test.cache.infinispan.tm.XaConnectionProvider;
|
||||||
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
import org.hibernate.test.cache.infinispan.util.InfinispanTestingSetup;
|
||||||
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
import org.hibernate.test.cache.infinispan.util.TxUtil;
|
import org.hibernate.test.cache.infinispan.util.TxUtil;
|
||||||
import org.hibernate.testing.BeforeClassOnce;
|
|
||||||
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
|
|
||||||
import org.hibernate.test.cache.infinispan.tm.JtaPlatformImpl;
|
|
||||||
|
|
||||||
import org.hibernate.testing.junit4.CustomParameterized;
|
|
||||||
import org.infinispan.configuration.cache.CacheMode;
|
import org.infinispan.configuration.cache.CacheMode;
|
||||||
|
import org.infinispan.AdvancedCache;
|
||||||
|
import org.infinispan.commands.write.PutKeyValueCommand;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
@ -89,6 +96,7 @@ public abstract class AbstractFunctionalTest extends BaseNonConfigCoreFunctional
|
||||||
public boolean addVersions;
|
public boolean addVersions;
|
||||||
|
|
||||||
protected boolean useJta;
|
protected boolean useJta;
|
||||||
|
protected List<Runnable> cleanup = new ArrayList<>();
|
||||||
|
|
||||||
@CustomParameterized.Order(0)
|
@CustomParameterized.Order(0)
|
||||||
@Parameterized.Parameters(name = "{0}, {6}")
|
@Parameterized.Parameters(name = "{0}, {6}")
|
||||||
|
@ -121,6 +129,12 @@ public abstract class AbstractFunctionalTest extends BaseNonConfigCoreFunctional
|
||||||
useJta = jtaPlatformClass != null;
|
useJta = jtaPlatformClass != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void runCleanup() {
|
||||||
|
cleanup.forEach(Runnable::run);
|
||||||
|
cleanup.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getMappings() {
|
public String[] getMappings() {
|
||||||
return new String[] {
|
return new String[] {
|
||||||
|
@ -198,4 +212,25 @@ public abstract class AbstractFunctionalTest extends BaseNonConfigCoreFunctional
|
||||||
protected void markRollbackOnly(Session session) {
|
protected void markRollbackOnly(Session session) {
|
||||||
TxUtil.markRollbackOnly(useJta, session);
|
TxUtil.markRollbackOnly(useJta, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected CountDownLatch expectAfterUpdate(AdvancedCache cache, int numUpdates) {
|
||||||
|
return expectPutWithValue(cache, value -> value instanceof FutureUpdate, numUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CountDownLatch expectEvict(AdvancedCache cache, int numUpdates) {
|
||||||
|
return expectPutWithValue(cache, value -> value instanceof TombstoneUpdate && ((TombstoneUpdate) value).getValue() == null, numUpdates);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CountDownLatch expectPutWithValue(AdvancedCache cache, Predicate<Object> valuePredicate, int numUpdates) {
|
||||||
|
if (!cacheMode.isInvalidation() && accessType != AccessType.NONSTRICT_READ_WRITE) {
|
||||||
|
CountDownLatch latch = new CountDownLatch(numUpdates);
|
||||||
|
ExpectingInterceptor.get(cache)
|
||||||
|
.when((ctx, cmd) -> cmd instanceof PutKeyValueCommand && valuePredicate.test(((PutKeyValueCommand) cmd).getValue()))
|
||||||
|
.countDown(latch);
|
||||||
|
cleanup.add(() -> ExpectingInterceptor.cleanup(cache));
|
||||||
|
return latch;
|
||||||
|
} else {
|
||||||
|
return new CountDownLatch(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -111,9 +111,8 @@ public abstract class AbstractNonInvalidationTest extends SingleNodeTest {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void cleanup() throws Exception {
|
public void cleanup() throws Exception {
|
||||||
for (Runnable runnable : cleanup) {
|
cleanup.forEach(Runnable::run);
|
||||||
runnable.run();
|
cleanup.clear();
|
||||||
}
|
|
||||||
withTxSession(s -> {
|
withTxSession(s -> {
|
||||||
s.createQuery("delete from Item").executeUpdate();
|
s.createQuery("delete from Item").executeUpdate();
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ import java.io.StringWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
@ -27,6 +28,9 @@ import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||||
|
|
||||||
import org.hibernate.test.cache.infinispan.functional.entities.Contact;
|
import org.hibernate.test.cache.infinispan.functional.entities.Contact;
|
||||||
import org.hibernate.test.cache.infinispan.functional.entities.Customer;
|
import org.hibernate.test.cache.infinispan.functional.entities.Customer;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestTimeService;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -48,6 +52,7 @@ public class ConcurrentWriteTest extends SingleNodeTest {
|
||||||
private static final int THINK_TIME_MILLIS = 10;
|
private static final int THINK_TIME_MILLIS = 10;
|
||||||
private static final long LAUNCH_INTERVAL_MILLIS = 10;
|
private static final long LAUNCH_INTERVAL_MILLIS = 10;
|
||||||
private static final Random random = new Random();
|
private static final Random random = new Random();
|
||||||
|
private static final TestTimeService TIME_SERVICE = new TestTimeService();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kill switch used to stop all users when one fails
|
* kill switch used to stop all users when one fails
|
||||||
|
@ -70,6 +75,12 @@ public class ConcurrentWriteTest extends SingleNodeTest {
|
||||||
TERMINATE_ALL_USERS = false;
|
TERMINATE_ALL_USERS = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings(settings);
|
||||||
|
settings.put(TestInfinispanRegionFactory.TIME_SERVICE, TIME_SERVICE);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void cleanupTest() throws Exception {
|
protected void cleanupTest() throws Exception {
|
||||||
try {
|
try {
|
||||||
|
@ -90,14 +101,14 @@ public class ConcurrentWriteTest extends SingleNodeTest {
|
||||||
// setup
|
// setup
|
||||||
sessionFactory().getStatistics().clear();
|
sessionFactory().getStatistics().clear();
|
||||||
// wait a while to make sure that timestamp comparison works after invalidateRegion
|
// wait a while to make sure that timestamp comparison works after invalidateRegion
|
||||||
Thread.sleep(1);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
Customer customer = createCustomer( 0 );
|
Customer customer = createCustomer( 0 );
|
||||||
final Integer customerId = customer.getId();
|
final Integer customerId = customer.getId();
|
||||||
getCustomerIDs().add( customerId );
|
getCustomerIDs().add( customerId );
|
||||||
|
|
||||||
// wait a while to make sure that timestamp comparison works after collection remove (during insert)
|
// wait a while to make sure that timestamp comparison works after collection remove (during insert)
|
||||||
Thread.sleep(1);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
assertNull( "contact exists despite not being added", getFirstContact( customerId ) );
|
assertNull( "contact exists despite not being added", getFirstContact( customerId ) );
|
||||||
|
|
||||||
|
@ -134,6 +145,8 @@ public class ConcurrentWriteTest extends SingleNodeTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ignoring the test as it's more of a stress-test: this should be enabled manually
|
||||||
|
@Ignore
|
||||||
@Test
|
@Test
|
||||||
public void testManyUsers() throws Throwable {
|
public void testManyUsers() throws Throwable {
|
||||||
try {
|
try {
|
||||||
|
@ -153,7 +166,6 @@ public class ConcurrentWriteTest extends SingleNodeTest {
|
||||||
futures.add( future );
|
futures.add( future );
|
||||||
Thread.sleep( LAUNCH_INTERVAL_MILLIS ); // rampup
|
Thread.sleep( LAUNCH_INTERVAL_MILLIS ); // rampup
|
||||||
}
|
}
|
||||||
// barrier.await(); // wait for all threads to be ready
|
|
||||||
barrier.await( 2, TimeUnit.MINUTES ); // wait for all threads to finish
|
barrier.await( 2, TimeUnit.MINUTES ); // wait for all threads to finish
|
||||||
log.info( "All threads finished, let's shutdown the executor and check whether any exceptions were reported" );
|
log.info( "All threads finished, let's shutdown the executor and check whether any exceptions were reported" );
|
||||||
for ( Future<Void> future : futures ) {
|
for ( Future<Void> future : futures ) {
|
||||||
|
@ -367,7 +379,7 @@ public class ConcurrentWriteTest extends SingleNodeTest {
|
||||||
thinkRandomTime();
|
thinkRandomTime();
|
||||||
++completedIterations;
|
++completedIterations;
|
||||||
if ( trace ) {
|
if ( trace ) {
|
||||||
log.tracef( "Iteration completed {0}", completedIterations );
|
log.tracef( "Iteration completed %d", completedIterations );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import org.hibernate.cache.infinispan.util.InfinispanMessageLogger;
|
||||||
import org.hibernate.stat.SecondLevelCacheStatistics;
|
import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||||
import org.hibernate.stat.Statistics;
|
import org.hibernate.stat.Statistics;
|
||||||
import org.hibernate.test.cache.infinispan.functional.entities.Item;
|
import org.hibernate.test.cache.infinispan.functional.entities.Item;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestInfinispanRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.TestTimeService;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
@ -25,7 +27,8 @@ import static org.junit.Assert.assertEquals;
|
||||||
* @since 4.1
|
* @since 4.1
|
||||||
*/
|
*/
|
||||||
public class ReadOnlyTest extends SingleNodeTest {
|
public class ReadOnlyTest extends SingleNodeTest {
|
||||||
static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog(ReadOnlyTest.class);
|
protected static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog(ReadOnlyTest.class);
|
||||||
|
protected static final TestTimeService TIME_SERVICE = new TestTimeService();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Object[]> getParameters() {
|
public List<Object[]> getParameters() {
|
||||||
|
@ -76,7 +79,7 @@ public class ReadOnlyTest extends SingleNodeTest {
|
||||||
log.info("Entry persisted, let's load and delete it.");
|
log.info("Entry persisted, let's load and delete it.");
|
||||||
|
|
||||||
cleanupCache();
|
cleanupCache();
|
||||||
Thread.sleep(10);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
withTxSession(s -> {
|
withTxSession(s -> {
|
||||||
Item found = s.load(Item.class, item.getId());
|
Item found = s.load(Item.class, item.getId());
|
||||||
|
@ -88,4 +91,10 @@ public class ReadOnlyTest extends SingleNodeTest {
|
||||||
s.delete(found);
|
s.delete(found);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addSettings(Map settings) {
|
||||||
|
super.addSettings(settings);
|
||||||
|
settings.put(TestInfinispanRegionFactory.TIME_SERVICE, TIME_SERVICE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
s.persist( another );
|
s.persist( another );
|
||||||
});
|
});
|
||||||
// The collection has been removed, but we can't add it again immediately using putFromLoad
|
// The collection has been removed, but we can't add it again immediately using putFromLoad
|
||||||
Thread.sleep(1);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
withTxSession(s -> {
|
withTxSession(s -> {
|
||||||
Item loaded = s.load( Item.class, item.getId() );
|
Item loaded = s.load( Item.class, item.getId() );
|
||||||
|
@ -386,7 +386,7 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() );
|
SecondLevelCacheStatistics slcs = stats.getSecondLevelCacheStatistics( Item.class.getName() );
|
||||||
sessionFactory().getCache().evictEntityRegion( Item.class.getName() );
|
sessionFactory().getCache().evictEntityRegion( Item.class.getName() );
|
||||||
|
|
||||||
Thread.sleep(1);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
assertEquals(0, slcs.getPutCount());
|
assertEquals(0, slcs.getPutCount());
|
||||||
assertEquals( 0, slcs.getElementCountInMemory() );
|
assertEquals( 0, slcs.getElementCountInMemory() );
|
||||||
|
@ -436,8 +436,8 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
|
|
||||||
// Delay added to guarantee that query cache results won't be considered
|
// Delay added to guarantee that query cache results won't be considered
|
||||||
// as not up to date due to persist session and query results from first
|
// as not up to date due to persist session and query results from first
|
||||||
// query happening within same 100ms gap.
|
// query happening simultaneously.
|
||||||
Thread.sleep( 100 );
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
withTxSession(s -> s.createQuery( "from Item" ).setCacheable( true ).list());
|
withTxSession(s -> s.createQuery( "from Item" ).setCacheable( true ).list());
|
||||||
|
|
||||||
|
@ -459,8 +459,8 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
|
|
||||||
// Delay added to guarantee that query cache results won't be considered
|
// Delay added to guarantee that query cache results won't be considered
|
||||||
// as not up to date due to persist session and query results from first
|
// as not up to date due to persist session and query results from first
|
||||||
// query happening within same 100ms gap.
|
// query happening simultaneously.
|
||||||
Thread.sleep( 100 );
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
withTxSession(s -> {
|
withTxSession(s -> {
|
||||||
s.createQuery("from Item").setCacheable(true).list();
|
s.createQuery("from Item").setCacheable(true).list();
|
||||||
|
@ -476,8 +476,8 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
saveSomeCitizens();
|
saveSomeCitizens();
|
||||||
|
|
||||||
// Clear the cache before the transaction begins
|
// Clear the cache before the transaction begins
|
||||||
ReadWriteTest.this.cleanupCache();
|
cleanupCache();
|
||||||
Thread.sleep(10);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
withTxSession(s -> {
|
withTxSession(s -> {
|
||||||
State france = ReadWriteTest.this.getState(s, "Ile de France");
|
State france = ReadWriteTest.this.getState(s, "Ile de France");
|
||||||
|
@ -554,8 +554,8 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO: Clear caches manually via cache manager (it's faster!!)
|
// TODO: Clear caches manually via cache manager (it's faster!!)
|
||||||
this.cleanupCache();
|
cleanupCache();
|
||||||
Thread.sleep(10);
|
TIME_SERVICE.advance(1);
|
||||||
stats.setStatisticsEnabled( true );
|
stats.setStatisticsEnabled( true );
|
||||||
stats.clear();
|
stats.clear();
|
||||||
|
|
||||||
|
@ -614,7 +614,7 @@ public class ReadWriteTest extends ReadOnlyTest {
|
||||||
assertEquals(2, slcStats.getPutCount());
|
assertEquals(2, slcStats.getPutCount());
|
||||||
|
|
||||||
cache.evictEntityRegions();
|
cache.evictEntityRegions();
|
||||||
Thread.sleep(10);
|
TIME_SERVICE.advance(1);
|
||||||
|
|
||||||
assertEquals(0, slcStats.getElementCountInMemory());
|
assertEquals(0, slcStats.getElementCountInMemory());
|
||||||
assertFalse("2lc entity cache is expected to not contain Citizen id = " + citizens.get(0).getId(),
|
assertFalse("2lc entity cache is expected to not contain Citizen id = " + citizens.get(0).getId(),
|
||||||
|
|
|
@ -116,15 +116,6 @@ public abstract class DualNodeTest extends AbstractFunctionalTest {
|
||||||
return JtaTransactionCoordinatorBuilderImpl.class;
|
return JtaTransactionCoordinatorBuilderImpl.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void sleep(long ms) {
|
|
||||||
try {
|
|
||||||
Thread.sleep( ms );
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
log.warn( "Interrupted during sleep", e );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void configureSecondNode(StandardServiceRegistryBuilder ssrb) {
|
protected void configureSecondNode(StandardServiceRegistryBuilder ssrb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,6 @@ import static org.mockito.Mockito.spy;
|
||||||
public class EntityCollectionInvalidationTest extends DualNodeTest {
|
public class EntityCollectionInvalidationTest extends DualNodeTest {
|
||||||
private static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog( EntityCollectionInvalidationTest.class );
|
private static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog( EntityCollectionInvalidationTest.class );
|
||||||
|
|
||||||
private static final long SLEEP_TIME = 50l;
|
|
||||||
private static final Integer CUSTOMER_ID = new Integer( 1 );
|
private static final Integer CUSTOMER_ID = new Integer( 1 );
|
||||||
|
|
||||||
private EmbeddedCacheManager localManager, remoteManager;
|
private EmbeddedCacheManager localManager, remoteManager;
|
||||||
|
@ -138,16 +137,10 @@ public class EntityCollectionInvalidationTest extends DualNodeTest {
|
||||||
assertTrue( remoteListener.isEmpty() );
|
assertTrue( remoteListener.isEmpty() );
|
||||||
assertTrue( localListener.isEmpty() );
|
assertTrue( localListener.isEmpty() );
|
||||||
|
|
||||||
// Sleep a bit to let async commit propagate. Really just to
|
|
||||||
// help keep the logs organized for debugging any issues
|
|
||||||
sleep( SLEEP_TIME );
|
|
||||||
|
|
||||||
log.debug( "Find node 0" );
|
log.debug( "Find node 0" );
|
||||||
// This actually brings the collection into the cache
|
// This actually brings the collection into the cache
|
||||||
getCustomer( ids.customerId, localFactory );
|
getCustomer( ids.customerId, localFactory );
|
||||||
|
|
||||||
sleep( SLEEP_TIME );
|
|
||||||
|
|
||||||
// Now the collection is in the cache so, the 2nd "get"
|
// Now the collection is in the cache so, the 2nd "get"
|
||||||
// should read everything from the cache
|
// should read everything from the cache
|
||||||
log.debug( "Find(2) node 0" );
|
log.debug( "Find(2) node 0" );
|
||||||
|
@ -182,7 +175,6 @@ public class EntityCollectionInvalidationTest extends DualNodeTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
ids = modifyCustomer( ids.customerId, remoteFactory );
|
ids = modifyCustomer( ids.customerId, remoteFactory );
|
||||||
sleep( 250 );
|
|
||||||
assertLoadedFromCache( remoteListener, ids.customerId, ids.contactIds );
|
assertLoadedFromCache( remoteListener, ids.customerId, ids.contactIds );
|
||||||
|
|
||||||
if (modifyLatch != null) {
|
if (modifyLatch != null) {
|
||||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import org.hibernate.Criteria;
|
import org.hibernate.Criteria;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
|
@ -38,8 +40,6 @@ public class NaturalIdInvalidationTest extends DualNodeTest {
|
||||||
|
|
||||||
private static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog(NaturalIdInvalidationTest.class);
|
private static final InfinispanMessageLogger log = InfinispanMessageLogger.Provider.getLog(NaturalIdInvalidationTest.class);
|
||||||
|
|
||||||
private static final long SLEEP_TIME = 50l;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Object[]> getParameters() {
|
public List<Object[]> getParameters() {
|
||||||
return getParameters(true, true, true, true);
|
return getParameters(true, true, true, true);
|
||||||
|
@ -77,20 +77,18 @@ public class NaturalIdInvalidationTest extends DualNodeTest {
|
||||||
assertTrue(remoteListener.isEmpty());
|
assertTrue(remoteListener.isEmpty());
|
||||||
assertTrue(localListener.isEmpty());
|
assertTrue(localListener.isEmpty());
|
||||||
|
|
||||||
|
CountDownLatch remoteUpdateLatch = expectAfterUpdate(remoteNaturalIdCache.getAdvancedCache(), 2);
|
||||||
saveSomeCitizens(localFactory);
|
saveSomeCitizens(localFactory);
|
||||||
|
|
||||||
|
assertTrue(remoteUpdateLatch.await(2, TimeUnit.SECONDS));
|
||||||
|
|
||||||
assertTrue(remoteListener.isEmpty());
|
assertTrue(remoteListener.isEmpty());
|
||||||
assertTrue(localListener.isEmpty());
|
assertTrue(localListener.isEmpty());
|
||||||
|
|
||||||
// Sleep a bit to let async commit propagate. Really just to
|
|
||||||
// help keep the logs organized for debugging any issues
|
|
||||||
sleep( SLEEP_TIME );
|
|
||||||
|
|
||||||
log.debug("Find node 0");
|
log.debug("Find node 0");
|
||||||
// This actually brings the collection into the cache
|
// This actually brings the collection into the cache
|
||||||
getCitizenWithCriteria(localFactory);
|
getCitizenWithCriteria(localFactory);
|
||||||
|
|
||||||
sleep( SLEEP_TIME );
|
|
||||||
// Now the collection is in the cache so, the 2nd "get"
|
// Now the collection is in the cache so, the 2nd "get"
|
||||||
// should read everything from the cache
|
// should read everything from the cache
|
||||||
log.debug( "Find(2) node 0" );
|
log.debug( "Find(2) node 0" );
|
||||||
|
@ -117,8 +115,9 @@ public class NaturalIdInvalidationTest extends DualNodeTest {
|
||||||
|
|
||||||
// Modify customer in remote
|
// Modify customer in remote
|
||||||
remoteListener.clear();
|
remoteListener.clear();
|
||||||
|
CountDownLatch localUpdate = expectEvict(localNaturalIdCache.getAdvancedCache(), 1);
|
||||||
deleteCitizenWithCriteria(remoteFactory);
|
deleteCitizenWithCriteria(remoteFactory);
|
||||||
sleep(250);
|
assertTrue(localUpdate.await(2, TimeUnit.SECONDS));
|
||||||
|
|
||||||
Set localKeys = localNaturalIdCache.keySet();
|
Set localKeys = localNaturalIdCache.keySet();
|
||||||
assertEquals(1, localKeys.size());
|
assertEquals(1, localKeys.size());
|
||||||
|
@ -222,18 +221,6 @@ public class NaturalIdInvalidationTest extends DualNodeTest {
|
||||||
log.debug( event.toString() );
|
log.debug( event.toString() );
|
||||||
if ( !event.isPre() ) {
|
if ( !event.isPre() ) {
|
||||||
visited.add(event.getKey().toString());
|
visited.add(event.getKey().toString());
|
||||||
// Integer primKey = (Integer) cacheKey.getKey();
|
|
||||||
// String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey;
|
|
||||||
// log.debug( "MyListener[" + name + "] - Visiting key " + key );
|
|
||||||
// // String name = fqn.toString();
|
|
||||||
// String token = ".functional.";
|
|
||||||
// int index = key.indexOf( token );
|
|
||||||
// if ( index > -1 ) {
|
|
||||||
// index += token.length();
|
|
||||||
// key = key.substring( index );
|
|
||||||
// log.debug( "MyListener[" + name + "] - recording visit to " + key );
|
|
||||||
// visited.add( key );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ import java.util.NavigableMap;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.BlockingDeque;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.ConcurrentSkipListMap;
|
import java.util.concurrent.ConcurrentSkipListMap;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
|
@ -37,6 +38,7 @@ import java.util.concurrent.Executors;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
import java.util.concurrent.ForkJoinTask;
|
import java.util.concurrent.ForkJoinTask;
|
||||||
import java.util.concurrent.Future;
|
import java.util.concurrent.Future;
|
||||||
|
import java.util.concurrent.LinkedBlockingDeque;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
@ -159,7 +161,7 @@ public abstract class CorrectnessTestCase {
|
||||||
return new HashMap<>();
|
return new HashMap<>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private List<Exception> exceptions = Collections.synchronizedList(new ArrayList<>());
|
private BlockingDeque<Exception> exceptions = new LinkedBlockingDeque<>();
|
||||||
|
|
||||||
public String getDbName() {
|
public String getDbName() {
|
||||||
return getClass().getName().replaceAll("\\W", "_");
|
return getClass().getName().replaceAll("\\W", "_");
|
||||||
|
@ -407,13 +409,8 @@ public abstract class CorrectnessTestCase {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long testEnd = System.currentTimeMillis() + EXECUTION_TIME;
|
Exception failure = exceptions.poll(EXECUTION_TIME, TimeUnit.SECONDS);
|
||||||
while (System.currentTimeMillis() < testEnd) {
|
if (failure != null) exceptions.addFirst(failure);
|
||||||
if (!exceptions.isEmpty()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Thread.sleep(1000);
|
|
||||||
}
|
|
||||||
running = false;
|
running = false;
|
||||||
exec.shutdown();
|
exec.shutdown();
|
||||||
if (!exec.awaitTermination(1000, TimeUnit.SECONDS)) throw new IllegalStateException();
|
if (!exec.awaitTermination(1000, TimeUnit.SECONDS)) throw new IllegalStateException();
|
||||||
|
|
|
@ -73,15 +73,11 @@ public class TimestampsRegionImplTest extends AbstractGeneralDataRegionTest {
|
||||||
registry,
|
registry,
|
||||||
getCacheTestSupport()
|
getCacheTestSupport()
|
||||||
);
|
);
|
||||||
// Sleep a bit to avoid concurrent FLUSH problem
|
|
||||||
avoidConcurrentFlush();
|
|
||||||
|
|
||||||
InfinispanRegionFactory regionFactory2 = CacheTestUtil.startRegionFactory(
|
InfinispanRegionFactory regionFactory2 = CacheTestUtil.startRegionFactory(
|
||||||
registry2,
|
registry2,
|
||||||
getCacheTestSupport()
|
getCacheTestSupport()
|
||||||
);
|
);
|
||||||
// Sleep a bit to avoid concurrent FLUSH problem
|
|
||||||
avoidConcurrentFlush();
|
|
||||||
|
|
||||||
TimestampsRegionImpl region = (TimestampsRegionImpl) regionFactory.buildTimestampsRegion(
|
TimestampsRegionImpl region = (TimestampsRegionImpl) regionFactory.buildTimestampsRegion(
|
||||||
getStandardRegionName(REGION_PREFIX),
|
getStandardRegionName(REGION_PREFIX),
|
||||||
|
|
|
@ -65,21 +65,6 @@ public class CacheTestSupport {
|
||||||
throwStoredException();
|
throwStoredException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void avoidConcurrentFlush() {
|
|
||||||
// JG 2.6.1 has a problem where calling flush more than once too quickly
|
|
||||||
// can result in several second delays
|
|
||||||
sleep( 100 );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sleep(long ms) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(ms);
|
|
||||||
}
|
|
||||||
catch (InterruptedException e) {
|
|
||||||
log.warn("Interrupted during sleep", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanUp() {
|
private void cleanUp() {
|
||||||
for (Iterator it = factories.iterator(); it.hasNext(); ) {
|
for (Iterator it = factories.iterator(); it.hasNext(); ) {
|
||||||
try {
|
try {
|
||||||
|
@ -105,7 +90,6 @@ public class CacheTestSupport {
|
||||||
finally {
|
finally {
|
||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
avoidConcurrentFlush();
|
|
||||||
}
|
}
|
||||||
caches.clear();
|
caches.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,39 +172,6 @@ public class CacheTestUtil {
|
||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes {@link #assertEqualsEventually(Object, Callable, long, TimeUnit)} without time limit.
|
|
||||||
* @param expected
|
|
||||||
* @param callable
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
public static <T> void assertEqualsEventually(T expected, Callable<T> callable) throws Exception {
|
|
||||||
assertEqualsEventually(expected, callable, -1, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Periodically calls callable and compares returned value with expected value. If the value matches to expected,
|
|
||||||
* the method returns. If callable throws an exception, this is propagated. If the returned value does not match to
|
|
||||||
* expected before timeout, {@link TimeoutException} is thrown.
|
|
||||||
* @param expected
|
|
||||||
* @param callable
|
|
||||||
* @param timeout If non-positive, there is no limit.
|
|
||||||
* @param timeUnit
|
|
||||||
* @param <T>
|
|
||||||
*/
|
|
||||||
public static <T> void assertEqualsEventually(T expected, Callable<T> callable, long timeout, TimeUnit timeUnit) throws Exception {
|
|
||||||
long now, deadline = timeout <= 0 ? Long.MAX_VALUE : System.currentTimeMillis() + timeUnit.toMillis(timeout);
|
|
||||||
for (;;) {
|
|
||||||
T value = callable.call();
|
|
||||||
if (EqualsHelper.equals(value, expected)) return;
|
|
||||||
now = System.currentTimeMillis();
|
|
||||||
if (now < deadline) {
|
|
||||||
Thread.sleep(Math.min(100, deadline - now));
|
|
||||||
} else break;
|
|
||||||
}
|
|
||||||
throw new TimeoutException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SessionFactoryOptions sfOptionsForStart() {
|
public static SessionFactoryOptions sfOptionsForStart() {
|
||||||
return new SessionFactoryOptionsImpl(
|
return new SessionFactoryOptionsImpl(
|
||||||
new SessionFactoryBuilderImpl.SessionFactoryOptionsStateStandardImpl(
|
new SessionFactoryBuilderImpl.SessionFactoryOptionsStateStandardImpl(
|
||||||
|
|
|
@ -8,12 +8,14 @@ import org.infinispan.interceptors.base.BaseCustomInterceptor;
|
||||||
import org.infinispan.util.logging.Log;
|
import org.infinispan.util.logging.Log;
|
||||||
import org.infinispan.util.logging.LogFactory;
|
import org.infinispan.util.logging.LogFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
|
import java.util.function.BooleanSupplier;
|
||||||
|
|
||||||
|
|
||||||
public class ExpectingInterceptor extends BaseCustomInterceptor {
|
public class ExpectingInterceptor extends BaseCustomInterceptor {
|
||||||
|
@ -56,23 +58,36 @@ public class ExpectingInterceptor extends BaseCustomInterceptor {
|
||||||
succeeded = true;
|
succeeded = true;
|
||||||
return retval;
|
return retval;
|
||||||
} finally {
|
} finally {
|
||||||
log.tracef("After command %s", command);
|
log.tracef("After command(successful=%s) %s", succeeded, command);
|
||||||
|
List<Runnable> toExecute = new ArrayList<>();
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
for (Iterator<Condition> iterator = conditions.iterator(); iterator.hasNext(); ) {
|
for (Iterator<Condition> iterator = conditions.iterator(); iterator.hasNext(); ) {
|
||||||
Condition condition = iterator.next();
|
Condition condition = iterator.next();
|
||||||
|
log.tracef("Testing condition %s", condition);
|
||||||
if ((condition.success == null || condition.success == succeeded) && condition.predicate.test(ctx, command)) {
|
if ((condition.success == null || condition.success == succeeded) && condition.predicate.test(ctx, command)) {
|
||||||
assert condition.action != null;
|
assert condition.action != null;
|
||||||
condition.action.run();
|
log.trace("Condition succeeded");
|
||||||
iterator.remove();
|
toExecute.add(condition.action);
|
||||||
|
if (condition.removeCheck == null || condition.removeCheck.getAsBoolean()) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.trace("Condition test failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// execute without holding the lock
|
||||||
|
for (Runnable runnable : toExecute) {
|
||||||
|
log.tracef("Executing %s", runnable);
|
||||||
|
runnable.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Condition {
|
public class Condition {
|
||||||
private final BiPredicate<InvocationContext, VisitableCommand> predicate;
|
private final BiPredicate<InvocationContext, VisitableCommand> predicate;
|
||||||
private final Boolean success;
|
private final Boolean success;
|
||||||
|
private BooleanSupplier removeCheck;
|
||||||
private Runnable action;
|
private Runnable action;
|
||||||
|
|
||||||
public Condition(BiPredicate<InvocationContext, VisitableCommand> predicate, Boolean success) {
|
public Condition(BiPredicate<InvocationContext, VisitableCommand> predicate, Boolean success) {
|
||||||
|
@ -80,20 +95,36 @@ public class ExpectingInterceptor extends BaseCustomInterceptor {
|
||||||
this.success = success;
|
this.success = success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(Runnable action) {
|
public Condition run(Runnable action) {
|
||||||
assert this.action == null;
|
assert this.action == null;
|
||||||
this.action = action;
|
this.action = action;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void countDown(CountDownLatch latch) {
|
public Condition countDown(CountDownLatch latch) {
|
||||||
assert action == null;
|
return run(() -> latch.countDown()).removeWhen(() -> latch.getCount() == 0);
|
||||||
action = () -> latch.countDown();
|
}
|
||||||
|
|
||||||
|
public Condition removeWhen(BooleanSupplier check) {
|
||||||
|
assert this.removeCheck == null;
|
||||||
|
this.removeCheck = check;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cancel() {
|
public void cancel() {
|
||||||
synchronized (ExpectingInterceptor.class) {
|
synchronized (ExpectingInterceptor.this) {
|
||||||
conditions.remove(this);
|
conditions.remove(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
final StringBuilder sb = new StringBuilder("Condition{");
|
||||||
|
sb.append("predicate=").append(predicate);
|
||||||
|
sb.append(", success=").append(success);
|
||||||
|
sb.append(", action=").append(action);
|
||||||
|
sb.append('}');
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,13 @@ public class TestInfinispanRegionFactory extends InfinispanRegionFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected EmbeddedCacheManager createCacheManager(ConfigurationBuilderHolder holder) {
|
protected EmbeddedCacheManager createCacheManager(ConfigurationBuilderHolder holder) {
|
||||||
|
// If the cache manager has been provided by calling setCacheManager, don't create a new one
|
||||||
|
EmbeddedCacheManager cacheManager = getCacheManager();
|
||||||
|
if (cacheManager != null) {
|
||||||
|
return cacheManager;
|
||||||
|
}
|
||||||
amendConfiguration(holder);
|
amendConfiguration(holder);
|
||||||
DefaultCacheManager cacheManager = new DefaultCacheManager(holder, true);
|
cacheManager = new DefaultCacheManager(holder, true);
|
||||||
if (timeService != null) {
|
if (timeService != null) {
|
||||||
cacheManager.getGlobalComponentRegistry().registerComponent(timeService, TimeService.class);
|
cacheManager.getGlobalComponentRegistry().registerComponent(timeService, TimeService.class);
|
||||||
cacheManager.getGlobalComponentRegistry().rewire();
|
cacheManager.getGlobalComponentRegistry().rewire();
|
||||||
|
|
Loading…
Reference in New Issue