blob: 944c3055581b9c1b993de4235d39c15bfa25d370 [file] [log] [blame]
/*=========================================================================
* Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
* This product is protected by U.S. and international copyright
* and intellectual property laws. Pivotal products are covered by
* one or more patents listed at http://www.pivotal.io/patents.
*=========================================================================
*/
package com.gemstone.gemfire.cache30;
import java.io.File;
import java.util.Properties;
import com.gemstone.gemfire.SystemFailure;
import com.gemstone.gemfire.cache.AttributesFactory;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheException;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.CacheLoader;
import com.gemstone.gemfire.cache.CacheLoaderException;
import com.gemstone.gemfire.cache.CacheTransactionManager;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.EntryEvent;
import com.gemstone.gemfire.cache.EvictionAction;
import com.gemstone.gemfire.cache.EvictionAttributes;
import com.gemstone.gemfire.cache.InterestPolicy;
import com.gemstone.gemfire.cache.LoaderHelper;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.Scope;
import com.gemstone.gemfire.cache.SubscriptionAttributes;
import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.internal.OSProcess;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
import com.gemstone.gemfire.internal.cache.LocalRegion;
import com.gemstone.gemfire.internal.cache.control.InternalResourceManager.ResourceType;
import com.gemstone.gemfire.internal.cache.lru.HeapEvictor;
import com.gemstone.gemfire.internal.cache.lru.LRUStatistics;
import dunit.Host;
import dunit.VM;
/**
* Tests the basic functionality of the lru eviction
* controller and its statistics.
*
* @author David Whitlock
*
* @since 3.2
*/
public class LRUEvictionControllerDUnitTest extends CacheTestCase {
private static boolean usingMain = false;
/**
* Creates a new <code>LRUEvictionControllerDUnitTest</code>
*/
public LRUEvictionControllerDUnitTest(String name) {
super(name);
}
/**
* Returns the <code>LRUStatistics</code> for the given region
*/
private LRUStatistics getLRUStats(Region region) {
final LocalRegion l = (LocalRegion) region;
return l.getEvictionController().getLRUHelper().getStats();
}
//////// Test Methods
/**
* Carefully verifies that region operations effect the {@link
* LRUStatistics} as expected.
*/
public void testRegionOperations() throws CacheException {
int threshold = 10;
final String name = this.getUniqueName();
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.LOCAL);
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(threshold));
Region region;
if (usingMain) {
DistributedSystem system =
DistributedSystem.connect(new Properties());
Cache cache = CacheFactory.create(system);
region = cache.createRegion("Test",
factory.create());
} else {
region = createRegion(name, factory.create());
}
LRUStatistics lruStats = getLRUStats(region);
assertNotNull(lruStats);
for (int i = 1; i <= 10; i++) {
Object key = new Integer(i);
Object value = String.valueOf(i);
region.put(key, value);
assertEquals(i, lruStats.getCounter());
assertEquals(0, lruStats.getEvictions());
}
for (int i = 11; i <= 20; i++) {
Object key = new Integer(i);
Object value = String.valueOf(i);
region.put(key, value);
assertEquals(10, lruStats.getCounter());
assertEquals(i - 10, lruStats.getEvictions());
}
}
/**
* Carefully verifies that region operations effect the {@link
* LRUStatistics} as expected in the presense of a {@link
* CacheLoader}.
*/
public void testCacheLoader() throws CacheException {
int threshold = 10;
final String name = this.getUniqueName();
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.LOCAL);
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(threshold));
factory.setCacheLoader(new CacheLoader() {
public Object load(LoaderHelper helper)
throws CacheLoaderException {
return "LOADED VALUE";
}
public void close() { }
});
Region region;
if (usingMain) {
DistributedSystem system =
DistributedSystem.connect(new Properties());
Cache cache = CacheFactory.create(system);
region = cache.createRegion("Test",
factory.create());
} else {
region = createRegion(name, factory.create());
}
LRUStatistics lruStats = getLRUStats(region);
assertNotNull(lruStats);
for (int i = 1; i <= 10; i++) {
Object key = new Integer(i);
Object value = String.valueOf(i);
region.put(key, value);
assertEquals(i, lruStats.getCounter());
assertEquals(0, lruStats.getEvictions());
}
for (int i = 11; i <= 20; i++) {
Object key = new Integer(i);
// Object value = String.valueOf(i);
// Invoke loader
region.get(key);
assertEquals(10, lruStats.getCounter());
assertEquals(i - 10, lruStats.getEvictions());
}
}
/**
* Tests an <code>LRUCapacityController</code> of size 1.
*/
public void testSizeOne() throws CacheException {
int threshold = 1;
final String name = this.getUniqueName();
AttributesFactory factory = new AttributesFactory();
factory.setOffHeap(isOffHeapEnabled());
factory.setScope(Scope.LOCAL);
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(threshold));
factory.setCacheLoader(new CacheLoader() {
public Object load(LoaderHelper helper)
throws CacheLoaderException {
return "LOADED VALUE";
}
public void close() { }
});
Region region;
if (usingMain) {
DistributedSystem system =
DistributedSystem.connect(new Properties());
Cache cache = CacheFactory.create(system);
region = cache.createRegion("Test",
factory.create());
} else {
region = createRegion(name, factory.create());
}
LRUStatistics lruStats = getLRUStats(region);
assertNotNull(lruStats);
for (int i = 1; i <= 1; i++) {
Object key = new Integer(i);
Object value = String.valueOf(i);
region.put(key, value);
assertEquals(1, lruStats.getCounter());
assertEquals(0, lruStats.getEvictions());
}
for (int i = 2; i <= 10; i++) {
Object key = new Integer(i);
Object value = String.valueOf(i);
region.put(key, value);
assertEquals(1, lruStats.getCounter());
assertEquals(i - 1, lruStats.getEvictions());
}
for (int i = 11; i <= 20; i++) {
Object key = new Integer(i);
// Object value = String.valueOf(i);
// Invoke loader
region.get(key);
assertEquals(1, lruStats.getCounter());
assertEquals(i - 1, lruStats.getEvictions());
}
}
/**
* Tests that a single set of eviction attributes can be used multiple times
* (and does the right thing).
*/
public void testMultipleUsesOfEvictionAttributes()
throws CacheException, CloneNotSupportedException {
int threshold = 42;
final String name = this.getUniqueName();
AttributesFactory factory = new AttributesFactory();
factory.setScope(Scope.LOCAL);
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(threshold));
Region region =
createRegion(name, factory.create());
RegionAttributes ra = region.getAttributes();
Region r2 = createRegion(name + 2, ra);
factory = new AttributesFactory(ra);
Region r3 = createRegion(name + 3, factory.create());
assertEquals(region.getAttributes().getEvictionAttributes(), r2.getAttributes().getEvictionAttributes());
assertEquals(r2.getAttributes().getEvictionAttributes(), r3.getAttributes().getEvictionAttributes());
{
LocalRegion lRegion = (LocalRegion) region;
LocalRegion lr2 = (LocalRegion) r2;
LocalRegion lr3 = (LocalRegion) r3;
assertNotSame(lRegion.getEvictionController(), lr2.getEvictionController());
assertEquals(lRegion.getEvictionController(), lr2.getEvictionController());
assertNotSame(lr2.getEvictionController(), lr3.getEvictionController());
assertEquals(lr2.getEvictionController(), lr3.getEvictionController());
}
}
/**
* Tests that a Region with an LRU capacity controller can be
* accessed from inside a cache listener.
*/
public void testBug31592() throws Exception {
final String name = this.getUniqueName();
final Object key = "KEY";
final Object value = "VALUE";
final Object key2 = "KEY2";
final Object value2 = "VALUE2";
AttributesFactory factory = new AttributesFactory();
factory.setOffHeap(isOffHeapEnabled());
factory.setScope(Scope.LOCAL);
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(10));
final Region region =
createRegion(name, factory.create());
region.put(key, value);
final Throwable[] errors = new Throwable[1];
region.getAttributesMutator().addCacheListener(new
CacheListenerAdapter() {
public void afterCreate(EntryEvent event) {
try {
getLogWriter().info("AFTER CREATE");
region.put(key, value2);
}
catch (VirtualMachineError e) {
SystemFailure.initiateFailure(e);
throw e;
}
catch (Throwable ex) {
region.getCache().getLogger().severe(
"failed to access cache from listener", ex);
errors[0] = ex;
}
}
});
region.put(key2, value2);
assertNull(errors[0]);
assertEquals(value2, region.get(key));
assertEquals(value2, region.get(key2));
}
/**
* Tests that a capacity controller with LOCAL_DESTROY eviction action
* cannot be installed into a region
*/
public void testCCMirrored() throws Exception {
final String name = this.getUniqueName();
AttributesFactory factory = new AttributesFactory();
factory.setOffHeap(isOffHeapEnabled());
factory.setEvictionAttributes(EvictionAttributes.createLRUEntryAttributes(10));
factory.setDataPolicy(DataPolicy.REPLICATE);
Region r = createRegion(name, factory.create());
RegionAttributes ra = r.getAttributes();
assertEquals(DataPolicy.PRELOADED, ra.getDataPolicy());
assertEquals(new SubscriptionAttributes(InterestPolicy.ALL),
ra.getSubscriptionAttributes());
r.destroyRegion();
}
/**
* Create two regions, one a "feed" that performs transactions
* which are replicated to a region with an Entry LRU set to one
* Asserts that the LRU rules are observed
* @throws Exception
*/
public void testReplicationAndTransactions() throws Exception {
final String r1 = this.getUniqueName() + "-1";
final String r2 = this.getUniqueName() + "-2";
final String r3 = this.getUniqueName() + "-3";
VM feeder = Host.getHost(0).getVM(3);
VM repl = Host.getHost(0).getVM(2);
final int maxEntries = 1;
final int numEntries = 10000;
final int txBatchSize = 10;
assertTrue(numEntries > txBatchSize); // need at least one batch
CacheSerializableRunnable createRegion =
new CacheSerializableRunnable("Create Replicate Region") {
public void run2() throws CacheException {
AttributesFactory factory = new AttributesFactory();
factory.setOffHeap(isOffHeapEnabled());
factory.setEvictionAttributes(
EvictionAttributes.createLRUEntryAttributes(maxEntries,
EvictionAction.OVERFLOW_TO_DISK));
factory.setDataPolicy(DataPolicy.REPLICATE);
File[] diskDirs = new File[1];
diskDirs[0] = new File("overflowDir/" + OSProcess.getId());
diskDirs[0].mkdirs();
factory.setDiskStoreName(getCache().createDiskStoreFactory()
.setDiskDirs(diskDirs)
.create("LRUEvictionControllerDUnitTest")
.getName());
factory.setDiskSynchronous(true);
factory.setScope(Scope.DISTRIBUTED_ACK);
RegionAttributes a = factory.create();
createRegion(r1, a);
createRegion(r2, a);
createRegion(r3, a);
}
};
feeder.invoke(createRegion);
repl.invoke(createRegion);
feeder.invoke(new CacheSerializableRunnable("put " + numEntries +
" entries and assert " + maxEntries + " max entries") {
public void run2() throws CacheException {
Cache c = getCache();
CacheTransactionManager txm = c.getCacheTransactionManager();
Region reg1 = getRootRegion().getSubregion(r1);
assertNotNull(reg1);
Region reg2 = getRootRegion().getSubregion(r2);
assertNotNull(reg2);
Region reg3 = getRootRegion().getSubregion(r3);
assertNotNull(reg3);
boolean startTx = false;
final Region[] r = {reg1, reg2, reg3};
for (int i=0; i<numEntries; i++){
if (i%txBatchSize == 0) {
txm.begin();
startTx = true;
}
reg1.create("r1-key-" + i, "r1-value-" +i);
reg2.create("r2-key-" + i, "r2-value-" +i);
reg3.create("r3-key-" + i, "r3-value-" +i);
if (i%txBatchSize == (txBatchSize-1)) {
txm.commit();
try { // allow stats to get a sample in
Thread.sleep(20);
} catch (InterruptedException ie){
fail("interrupted");
}
startTx = false;
}
}
if (startTx) {
txm.commit();
}
for(int i =0; i<r.length; i++) {
assertEquals(numEntries, r[i].size());
{
LocalRegion lr = (LocalRegion) r[i];
assertEquals(maxEntries, lr.getEvictionController().getLRUHelper().getStats().getLimit());
assertEquals(maxEntries, lr.getEvictionController().getLRUHelper().getStats().getCounter());
}
}
}
});
repl.invoke(new CacheSerializableRunnable("Replicate asserts " +
maxEntries + " max entries" ) {
public void run2() throws CacheException {
getCache();
Region reg1 = getRootRegion().getSubregion(r1);
Region reg2 = getRootRegion().getSubregion(r2);
Region reg3 = getRootRegion().getSubregion(r3);
final Region[] r = {reg1, reg2, reg3};
for(int i =0; i<r.length; i++) {
assertNotNull(r[i]);
assertEquals(numEntries, r[i].size());
{
LocalRegion lr = (LocalRegion) r[i];
assertEquals(maxEntries, lr.getEvictionController().getLRUHelper().getStats().getLimit());
assertEquals(maxEntries, lr.getEvictionController().getLRUHelper().getStats().getCounter());
}
}
}
});
}
protected boolean isOffHeapEnabled() {
return false;
}
protected HeapEvictor getEvictor() {
return ((GemFireCacheImpl) getCache()).getHeapEvictor();
}
protected ResourceType getResourceType() {
return ResourceType.HEAP_MEMORY;
}
public static void main(String[] args) throws Exception {
usingMain = true;
(new LRUEvictionControllerDUnitTest("test")).testSizeOne();
}
}