I'm transitioning from Ehcache2.X to Ehcache3.3.1 and I can't find a way to get the time-to-live configuration for a cache at run-time. Previously I used:
cache.getCacheConfiguration().getTimeToLiveSeconds()
Now, it looks like I need to do something akin to:
cache.getRuntimeConfiguration().getExpiry().getExpiryForCreation().getLength()
but, getExpiryForCreation() requires a key, value pair for a specific element and appears to return the duration for that element.
Am I missing something in the API or docs?
I will post here the same answer as on the ehcache mailing list.
An Expiry implementation can be very dynamic and select the expiry time using a given cached key and value.
If you know that you did something like
Expirations.timeToLiveExpiration(Duration.of(20, TimeUnit.SECONDS))
to create it, then, it won't be dynamic. So you can do
cache.getRuntimeConfiguration().getExpiry().getExpiryForCreation(null, null)
to get the duration of a cache entry after creation.
If you then want to dynamically change the TTL, it is possible but you will need to provided your own Expiry implementation (not really hard to do). With a setter for the TTL.
However, the new value will only apply to new added entries. Existing entries won't see their TTLs changed. This is because we calculate the expiration timestamp when the entry is added. Instead of reapplying the duration all the time. For performance reasons.
Related
We are trying to have custom expiry for each record in our map.
Each object has the field 'long expireDate' which is time in millis when we want the object to be removed.
Are we able too implement some policy to remove records based on the value of this field for each entry?
Looked into this question but this is per entry via a put.
Setting TTL/Record Expiry in hazelcast
IMap::put(Key, Value, TTL, TimeUnit)
The issue with this is 95% of our entries are placed there using a putAll and hence it cant be provided this way.
The IMap.setTTL() method, available in IMDG 3.11 and later, allows you to set individual TTL values on entries within the Map. I think the solution here would be to write a small procedure that reads the entry's expireDate value, calculates an offset from current system time, and sets the TTL for the map entry to that offset.
This procedure could then be executed as either an EntryProcessor (perhaps immediately following a putAll operation, using the same set of keys), or as a MapListener that would be triggered whenever an entry was added (or updated, if updates sometimes alter the expireData value).
I have the following use case where I need an entry to be evicted from an IMap, no matter how many times it is Updated. My key is a String and my value is a Java Object.
If for example, an entry is added on 12th May, it needs to be evicted after 14 days, i.e. 26th May, no matter how many times it is updated.
Hazelcast has a tag in its configuration called time-to-live-seconds, where you can configure how much time an entry can stay in a map.
So from Hazelcast Documentation,
"Maximum time in seconds for each entry to stay on the map. If it is not 0, entries that are older than this time and not updated for this time are evicted automatically. Valid values are integers between 0 and Integer.MAX VALUE. Its default value is 0, which means infinite. If it is not 0, entries are evicted regardless of the set eviction-policy."
So, with the above, if you consider the above example, an entry added originally on 12th May and then updated on 24th May will be removed 14 days after the 24th of May, not on 26th May.
Hence, to solve the above problem, I am using the following approach. When I have to update an entry, I am first getting the EntryView from the Map and then using that obtaining the Expiration Time. Then getting the current time and taking the difference of expiration time with the current time and then updating the value, with time-to-live as the difference of expiration time and the current time.
Employee employee= IMap.get("A12");
employee.setDescr("loasfdeff");
EntryView<String,Employee> entryView=iMap.getEntryView("A12");
Long expirationTime=entryView.getExpirationTime();
Long currentTime=System.currentTimeMillis();
Long difference=expirationTime-currentTime;
iMap.set("A12",employee, difference, TimeUnit.MILLISECONDS);
I have tested the above approach, and it works. Although, I would like to explore other alternatives to see if there is anything hazelcast provides out of the box, to help me solve my use-case.
Any help is much appreciated!
EDIT-
GITHUB ISSUE- https://github.com/hazelcast/hazelcast/issues/13012
You are correct in how the TTL operates. A simple update of an entry is essentially the same as putting a new entry, so the system can’t interpret the intention. However, this would be a nice enhancement: adding a switch to preserve the expiration datetime.
I have a couple of alternative approaches:
1) Consider adding a timestamp field to the value object and setting this to the current time on the original object put. Once that’s present you could write an executor service to run at intervals and invalidate the objects based on the overall TTL you want. You can index this field as well to make it more performant.
2) You can write a custom eviction policy by extending the MapCustomEvictionPolicy class and applying that to your map. You would most likely still need to add a timestamp in the value (or key if you wanted to make that a custom object). You would then have a blank slate for how you want this to work.
I’ll create a product enhancement request for this in the meantime. Could probably get it in the next release as it doesn’t seem too hard of an add.
Is there a way to update an item in couchbase without altering its expiration time? I am using Java SDK and Couchbase 3
No, this is not possible right now. The simple reason is that the underlying protocol does not allow for it - everytime the document is modified its expiration time is reset.
The only reasonable workaround I can think of right now can be used when your expiration times are long and a small change won't matter: when you create a view you can grab the TTL as part of the meta information. So you load the current TTL and write the new document with this TTL (maybe then even substracting the time your business processing took). This would approximate it (and it can also work with N1QL).
Sorry for the poor title but I didn't know how else to phrase my use case.
I'm trying to use a Guava cache to load user profile objects keyed by their IDs. The catch is that the profiles may change over time, so I need to key the request by the date as well. Further, I'd only like to cache a single profile for a single user (instead of 7 different profiles for every day of the week for a single user).
Is there any way to replace existing cache entries with newly loaded ones only if the date changes, instead of adding a new cache entry for the new unique key?
For clarity:
A sample key would look like <user id, date>
If I have a cached entry that is keyed by <123, "2013-02-13">, and a request comes in for <123, "2013-02-14">, there should only be one entry in the cache for user 123 after loading the new profile.
Thanks!
It sounds like what you should be doing is to have a Cache<UserId, DateAndProfile>, and then to check yourself if the DateAndProfile needs to be overwritten. The Guava caching API isn't going to let you treat different keys as "sort of the same" in any fancy way.
My Java web application (tomcat) gets all of its data from an SQL database. However, large parts of this database are only updated once a day via a batchjob. Since queries on these tables tend do be rather slow, I want to cache the results.
Before rolling my own solution, I wanted to check out existing cache solutions for java. Obviously, I searched stackoverflow and found references and recommendations for ehcache.
But looking through the documentation it seems it only allows for setting the lifetime of cached objects as a duration (e.g. expire 1 hour after added), while I want an expiry based on a fixed time (e.g. expire at 0h30 am).
Does anyone know a cache library that allows such expiry behaviour? Or how to do this with ehcache if that's possible?
EhCache allows you programmatically set the expiry duration on an individual cache element when you create it. The values configured in ehcache.xml are just defaults.
If you know the specific absolute time that the element should expire, then you can calculate the difference in seconds between then and "now" (i.e. the time you add to the cache), and set that as the time-to-live duration, using Element.setTimeToLive()
Do you need a full blown cache solution? You use standard Maps and then have a job scheduled to clear them at the required time.