Archive for the ‘Guava Cache’ Category

Guava Cache

Posted: September 11, 2017 in Cache, General, Guava Cache
Tags: , , , ,

Data requests like database queries, extensive computations, file reads or report composition, come at a dear price of high latency times. Caching APIs can lower that price, yielding a drop in latencies, considerable increases in performance, improved concurrency and scalability plus savings in bandwidth and a reduction in server costs.

A Cache is similar to ConcurrentMap, but not quite the same. The most fundamental difference is that a ConcurrentMap persists all elements that are added to it until they are explicitly removed. A Cache on the other hand is generally configured to evict entries automatically, in order to constrain its memory footprint.

In some cases a LoadingCache can be useful even if it doesn’t evict entries, due to its automatic cache loading.
com.google.common.cache.LoadingCache loads data in cache automatically. Data remains in cache until it is evicted or cache is invalidated. LoadingCache is thread safe. This class provides different methods to access data for the given key. Some methods of this class are get(K key), asMap(), getUnchecked(K key), refresh(K key).

Guava Library cache interface allows standard caching operations like get, put and invalidate.
Get operation returns the value associated by the key, put operation stores value associated by the key
and invalidate operation discards the value associated with the key.

The Guava Cache is an incremental cache, in the sense that when you request an object from the cache, it checks to see if it already has the corresponding value for the supplied key. If it does, it simply returns it (assuming it hasn’t expired). If it doesn’t already have the value, it uses a CacheLoader to fetch the value and then it stores the value in the cache and returns it. This way, the cache is growing as new values are requested.

Note: In order to get values that are not currently in cache, there is CacheLoader interface that implements load operation.

Guava caching utilities are applicable whenever:

  1. You are willing to spend some memory to improve speed.
  2. You expect that keys will sometimes get queried more than once.
  3. Your cache will not need to store more data than what would fit in RAM.
    (Guava caches are local to a single run of your application. They do not store data in files, or on outside servers)

Lets see how Guava cache works with a simple example.
We need to cache all the car models and then get them based on model number.
We will define a cache that can hold 100 car models and will expire the keys after 10 seconds

Step 1: Car.java – Object to be cached

package suhas.guava.cache;

public class Car {

private Integer modelNo;
private String modelName;

public Car(Integer modelNo, String modelName) {
super();
this.modelNo = modelNo;
this.modelName = modelName;
}

public Car(Integer modelNo) {
super();
this.modelNo = modelNo;
}

public Integer getModelNo() {
return modelNo;
}

public void setModelNo(Integer modelNo) {
this.modelNo = modelNo;
}

public String getModelName() {
return modelName;
}

public void setModelName(String modelName) {
this.modelName = modelName;
}

@Override
public String toString() {
return “Car [modelNo=” + modelNo + “, modelName=” + modelName + “]”;
}

}

Step 2: CacheUtil.java – Gauva Cache Implementation

package suhas.guava.cache;

import java.util.concurrent.TimeUnit;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

public class CacheUtil {

private static LoadingCache carCache;

static {
carCache = CacheBuilder.newBuilder().maximumSize(100).expireAfterWrite(10, TimeUnit.SECONDS)
.build(new CacheLoader() {
@Override
public Car load(Integer id) throws Exception {
return getCarByModelNo(id);
}
});
}

public static LoadingCache getLoadingCache() {
return carCache;
}

public static Car getCarByModelNo(int modelNo) {
System.out.println(“–Executing getCarByModelNo for model No #” + modelNo + ” ——–“);
// Perform any expensive operation like loading lookups from DB in your projects.
Car car1 = new Car(1, “Audi”);
Car car2 = new Car(2, “Mercedez”);
if (modelNo == 1) {
return car1;
} else {
return car2;
}
}
}

Step 3: CacheTest.java – Let’s test how Guava cache works.

package suhas.guava.cache;

import java.util.concurrent.ExecutionException;

import com.google.common.cache.LoadingCache;

public class CacheTest {

public static void main(String[] args) {
try {
CacheTest test = new CacheTest();
// Access car first time with id 1, getCarByModelNo() will be called.
System.out.println(“Model Selected :: ” + test.getCarModel(1));
System.out.println(“—————————-“);
// Access car first time with id 2, getCarByModelNo() will be called.
System.out.println(“Model Selected :: ” + test.getCarModel(2));
System.out.println(“—————————-“);
System.out.println(“Trying to get same models again”);
// Access car second time with id 1 and 2, getCarByModelNo() will not be called.
System.out.println(“Model Re-Selected :: ” + test.getCarModel(1));
System.out.println(“Model Re-Selected :: ” + test.getCarModel(2));
System.out.println(“—————————-“);
} catch (Exception e) {
e.printStackTrace();
}

}

private Car getCarModel(Integer modelNo) throws ExecutionException {
LoadingCache carCache = CacheUtil.getLoadingCache();
System.out.println(“Cache Stats :: ” + carCache.stats());
System.out.println(“Cache Size :: ” + carCache.size());
return carCache.get(modelNo);
}
}

Advertisements