Can I set an expiry policy for some specify entry?

classic Classic list List threaded Threaded
7 messages Options
Jackey Jackey
Reply | Threaded
Open this post in threaded view
|

Can I set an expiry policy for some specify entry?

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 


VE VE
Reply | Threaded
Open this post in threaded view
|

Re: Can I set an expiry policy for some specify entry?

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 <[hidden email]> 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 

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 



Anton Vinogradov Anton Vinogradov
Reply | Threaded
Open this post in threaded view
|

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 <[hidden email]> 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 <[hidden email]> 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 

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 




Jackey Jackey
Reply | Threaded
Open this post in threaded view
|

Re: Can I set an expiry policy for some specify entry?

In reply to this post by VE
Hi Vladimir,

Thank you for your help. I have tested your test case, but it was not worked. It is failed as the got cache1 is null.
  Here is the output result and exception,

[09:23:09,404][INFO ][test-runner][GridDiscoveryManager] Topology snapshot [ver=1, servers=1, clients=0, CPUs=8, heap=3.5GB]
[09:23:09,432][INFO ][exchange-worker-#43%examples.EventsExamplesSelfTest0%][GridCacheProcessor] Started cache [name=DiffCache, mode=PARTITIONED]
[09:23:09,472][INFO ][exchange-worker-#43%examples.EventsExamplesSelfTest0%][GridDhtPreloader] <DiffCache> Starting rebalancing in SYNC mode: DiffCache
EventsExamplesSelfTest.testExpiry cache1 = null
[09:23:09,475][INFO ][main][root] >>> Stopping test: testExpiry in 1557 ms <<<
[09:23:09,476][INFO ][main][root] >>> Stopping grid [name=examples.EventsExamplesSelfTest0, id=003ae91f-041c-4cd0-a36f-2cad4e238000]
[09:23:09,474][ERROR][main][root] Test failed.
java.lang.NullPointerException
at org.apache.ignite.examples.EventsExamplesSelfTest.testExpiry(EventsExamplesSelfTest.java:61)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at junit.framework.TestCase.runTest(TestCase.java:176)
at org.apache.ignite.testframework.junits.GridAbstractTest.runTestInternal(GridAbstractTest.java:1665)
at org.apache.ignite.testframework.junits.GridAbstractTest.access$000(GridAbstractTest.java:111)
at org.apache.ignite.testframework.junits.GridAbstractTest$6.run(GridAbstractTest.java:1603)

Here is the testing case:

public class EventsExamplesSelfTest extends GridAbstractExamplesTest {
public void testExpiry() throws Exception {
Ignite ignite = startGrid(0);

CacheConfiguration<Integer, Integer> cfg = new CacheConfiguration<>();

cfg.setName("DiffCache");
cfg.setCacheMode(CacheMode.PARTITIONED);
cfg.setRebalanceMode(CacheRebalanceMode.SYNC);
cfg.setBackups(1);

ignite.getOrCreateCache(cfg);

IgniteCache<Object, Object> cache1 = ignite.cache(null);

System.out.println("EventsExamplesSelfTest.testExpiry cache1 = " + cache1);

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.
}
}

I have tried to do something like the expiry policies wrapper, and it is just a semi-finished, and I am not sure will it be worked for the all situations.

I would like to share my idea and codes in the next response, hope you and other guys to given any suggestions.

Thanks again.

Lin.

------------------ Original ------------------
From:  "Vladimir Ershov";<[hidden email]>;
Date:  Tue, Dec 1, 2015 08:33 PM
To:  "user"<[hidden email]>;
Subject:  Re: Can I set an expiry policy for some specify entry?

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 <[hidden email]> 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 

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 



Jackey Jackey
Reply | Threaded
Open this post in threaded view
|

Re: Can I set an expiry policy for some specify entry?

In reply to this post by Jackey
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";<[hidden email]>;
Date:  Tue, Dec 1, 2015 10:01 PM
To:  "user"<[hidden email]>;
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 <[hidden email]> 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 <[hidden email]> 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 

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 




Jackey Jackey
Reply | Threaded
Open this post in threaded view
|

Re: Can I set an expiry policy for some specify entry?

Another question is when and where should I call the wrapper.delExpiryPolicy. 
currently, I haven't found the right place.


------------------ Original ------------------
From:  "Lin";<[hidden email]>;
Date:  Wed, Dec 2, 2015 10:06 AM
To:  "user"<[hidden email]>;
Subject:  Re: Can I set an expiry policy for some specify entry?

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";<[hidden email]>;
Date:  Tue, Dec 1, 2015 10:01 PM
To:  "user"<[hidden email]>;
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 <[hidden email]> 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 <[hidden email]> 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

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




Jackey Jackey
Reply | Threaded
Open this post in threaded view
|

Re: Can I set an expiry policy for some specify entry?

Hi all,

We can easily set an expiry policy for any entry. Sorry to Anton  and Vladimir , you are right.

Talk is cheap, show you the code...

the test case
public static void testPut1() throws Exception {
getCache().put("key","val", TimeUnit.SECONDS.toMillis(1));
String val = (String)getCache().get("key");
A.notNullOrEmpty(val, "get failed with " + val);
A.ensure(val.equals("val"), "val failed with " + val);

TimeUnit.SECONDS.sleep(1);
A.ensure(null == getCache().get("key"), "key is not expired.");

// five seconds
getCache().put("key", "val", TimeUnit.SECONDS.toMillis(5));
A.ensure("val".equals(getCache().get("key")), "put failed");
getCache().remove("key"); // remove it immediately
A.ensure(null == getCache().get("key"), "key is not removed.");
}

the implementation of put with expired time,
public void put(Object key, Object value, long expireTime) {
ExpiryPolicy plc = new CreatedExpiryPolicy(new Duration(TimeUnit.MILLISECONDS,expireTime));
IgniteCache cache0 = cache.withExpiryPolicy(plc); // I have been made confused here, the previous implementation was cache = cache.withExpiryPolicy(plc);
cache0.getAndPut(key, value);
}
Thank you, Valdimir and Anton. Thanks everyone.

Regards,

Lin