package org.jboss.cache.eviction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.RegionImpl;
import org.jboss.cache.RegionManager;
import org.jboss.cache.RegionManagerImpl;
import org.jboss.cache.util.TestingUtil;
import org.testng.annotations.AfterMethod;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertTrue;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Unit tests for LRUAlgorithm.
*
* @author Ben Wang, Feb 11, 2004
* @author Daniel Huang (dhuang@jboss.org)
*/
@Test(groups = "functional", testName = "eviction.LRUAlgorithmTest")
public class LRUAlgorithmTest extends EvictionTestsBase
{
RegionManager regionManager;
LRUAlgorithm algorithm;
LRUAlgorithmConfig config;
Log log = LogFactory.getLog(LRUAlgorithm.class);
@BeforeMethod(alwaysRun = true)
public void setUp() throws Exception
{
regionManager = new RegionManagerImpl();
config = new LRUAlgorithmConfig();
config.setTimeToLive(-1);
algorithm = (LRUAlgorithm) createAndAssignToRegion("/a/b", regionManager, config);
}
@AfterMethod(alwaysRun = true)
public void tearDown() throws Exception
{
regionManager = null;
config = null;
algorithm = null;
}
/**
* maxNodes = 1. Eception is evictFromCacheNode. Should be commented for now.
*/
public void testEvictException() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(1);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 1, algorithm.getEvictionQueue().getNumberOfNodes());
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 1, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* maxNodes = -1 case
*/
public void testMaxNode1() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(-1);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 2, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* maxNodes = 0 case
*/
public void testMaxNode2() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(0);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 0, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* maxNodes = 1
*/
public void testMaxNode3() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(1);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 1, algorithm.getEvictionQueue().getNumberOfNodes());
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 1, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* TimeToIdleSeconds = 0
*/
public void testIdleTimeSeconds1() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(-1);
config.setTimeToLive(-1);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size should be ", 2, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* TimeToIdleSeconds = 1
*/
public void testIdleTimeSeconds2() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(-1);
config.setTimeToLive(1000);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size #1: ", 3, algorithm.getEvictionQueue().getNumberOfNodes());
TestingUtil.sleepThread(1100);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size #2: ", 0, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* TimeToIdleSeconds = 1 with node visited in between.
*/
public void testIdleTimeSeconds3() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(-1);
config.setTimeToLive(1000);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size #1: ", 3, algorithm.getEvictionQueue().getNumberOfNodes());
TestingUtil.sleepThread(1100);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.VISIT_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size #2: ", 1, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* MaxAgeSeconds = 1 with 3 nodes.
*
* @throws Exception
*/
public void testMaxAgeSeconds1() throws Exception
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(-1);
config.setTimeToLive(-1);
config.setMaxAge(1000);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size #1: ", 3, algorithm.getEvictionQueue().getNumberOfNodes());
TestingUtil.sleepThread(1100);
algorithm.process(region.getEvictionEventQueue());
assertEquals("Queue size #2: ", 0, algorithm.getEvictionQueue().getNumberOfNodes());
}
/**
* Generic combo case.
*/
public void testCombo1() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
Fqn fqn4 = Fqn.fromString("/a/b/f");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
// Should have a maximum of 2 nodes.
config.setMaxNodes(2);
config.setTimeToLive(1000);
config.setMaxAge(3000);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn4, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
EvictionQueue eq = algorithm.getEvictionQueue();
int numNodesInQueue = eq.getNumberOfNodes();
assert 2 == numNodesInQueue : "Queue size #1: expected 2 but was " + numNodesInQueue;
// make sure all nodes now expire
TestingUtil.sleepThread(1100);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
numNodesInQueue = eq.getNumberOfNodes();
assert 1 == numNodesInQueue : "Queue size #2: expected 1 but was " + numNodesInQueue;
TestingUtil.sleepThread(3100);
// visit the node now to prevent the idle time from doing the pruning - node still gets pruned but by
// max age.
region.registerEvictionEvent(fqn3, EvictionEvent.Type.VISIT_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
numNodesInQueue = eq.getNumberOfNodes();
assert 0 == numNodesInQueue : "Queue size #3: expected 0 but was " + numNodesInQueue;
}
/**
* Generic combo case with newly added node should be around.
*/
public void testCombo2() throws EvictionException
{
Fqn fqn1 = Fqn.fromString("/a/b/c");
Fqn fqn2 = Fqn.fromString("/a/b/d");
Fqn fqn3 = Fqn.fromString("/a/b/e");
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxNodes(2);
config.setTimeToLive(1000);
config.setMaxAge(3000);
region.registerEvictionEvent(fqn1, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.ADD_NODE_EVENT);
region.registerEvictionEvent(fqn2, EvictionEvent.Type.REMOVE_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
EvictionQueue eq = algorithm.getEvictionQueue();
int numNodesInQueue = eq.getNumberOfNodes();
assert 1 == numNodesInQueue : "Queue size #1: expected 1 but was " + numNodesInQueue;
// make sure existing events all time out
TestingUtil.sleepThread(1100);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.ADD_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
numNodesInQueue = eq.getNumberOfNodes();
assert 1 == numNodesInQueue : "Queue size #2: expected 1 but was " + numNodesInQueue;
TestingUtil.sleepThread(3100);
region.registerEvictionEvent(fqn3, EvictionEvent.Type.VISIT_NODE_EVENT);
algorithm.process(region.getEvictionEventQueue());
numNodesInQueue = eq.getNumberOfNodes();
assert 0 == numNodesInQueue : "Queue size #3: expected 0 but was " + numNodesInQueue;
}
public void testEvictionSortOrder() throws EvictionException
{
RegionImpl region = (RegionImpl) regionManager.getRegion("/a/b", true);
config.setMaxAge(1000000);
config.setMaxNodes(0);
config.setTimeToLive(1000000);
for (int i = 0; i < 100; i++)
{
Fqn fqn = Fqn.fromString("/a/b/" + Integer.toString(i));
region.registerEvictionEvent(fqn, EvictionEvent.Type.ADD_NODE_EVENT);
}
algorithm.process(region.getEvictionEventQueue());
for (int i = 0; i < 100; i++)
{
Fqn fqn = Fqn.fromString("/a/b/" + Integer.toString(i));
if (i % 2 == 0)
{
region.registerEvictionEvent(fqn, EvictionEvent.Type.VISIT_NODE_EVENT);
}
}
algorithm.process(region.getEvictionEventQueue());
LRUQueue queue = (LRUQueue) algorithm.getEvictionQueue();
NodeEntry ne;
int count = 0;
while ((ne = queue.getFirstLRUNodeEntry()) != null)
{
if (count < 50)
{
assertEquals(1, ne.getNumberOfNodeVisits());
}
else
{
assertEquals(2, ne.getNumberOfNodeVisits());
}
queue.removeNodeEntry(ne);
count++;
}
for (int i = 0; i < 100; i++)
{
Fqn fqn = Fqn.fromString("/a/b/" + Integer.toString(i));
region.registerEvictionEvent(fqn, EvictionEvent.Type.ADD_NODE_EVENT);
}
algorithm.process(region.getEvictionEventQueue());
long lastCreateTimestamp = 0;
while ((ne = queue.getFirstMaxAgeNodeEntry()) != null)
{
assertTrue(ne.getCreationTimeStamp() >= lastCreateTimestamp);
lastCreateTimestamp = ne.getCreationTimeStamp();
queue.removeNodeEntry(ne);
}
}
}