package org.jboss.cache.eviction;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.xml.XmlHelper;
import org.jboss.cache.factories.UnitTestCacheConfigurationFactory;
import org.jboss.cache.factories.XmlConfigurationParser;
import org.jboss.cache.config.Configuration;
import org.jboss.cache.config.EvictionConfig;
import org.jboss.cache.interceptors.EvictionInterceptor;
import org.jboss.cache.misc.TestingUtil;
import org.jboss.cache.transaction.DummyTransactionManagerLookup;
import static org.testng.AssertJUnit.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.w3c.dom.Element;
import javax.transaction.TransactionManager;
import java.util.Iterator;
import java.util.List;
/**
* Tests the eviction and the possible lack of locking nodes.
* The configuration is with an aggressive eviction policy, 100 objects 2 seconds interval.
* <p/>
* It is possible that the number needs to be changed a little, depending on the machine speed.
*
* @author fhenning
*/
@Test(groups = {"functional"})
public class OptimisticEvictionTest
{
//Maximum number of runs 2^20
private static final int NUMBER_OF_RUNS = 1 << 20;
//Initial number of nodes
private static final int NUMBER_NODES = 256;
private Fqn<Object> region = new Fqn<Object>("testingRegion");
private TransactionManager txManager;
private CacheSPI<Object, Object> cache;
@BeforeMethod(alwaysRun = true)
public void setUp() throws Exception
{
txManager = new DummyTransactionManagerLookup().getTransactionManager();
Configuration config = UnitTestCacheConfigurationFactory.createConfiguration(Configuration.CacheMode.LOCAL, true);
config.setNodeLockingOptimistic(true);
config.setEvictionConfig(buildEvictionConfig());
cache = (CacheSPI<Object, Object>) new DefaultCacheFactory().createCache(config);
}
private EvictionConfig buildEvictionConfig() throws Exception
{
String xml = " <attribute name=\"EvictionPolicyConfig\">\n" +
" <config>\n" +
" <attribute name=\"wakeUpIntervalSeconds\">1</attribute>\n" +
" <!-- Name of the DEFAULT eviction policy class.-->\n" +
" <attribute name=\"policyClass\">org.jboss.cache.eviction.LRUPolicy</attribute>\n" +
" <region name=\"/_default_\">\n" +
" <attribute name=\"maxNodes\">10</attribute>\n" +
" <attribute name=\"timeToLiveSeconds\">0</attribute>\n" +
" <attribute name=\"maxAgeSeconds\">0</attribute>\n" +
" </region>\n" +
" <region name=\"/testingRegion\">\n" +
" <attribute name=\"maxNodes\">10</attribute>\n" +
" <attribute name=\"timeToLiveSeconds\">0</attribute>\n" +
" <attribute name=\"maxAgeSeconds\">0</attribute>\n" +
" </region>\n" +
" <region name=\"/timeBased\">\n" +
" <attribute name=\"maxNodes\">10</attribute>\n" +
" <attribute name=\"timeToLiveSeconds\">1</attribute>\n" +
" <attribute name=\"maxAgeSeconds\">1</attribute>\n" +
" </region>\n" +
" </config>\n" +
" </attribute>";
Element element = XmlHelper.stringToElement(xml);
return XmlConfigurationParser.parseEvictionConfig(element);
}
@AfterMethod(alwaysRun = true)
public void tearDown() throws Exception
{
if (cache != null)
{
// shut down any existing txs
try
{
if (cache.getTransactionManager().getTransaction() != null)
{
cache.getTransactionManager().rollback();
}
}
catch (Exception e)
{
// ignore
}
cache.stop();
cache = null;
}
}
public void testEvictionError() throws Exception
{
//Initialize the cache via a map
for (int i = 0; i < NUMBER_NODES; i++)
{
cache.put(new Fqn<Object>(region, i), i, i);
}
for (int i = 0; i < NUMBER_OF_RUNS; i++)
{
txManager.begin();
cache.get(region, i % NUMBER_NODES);
txManager.commit();
}
}
public void testEvictionOccurence() throws Exception
{
cache.put("/timeBased/test", "key", "value");
assertTrue(cache.exists("/timeBased/test"));
// wait for it to be evicted.
TestingUtil.sleepThread(3000);
assertTrue(!cache.exists("/timeBased/test"));
}
public void testInterceptorChain() throws Exception
{
List interceptors = cache.getInterceptorChain();
System.out.println(interceptors);
Iterator i = interceptors.iterator();
boolean found = false;
while (i.hasNext())
{
Object o = i.next();
if (o instanceof EvictionInterceptor)
{
found = true;
}
}
assertTrue("Eviction interceptor should be in interceptor chain.", found);
}
public void testCompleteRemoval() throws Exception
{
String rootStr = "/timeBased/";
// Add a parent, then a child. LRU will evict the parent,
// then the child, leaving behind an empty parent
Fqn<String> parent = Fqn.fromString(rootStr + "parent");
cache.put(parent, "key", "value");
cache.put(new Fqn<String>(parent, "child"), "key", "value");
// Give eviction time to run a few times, then confirm parent
// is completely gone
TestingUtil.sleepThread(5500);
assertFalse("Parent completely removed", cache.getRoot().hasChild(parent));
}
}