/*
* INESC-ID, Instituto de Engenharia de Sistemas e Computadores Investigação e Desevolvimento em Lisboa
* Copyright 2013 INESC-ID and/or its affiliates and other
* contributors as indicated by the @author tags. All rights reserved.
* See the copyright.txt in the distribution for a full listing of
* individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3.0 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.infinispan.loaders;
import org.infinispan.Cache;
import org.infinispan.config.Configuration;
import org.infinispan.configuration.cache.VersioningScheme;
import org.infinispan.container.DataContainer;
import org.infinispan.container.entries.InternalCacheEntry;
import org.infinispan.loaders.dummy.DummyInMemoryCacheStore;
import org.infinispan.manager.EmbeddedCacheManager;
import org.infinispan.test.AbstractInfinispanTest;
import org.infinispan.test.TestingUtil;
import org.infinispan.test.fwk.TestCacheManagerFactory;
import org.infinispan.transaction.TransactionMode;
import org.infinispan.util.concurrent.IsolationLevel;
import org.infinispan.util.logging.Log;
import org.infinispan.util.logging.LogFactory;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import javax.transaction.TransactionManager;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
/**
* // TODO: Document this
*
* @author Pedro Ruivo
* @since 5.2
*/
@Test(groups = "functional", testName = "loaders.WriteSkewCacheLoaderFunctionalTest")
public class WriteSkewCacheLoaderFunctionalTest extends AbstractInfinispanTest {
Cache cache;
CacheStore store;
TransactionManager tm;
Configuration cfg;
EmbeddedCacheManager cm;
long lifespan = 60000000; // very large lifespan so nothing actually expires
@BeforeTest
public void setUp() {
cfg = new Configuration().fluent()
.loaders()
.addCacheLoader(new DummyInMemoryCacheStore.Cfg()
.storeName(this.getClass().getName())) // in order to use the same store
.transaction().transactionMode(TransactionMode.TRANSACTIONAL)
.versioning().enable().versioningScheme(VersioningScheme.SIMPLE)
.locking().isolationLevel(IsolationLevel.REPEATABLE_READ).writeSkewCheck(true)
.clustering().mode(Configuration.CacheMode.REPL_SYNC).sync()
.build();
cm = TestCacheManagerFactory.createCacheManager(cfg);
cache = cm.getCache();
store = TestingUtil.extractComponent(cache, CacheLoaderManager.class).getCacheStore();
tm = TestingUtil.getTransactionManager(cache);
}
@AfterTest
public void tearDown() {
TestingUtil.killCacheManagers(cm);
cache = null;
cm = null;
cfg = null;
tm = null;
store = null;
}
@AfterMethod
public void afterMethod() throws CacheLoaderException {
if (cache != null) cache.clear();
if (store != null) store.clear();
}
private void assertInCacheAndStore(Object key, Object value) throws CacheLoaderException {
assertInCacheAndStore(key, value, -1);
}
private void assertInCacheAndStore(Object key, Object value, long lifespanMillis) throws CacheLoaderException {
assertInCacheAndStore(cache, store, key, value, lifespanMillis);
}
private void assertInCacheAndStore(Cache cache, CacheStore store, Object key, Object value) throws CacheLoaderException {
assertInCacheAndStore(cache, store, key, value, -1);
}
private void assertInCacheAndStore(Cache cache, CacheStore store, Object key, Object value, long lifespanMillis) throws CacheLoaderException {
InternalCacheEntry se = cache.getAdvancedCache().getDataContainer().get(key, null);
testStoredEntry(se, value, lifespanMillis, "Cache", key);
se = store.load(key);
testStoredEntry(se, value, lifespanMillis, "Store", key);
}
private void testStoredEntry(InternalCacheEntry entry, Object expectedValue, long expectedLifespan, String src, Object key) {
assert entry != null : src + " entry for key " + key + " should NOT be null";
assert entry.getValue().equals(expectedValue) : src + " should contain value " + expectedValue + " under key " + entry.getKey() + " but was " + entry.getValue() + ". Entry is " + entry;
assert entry.getLifespan() == expectedLifespan : src + " expected lifespan for key " + key + " to be " + expectedLifespan + " but was " + entry.getLifespan() + ". Entry is " + entry;
}
private void assertNotInCacheAndStore(Cache cache, CacheStore store, Object... keys) throws CacheLoaderException {
for (Object key : keys) {
assert !cache.getAdvancedCache().getDataContainer().containsKey(key, null) : "Cache should not contain key " + key;
assert !store.containsKey(key) : "Store should not contain key " + key;
}
}
private void assertNotInCacheAndStore(Object... keys) throws CacheLoaderException {
assertNotInCacheAndStore(cache, store, keys);
}
private void assertInStoreNotInCache(Object... keys) throws CacheLoaderException {
assertInStoreNotInCache(cache, store, keys);
}
private void assertInStoreNotInCache(Cache cache, CacheStore store, Object... keys) throws CacheLoaderException {
for (Object key : keys) {
assert !cache.getAdvancedCache().getDataContainer().containsKey(key, null) : "Cache should not contain key " + key;
assert store.containsKey(key) : "Store should contain key " + key;
}
}
private void assertInCacheAndNotInStore(Object... keys) throws CacheLoaderException {
assertInCacheAndNotInStore(cache, store, keys);
}
private void assertInCacheAndNotInStore(Cache cache, CacheStore store, Object... keys) throws CacheLoaderException {
for (Object key : keys) {
assert cache.getAdvancedCache().getDataContainer().containsKey(key, null) : "Cache should not contain key " + key;
assert !store.containsKey(key) : "Store should contain key " + key;
}
}
public void testPreloadingInTransactionalCache() throws Exception {
Configuration preloadingCfg = cfg.clone();
preloadingCfg.getCacheLoaderManagerConfig().setPreload(true);
((DummyInMemoryCacheStore.Cfg) preloadingCfg.getCacheLoaderManagerConfig().getFirstCacheLoaderConfig()).setStoreName("preloadingCache");
cm.defineConfiguration("preloadingCache", preloadingCfg);
Cache preloadingCache = cm.getCache("preloadingCache");
CacheStore preloadingStore = TestingUtil.extractComponent(preloadingCache, CacheLoaderManager.class).getCacheStore();
assert preloadingCache.getConfiguration().getCacheLoaderManagerConfig().isPreload();
assertNotInCacheAndStore(preloadingCache, preloadingStore, "k1", "k2", "k3", "k4");
preloadingCache.put("k1", "v1");
preloadingCache.put("k2", "v2", lifespan, MILLISECONDS);
preloadingCache.put("k3", "v3");
preloadingCache.put("k4", "v4", lifespan, MILLISECONDS);
for (int i = 1; i < 5; i++) {
if (i % 2 == 1)
assertInCacheAndStore(preloadingCache, preloadingStore, "k" + i, "v" + i);
else
assertInCacheAndStore(preloadingCache, preloadingStore, "k" + i, "v" + i, lifespan);
}
DataContainer c = preloadingCache.getAdvancedCache().getDataContainer();
assert c.size(null) == 4;
preloadingCache.stop();
assert c.size(null) == 0;
preloadingCache.start();
assert preloadingCache.getConfiguration().getCacheLoaderManagerConfig().isPreload();
c = preloadingCache.getAdvancedCache().getDataContainer();
assert c.size(null) == 4;
for (int i = 1; i < 5; i++) {
if (i % 2 == 1)
assertInCacheAndStore(preloadingCache, preloadingStore, "k" + i, "v" + i);
else
assertInCacheAndStore(preloadingCache, preloadingStore, "k" + i, "v" + i, lifespan);
}
TransactionManager transactionManager = preloadingCache.getAdvancedCache().getTransactionManager();
transactionManager.begin();
assert preloadingCache.get("k1") == "v1" : "k1 value is different from v1";
preloadingCache.put("k1", "new-v1");
transactionManager.commit();
}
}