package org.infinispan.statetransfer;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.CacheMode;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.dummy.DummyInMemoryStoreConfigurationBuilder;
import org.infinispan.persistence.spi.AdvancedCacheLoader;
import org.infinispan.persistence.spi.CacheLoader;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TransportFlags;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Added tests that verify when a rehash occurs that the store contents are updated properly
*
* @author William Burns
* @since 6.0
*/
@Test(groups = "functional", testName = "statetransfer.StateTransferDistSharedCacheLoaderFunctionalTest")
public class StateTransferDistSharedCacheLoaderFunctionalTest extends StateTransferFunctionalTest {
ThreadLocal<Boolean> sharedCacheLoader = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return true;
}
};
ThreadLocal<Boolean> fetchPersistentState = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return true;
}
};
int id;
static final int INSERTION_COUNT = 500;
@BeforeMethod
public void beforeEachMethod() {
sharedCacheLoader.set(true);
fetchPersistentState.set(true);
}
protected void createCacheManagers() throws Throwable {
super.createCacheManagers();
configurationBuilder.clustering().cacheMode(CacheMode.DIST_SYNC);
}
@Override
protected EmbeddedCacheManager createCacheManager(String cacheName) {
configurationBuilder.persistence().clearStores();
DummyInMemoryStoreConfigurationBuilder dimcs = new DummyInMemoryStoreConfigurationBuilder(configurationBuilder.persistence());
if (sharedCacheLoader.get()) {
dimcs.storeName(getClass().getName());
} else {
dimcs.storeName(getClass().getName() + id++);
}
dimcs.fetchPersistentState(false).purgeOnStartup(false).shared(sharedCacheLoader.get()).preload(true);
configurationBuilder.persistence().passivation(false).addStore(dimcs).fetchPersistentState(fetchPersistentState.get());
// Want to enable eviction, but don't actually evict anything
configurationBuilder.eviction().strategy(EvictionStrategy.LIRS).maxEntries(INSERTION_COUNT * 10);
EmbeddedCacheManager cm = addClusterEnabledCacheManager(configurationBuilder, new TransportFlags().withMerge(true));
cm.defineConfiguration(cacheName, configurationBuilder.build());
return cm;
}
public void testSharedFetchedStoreEntriesUnaffected() throws Exception {
Cache<Object, Object> cache1, cache2, cache3;
EmbeddedCacheManager cm1 = createCacheManager(cacheName);
cache1 = cm1.getCache(cacheName);
writeLargeInitialData(cache1);
assertEquals(INSERTION_COUNT, getDataContainerSize(cache1));
verifyInitialDataOnLoader(cache1);
EmbeddedCacheManager cm2 = createCacheManager(cacheName);
cache2 = cm2.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2);
assertEquals(INSERTION_COUNT, getDataContainerSize(cache1));
assertEquals(INSERTION_COUNT, getDataContainerSize(cache2));
verifyInitialDataOnLoader(cache2);
EmbeddedCacheManager cm3 = createCacheManager(cacheName);
cache3 = cm3.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2, cache3);
// Need an additional wait for the non-owned entries to be deleted from the data containers
eventuallyEquals(INSERTION_COUNT * 2, () -> getDataContainerSize(cache1, cache2, cache3));
// Shared cache loader should have all the contents still
verifyInitialDataOnLoader(cache3);
}
public void testUnsharedNotFetchedStoreEntriesRemovedProperly() throws Exception {
sharedCacheLoader.set(false);
fetchPersistentState.set(false);
Cache<Object, Object> cache1, cache2, cache3;
EmbeddedCacheManager cm1 = createCacheManager(cacheName);
cache1 = cm1.getCache(cacheName);
writeLargeInitialData(cache1);
assertEquals(INSERTION_COUNT, cache1.getAdvancedCache().getDataContainer().size());
verifyInitialDataOnLoader(cache1);
EmbeddedCacheManager cm2 = createCacheManager(cacheName);
cache2 = cm2.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2);
assertEquals(INSERTION_COUNT, getDataContainerSize(cache1));
assertEquals(INSERTION_COUNT, getDataContainerSize(cache2));
verifyCacheLoaderCount(INSERTION_COUNT, cache2);
EmbeddedCacheManager cm3 = createCacheManager(cacheName);
cache3 = cm3.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2, cache3);
// Need an additional wait for the non-owned entries to be deleted from the data containers
eventuallyEquals(INSERTION_COUNT * 2, () -> getDataContainerSize(cache1, cache2, cache3));
// TODO Shouldn't this work?
//verifyCacheLoaderCount(INSERTION_COUNT * 2, cache1, cache2, cache3);
}
public void testUnsharedFetchedStoreEntriesRemovedProperly() throws Exception {
sharedCacheLoader.set(false);
Cache<Object, Object> cache1, cache2, cache3;
EmbeddedCacheManager cm1 = createCacheManager(cacheName);
cache1 = cm1.getCache(cacheName);
writeLargeInitialData(cache1);
assertEquals(INSERTION_COUNT, cache1.getAdvancedCache().getDataContainer().size());
verifyInitialDataOnLoader(cache1);
EmbeddedCacheManager cm2 = createCacheManager(cacheName);
cache2 = cm2.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2);
assertEquals(INSERTION_COUNT, cache1.getAdvancedCache().getDataContainer().size());
assertEquals(INSERTION_COUNT, cache2.getAdvancedCache().getDataContainer().size());
verifyCacheLoaderCount(INSERTION_COUNT, cache2);
EmbeddedCacheManager cm3 = createCacheManager(cacheName);
cache3 = cm3.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2, cache3);
// Need an additional wait for the non-owned entries to be deleted from the data containers
eventuallyEquals(INSERTION_COUNT * 2, () -> getDataContainerSize(cache1, cache2, cache3));
// TODO Shouldn't this work?
//verifyCacheLoaderCount(INSERTION_COUNT * 2, cache1, cache2, cache3);
}
public void testSharedNotFetchedStoreEntriesRemovedProperly() throws Exception {
fetchPersistentState.set(false);
Cache<Object, Object> cache1, cache2, cache3;
EmbeddedCacheManager cm1 = createCacheManager(cacheName);
cache1 = cm1.getCache(cacheName);
writeLargeInitialData(cache1);
assertEquals(INSERTION_COUNT, cache1.getAdvancedCache().getDataContainer().size());
verifyInitialDataOnLoader(cache1);
EmbeddedCacheManager cm2 = createCacheManager(cacheName);
cache2 = cm2.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2);
assertEquals(INSERTION_COUNT, cache1.getAdvancedCache().getDataContainer().size());
assertEquals(INSERTION_COUNT, cache2.getAdvancedCache().getDataContainer().size());
verifyCacheLoaderCount(INSERTION_COUNT, cache2);
EmbeddedCacheManager cm3 = createCacheManager(cacheName);
cache3 = cm3.getCache(cacheName);
TestingUtil.waitForNoRebalance(cache1, cache2, cache3);
// Shared cache loader should have all the contents still
verifyInitialDataOnLoader(cache3);
// Need an additional wait for the non-owned entries to be deleted from the data containers
eventuallyEquals(INSERTION_COUNT * 2, () -> getDataContainerSize(cache1, cache2, cache3));
}
protected int getDataContainerSize(Cache<?, ?>... caches) {
int count = 0;
for (Cache<?, ?> c : caches) {
count += c.getAdvancedCache().getDataContainer().size();
}
return count;
}
protected void writeLargeInitialData(final Cache<Object, Object> c) {
for (int i = 0; i < INSERTION_COUNT; ++i) {
c.put("key " + i, "value " + i);
}
}
private void verifyCacheLoaderCount(int expectedCount, Cache... caches) {
int count = 0;
for (Cache<Object, Object> cache : caches) {
count += ((AdvancedCacheLoader) TestingUtil.getFirstLoader(cache)).size();
}
assertEquals(expectedCount, count);
}
protected void verifyInitialDataOnLoader(Cache<Object, Object> c) {
CacheLoader l = TestingUtil.getFirstLoader(c);
for (int i = 0; i < INSERTION_COUNT; ++i) {
assertTrue("Didn't contain key " + i, l.contains("key " + i));
}
for (int i = 0; i < INSERTION_COUNT; ++i) {
assertEquals("value " + i, l.load("key " + i).getValue());
}
}
}