Cache evicts entries before the expireAfterWrite time

1,220 views
Skip to first unread message

luis...@gmail.com

unread,
Oct 30, 2013, 1:45:18 PM10/30/13
to guava-...@googlegroups.com
Hi,

we have the following LoadingCache build with a expireAfterWrite configuracion with 3600 seconds.
We are expecting to see the values at least for 1 hour but what is currently happening (in production environments) is that the cache is getting
the entries evicted before that time in seconds.
After an entry is evicted we remove the value from another map created.
Just wondering if anyone has expirenced the same issue.

LoadingCache<String, HotelViewDto> cache = CacheBuilder.newBuilder()
                    .expireAfterWrite(3600, TimeUnit.SECONDS)
                    .removalListener(new RemovalListener<String, HotelViewDto>() {
                        @Override
                        public void onRemoval(RemovalNotification<String, HotelViewDto> notification) {
                            if (notification.getCause() == RemovalCause.EXPIRED) {
                                map.get(notification.getValue().getAccomCode()).remove(notification.getValue());
                            }
                        }
                    })
                    .build(new CacheLoader<String, HotelViewDto>() {
                        public HotelViewDto load(String sessionId) {
                            //no loading indeed
                            return null;
                        }
                    });
        }


Thanks!

Louis Wasserman

unread,
Oct 30, 2013, 1:49:15 PM10/30/13
to luis...@gmail.com, guava-discuss
Questions:

1) Can you provide a reproducible test case?
2) Why are you passing a dummy CacheLoader instead of using the no-argument build() method to return a Cache (not a LoadingCache) ?
--
--
guava-...@googlegroups.com
Project site: http://guava-libraries.googlecode.com
This group: http://groups.google.com/group/guava-discuss
 
This list is for general discussion.
To report an issue: http://code.google.com/p/guava-libraries/issues/entry
To get help: http://stackoverflow.com/questions/ask (use the tag "guava")
---
You received this message because you are subscribed to the Google Groups "guava-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to guava-discus...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/guava-discuss/bc611532-b554-44b3-8645-2be9064b36be%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

luis...@gmail.com

unread,
Oct 30, 2013, 1:59:38 PM10/30/13
to guava-...@googlegroups.com, luis...@gmail.com
Hi Louis,

thanks for the quick reply. Answering:

1)-. Right now we can't reproduce the issue with a test case. We are trying but with no luck. It only happens in our production environment. 
2)-. You are right, we missed the Cache. We'll change the constructor to build a Cache instead of a LoadingCache.

Adding more info, we build the cache in a spring bean bean in the @PostConstruct life cycle.
We add values to cache and to anocher map (which will have the real count of elements)
Before getting the count of elements in that map, we invoke the cache.cleanUp() method to force a cleanup, and trigger the possible onRemoval() in case there are object to evict.

Thanks!

Tim Peierls

unread,
Oct 30, 2013, 2:03:56 PM10/30/13
to Louis Wasserman, luis...@gmail.com, guava-discuss
On Wed, Oct 30, 2013 at 1:49 PM, Louis Wasserman <wasserm...@gmail.com> wrote:
Why are you passing a dummy CacheLoader instead of using the no-argument build() method to return a Cache (not a LoadingCache) ?

broken dummy CacheLoader, to boot: The value returned from load(K) must not be null (according to the docs, including the emphasis).

--tim

luis...@gmail.com

unread,
Oct 30, 2013, 2:08:44 PM10/30/13
to guava-...@googlegroups.com, Louis Wasserman, luis...@gmail.com, t...@peierls.net
Can this be the issue why entries are getting expired before the expireAfterWrite time? We are changing to a Cache as pointed out by Louis since we don't really pre load anything.

Louis Wasserman

unread,
Oct 30, 2013, 2:09:20 PM10/30/13
to luis...@gmail.com, guava-...@googlegroups.com, Louis Wasserman, t...@peierls.net
It's not likely to be the actual issue; it just seemed worth mentioning.


--
--
guava-...@googlegroups.com
Project site: http://guava-libraries.googlecode.com
This group: http://groups.google.com/group/guava-discuss
 
This list is for general discussion.
To report an issue: http://code.google.com/p/guava-libraries/issues/entry
To get help: http://stackoverflow.com/questions/ask (use the tag "guava")
---
You received this message because you are subscribed to the Google Groups "guava-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to guava-discus...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.



--
Louis Wasserman

rle...@eyeviewdigital.com

unread,
Jul 26, 2018, 4:46:55 PM7/26/18
to guava-discuss
I'm having the same issue but using a no-argument build() like follows:

CacheBuilder.newBuilder().maximumSize(10).expireAfterWrite(12, TimeUnit.MINUTES).build()

Do you remember what was causing this issue?

In my case maximumSize should not have an effect since I'm using the same single key each time.

Thanks.

Benjamin Manes

unread,
Jul 26, 2018, 8:24:13 PM7/26/18
to rle...@eyeviewdigital.com, guava-discuss
Can you please write a unit test to reproduce the problem? You can use CacheBuilder#ticker to configure the time source, and manipulate it accordingly. See FakeTicker in guava-testlib if helpful. 

Things to note:
 - Expiration is on-demand rather than a background thread, so cleanUp() might be required to force notifications
 - maximumSize is an upper bound, but eviction may occur prematurely. The CacheBuilder#concurrencyLevel determines the number of segments which evict independently, with 4 segments by default. 
 - If you are using a single-key cache, you might find Suppliers#memoizeWithExpiration to be a better fit.



This group: http://groups.google.com/group/guava-discuss
 
This list is for general discussion.

---
You received this message because you are subscribed to the Google Groups "guava-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to guava-discuss+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/guava-discuss/d44f80a4-452e-4e16-91c1-aa254e2a4c70%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

rle...@eyeviewdigital.com

unread,
Jul 27, 2018, 2:20:01 PM7/27/18
to guava-discuss
Hi Ben,

I cannot reproduce the issue with a reduced unit test, and I cannot reproduce the same issue using the same code I have in production but running it in my development environment.
This only happens to me in the production environment/servers.

About the points you mentioned:
- My case happens when cache is being evicted before the cache time configured under expireAfterWrite
- OK this may be the cause but would be weird since right now I'm using just a single key in the cache, so there shouldn't be any need to do any cleanup or premature eviction
- This would work with a single key but I need this to support multiple (new keys coming in the future)

It is probably a silly issue but I can't figure what it is, I'll keep digging and notify here if I find anything.

Any other suggestions are welcomed.

Thanks.
To unsubscribe from this group and stop receiving emails from it, send an email to guava-discus...@googlegroups.com.

Benjamin Manes

unread,
Jul 27, 2018, 3:07:26 PM7/27/18
to rle...@eyeviewdigital.com, guava-discuss
Can you see if the issue is reproducable with Caffeine, the Java 8 rewrite? Currently my unit tests pass for both libraries.

I wonder whether you are running into some NTP-style synchronization issue, where the drift is causing odd behaviors. Usually the default Ticker's nanoTime() should not be effected by the that clock (unlike currentTimeMillis()), but production might be running on a hypervisor that allows it to be.

To unsubscribe from this group and stop receiving emails from it, send an email to guava-discuss+unsubscribe@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/guava-discuss/2e142546-d0a1-4e18-9a23-15ee977117b8%40googlegroups.com.

rle...@eyeviewdigital.com

unread,
Aug 2, 2018, 4:38:39 PM8/2/18
to guava-discuss
Hi Ben

I created a unit test (http://eyeview-tmp.s3.amazonaws.com/rleira/TestGuavaCacheEviction.java) which runs ok BOTH in the my local env and in the server! but the production code still fails ('getIfPresent' returns always a null element).
My production code is not much different from the reduced test case, so I guess the difference here (the timer) must be what is failing.
I also tested removing the 'maximumSize' from in the cache instantiation in the production code and it also didn't work.

I'll try to test it with caffeine but currently I'm looking for different options to implement what I need without adding a new dependency.

I'll update this post if I have any news.

Thanks

rle...@eyeviewdigital.com

unread,
Aug 6, 2018, 12:13:21 PM8/6/18
to guava-discuss
After more debugging we found out that the issue was - as everything was pointing, NOT related to guava's cache code.
The bug was in the existing custom code and not in the code that was using the guava cache. More specifically in the injection of the class in the scheduled job (was not a signleton instance and therefore was being recreated on every call).

Thanks for the help Ben, and sorry for the noise.
Reply all
Reply to author
Forward
0 new messages