How does timed cache expiry work?

时间秒杀一切 提交于 2019-12-12 03:45:21

问题


I know that Guava Cache allows individual caches to be configured with an expiry time. Does Guava do this using a timer that wakes up after a configured number of seconds to invalidate the cache?

I have a transaction that is long-running. Whatever is in the cache at the start of the transaction, I would like it to continue till the end of the transaction. So even if the number of seconds of validity of a cache gets expired during the transaction, the values accessed from the cache should remain intact till we reach the end of transaction. Is this possible in Guava?

Thanks,
Yash


回答1:


From When Does Cleanup Happen? · CachesExplained · google/guava Wiki:

Caches built with CacheBuilder do not perform cleanup and evict values "automatically," or instantly after a value expires, or anything of the sort. Instead, it performs small amounts of maintenance during write operations, or during occasional read operations if writes are rare.

The reason for this is as follows: if we wanted to perform Cache maintenance continuously, we would need to create a thread, and its operations would be competing with user operations for shared locks. Additionally, some environments restrict the creation of threads, which would make CacheBuilder unusable in that environment.

Instead, we put the choice in your hands. If your cache is high-throughput, then you don't have to worry about performing cache maintenance to clean up expired entries and the like. If your cache does writes only rarely and you don't want cleanup to block cache reads, you may wish to create your own maintenance thread that calls Cache.cleanUp() at regular intervals.

If you want to schedule regular cache maintenance for a cache which only rarely has writes, just schedule the maintenance using ScheduledExecutorService.

As such, if you are only doing reads you "might" be good if you do a Cache.cleanUp() just before and after your transaction but there is still no guarantee.

However, instead of trying to force items to stay in the cache you might instead simply evict items to another cache/map using a removalListener and then when you read you will first need to check the cache and then, if it wasn't there, check the items evicted during the long-running transaction.

The following is an oversimplified example:

Map<Integer, String> evicted = new ConcurrentHashMap<>();
Cache<Integer, String> cache = CacheBuilder.newBuilder()
        .expireAfterAccess(2, SECONDS)
        .removalListener((RemovalListener<Integer, String>) notification -> 
                evicted.put(notification.getKey(), notification.getValue()))
        .build();
assert evicted.size() == 0 && cache.size() == 0;
cache.put(0, "a");
cache.put(1, "b");
cache.put(2, "c");
assert evicted.size() == 0 && cache.size() == 3;
sleepUninterruptibly(1, SECONDS);
assert evicted.size() == 0 && cache.size() == 3;
cache.put(3, "d");
assert evicted.size() == 0 && cache.size() == 4;
sleepUninterruptibly(1, SECONDS);
cache.cleanUp();
assert evicted.size() == 3 && cache.size() == 1;
Integer key = 2;
String value;
{
    value = cache.getIfPresent(key);
    if (value == null) value = evicted.get(key);
}
assert Objects.equals(value, "c");

Your actual code would need to conditionally put into evicted, clean-up evicted, manage multiple evicted objects if your running long-running transactions concurrently or use a common cache between the threads with a different eviction strategy, etc. but hopefully this demonstrates the idea sufficiently to get you started.



来源:https://stackoverflow.com/questions/39250083/how-does-timed-cache-expiry-work

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!