/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.cache.interceptors;
import org.jboss.cache.CacheSPI;
import org.jboss.cache.DefaultCacheFactory;
import org.jboss.cache.Fqn;
import org.jboss.cache.InvocationContext;
import org.jboss.cache.Node;
import org.jboss.cache.NodeSPI;
import org.jboss.cache.Region;
import org.jboss.cache.RegionManager;
import org.jboss.cache.config.EvictionConfig;
import org.jboss.cache.config.EvictionRegionConfig;
import org.jboss.cache.eviction.DummyEvictionConfiguration;
import org.jboss.cache.eviction.EvictedEventNode;
import org.jboss.cache.eviction.NodeEventType;
import org.jboss.cache.lock.IsolationLevel;
import org.jboss.cache.marshall.MethodCall;
import org.jboss.cache.marshall.MethodCallFactory;
import org.jboss.cache.marshall.MethodDeclarations;
import org.jboss.cache.misc.TestingUtil;
import static org.testng.AssertJUnit.*;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author Daniel Huang (dhuang@jboss.org)
* @version $Revision: $
*/
@Test(groups = "functional")
public class EvictionInterceptorTest
{
private static final String fqn1 = "/a/b/c";
private static final String fqn2 = "/a/b";
private static final String fqn3 = "/a/b/d";
private static final String fqn4 = "/d/e/f";
private CacheSPI<Object, Object> cache;
private Interceptor interceptor;
private RegionManager regionManager;
@BeforeMethod(alwaysRun = true)
public void setUp() throws Exception
{
cache = (CacheSPI<Object, Object>) new DefaultCacheFactory().createCache(false);
cache.getConfiguration().setTransactionManagerLookupClass("org.jboss.cache.transaction.DummyTransactionManagerLookup");
cache.getConfiguration().setIsolationLevel(IsolationLevel.SERIALIZABLE);
cache.getConfiguration().setCacheMode("LOCAL");
EvictionConfig ec = new EvictionConfig();
List<EvictionRegionConfig> ercs = new LinkedList<EvictionRegionConfig>();
ercs.add(new EvictionRegionConfig(Fqn.ROOT, new DummyEvictionConfiguration()));
ercs.add(new EvictionRegionConfig(Fqn.fromString("/a/b/c"), new DummyEvictionConfiguration()));
ercs.add(new EvictionRegionConfig(Fqn.fromString("/a/b/c/d"), new DummyEvictionConfiguration()));
ercs.add(new EvictionRegionConfig(Fqn.fromString("/a/b"), new DummyEvictionConfiguration()));
ercs.add(new EvictionRegionConfig(Fqn.fromString("/d/e/f"), new DummyEvictionConfiguration()));
ercs.add(new EvictionRegionConfig(Fqn.fromString("/d/e/g"), new DummyEvictionConfiguration()));
ercs.add(new EvictionRegionConfig(Fqn.fromString("/d/e"), new DummyEvictionConfiguration()));
ec.setEvictionRegionConfigs(ercs);
cache.getConfiguration().setEvictionConfig(ec);
cache.start();
interceptor = TestingUtil.extractComponentRegistry(cache).getComponent(Interceptor.class);
regionManager = cache.getRegionManager();
}
@AfterMethod(alwaysRun = true)
public void tearDown() throws Exception
{
TestingUtil.killCaches(cache);
}
@SuppressWarnings("unchecked")
private NodeSPI<Object, Object> cast(Node node)
{
return (NodeSPI<Object, Object>) node;
}
public void testVisitNode() throws Throwable
{
// make sure node that doesn't exist does not result in a node visit event.
MethodCall mc = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal_id,
Fqn.fromString(fqn1));
interceptor.invoke(InvocationContext.fromMethodCall(mc));
Region regionABC = regionManager.getRegion(fqn1, false);
assertNull(regionABC.takeLastEventNode());
putQuietly(fqn1, "key", "value");
NodeSPI<Object, Object> node = cast(cache.peek(Fqn.fromString(fqn1), false, false));
assertNotNull(node);
assertEquals("value", node.getDirect("key"));
putQuietly(fqn3, "key", "value");
node = cast(cache.peek(Fqn.fromString(fqn3), false, false));
assertNotNull(node);
assertEquals("value", node.getDirect("key"));
mc = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal_id,
Fqn.fromString(fqn1));
interceptor.invoke(InvocationContext.fromMethodCall(mc));
regionABC = regionManager.getRegion(fqn1, false);
EvictedEventNode event = regionABC.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn1, event.getFqn().toString());
assertNull(regionABC.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal_id,
Fqn.fromString(fqn2));
interceptor.invoke(InvocationContext.fromMethodCall(mc));
Region regionAB = regionManager.getRegion(fqn2, false);
event = regionAB.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn2, event.getFqn().toString());
assertNull(regionAB.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.getDataMapMethodLocal_id, Fqn.fromString(fqn3));
interceptor.invoke(InvocationContext.fromMethodCall(mc));
Region regionABD = regionManager.getRegion(fqn3, false);
event = regionABD.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn3, event.getFqn().toString());
assertNull(regionABD.takeLastEventNode());
for (int i = 0; i < 10; i++)
{
Fqn fqn = Fqn.fromString(fqn3);
mc = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal_id, fqn);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
}
for (int i = 0; i < 10; i++)
{
Region region = regionManager.getRegion(fqn3, false);
event = region.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn3, event.getFqn().toString());
}
assertNull(regionManager.getRegion(fqn3, false).takeLastEventNode());
// check null handling.
mc = MethodCallFactory.create(MethodDeclarations.getDataMapMethodLocal_id, new Object[]{null});
interceptor.invoke(InvocationContext.fromMethodCall(mc));
}
/**
* Helper to quietly add something into the cache without generating eviction events
*
* @param fqn fqn to add
* @param key key
* @param value value
*/
private void putQuietly(String fqn, Object key, Object value)
{
putQuietly(Fqn.fromString(fqn), key, value);
}
/**
* Helper to quietly add something into the cache without generating eviction events
*
* @param fqn fqn to add
* @param key key
* @param value value
*/
private void putQuietly(Fqn fqn, Object key, Object value)
{
NodeSPI root = cache.getRoot();
NodeSPI child = root;
for (int i = 0; i < fqn.size(); i++)
{
child = child.addChildDirect(new Fqn(fqn.get(i)));
}
assert child.getFqn().equals(fqn);
child.putDirect(key, value);
}
public void testVisitElement() throws Throwable
{
// make sure a get/visit on an empty node and empty element results in no cache events being added to event queue
// aka MarshRegion.
Fqn fqn = Fqn.fromString(fqn4);
Object key = "key";
MethodCall mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
Region region = regionManager.getRegion(fqn.toString(), false);
assertNull(region.takeLastEventNode());
// add the node but try to get on a null element should result in no cache events being added to Region.
putQuietly(fqn, "wrongkey", "");
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertNull(region.takeLastEventNode());
// now make sure if we try to get on the node/key we just created in cache, that this DOES add a EvictedEventNode to
// the MarshRegion.
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, "wrongkey", false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
EvictedEventNode event = region.takeLastEventNode();
assertEquals(fqn, event.getFqn());
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertNull(region.takeLastEventNode());
putQuietly(fqn4, key, "value");
// test on element granularity configured node.
fqn = Fqn.fromString(fqn4);
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
region = regionManager.getRegion(fqn.toString(), false);
event = region.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertNull(region.takeLastEventNode());
fqn = Fqn.fromString("/d/e/g");
for (int i = 0; i < 100; i++)
{
key = i;
putQuietly("/d/e/g", key, "");
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, true);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
}
region = regionManager.getRegion(fqn.toString(), false);
for (int i = 0; i < 100; i++)
{
event = region.takeLastEventNode();
assertEquals(fqn, event.getFqn());
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
}
putQuietly("/a/b/c", key, "");
fqn = Fqn.fromString("/a/b/c");
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
region = regionManager.getRegion(fqn.toString(), false);
event = region.takeLastEventNode();
assertNull(region.takeLastEventNode());
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
for (int i = 0; i < 100; i++)
{
key = i;
putQuietly(fqn, key, "");
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, true);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
}
for (int i = 0; i < 100; i++)
{
event = region.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
}
assertNull(region.takeLastEventNode());
}
public void testCreateNode() throws Throwable
{
Map<Object, Object> data = new HashMap<Object, Object>();
for (int i = 0; i < 100; i++)
{
data.put(i, i);
}
// this region is node granularity
Fqn fqn = Fqn.fromString("/a/b/c");
MethodCall mc = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal_id, null, fqn, data, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
Region region = regionManager.getRegion(fqn.toString(), false);
EvictedEventNode event = region.takeLastEventNode();
assertEquals(NodeEventType.ADD_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(100, event.getElementDifference());
NodeSPI<Object, Object> node = cast(cache.peek(fqn, false, false));
assertNotNull(node);
for (int i = 0; i < 100; i++)
{
assertTrue(node.getDataDirect().containsKey(i));
assertEquals(i, node.getDirect(i));
}
for (int i = 0; i < 100; i++)
{
mc = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal_id, null, fqn, i,
"value", false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertEquals("value", cache.peek(fqn, false, false).getDirect(i));
}
for (int i = 0; i < 100; i++)
{
event = region.takeLastEventNode();
assertNotNull(event);
assertEquals(fqn, event.getFqn());
assertEquals(NodeEventType.ADD_ELEMENT_EVENT, event.getEventType());
}
assertNull(region.takeLastEventNode());
fqn = Fqn.fromString("/a/b");
mc = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal_id, null, fqn, data, false, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
event = regionManager.getRegion(fqn.toString(), false).takeLastEventNode();
assertFalse(event.isResetElementCount());
assertEquals(NodeEventType.ADD_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(100, event.getElementDifference());
assertNull(regionManager.getRegion(fqn.toString(), false).takeLastEventNode());
node = cast(cache.peek(fqn, false, false));
assertEquals(100, node.getDataDirect().size());
assertNotNull(node);
for (int i = 0; i < 100; i++)
{
assertTrue(node.getDataDirect().containsKey(i));
assertEquals(i, node.getDirect(i));
}
mc = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal_id, null, fqn, data, false, true);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
event = regionManager.getRegion(fqn.toString(), false).takeLastEventNode();
assertEquals(NodeEventType.ADD_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(100, event.getElementDifference());
assertTrue(event.isResetElementCount());
assertNull(regionManager.getRegion(fqn.toString(), false).takeLastEventNode());
node = cast(cache.getNode(fqn));
assertEquals(100, node.getData().size());
assertNotNull(node);
for (int i = 0; i < 100; i++)
{
assertTrue(node.getDataDirect().containsKey(i));
assertEquals(i, node.getDirect(i));
}
}
public void testCreateElement() throws Throwable
{
Fqn fqn = Fqn.fromString("/d/e/f");
Region region = regionManager.getRegion(fqn.toString(), false);
Object key = "key";
Object value = "value";
MethodCall mc = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal_id,
null, fqn, key, value, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertEquals("value", cache.peek(fqn, false, false).getDirect(key));
EvictedEventNode event = region.takeLastEventNode();
assertEquals(NodeEventType.ADD_ELEMENT_EVENT, event.getEventType());
assertEquals(1, event.getElementDifference());
assertEquals(fqn, event.getFqn());
assertEquals("value", cache.peek(fqn, false, false).getDirect(key));
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal_id,
null, fqn, key, value, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertEquals("value", cache.peek(fqn, false, false).getDirect(key));
event = region.takeLastEventNode();
assertEquals(NodeEventType.ADD_ELEMENT_EVENT, event.getEventType());
assertEquals(1, event.getElementDifference());
assertEquals(fqn, event.getFqn());
assertEquals("value", cache.peek(fqn, false, false).getDirect(key));
assertNull(region.takeLastEventNode());
}
public void testRemoveNode() throws Throwable
{
Fqn fqn = Fqn.fromString("/a/b/c");
putQuietly(fqn, "a", "b");
putQuietly(fqn, "b", "c");
MethodCall mc = MethodCallFactory.create(MethodDeclarations.removeDataMethodLocal_id, null, fqn, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertEquals(0, cache.peek(fqn, false, false).getDataDirect().size());
Region region = regionManager.getRegion(fqn.toString(), false);
EvictedEventNode event = region.takeLastEventNode();
assertEquals(NodeEventType.REMOVE_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal_id, null, fqn, false, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertNull(cache.peek(fqn, false, false));
event = region.takeLastEventNode();
assertEquals(NodeEventType.REMOVE_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertNull(region.takeLastEventNode());
}
public void testRemoveElement() throws Throwable
{
Fqn fqn = Fqn.fromString("/a/b/c");
putQuietly(fqn, "a", "b");
putQuietly(fqn, "b", "c");
MethodCall mc = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal_id,
null, fqn, "a", false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertNull(cache.get(fqn, "a"));
Region region = regionManager.getRegion(fqn.toString(), false);
EvictedEventNode event = region.takeLastEventNode();
assertEquals(NodeEventType.REMOVE_ELEMENT_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(1, event.getElementDifference());
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal_id,
null, fqn, "b", false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertNull(cache.get(fqn, "b"));
event = region.takeLastEventNode();
assertEquals(NodeEventType.REMOVE_ELEMENT_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(1, event.getElementDifference());
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal_id,
null, fqn, "b", false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
event = region.takeLastEventNode();
assertNull(event);
}
public void testMixedEvent() throws Throwable
{
Map<Object, Object> data = new HashMap<Object, Object>();
for (int i = 0; i < 100; i++)
{
data.put(i, i);
}
// this region is node granularity
Fqn fqn = Fqn.fromString("/a/b/c");
MethodCall mc = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal_id, null, fqn, data, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
Region region = regionManager.getRegion(fqn.toString(), false);
EvictedEventNode event = region.takeLastEventNode();
assertEquals(NodeEventType.ADD_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(100, event.getElementDifference());
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal_id,
fqn);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
event = region.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal_id, null, fqn, false, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertNull(cache.getNode(fqn));
event = region.takeLastEventNode();
assertEquals(NodeEventType.REMOVE_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertNull(region.takeLastEventNode());
Object key = "key";
Object value = "value";
mc = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal_id,
null, fqn, key, value, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertEquals("value", cache.peek(fqn, false, false).getDirect(key));
event = region.takeLastEventNode();
assertEquals(NodeEventType.ADD_ELEMENT_EVENT, event.getEventType());
assertEquals(1, event.getElementDifference());
assertEquals(fqn, event.getFqn());
assertEquals("value", cache.peek(fqn, false, false).getDirect(key));
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal_id, fqn, key, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
region = regionManager.getRegion(fqn.toString(), false);
event = region.takeLastEventNode();
assertEquals(NodeEventType.VISIT_NODE_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertNull(region.takeLastEventNode());
mc = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal_id,
null, fqn, key, false);
interceptor.invoke(InvocationContext.fromMethodCall(mc));
assertNull(cache.get(fqn, key));
event = region.takeLastEventNode();
assertEquals(NodeEventType.REMOVE_ELEMENT_EVENT, event.getEventType());
assertEquals(fqn, event.getFqn());
assertEquals(1, event.getElementDifference());
assertNull(region.takeLastEventNode());
}
}