plastique
plastique

Reputation: 1204

How to recognize whenever get from Guava Loading cache is hit or miss?

I use LoadingCache<KEY, VALUE> from Google's guava library. It works well. But my use case requires me to recognize when acquired value was returned from cache itself or loaded by given CacheLoader. Is there a way to recognize source of the value ?

Upvotes: 1

Views: 2753

Answers (2)

proletariat
proletariat

Reputation: 1

Yes, it is possible to recognize the source by using CacheStats.

CacheStats class provides you methods like hitCount(), loadCount(), loadSuccessCount(), requestCount() (the link above contains explanation for what each method does) that will help you know when data from looked up from cache and when it was loaded from db.

To get the stats, you'll have to use recordStats() method with CacheBuilder when creating a new LoadingCache.

LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
       .maximumSize(1000)
       .expireAfterWrite(10, TimeUnit.MINUTES)
       .removalListener(MY_LISTENER)
       .recordStats() // <- add this
       .build(
           new CacheLoader<Key, Graph>() {
             @Override
             public Graph load(Key key) throws AnyException {
               return createExpensiveGraph(key);
             }
           });

Upvotes: 0

cruftex
cruftex

Reputation: 5723

We had a similar requirement. In our case we set HTTP-headers for debugging purposes, whether the request was a cache hit or a cache miss. There no way to do this in a single cache request. A pattern getting close to what you want looks like:

   boolean hit = true;
   Object result = cache.getIfPresent(key);
   if (result == null) {
     hit = false;
     result = cache.get(key);
   }
   // result: either from the cache or loaded
   // hit: is true if it was in the cache

In a concurrent scenario there could be multiple request on the same key at the same time. So there are two caveats:

  • There will be more requests indicating a miss than loader calls, because requests for the same key would block and proceed once the loader is finished.
  • Since above is not atomic, there is a slight chance that the loader completes between getIfPresent and get, so a false miss would be indicated

For statistical and debugging purposes it is good enough.

You asked for:

But my use case requires me to recognize when acquired value was returned from cache itself or loaded by given CacheLoader.

This requirement cannot be fulfilled, since it can happen, in concurrent scenarios, as described above, that the item is not returned from the cache, but blocks because the entry is currently loaded. So outcome is either a miss or hit. Or the outcome is a hit, a load or was blocked for load.

Other approaches:

  • You can set a thread local variable in the loader to indicate that the loader was called
  • Some times you have a unique request ID in your logging/monitoring/application context. You could add that to your cached value. Then everybody can check whether the value was loaded in the current context or not.
  • With the above you start implementing mechanisms that tracing and logging tools do, so maybe use a tracing library right away
  • If you switch to a JCache based based API or to cache2k you can check atomically via the entry processor whether the entry is present and issue a load
  • Drop the loader and use an atomic map operation like computeIfAbsent

Please mind that applications might evolve and the caching library might be changed or maybe you want to switch to asynchronous loading. Try to keep things simple, portable and not causing performance overhead.

Ultimately, speak to your downstream consumer and clarify what is needed, what would be sufficient and what is doable. Since caching seems to be in your domain, you have the responsibility that things are not impacting the system performance at the end. So any requirements should be made collaboratively and always need technical compromises.

Upvotes: 2

Related Questions