Set up both TTL and TTI in Ehcache 3 XML configuration

2,414 views
Skip to first unread message

Sergey Chupov

unread,
Apr 14, 2017, 9:15:08 AM4/14/17
to ehcache-users
  1. What version of Ehcache you are currently using;
  2. Paste the configuration for the Cache/CacheManager you have an issue with;
  3. Add any name and version of other library or framework you use Ehcache with (e.g. Hibernate);
  4. Providing JDK and OS versions maybe useful as well.

What I am trying to accomplish is to set up both TTL (time to live) and TTI (time to idle) for a cache, so that the key either expires after TTL time or it can be expired earlier in case in hasn't been accessed for TTI period.

In Ehcache 2 it was possible with the following configuration:

<cache name="my.custom.Cache"
       timeToIdleSeconds="10"
       timeToLiveSeconds="120">
</cache>

In Ehcache 3 the analogous configuration block looks like the following:

<cache alias="my.custom.Cache">
    <expiry>
        <tti unit="seconds">10</tti>
        <ttl unit="minutes">2</ttl>
    </expiry>
</cache>

The problem is that such configuration is considered invalid since ehcache.xsd states that there should only be one option under expiry tag (either tti or ttl, but not both).

Louis Jacomet

unread,
Apr 14, 2017, 9:35:09 AM4/14/17
to ehcache-users
Hi Sergey,

In order to achieve what you want, you need to create a custom Expiry, which you can do with the Expirations.builder() that was introduced in 3.3.1, or with a custom implementation of the Expiry interface.

Note however that your explanation of what the expiration did in Ehcache 2 is slightly incorrect. When you combine TTL and TTI, the element remains valid for the whole TTL whether it is accessed or not. However, if it is accessed close to the end of the TTL period, the last access time + TTI can make it stay for longer in the cache. And if it is access again during that period, the last access time is updated again thus extending the life of the mapping.

The way Expiry works in Ehcache 3 is slightly different, as effectively we compute an expiration time each time the mapping is created, accessed or updated. This is done to reduce overhead in stored mappings.

So if you configure your Expiry with getExpiryForCreation returning 120 seconds but getExpiryForAccess returning 10 seconds, a created but never access element will be considered expired after 120 seconds. While a created but accessed element will be considered expired 10 seconds after the last access, even if that time is still within the 120 seconds.
TTI is really a weird concept when you think about it, that we kept for JCache compatibiliy, but which is effectively closer to eviction than expiration. Because what does it mean for the freshness of a value that it is being read? While it indeed means this is a useful value in the cache that should not be evicted.

Regards,
Louis

--
You received this message because you are subscribed to the Google Groups "ehcache-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ehcache-user...@googlegroups.com.
To post to this group, send email to ehcach...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ehcache-users/4bdb5ba7-6ef2-48e8-b674-db2d02ade262%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sergey Chupov

unread,
Apr 14, 2017, 10:02:35 AM4/14/17
to ehcache-users
Hi Louis,

Thanks a lot for explaining the cooperation of TTI and TTL! If I understood you correctly, the way it works is different in Ehcache 2 and Ehcache 3, and only the latter one works as I described? I mean fundamentally the difference is that in v2 it was impossible that the key expires before TTL, but in v3 it's possible in some cases if the key has been accessed at least once and TTI < TTL.

Also, I see that there's no way to configure both values from XML, only the code configuration makes it possible, right?

Louis Jacomet

unread,
Apr 14, 2017, 10:08:06 AM4/14/17
to ehcache-users
You are correct for the explanation.

And in XML, you cannot use the tti and ttl shortcut in combination. But you can configure an expiry by fully qualified class name. We should consider extending the XML system so that you can do some equivalent of the added builder in code.

Louis

Sergey Chupov

unread,
Apr 14, 2017, 10:19:26 AM4/14/17
to ehcache-users
Yes, that's exactly what I've done.

Here is my config part:
<cache alias="my.custom.Cache">
    <expiry>
        <class>my.custom.CacheExpiry</class>
    </expiry>
</cache>

And an interface implementation:
package my.custom;

import javax.cache.expiry.Duration;
import javax.cache.expiry.ExpiryPolicy;
import java.util.concurrent.TimeUnit;

public class CacheExpiry implements ExpiryPolicy
{
private static final Duration TWO_MINUTES = new Duration( TimeUnit.MINUTES, 2 );

@Override
public Duration getExpiryForCreation()
{
return Duration.ONE_MINUTE;
}

@Override
public Duration getExpiryForAccess()
{
return TWO_MINUTES;
}

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

It's just that I'm trying to stick with JSR 107 API, so using interface from javax.cache. 

Sergey Chupov

unread,
Apr 18, 2017, 10:18:43 AM4/18/17
to ehcache-users
There is a problem with this appoach - when using javax.cache.expiry.ExpiryPolicy interface and specifying it in ehcache.xml, I'm receiving the following error:
Caused by: java.lang.ClassCastException: class com.backendless.cache.BillingUsageExpiry
        at java.lang.Class.asSubclass(Class.java:3404)
        at org.ehcache.xml.XmlConfiguration.getInstanceOfName(XmlConfiguration.java:352)
        at org.ehcache.xml.XmlConfiguration.getExpiry(XmlConfiguration.java:336)
        at org.ehcache.xml.XmlConfiguration.parseConfiguration(XmlConfiguration.java:292)
        at org.ehcache.xml.XmlConfiguration.<init>(XmlConfiguration.java:163)
        ... 146 more

Should this be considered as a bug? Unfortunately, I cannot configure this in the code currently, so xml configuration is the only option.

Louis Jacomet

unread,
Apr 18, 2017, 11:19:42 AM4/18/17
to ehcache-users
Hi Sergey,

You cannot use a JCache type there, you have to use the Ehcache one.
Why do you want the JCache type?

Regards,
Louis

Henri Tremblay

unread,
Apr 18, 2017, 11:27:35 AM4/18/17
to ehcach...@googlegroups.com
Is BillingUsageExpiry implementing org.ehcache.expiry.Expiry?

To unsubscribe from this group and stop receiving emails from it, send an email to ehcache-users+unsubscribe@googlegroups.com.

To post to this group, send email to ehcach...@googlegroups.com.

Sergey Chupov

unread,
Apr 18, 2017, 1:04:27 PM4/18/17
to ehcache-users
I thought it should be a part of JSR 107 compliance. I want to use it to abstract away from a concrete cache implementation.

Sergey Chupov

unread,
Apr 18, 2017, 1:05:33 PM4/18/17
to ehcache-users
No, it's implementing javax.cache.expiry.ExpiryPolicy, defined in JSR 107. It works fine when using org.ehcache.expiry.Expiry, but that's not quite what I would like to accomplish.
Is BillingUsageExpiry implementing org.ehcache.expiry.Expiry?

Louis Jacomet

unread,
Apr 18, 2017, 2:50:40 PM4/18/17
to ehcache-users
Sergey,

The moment you use XML, you are outside of the scope of JSR-107.
If you want to stick to pure JCache, you have to use programmatic configuration.

Regards,
Louis

Henri Tremblay

unread,
Apr 18, 2017, 3:21:16 PM4/18/17
to ehcach...@googlegroups.com
And you will quickly notice that it is impossible to stick with JSR-107 to get the full power of the underlying framework. Not only for EHCache, for any framework.

Specifications like JCache are always the lowest denominator. You will have the same problem with JPA and Hibernate for instance.

So don't worry about using implementation specific items. Everybody does.

Cheers,
Henri

To unsubscribe from this group and stop receiving emails from it, send an email to ehcache-users+unsubscribe@googlegroups.com.

To post to this group, send email to ehcach...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/ehcache-users/69f8dd11-a390-4c06-b233-32577a3cd830%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "ehcache-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ehcache-users+unsubscribe@googlegroups.com.

To post to this group, send email to ehcach...@googlegroups.com.

Sergey Chupov

unread,
Apr 18, 2017, 3:24:00 PM4/18/17
to ehcache-users
Well, I would, but I do have some problems with the Ehcache 3 implementation. For example, in the topic above i was trying to implement a kind of replication for removal operation, but was stuck when found no way to retrieve a cache event's cache name - while it is present in JCache reference. So in this way an implementation is not extending the specification, but limiting it

--
You received this message because you are subscribed to the Google Groups "ehcache-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ehcache-user...@googlegroups.com.
To post to this group, send email to ehcach...@googlegroups.com.

Alex Snaps

unread,
Apr 18, 2017, 3:58:21 PM4/18/17
to ehcache-users
You could just inject whatever it is you need at wiring time, couldn't you? 
Just have the instance of the listener being registered with the cache take the name of the cache... Or inject the CacheManager instance this (kinda singleton) listener is using and look things up from there. I mean building a "reverse lookup table" would be pretty straight forward... 


For more options, visit https://groups.google.com/d/optout.
--
Alex Snaps
Twitter: @alexsnaps
Reply all
Reply to author
Forward
0 new messages