package org.jboss.cache.eviction;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.jboss.cache.Fqn;
import org.jboss.cache.PropertyConfigurator;
import org.jboss.cache.TreeCache;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.misc.TestingUtil;
/**
* Unit tests for LRU Policy.
*
* @author Ben Wang, Feb 11, 2004
* @author Daniel Huang - dhuang@jboss.org
* @version $Revision: 3477 $
*/
public class LRUPolicyTest extends TestCase
{
TreeCache cache_;
int wakeupIntervalMillis_ = 0;
final String ROOT_STR = "/test";
Throwable t1_ex, t2_ex;
final long DURATION = 10000;
boolean isTrue;
public LRUPolicyTest(String s)
{
super(s);
}
public void setUp() throws Exception
{
super.setUp();
initCaches();
wakeupIntervalMillis_ = cache_.getEvictionThreadWakeupIntervalSeconds() * 1000;
log("wakeupInterval is " + wakeupIntervalMillis_);
if (wakeupIntervalMillis_ < 0)
fail("testEviction(): eviction thread wake up interval is illegal " + wakeupIntervalMillis_);
t1_ex = t2_ex = null;
isTrue = true;
}
public void initCaches() throws Exception
{
cache_ = new TreeCache();
PropertyConfigurator config = new PropertyConfigurator();
config.configure(cache_, "META-INF/local-lru-eviction-service.xml"); // read in generic local xml
cache_.setTransactionManagerLookupClass("org.jboss.cache.DummyTransactionManagerLookup");
cache_.setIsolationLevel(IsolationLevel.SERIALIZABLE);
cache_.startService();
}
public void tearDown() throws Exception
{
super.tearDown();
cache_.stopService();
}
public void testInUseEviction() throws Exception
{
String rootStr = "/org/jboss/test/data/inuse/";
Fqn fqn;
// cache_.put("/", "a", "b");
// TestingUtil.sleepThread(wakeupIntervalMillis_ + 500);
for (int i = 0; i < 10; i++)
{
String str = rootStr + i;
fqn = Fqn.fromString(str);
cache_.put(fqn, str, str);
}
TestingUtil.sleepThread(wakeupIntervalMillis_ + 500);
cache_.getEvictionRegionManager().markNodeCurrentlyInUse(Fqn.fromString(rootStr + 5), 0);
for (int i = 10; i < 15; i++)
{
String str = rootStr + i;
fqn = Fqn.fromString(str);
cache_.put(fqn, str, str);
}
TestingUtil.sleepThread(wakeupIntervalMillis_ + 500);
for (int i = 0; i < 5; i++)
{
assertNull(cache_.get(Fqn.fromString(rootStr + i)));
}
assertNotNull(cache_.get(Fqn.fromString(rootStr + 5)));
for (int i = 6; i < 11; i++)
{
assertNull(cache_.get(Fqn.fromString(rootStr + i)));
}
for (int i = 11; i < 15; i++)
{
assertNotNull(cache_.get(Fqn.fromString(rootStr + i)));
}
TestingUtil.sleepThread(wakeupIntervalMillis_ *2 + 500);
assertNotNull(cache_.get(Fqn.fromString(rootStr + 5)));
cache_.getEvictionRegionManager().unmarkNodeCurrentlyInUse(Fqn.fromString(rootStr +5));
TestingUtil.sleepThread(wakeupIntervalMillis_ *2 + 500);
assertNull(cache_.get(Fqn.fromString(rootStr + 5)));
}
public void testEviction()
{
String rootStr = "/org/jboss/test/data/";
for (int i = 0; i < 10; i++)
{
String str = rootStr + i;
Fqn fqn = Fqn.fromString(str);
try
{
cache_.put(fqn, str, str);
}
catch (Exception e)
{
fail("Failed to insert data" + e);
e.printStackTrace();
}
}
System.out.println(cache_.toString());
TestingUtil.sleepThread(wakeupIntervalMillis_ + 500);
System.out.println(cache_.toString());
try
{
String val = (String) cache_.get(rootStr + "3", rootStr + "3");
assertNull("DataNode should be empty ", val);
}
catch (Exception e)
{
e.printStackTrace();
fail("Failed to get" + e);
}
}
public void testNodeVisited()
{
String rootStr = "/org/jboss/test/data/";
for (int i = 0; i < 10; i++)
{
String str = rootStr + i;
Fqn fqn = Fqn.fromString(str);
try
{
cache_.put(fqn, str, str);
}
catch (Exception e)
{
fail("Failed to insert data" + e);
e.printStackTrace();
}
}
System.out.println("cache is:\n" + cache_.toString(true));
int period = (wakeupIntervalMillis_ / 2 + 500);
log("sleeping for " + period + "ms");
TestingUtil.sleepThread(period); // it really depends the eviction thread time.
String str = rootStr + "7";
Fqn fqn = Fqn.fromString(str);
try
{
cache_.get(fqn, str); // just to keep it fresh
System.out.println("-- sleeping for " + period + "ms");
TestingUtil.sleepThread(period); // it really depends the eviction thread time.
cache_.get(fqn, str); // just to keep it fresh
System.out.println("-- sleeping for " + period + "ms");
TestingUtil.sleepThread(period); // it really depends the eviction thread time.
String val = (String) cache_.get(rootStr + "3", rootStr + "3");
System.out.println("-- val=" + val);
assertNull("DataNode should be empty ", val);
val = (String) cache_.get(rootStr + "7", rootStr + "7");
System.out.println("-- val=" + val);
assertNotNull("DataNode should not be empty ", val);
System.out.println("-- sleeping for " + (wakeupIntervalMillis_ + 1000) + "ms");
TestingUtil.sleepThread(wakeupIntervalMillis_ + 1000);
val = (String) cache_.get(rootStr + "7", rootStr + "7");
System.out.println("-- val=" + val);
assertNull("DataNode should be empty ", val);
}
catch (Exception e)
{
e.printStackTrace();
fail("Failed to evict" + e);
}
}
public void testNodeRemoved()
{
String rootStr = "/org/jboss/test/data/";
for (int i = 0; i < 10; i++)
{
String str = rootStr + i + "/" + i;
Fqn fqn = Fqn.fromString(str);
try
{
cache_.put(fqn, str, str);
}
catch (Exception e)
{
fail("Failed to insert data" + e);
e.printStackTrace();
}
}
int period = (wakeupIntervalMillis_ / 2 + 500);
log("period is " + period);
// TestingUtil.sleepThread(period); // it really depends the eviction thread time.
String str1 = rootStr + "7";
Fqn fqn1 = Fqn.fromString(str1);
String str2 = rootStr + "7/7";
Fqn fqn2 = Fqn.fromString(str2);
try
{
cache_.get(fqn1, str1); // just to keep it fresh
cache_.get(fqn2, str2); // just to keep it fresh
TestingUtil.sleepThread(period); // it really depends the eviction thread time.
cache_.get(fqn1, str1); // just to keep it fresh
cache_.get(fqn2, str2); // just to keep it fresh
TestingUtil.sleepThread(period); // it really depends the eviction thread time.
String val = (String) cache_.get(rootStr + "7/7", rootStr + "7/7");
assertNotNull("DataNode should not be empty ", val);
cache_.remove(fqn1);
TestingUtil.sleepThread(wakeupIntervalMillis_ + 500);
val = (String) cache_.get(rootStr + "7/7", rootStr + "7/7");
assertNull("DataNode should be empty ", val);
}
catch (Exception e)
{
e.printStackTrace();
fail("Failed to evict" + e);
}
}
public void testCompleteRemoval() throws Exception
{
String rootStr = "/test/";
// Add a parent, then a child. LRU will evict the parent,
// then the child, leaving behind an empty parent
Fqn parent = Fqn.fromString(rootStr + "parent");
cache_.put(parent, "key", "value");
cache_.put(new Fqn(parent, "child"), "key", "value");
// Give eviction time to run a few times, then confirm parent
// is completely gone
TestingUtil.sleepThread((wakeupIntervalMillis_ * 4) + 100);
assertFalse("Parent completely removed", cache_.exists(parent));
}
class MyPutter extends Thread
{
public MyPutter(String name)
{
super(name);
}
public void run()
{
int i = 0;
final String myName = ROOT_STR + "/test1/node" + getName();
while (isTrue)
{
try
{
cache_.put(myName + i++, "value", new Integer(i));
sleep(1);
}
catch (Throwable e)
{
e.printStackTrace();
if (t1_ex == null)
t1_ex = e;
}
}
}
}
public void testConcurrentPutAndEvict() throws Exception
{
cache_.setIsolationLevel(IsolationLevel.REPEATABLE_READ);
cache_.put(ROOT_STR + "/concurrentPutAndEvict", "value", new Integer(1));
for (int i = 0; i < 10; i++)
{
new MyPutter("Putter" + i).start();
}
int counter = 0;
while (true)
{
counter++;
if (t1_ex != null)
{
fail("Exception generated in put() " + t1_ex);
}
log("nodes/locks: " + cache_.getNumberOfNodes() + "/" + cache_.getNumberOfLocksHeld());
TestingUtil.sleepThread(1000);
if (counter > 10)
{ // run for 10 seconds
isTrue = false;
break;
}
}
}
public void testForEvictionInternalError()
{
try
{
// String rootStr = "org/jboss/test/data/";
String rootStr = "/test/testdata";
for (int i = 0; i < 10; i++)
{
String str = rootStr + i;
Fqn fqn = Fqn.fromString(str);
try
{
cache_.put(fqn, str, str);
}
catch (Exception e)
{
fail("Failed to insert data" + e);
e.printStackTrace();
}
}
// wait for an eviction
TestingUtil.sleepThread(2 * wakeupIntervalMillis_ + 2000);
String val = (String) cache_.get(rootStr + "3", rootStr + "3");
assertNull("DataNode should be empty ", val);
// reinsert the elements
for (int i = 0; i < 10; i++)
{
String str = rootStr + i;
Fqn fqn = Fqn.fromString(str);
try
{
cache_.put(fqn, str, str);
}
catch (Exception e)
{
fail("Failed to insert data" + e);
e.printStackTrace();
}
}
// clear the root
Fqn root = cache_.get("/").getFqn();
cache_.remove(root);
// wait for an eviction
TestingUtil.sleepThread(2 * wakeupIntervalMillis_ + 1000);
val = (String) cache_.get(rootStr + "3", rootStr + "3");
assertNull("DataNode should be empty ", val);
}
catch (Exception e)
{
e.printStackTrace();
fail("Failed to get" + e);
}
}
public void testLegacyAPI() throws Exception
{
RegionManager regionManager = cache_.getEvictionRegionManager();
Region region = regionManager.createRegion("/123", new LRUAlgorithm());
region.setTimeToLiveSeconds(5);
region.setMaxNodes(5000);
assertEquals(5000, ((LRUConfiguration) region.getEvictionConfiguration()).getMaxNodes());
assertEquals(5, ((LRUConfiguration) region.getEvictionConfiguration()).getTimeToLiveSeconds());
String rootStr = "/123/node";
for (int i = 0; i < 10; i++)
{
Fqn fqn = Fqn.fromString(rootStr + Integer.toString(i));
cache_.put(fqn, fqn.toString(), fqn.toString());
}
assertEquals(rootStr + "5", cache_.get(rootStr + "5", rootStr + "5"));
TestingUtil.sleepThread(2 * wakeupIntervalMillis_ + 2000);
assertNull("DataNode should be null", cache_.get(rootStr + "5"));
}
void log(String msg)
{
System.out.println("-- " + msg);
}
public static Test suite()
{
return new TestSuite(LRUPolicyTest.class);
}
public static void main(String[] args)
{
junit.textui.TestRunner.run(suite());
}
}