-
1. Re: How to exclude some objects from eviction ?
galder.zamarreno Mar 23, 2012 7:29 AM (in response to dudalov)It's easy, you can set default eviction/expiration settings in the config, and for the keep-forever objects, call put passing the right parameters for expiration (a negative value) via: http://goo.gl/Y8Ogc
-
2. Re: How to exclude some objects from eviction ?
dudalov Mar 23, 2012 2:42 PM (in response to galder.zamarreno)Sigh. No luck. Here’s what I tried in a unit test, but it didn’t work as expected. First I added two "immortal" Objects using
Cache<K,V>.put(id, object)
Then I added "mortal" objects to exceed cache size
long MORTAL_LIFESPAN = 10 * 365L;
TimeUnit MORTAL_UNIT = TimeUnit.DAYS;
Cache<K,V>.put(id, object, MORTAL_LIFESPAN, MORTAL_UNIT, MORTAL_LIFESPAN, MORTAL_UNIT)
I also added a listeneter to see when "immortal" objects are evicted. They were removed as soon as cache reached the configured capacity. It doesn't look like these objects were treated differently.
It was tested with the settings from the "replication" example with only one cache node. Specifically,
_manager = new DefaultCacheManager(
GlobalConfigurationBuilder.defaultClusteredBuilder()
.transport().addProperty("configurationFile", "jgroups.xml").build(),
new ConfigurationBuilder()
.clustering().cacheMode(CacheMode.REPL_SYNC).build()
);
Configuration config = new ConfigurationBuilder().eviction()
.maxEntries(cacheSize).strategy(evictionStrategy)
.expiration().wakeUpInterval(5000L).maxIdle(120000L)
.clustering().cacheMode(CacheMode.REPL_SYNC)
.build();
_manager.defineConfiguration(cacheName, config);
Cache<String, String> _infinispanCache = _manager.getCache(cacheName);
I also ran this test with explicit -1 for lifespan and idleTime, but the result was the same. Do I need to specify any other settings for cache or manager to make it work? Did I miss any?
Thanks
-
3. Re: How to exclude some objects from eviction ?
galder.zamarreno Mar 26, 2012 12:16 PM (in response to dudalov)I think you're confusing the concepts of eviction of expiration here.
Expiration is about deleting stuff forever (maxIdle and lifespan params). This can certainly be overriden.
Eviction is another thing, is about maintaining the cache under certain size. This cannot be overriden. Even if data must live forever, if the capacity is exceeded, data will be deleted according to the algorithm chosen, LRU/LIRS. This is irrespective of the lifespan of the data... see https://docs.jboss.org/author/x/MwY5 for more info
-
4. Re: How to exclude some objects from eviction ?
dudalov Apr 10, 2012 5:52 PM (in response to galder.zamarreno)I understand that these settings are different and that they are used for different purposes, but it’s what was suggested in the response #1 and what according to the documentation was a solution prior 4.2 release. I tried the suggested way but it didn’t work. Did I misread the directions? Is it supported configuration? Again, here’s what I’m looking for:
a1, a2, …. aN a limited set of keep-forever objects (e.g. often used system entries)
b1, b2, ………… bM less important Objects of the same type
I want to keep both As and Bs in the same cache, but evict only Bs when the cache is full.
I can tell A from B when I add them to the cache, so I can call “put” with different parameters if needed. Is it achievable? If “yes” then “how”?
Thank you
-
5. Re: How to exclude some objects from eviction ?
galder.zamarreno Apr 11, 2012 12:03 PM (in response to dudalov)Hmmm, I don't see what's wrong here exactly. What about you provide a unit test with the code that you had and the assertions that you expect?
-
6. Re: How to exclude some objects from eviction ?
dudalov Apr 11, 2012 5:12 PM (in response to galder.zamarreno)Sorry, I don't see any "attach" option, so dumping the whole test here:
package dev.cache.infinispan;
import java.util.Date;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import org.infinispan.Cache;
import org.infinispan.eviction.EvictionStrategy;
import org.infinispan.manager.DefaultCacheManager;
import org.infinispan.notifications.Listener;
import org.infinispan.notifications.cachelistener.annotation.CacheEntriesEvicted;
import org.infinispan.notifications.cachelistener.event.CacheEntriesEvictedEvent;
import org.infinispan.configuration.cache.Configuration;
import org.infinispan.configuration.cache.ConfigurationBuilder;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import junit.textui.TestRunner;
public class KeepForeverTest extends TestCase {
private static String CLASSNAME = KeepForeverTest.class.getCanonicalName();
private DefaultCacheManager _manager;
private static final long FOREVER_LIFESPAN = -1; //
private static final TimeUnit FOREVER_UNIT = TimeUnit.DAYS;
private static final long MORTAL_LIFESPAN = 10 * 365L; //
private static final TimeUnit MORTAL_UNIT = TimeUnit.DAYS;
private static void debug(String method, String msg) {
System.out.format("[%s] %s : %s : %s\n", CLASSNAME, new Date(), method, msg);
}
public KeepForeverTest() {
}
protected void setUp() throws Exception {
super.setUp();
_manager = new DefaultCacheManager();
/*
GlobalConfigurationBuilder.defaultClusteredBuilder()
.transport().addProperty("configurationFile", "jgroups.xml").build(),
new ConfigurationBuilder()
.clustering().cacheMode(CacheMode.REPL_SYNC).build()
);
*/
}
protected void tearDown() throws Exception {
_manager.stop();
super.tearDown();
}
private Cache<String, String> getCache(String cacheName, int capacity) {
EvictionStrategy evictionStrategy = EvictionStrategy.LRU;
Configuration config = new ConfigurationBuilder().eviction()
.maxEntries(capacity).strategy(evictionStrategy)
.expiration().wakeUpInterval(5000L).maxIdle(120000L)
//.clustering().cacheMode(CacheMode.REPL_SYNC)
.build();
_manager.defineConfiguration(cacheName, config);
Cache<String, String> infinispanCache = _manager.getCache(cacheName);
return infinispanCache;
}
@org.junit.Test
public void testKeepForever() throws Exception {
String cacheName = "foo";
int capacity = 5;
Cache<String, String> cache = getCache(cacheName, capacity);
cache.addListener(new EntryChangeListener()); // to see when the resources are evicted
// 1. add two keep-forever objects
Resource rs1 = new Resource("immortal_1", "immortal_value1");
Resource rs2 = new Resource("immortal_2", "immortal_value2");
cache.put(rs1.getID(), rs1.getValue(), FOREVER_LIFESPAN, FOREVER_UNIT, FOREVER_LIFESPAN, FOREVER_UNIT);
cache.put(rs2.getID(), rs2.getValue(), FOREVER_LIFESPAN, FOREVER_UNIT, FOREVER_LIFESPAN, FOREVER_UNIT);
// 2. verify that resources were added to the cache
String expected_rs1 = cache.get(rs1.getID());
String expected_rs2 = cache.get(rs2.getID());
assertNotNull("Resource 1 should be presented in the cache", expected_rs1);
assertNotNull("Resource 2 should be presented in the cache", expected_rs2);
// 3. add more resources to make sure that the number exceeds the capacity
int numEntries = 10 * capacity; // 10 times more than cache capacity
for (int i=0; i<=numEntries; i++ ) {
Resource rs = new Resource("mortal_" + i, "value_" + i);
cache.put(rs.getID(), rs.getValue(), MORTAL_LIFESPAN, MORTAL_UNIT, MORTAL_LIFESPAN, MORTAL_UNIT);
}
// 4. Verify that immortal resources are in the cache
expected_rs1 = cache.get(rs1.getID());
expected_rs2 = cache.get(rs2.getID());
assertNotNull("Resource 1 should be preserved", expected_rs1);
assertNotNull("Resource 2 should be preserved", expected_rs2);
}
/**
*
* Inner classes
*
*/
private static class Resource {
private final String id;
private final String value;
public Resource(String id, String value) {
this.id = id;
this.value = value;
}
public String getID() {
return id;
}
public String getValue() {
return value;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Resource other = (Resource) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
@Listener
public static class EntryChangeListener {
@CacheEntriesEvicted
public void observeEvicted(CacheEntriesEvictedEvent<String, String> event) {
final String methodName = "observeEvicted";
if (!event.isPre()) {
Map<String, String> entries = event.getEntries();
Cache<String, String> cache = event.getCache();
for (Entry<String, String> entry : entries.entrySet()) {
debug(methodName, String.format(" next entry: key=%s value=%s", entry.getKey(), entry.getValue()));
}
}
}
}
public static void main(String[] args) {
(new TestRunner()).doRun(new TestSuite(KeepForeverTest.class));
}
}
-
7. Re: How to exclude some objects from eviction ?
galder.zamarreno Apr 18, 2012 4:58 AM (in response to dudalov)Thanks for attaching the test. Just to verify, do you see a failure saying: 'java.lang.AssertionError: Resource 1 should be preserved" ? That's after "// 4. Verify that immortal resources are in the cache"
-
8. Re: How to exclude some objects from eviction ?
galder.zamarreno Apr 18, 2012 3:21 PM (in response to galder.zamarreno)The reason the test fails is due to what I said before:
Galder Zamarreño wrote:
Eviction is another thing, is about maintaining the cache under certain size. This cannot be overriden. Even if data must live forever, if the capacity is exceeded, data will be deleted according to the algorithm chosen, LRU/LIRS. This is irrespective of the lifespan of the data... see https://docs.jboss.org/author/x/MwY5 for more info
Even if the data is immortal in theory, if the max capacitiy is exceeded, it might go according to the eviction policy. If you really want an immortal cache, you'll need to disable eviction.
-
9. Re: How to exclude some objects from eviction ?
dudalov Apr 18, 2012 4:18 PM (in response to galder.zamarreno)Thanks for the confirmation that what I was looking is not a supported option. I was confused by your first response "It's easy, you can set default eviction/expiration settings in the config ....".
Please let me know if you remember another way to achieve the same result (comment #4 above) within a single cache. Otherwise I'll use two different caches for immortal and mortal objects of the same type. That would double objects retrieval, since I would need to check both caches, but probably it could be optimized somehow. Thanks again.
Dmitry