I want to implement a cache using Guava's caching mechanism.
I have a DB query which returns a map, I want to cache the entire map but let it expire after a certain amount of time.
I realize Guava caches works as a per-item bases. We provide a key, the Cache will either returns the corresponding value from the cache or get it.
Is there a way to use Guava to get everything, cache it but timeout it after a certain time period of time and get everything again.
Many thanks
You can create an instance of Supplier<Map<K,V>> that fetches the entire map from the database, and then use Suppliers.memoizeWithExpiration to cache it.
Related:
Google Guava Supplier Example
http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Supplier.html
http://google.github.io/guava/releases/snapshot/api/docs/com/google/common/base/Suppliers.html
Related
I need to implement a LRU cache with a expiration time of 600s in Java. I searched and found the built-in LinkedHashMap class. It can remove the oldest elements when the size exceeds a limit, but it doesn't have a expiration time for elements.
What I can think of is to associate the timestamp when putting an element into the cache. When retrieving an element, check its timestamp; if the timestamp is older than 600s, then removes the element from the cache and returns 'not-found'.
Any better ideas? Any built-in solutions or best practice? I'd like to avoid reinventing the wheel.
How about just using Guava cache.
It supports all of these,
A builder of LoadingCache and Cache instances having any combination
of the following features:
automatic loading of entries into the cache
least-recently-used eviction when a maximum size is exceeded
time-based expiration of entries, measured since last access or last write
keys automatically wrapped in weak references
values automatically wrapped in weak or soft references
notification of evicted (or otherwise removed) entries
accumulation of cache access statistics
I suggest not implementing it by yourself, and look at already available implementations:
Guava Cache is a pretty descent option (it wa already recommended so I won't add a link here)
Caffeine A very nice cache implementation.
In case you want to know the difference between the two, read this thread in SO
I believe both will get you covered feature wise.
In addition if you're using frameworks like Spring it has in integration with them (later versions use caffeine, older are stick to guava):
Spring Cache
I am using Guava LoadingCache to cache some of the results. Using load method I fetch results from other source and put into cache using 'put(key,value)'.
Now the problem I am trying to solve is: I want to get all the available results in that cache with out passing any keys. Because I am interested in taking all the values presented in the cache at that time regardless of any specific keys.
getall(Iterable<?> keys) or getAllPresent(Iterable<?> keys) methods are there but those are expecting the keys to be passed.
You can use (Loading)Cache#asMap view and operate on returned ConcurrentMap. There's nice description on Guava wiki page:
You can view any Cache as a ConcurrentMap using its asMap view, but
how the asMap view interacts with the Cache requires some explanation.
cache.asMap() contains all entries that are currently loaded in the
cache. So, for example, cache.asMap().keySet() contains all the
currently loaded keys.
I have a singleton that contains some data I want to cache from a database. I'd like it to call the database and refresh its data every time it is accessed AND a certain amount of time has passed. The singleton pattern I used was the enum one from Effective Java. What do you think is the best way to accomplish this? Ideally, I would override some method that is called every time MySingleton.INSTANCE is called...but I don't know if such a method exists. Another idea is to include a call to the refresh method within every method that can be accessed by the client code...but this seems clumsy to me.
Instead of accessing the INSTANCE directly you can use
DataCache.getInstance().method();
The getInstance() can check if the data needs to be refreshed.
For such a scenario, a robust, performant and very well tested solution is a Caching Library like EHCache: http://ehcache.org/
It seems that what you need is a time-based eviction cache.
Take a look at Google Guava Cache library:
CacheBuilder provides two approaches to timed eviction:
expireAfterAccess(long duration, TimeUnit unit) Only expire entries after the specified duration has passed since the entry was last accessed by a read or a write. Note that the order in which entries are evicted will be similar to that of size-based eviction.
expireAfterWrite(long duration, TimeUnit unit) Expire entries after the specified duration has passed since the entry was created, or the most recent replacement of the value. This could be desirable if cached data grows stale after a certain amount of time.
So which approach do you need? You said:
I'd like it to call the database and refresh its data every time it is accessed AND a certain amount of time has passed.
A certain amount of time has passed since when?
Since entry was last read from your cache? It doesn't matter how much time has passed since entry was loaded from database? Then use expireAfterAccess()
Since entry was last loaded from database into your cache? Then use expireAfterWrite()
You can even use them both at the same time.
Here is such example: http://mkorytin.blogspot.com/2012/02/caching-objects-with-guava.html
I am currently using a ConcurrentHashMap in my application but I need to add the ability to expire entries after a timeout period efficiently (expireAfterWrite) and notify a removal listener whenever an entry is removed.
I see that CacheBuilder can provide what I need but I am hesitant to use it because my need is for a map, not a cache. I say this (difference between map and cache) because the guava cache documenatation says this
Generally, the Guava caching utilities are applicable whenever:
You are willing to spend some memory to improve speed.
You expect that keys will sometimes get queried more than once.
Your application would, in principle, work if every value was evicted from the cache immediately -- but you're trying to reduce
duplicated work.
Specifically the thrid bullet point is not okay in my application. I am storing values in the map/cache that I want to retrieve later (until its expiration). Also my keys generally get queried only one or two times, not many times to see caching benefits. So you see my requirement is for a map, not a cache in a sense. Is it still a good idea to use CacheBuilder as a map to store values that will expireAfterWrite and provide removalListener capability? Anybody know enough about the internals of CacheBuilder implementation to offer advice?
EDIT: Of course MapMaker caching features are deprecated in favor of CacheBuilder, my bad. Don't hesitate to use it:
Cache<Key, Graph> graphs = CacheBuilder.newBuilder()
.concurrencyLevel(4) // read docs for more details
.expireAfterWrite(yourExpireTime, TimeUnit.MINUTES)
.build();
and then use Cache#asMap() if you want it's view as ConcurrentMap.
Use another utility from Guava - MapMaker. From docs:
A builder of ConcurrentMap instances having any combination of the
following features:
keys or values automatically wrapped in weak or soft references
least-recently-used eviction when a maximum size is exceeded
time-based expiration of entries, measured since last access or last write
notification of evicted (or otherwise removed) entries
on-demand computation of values for keys not already present
(...)
The returned map is implemented as a hash table with similar
performance characteristics to ConcurrentHashMap. It supports all
optional operations of the ConcurrentMap interface. It does not permit
null keys or values.
In order to minimize the number of database queries I need some sort of cache to store pairs of data. My approach now is a hashtable (with Strings as keys, Integers as value). But I want to be able to detect updates in the database and replace the values in my "cache". What I'm looking for is something that makes my stored pairs invalid after a preset timespan, perhaps 10-15 minutes. How would I implement that? Is there something in the standard Java package I can use?
I would use some existing solution(there are many cache frameworks).
ehcache is great, it can reset the values on given timespan and i bet it can do much more(i only used that)
You can either use existing solutions (see previous reply)
Or if you want a challenge, make your own easy cache class (not recommended for production project, but it's a great learning experience.
You will need at least 3 members
A cache data stored as hashtable object,
Next cache expiration date
Cache expiration interval set via constructor.
Then simply have public data getter methods, which verify cache expiration status:
if not expired, call hastable's accessors;
if expired, first call "data load" method that is also called in the constructor to pre-populate and then call hashtable accessors.
For an even cooler cache class (I have implemented it in Perl at my job), you can have additional functionality you can implement:
Individual per-key cache expiration (coupled with overall total cache expiration)
Auto, semi-auto, and single-shot data reload (e.g., reload entire cache at once; reload a batch of data defined either by some predefined query, or reload individual data elements piecemail). The latter approach is very useful when your cache has many hits on the same exact keys - that way you don't need to reload universe every time 3 kets that are always accessed expire.
You could use a caching framework like OSCache, EHCache, JBoss Cache, JCS... If you're looking for something that follows a "standard", choose a framework that supports the JCache standard interface (javax.cache) aka JSR-107.
For simple needs like what you are describing, I'd look at EHCache or OSCache (I'm not saying they are basic, but they are simple to start with), they both support expiration based on time.
If I had to choose one solution, I'd recommend Ehcache which has my preference, especially now that it has joined Terracotta. And just for the record, Ehcache provides a preview implementation of JSR107 via the net.sf.cache.jcache package.