Guava Cache basic demo

25 07 2015

Here I go with the caching! Caching (and cache invalidation) is second one of the most difficult thing to do while programming (the first one is the naming things problem :P ). I’ll show the demo with Guava Cache (18.0). Source Code for this tutorial is on my GitHub: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo/Guava/GuavaCacheDemo

Caches Explained

You may want to get familiar with this article to get the idea of how cache works: https://code.google.com/p/guava-libraries/wiki/CachesExplained.

The Demo Introduction

Here I explain the basic app that accesses data via DAO. Let’s assume that data access is costly so the cache is needed. I want cache entries to expire after specified amount of time. Pretty simple.

Build Cache

Guava provides the cache builder. In my case I make use of it is as follows:

cache = CacheBuilder.newBuilder()
        .expireAfterWrite(5, TimeUnit.SECONDS)
        .build(new CacheLoader<String, String>() {
            @Override
            public String load(String key) throws Exception {
                return dataDao.getValueForKey(key);
            }
        });

I do two things here:

  1. set the desired expiration algorithm and time – entry will become invalid in 5 seconds after it was created or updated
  2. provide the method to load entry – Guava Cache will call this method when you will try to retrieve the value from the cache for the first time (when entry was not found in it yet) or if requested entry has expired. Here that method makes call to my DAO.

Expiration

Among few types of eviction (Size-based, timed, Reference-based) I use Timed eviction, There are two algorythms of expiration in that case. From guava doc:

  • expireAfterAccess(long, TimeUnit) Only expire entries after the specified duration has passed since the entry was last accessed by a read or a write.
  • expireAfterWrite(long, TimeUnit) 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.

expireAfterAccess works different. In opposed to expireAfterWrite, it expires entry if it was not accessed in cache in specified time. So if you constatly read that value within its expiration time, it will not get refreshed. expireAfterWrite expires entries based on its age in cache. So it will be refreshed if validity period passed, no matter how freqently you access it (it is done in lazy way, so if time passed, the value will be refreshed only when requested from cache).

Expiration details

In this StackOverflow answer the details are explained by Guava team member:

The Guava Cache implementation expires entries in the course of normal maintenance operations, which occur on a per-segment basis during cache write operations and occasionally during cache read operations. Entries usually aren’t expired at exactly their expiration time, just because Cache makes the deliberate decision not to create its own maintenance thread, but rather to let the user decide whether continuous maintenance is required.

I’m going to focus on expireAfterAccess, but the procedure for expireAfterWrite is almost identical. In terms of the mechanics, when you specify expireAfterAccess in the CacheBuilder, then each segment of the cache maintains a linked list access queue for entries in order from least-recent-access to most-recent-access. The cache entries are actually themselves nodes in the linked list, so when an entry is accessed, it removes itself from its old position in the access queue, and moves itself to the end of the queue.

When cache maintenance is performed, all the cache has to do is to expire every entry at the front of the queue until it finds an unexpired entry. This is straightforward and requires relatively little overhead, and it occurs in the course of normal cache maintenance. (Additionally, the cache deliberately limits the amount of work done in a single cleanup, minimizing the expense to any single cache operation.) Typically, the cost of cache maintenance is dominated by the expense of computing the actual entries in the cache.

The demo and the test

Test mechanism is simple. I set the cache entry expiration time to 5 seconds, and set up a loop to retrieve value from cache each second.

for (int i = 0; i < 20; i++) {
    cacheDemo.getValue("Blue");
    Thread.sleep(1000);
}

I have also added the log line in DAO on each data retrieval and a log line on cache value request. One in five log lines is a log by DAO data retrieval method. The cache value is a string with a timestamp. Notice that it gets updated each time the data is retrieved. This is how console output look like (bold lines are logged by DAO on data request):

Hello, Cache!
returning value from dao: value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:50:57.559
returning value from dao: value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:02.700
returning value from dao: value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
got value from cache for 'Blue': value for key Blue, refreshed from DAO at 20:51:07.703
...

Get the source code

Source code for this demo is on my GitHub: https://github.com/yacekmm/looksok/tree/GuavaCacheDemo/Guava/GuavaCacheDemo





JavaEE and Websockets support

24 05 2014

New release  of JEE has native Websockets support. This video introduces concept briefly:

The speaker has poor accent, but if you can stand it, the content is quite good as a introduction to topic.





JIRA & GreenHopper starter tutorials

17 08 2013

I found two very useful short screencasts presenting how to use GreenHopper in JIRA. These show the full Scrum workflow: Plan – Work – Report. This is a good starter introduction, however adjusting and configuring JIRA according to your needs may be required. To get started, firstly watch the videos below.

This video has short theoretical introduction, then Demo and after that Q&A session. If you’re not interested in Introduction, just skip to demo (7 min). Demo lasts only about 15 minutes.

The second screencast is quite similar, however, if you feel that you are not enough with GreenHopper then it is also definetely good to watch it:

Did I help you?
I manage this blog and share my knowledge for free sacrificing my time. If you appreciate it and find this information helpful, please consider making a donation in order to keep this page alive and improve quality

Donate Button with Credit Cards

Thank You!








%d bloggers like this: