package org.infinispan.eviction.impl;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNull;
import java.util.Collections;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.eviction.EvictionThreadPolicy;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.persistence.dummy.DummyInMemoryStoreConfigurationBuilder;
import org.infinispan.test.SingleCacheManagerTest;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.testng.annotations.Test;
@Test(groups = "functional", testName = "eviction.EvictionWithPassivationTest")
public class EvictionWithPassivationTest extends SingleCacheManagerTest {
public EvictionWithPassivationTest() {
// Cleanup needs to be after method, else LIRS can cause failures due to it not caching values due to hot
// size being equal to full container size
cleanup = CleanupPhase.AFTER_METHOD;
}
private final int EVICTION_MAX_ENTRIES = 2;
private ConfigurationBuilder buildCfg(EvictionThreadPolicy threadPolicy, EvictionStrategy strategy) {
ConfigurationBuilder cfg = new ConfigurationBuilder();
cfg
.persistence().passivation(true).addStore(DummyInMemoryStoreConfigurationBuilder.class).purgeOnStartup(true)
.invocationBatching().enable();
cfg.eviction().strategy(strategy);
// If the strategy is NONE then don't use thread policy or strategy or max entries (forces default strategy)
if (strategy != EvictionStrategy.NONE) {
cfg.eviction().threadPolicy(threadPolicy).maxEntries(EVICTION_MAX_ENTRIES);
}
return cfg;
}
@Override
protected EmbeddedCacheManager createCacheManager() throws Exception {
cacheManager = TestCacheManagerFactory.createCacheManager(getDefaultStandaloneCacheConfig(true));
for (EvictionStrategy s : EvictionStrategy.values()) {
for (EvictionThreadPolicy p : EvictionThreadPolicy.values()) {
cacheManager.defineConfiguration("test-" + p + "-" + s, buildCfg(p, s).build());
}
}
return cacheManager;
}
public void testNONE() {
// None doesn't use eviction policy so just using DEFAULT
runTest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.NONE);
}
public void testPiggybackLRU() {
runTest(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LRU);
}
public void testPiggybackLIRS() {
runTest(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LIRS);
}
public void testPiggybackUNORDERED() {
runTest(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.UNORDERED);
}
public void testDefaultLRU() {
runTest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LRU);
}
public void testDefaultLIRS() {
runTest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LIRS);
}
public void testDefaultUNORDERED() {
runTest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.UNORDERED);
}
public void testActivationInBatchRolledBackNONE() {
testActivationInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.NONE);
}
public void testActivationInBatchRolledBackPiggybackLRU() {
testActivationInBatchRolledBack(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LRU);
}
public void testActivationInBatchRolledBackPiggybackLIRS() {
testActivationInBatchRolledBack(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LIRS);
}
public void testActivationInBatchRolledBackPiggybackUNORDERED() {
testActivationInBatchRolledBack(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.UNORDERED);
}
public void testActivationInBatchRolledBackDefaultLRU() {
testActivationInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LRU);
}
public void testActivationInBatchRolledBackDefaultLIRS() {
testActivationInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LIRS);
}
public void testActivationInBatchRolledBackDefaultUNORDERED() {
testActivationInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.UNORDERED);
}
public void testActivationWithAnotherConcurrentRequestNONE() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.NONE);
}
public void testActivationWithAnotherConcurrentRequestPiggybackLRU() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LRU);
}
public void testActivationWithAnotherConcurrentRequestPiggybackLIRS() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LIRS);
}
public void testActivationWithAnotherConcurrentRequestPiggybackUNORDERED() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.UNORDERED);
}
public void testActivationWithAnotherConcurrentRequestDefaultLRU() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LRU);
}
public void testActivationWithAnotherConcurrentRequestDefaultLIRS() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LIRS);
}
public void testActivationWithAnotherConcurrentRequestDefaultUNORDERED() throws Exception {
testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy.DEFAULT, EvictionStrategy.UNORDERED);
}
public void testActivationPendingTransactionDoesNotAffectOthersNONE() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.NONE,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersPiggybackLRU() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LRU,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersPiggybackLIRS() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LIRS,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersPiggybackUNORDERED() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.UNORDERED,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersDefaultLRU() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LRU,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersDefaultLIRS() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LIRS,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersDefaultUNORDERED() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.UNORDERED,
"prev-value");
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValueNONE() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.NONE, null);
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValuePiggybackLRU() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LRU, null);
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValuePiggybackLIRS() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LIRS, null);
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValuePiggybackUNORDERED() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.UNORDERED, null);
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValueDefaultLRU() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LRU, null);
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValueDefaultLIRS() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LIRS, null);
}
public void testActivationPendingTransactionDoesNotAffectOthersEmptyValueDefaultUNORDERED() throws Throwable {
testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy.DEFAULT, EvictionStrategy.UNORDERED, null);
}
public void testActivationPutAllInBatchRolledBackNONE() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.NONE);
}
public void testActivationPutAllInBatchRolledBackPiggybackLRU() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LRU);
}
public void testActivationPutAllInBatchRolledBackPiggybackLIRS() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.LIRS);
}
public void testActivationPutAllInBatchRolledBackPiggybackUNORDERED() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.PIGGYBACK, EvictionStrategy.UNORDERED);
}
public void testActivationPutAllInBatchRolledBackDefaultLRU() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LRU);
}
public void testActivationPutAllInBatchRolledBackDefaultLIRS() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.LIRS);
}
public void testActivationPutAllInBatchRolledBackDefaultUNORDERED() throws Throwable {
testActivationPutAllInBatchRolledBack(EvictionThreadPolicy.DEFAULT, EvictionStrategy.UNORDERED);
}
private void runTest(EvictionThreadPolicy p, EvictionStrategy s) {
String name = "test-" + p + "-" + s;
Cache<String, String> testCache = cacheManager.getCache(name);
testCache.clear();
testCache.put("X", "4567");
testCache.put("Y", "4568");
testCache.put("Z", "4569");
if (!s.equals(EvictionStrategy.NONE)) {
assertEquals(EVICTION_MAX_ENTRIES, testCache.getAdvancedCache().getDataContainer().size());
assertEquals("4567", testCache.get("X"));
assertEquals(EVICTION_MAX_ENTRIES, testCache.getAdvancedCache().getDataContainer().size());
}
assertEquals("4567", testCache.get("X"));
assertEquals("4568", testCache.get("Y"));
assertEquals("4569", testCache.get("Z"));
for (int i = 0; i < 10; i++) {
testCache.getAdvancedCache().startBatch();
String k = "A" + i;
testCache.put(k, k);
k = "B" + i;
testCache.put(k, k);
testCache.getAdvancedCache().endBatch(true);
}
for (int i = 0; i < 10; i++) {
String k = "A" + i;
assertEquals(k, testCache.get(k));
k = "B" + i;
assertEquals(k, testCache.get(k));
}
}
private void testActivationInBatchRolledBack(EvictionThreadPolicy p, EvictionStrategy s) {
String name = "test-" + p + "-" + s;
Cache<String, String> testCache = cacheManager.getCache(name);
final String key = "X";
final String value = "4567";
testCache.clear();
testCache.put(key, value);
testCache.evict(key);
// Now make sure the act of activation for the entry is not tied to the transaction
testCache.startBatch();
assertEquals(value, testCache.get(key));
testCache.endBatch(false);
// The data should still be present even if a rollback occurred
assertEquals(value, testCache.get(key));
}
private void testActivationWithAnotherConcurrentRequest(EvictionThreadPolicy p, EvictionStrategy s) throws Exception {
String name = "test-" + p + "-" + s;
final Cache<String, String> testCache = cacheManager.getCache(name);
final String key = "Y";
final String value = "4568";
testCache.clear();
testCache.put(key, value);
testCache.evict(key);
// Now make sure the act of activation for the entry is not tied to the transaction
testCache.startBatch();
assertEquals(value, testCache.get(key));
// Another thread should be able to see the data as well!
Future<String> future = testCache.getAsync(key);
assertEquals(value, future.get(10, TimeUnit.SECONDS));
assertEquals(value, testCache.get(key));
testCache.endBatch(true);
// Lastly try the retrieval after batch was committed
assertEquals(value, testCache.get(key));
}
private void testActivationPendingTransactionDoesNotAffectOthers(EvictionThreadPolicy p, EvictionStrategy s,
String previousValue) throws Throwable {
String name = "test-" + p + "-" + s;
final Cache<String, String> testCache = cacheManager.getCache(name);
testCache.clear();
final String key = "Y";
final String value;
if (previousValue != null) {
testCache.put(key, previousValue);
value = previousValue + "4568";
} else {
value = "4568";
}
// evict so it is in the loader but not in data container
testCache.evict(key);
testCache.startBatch();
try {
if (previousValue != null) {
assertEquals(previousValue, testCache.put(key, value));
} else {
assertNull(testCache.put(key, value));
}
// In tx we should see new value
assertEquals(value, testCache.get(key));
// The spawned thread shouldn't see the new value yet, should see the old one still
Future<String> future = fork(() -> testCache.get(key));
if (previousValue != null) {
assertEquals(previousValue, future.get(10000, TimeUnit.SECONDS));
} else {
assertNull(future.get(10, TimeUnit.SECONDS));
}
} catch (Throwable e) {
testCache.endBatch(false);
throw e;
}
testCache.endBatch(true);
assertEquals(value, testCache.get(key));
}
private void testActivationPutAllInBatchRolledBack(EvictionThreadPolicy p, EvictionStrategy s) throws Exception {
String name = "test-" + p + "-" + s;
Cache<String, String> testCache = cacheManager.getCache(name);
final String key = "X";
final String value = "4567";
testCache.clear();
testCache.put(key, value);
testCache.evict(key);
// Now make sure the act of activation for the entry is not tied to the transaction
testCache.startBatch();
testCache.putAll(Collections.singletonMap(key, value + "-putall"));
testCache.endBatch(false);
// The data should still be present even if a rollback occurred
assertEquals(value, testCache.get(key));
}
}