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

Reply via email to