ehcache / ehcache-jcache

The Ehcache 2.x implementation of JSR107 (JCACHE)

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JCacheConfiguration ignores eternal flag if configured using ehcache.xml

tarioch opened this issue · comments

As far as I'm able to tell, if I configure the cache with an ehcache.xml and have set the cache to be eternal, this is getting ignored as the constructor of JCacheConfiguration always sets up an expiry policy.

Looks like this was introduced when fixing #26

@tarioch You configure the Cache in ehcache.xml, but still create a JCacheConfiguration for it? I must be confused, can you provide a small (even pseudo code, doesn't need to make javac happy) example of how to problem is experienced?

Sure

I have an ehcache.xml and then do

Caching.getCachingProvider().getCacheManager().getCache("foo");

to retrieve the cache.

This triggers JCacheManager.refreshAllCaches() which does

allCaches.put(s, new JCache(this, new JCacheConfiguration(cache.getCacheConfiguration()), cache));

which then ends up in the failing code block.

Oh ok... so the issue is what the JCacheConfiguration "pretends", but effectively the Cache does honor it, right? I misunderstood that. That being said it still needs fixing! I'll make sure that happens... Thanks!

The issue I noticed is that, JCache.getValue() starts triggering a remove as it is actually reading this generated JCache config.

@tarioch I'll try to put a test case together to reproduce this... I seem to see we'll expose the TTI & TTL values, but these may well be set in your config (along with the eternal flag), so that these get picked up, rather than them being 0?

Line 843-846 in net.sf.ehcache.config.CacheConfiguration (ehcache 2.8.3):

    public final void setEternal(boolean eternal) {
        checkDynamicChange();
        isEternalValueConflictingWithTTIOrTTL(eternal, getTimeToLiveSeconds(), getTimeToIdleSeconds());
        this.eternal = eternal;
        if (eternal) {
            setTimeToIdleSeconds(0);
            setTimeToLiveSeconds(0);
        }
    }

If eternal is true, set timeToIdleSeconds and timeToLiveSeconds to 0.

Line 93-108 in org.ehcache.jcache.JCacheConfiguration (ehcache-jcache 1.0.1):

                expiryPolicy = new ExpiryPolicy() {
                    @Override
                    public Duration getExpiryForCreation() {
                        return new Duration(TimeUnit.SECONDS, cacheConfiguration.getTimeToLiveSeconds());
                    }

                    @Override
                    public Duration getExpiryForAccess() {
                        return new Duration(TimeUnit.SECONDS, cacheConfiguration.getTimeToLiveSeconds());
                    }

                    @Override
                    public Duration getExpiryForUpdate() {
                        return getExpiryForCreation();
                    }
                };

If eternal is true, the value of exipryForCreation and expiryForAccess will be 0 seconds duration.

Line 138-141 in org.ehcache.jcache.JCache (ehcache-jcache 1.0.1):

    private Element getElement(final K key) {
        final Element element = ehcache.get(key);
        if (element == null)
            return null;
        final Duration expiryForUpdate = cfg.getExpiryPolicy().getExpiryForAccess();
        if(expiryForUpdate != null && expiryForUpdate.isZero()) {
            ehcache.removeElement(element);
        }
        return element;
    }

If the expireForAccess is zero, the cached element will be removed when call JCache#get(K key). So, if you configure eternal="true" in ehcache.xml, the cache will be expired immediately when you call get(K key).

Add these codes in org.ehcache.jcache.JCacheConfiguration may be fix it:

        if(cacheConfiguration.isEternal()){
            expiryPolicyFactory = EternalExpiryPolicy.factoryOf();
            expiryPolicy = expiryPolicyFactory.create();
        }else{
            expiryPolicyFactory = null;
            expiryPolicy = new ExpiryPolicy(){
                //...
            }
        }

Any reason this has not been fixed? The change is pretty simple, and presently its not possible to configure an eternal cache via ehcache.xml because of this. Unsure about the expiryPolicyFactory = null; in example above, but this seems to resolve the problem for me:

                if (cacheConfiguration.isEternal()) {
                    expiryPolicy = EternalExpiryPolicy.factoryOf().create();
                }
                else {
                    expiryPolicy = new ExpiryPolicy()
                    {
                        @Override
                        public Duration getExpiryForCreation() {
                            return new Duration(TimeUnit.SECONDS, cacheConfiguration.getTimeToLiveSeconds());
                        }

                        @Override
                        public Duration getExpiryForAccess() {
                            return new Duration(TimeUnit.SECONDS, cacheConfiguration.getTimeToLiveSeconds());
                        }

                        @Override
                        public Duration getExpiryForUpdate() {
                            return getExpiryForCreation();
                        }
                    };
                }
                expiryPolicyFactory = new FactoryBuilder.SingletonFactory<ExpiryPolicy>(expiryPolicy);

Sorry for noise above, sometimes github linking is a bit of PITA

Sorry, my bad. Remained assigned to me, but I was off on vacation. Back now though.
I'll get back to you. Did you sign the contributor agreement already?
See here: https://github.com/ehcache/ehcache3/wiki#contributor-agreement

Ah the project is alive.. yay. Will sent over signed legal mumbo jumbo shortly.

Cool! Thanks... Now, that being said, the project is slow moving though. I have to be honest with you: all our efforts are going into Ehcache3, this wrapper was a temporary solution for 2.x users. But all (including features that were only "proprietary" ones in the 2.x line, e.g. Offheap) go into the new dev line. Here: https://github.com/ehcache/ehcache3

@alexsnaps understood, and we'll consume ehcache3 once it stabilizes, but until then we are moving to use javax.cache api to allow us to switch the backend, so having the adapter for ehcache2 is helping us move forward while ehcache3 becomes more realistic for usage.