Hi Anton,
I have tried to create some expiry polices for different entries, and during
the testing, I found that I may have to hack some of the kernel codes of Ignite.
Am I right? Here is my hacking and test case. Any suggestions are welcome.
My wrapper implementation,
public class KeyValueExpiryPolicyWrapper implements ExpiryPolicy, Serializable {
// store the default policy
private ExpiryPolicy defaultPolicy;
// the policy for specified entries keys
private Map<Object, ExpiryPolicy> expiryPolicyMap;
public KeyValueExpiryPolicyWrapper(){
defaultPolicy = null;
expiryPolicyMap = new HashMap<>();
}
public void addExpiryPolicy(Object key, ExpiryPolicy policy) {
if (null != key)
expiryPolicyMap.put(key, policy);
}
public void delExpiryPolicy(Object key) {
if (null != key)
expiryPolicyMap.remove(key);
}
@Override
public Duration getExpiryForCreation() {
return null == defaultPolicy ? null :
defaultPolicy.getExpiryForCreation();
}
@Override
public Duration getExpiryForAccess() {
return null == defaultPolicy ? null :
defaultPolicy.getExpiryForAccess();
}
@Override
public Duration getExpiryForUpdate() {
return null == defaultPolicy ? null :
defaultPolicy.getExpiryForUpdate();
}
public Duration forAccess(Object key) {
A.notNull(key, "key is undefined.");
ExpiryPolicy policy = expiryPolicyMap.get(key);
System.out.println("KeyValueExpiryPolicyWrapper.forAccess, map = " +
expiryPolicyMap);
System.out.println("KeyValueExpiryPolicyWrapper.forAccess with key=" +
key + "" +
", policy = " + policy);
if (null == policy) {
policy = defaultPolicy;
}
return null == policy ? null : policy.getExpiryForAccess();
}
public Duration forCreation(Object key) {
A.notNull(key, "key is undefined.");
ExpiryPolicy policy = expiryPolicyMap.get(key);
System.out.println("KeyValueExpiryPolicyWrapper.forCreation, map = " +
expiryPolicyMap);
System.out.println("KeyValueExpiryPolicyWrapper.forCreation with key="
+ key + "" +
", policy = " + policy);
if (null == policy) {
policy = defaultPolicy;
}
return null == policy ? null : policy.getExpiryForCreation();
}
public Duration forUpdate(Object key) {
A.notNull(key, "key is undefined.");
ExpiryPolicy policy = expiryPolicyMap.get(key);
System.out.println("KeyValueExpiryPolicyWrapper.forUpdate, map = " +
expiryPolicyMap);
System.out.println("KeyValueExpiryPolicyWrapper.forUpdate with key=" +
key + "" +
", policy = " + policy);
if (null == policy) {
policy = defaultPolicy;
}
return null == policy ? null : policy.getExpiryForUpdate();
}
}
My hacking on GridCacheAdapter.java
1. hacking on
org.apache.ignite.internal.processors.cache.GridCacheAdapter#expiryPolicy
one parameter on entry's key is added.
/**
* Get the expiry policy for given key. If key is null, return the default
policy.
* @param plc Explicitly specified expiry policy for cache operation.
* @param key the key of the entry
* @return Expiry policy wrapper.
*/
@Nullable public IgniteCacheExpiryPolicy expiryPolicy(@Nullable ExpiryPolicy
plc, @Nullable Object key) {
if (plc == null)
plc = ctx.expiry();
return CacheExpiryPolicy.forPolicy(plc, key);
}
2. hacking on
org.apache.ignite.internal.processors.cache.GridCacheAdapter.CacheExpiryPolicy
*. one function `getRealkey` is added
*. modify the implementations of forPolicy
// get the entry's key
private static Object getRealKey(@Nullable final Object key){
Object key0 = key;
if (null != key) {
if (key instanceof KeyCacheObjectImpl){
// TODO(jackeylv) currently, we can only solve the type of
KeyCacheObjectImpl
key0 = ((KeyCacheObjectImpl) key).val;
}
}
return key0;
}/**
* @param expiryPlc Expiry policy.
* @param key
* @return Access expire policy.
*/
@Nullable private static CacheExpiryPolicy forPolicy(@Nullable final
ExpiryPolicy expiryPlc,
@Nullable final Object
key) {
if (expiryPlc == null)
return null;
return new CacheExpiryPolicy() {
@Override public long forAccess() {
if (null == key)
return CU.toTtl(expiryPlc.getExpiryForAccess()); //
added operation for polices wrapper.
if (expiryPlc instanceof KeyValueExpiryPolicyWrapper){
return CU.toTtl(((KeyValueExpiryPolicyWrapper)
expiryPlc).forAccess(getRealKey(key)));
}
System.err.println("forAccess,Key " + key + " given, by type error
on expiryPlc " + expiryPlc);
return CU.toTtl(expiryPlc.getExpiryForAccess());
}
@Override public long forCreate() {
if (null == key)
return CU.toTtl(expiryPlc.getExpiryForCreation());
if (expiryPlc instanceof KeyValueExpiryPolicyWrapper){
return CU.toTtl(((KeyValueExpiryPolicyWrapper)
expiryPlc).forCreation(getRealKey(key)));
}
System.err.println("forCreate, Key " + key + " given, by type error
on expiryPlc " + expiryPlc);
return CU.toTtl(expiryPlc.getExpiryForCreation());
}
@Override public long forUpdate() {
if (null == key)
return CU.toTtl(expiryPlc.getExpiryForUpdate());
if (expiryPlc instanceof KeyValueExpiryPolicyWrapper){
return CU.toTtl(((KeyValueExpiryPolicyWrapper)
expiryPlc).forUpdate(getRealKey(key)));
}
System.err.println("forUpdate, Key " + key + " given, by type error
on expiryPlc " + expiryPlc);
return CU.toTtl(expiryPlc.getExpiryForUpdate());
}
};
}
The test case,
public class ExpiryExample {
public static void test(Ignite ignite) {
IgniteCache cache = ignite.getOrCreateCache("ExpiryExample");
String k1 = "k1"; // k1 with given expiry policy
String k2 = "k2"; // k2 with default expiry policy
String v1 = "v1";
String v2 = "v2"; // A policies wrapper
KeyValueExpiryPolicyWrapper plc = new KeyValueExpiryPolicyWrapper();
plc.addExpiryPolicy(k1, new CreatedExpiryPolicy(new
Duration(TimeUnit.SECONDS,3)));
cache = cache.withExpiryPolicy(plc);
cache.put(k1, v1);
cache.put(k2, v2);
String result = (String) cache.get(k1);
System.out.println("ExpiryExample.main with k1 value = [" + result +
"]");
A.ensure(v1.equals(result), "get failed with "+result);
result = (String) cache.get(k2);
System.out.println("ExpiryExample.main with k2 value = [" + result +
"]");
A.ensure(v2.equals(result), "get failed with "+result); // sleep
for a while to make sure the k1-v1 entry expired.
try {
TimeUnit.SECONDS.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
// test the expired results.
result = (String)cache.get(k1);
System.out.println("ExpiryExample.main with k1 value = [" + result +
"]");
A.ensure(null == result, "cache entry not expired with "+result);
result = (String)cache.get(k2);
System.out.println("ExpiryExample.main with k2 value = [" + result +
"]");
A.ensure(v2.equals(result), "cache entry not right with "+result);
}
}
Currently, the simple test case is passed, but I am still worry about the
hacking, because there are still some questions need to be answered.
1. any better solutions then this one?
2. this solution changed the
org.apache.ignite.internal.processors.cache.GridCacheAdapter#expiryPolicy, and
some situation like getAll or other batching operations,
there are more than one keys in a request, and the expiry polices may be
different for different keys. How to solve it?
3. is there any pitfall in this solution?
Regards,
Lin.
------------------ Original ------------------
From: "Anton Vinogradov";<[email protected]>;
Date: Tue, Dec 1, 2015 10:01 PM
To: "user"<[email protected]>;
Subject: Re: Can I set an expiry policy for some specify entry?
Lin,
As you can see at example you can use cache.withExpiryPolicy() to gain cache
wrapper with specific ExpiryPolicy.
This policy will be used during operations on this cache wrapper, only.
You can create as much wrappers as you need and put/get/etc entries using them.
I recomend you to use CreatedExpiryPolicy to set ExpiryPolicy at entry
creation.
Comparision of ExpiryPolicies can be found here
https://apacheignite.readme.io/v1.4/docs/expiry-policies
Please have a look to other ExpiryPolicies, possible they will be more suitable
to your solution.
For example TouchedExpiryPolicy will renew timeout at each operation on entry.
On Tue, Dec 1, 2015 at 3:33 PM, Vladimir Ershov <[email protected]> wrote:
Hi Lin,
An expiry policy is working for all values, which were added through
cacheWithExpiryPolicy according to the next example:
IgniteCache<Object, Object> cacheWithExpiryPolicy = cache.withExpiryPolicy(
new CreatedExpiryPolicy(new Duration(TimeUnit.SECONDS, 5)));
You are welcome to find an explaining example in the end of this message.
It is also possible, that actually you are looking for something like eviction
policy. Please take a look here then:
https://apacheignite.readme.io/v1.5/docs/evictions
Please, provide the feedback, if this answer was useful, or not.
Thanks!
public void test() throws Exception {
Ignite ignite = startGrid(0); // some starting util method
CacheConfiguration<Integer, Integer> cfg = new CacheConfiguration<>();
cfg.setName(CACHE);
cfg.setCacheMode(CacheMode.PARTITIONED);
cfg.setRebalanceMode(CacheRebalanceMode.SYNC);
cfg.setBackups(1);
ignite.getOrCreateCache(cfg);
IgniteCache<Object, Object> cache1 = ignite.cache(null);
IgniteCache<Object, Object> cache2 = cache1.withExpiryPolicy(
new CreatedExpiryPolicy(new Duration(TimeUnit.SECONDS, 1)));
cache1.put(1, 1);
cache1.put(2, 2);
cache2.put(3, 3);
cache2.get(1); // Does not affect ExpiryPolicy.
U.sleep(2000);
assert cache1.get(1) == 1;
assert cache2.get(1) == 1; // not Expired
assert cache1.get(2) == 2;
assert cache1.get(3) == null; // Expired.
}
On Tue, Dec 1, 2015 at 10:47 AM, Lin <[email protected]> wrote:
Hi,
I have read the docs on jcache expiry policies, the policy will be used for
each operation invoked on the returned cache instance.
IgniteCache<Object, Object> cache = cache.withExpiryPolicy( new
CreatedExpiryPolicy(new Duration(TimeUnit.SECONDS, 5)));
and searched the nabble faq and found
http://apache-ignite-users.70518.x6.nabble.com/Does-IgniteCache-withExpiryPolicy-affect-existing-cache-entries-td1870.html
As I know, the expiry policy is worked for all the entries in the cache. I
would like to specify different expiry policies for some different entries,
How can I do?
Thanks for you help.
Regards,
Lin