package com.datascience.datastoring.adapters.kv; import com.google.common.cache.*; import org.apache.log4j.Logger; import java.util.Map; import java.util.concurrent.ExecutionException; /** * @Author: konrad */ public class CachedKV<V> implements IKVStorage<V>{ protected final static Logger log = Logger.getLogger(CachedKV.class); protected final IKVStorage<V> wrapped; protected LoadingCache<String, V> cache; public CachedKV(IKVStorage<V> wrapped, CacheBuilder cacheBuilder){ this.wrapped = wrapped; this.cache = cacheBuilder .removalListener(getRemovalListener()) .build(getDataLoader()); } public CachedKV(IKVStorage<V> wrapped, long cacheSize){ this(wrapped, CacheBuilder.newBuilder().maximumSize(cacheSize)); } protected RemovalListener<String, V> getRemovalListener(){ return new RemovalListener<String, V>() { @Override public void onRemoval(RemovalNotification<String, V> objectObjectRemovalNotification) { try{ if (objectObjectRemovalNotification.getCause() == RemovalCause.EXPLICIT){ wrapped.remove(objectObjectRemovalNotification.getKey()); } else { wrapped.put(objectObjectRemovalNotification.getKey(), objectObjectRemovalNotification.getValue()); } } catch (Exception ex){ log.error("CachedKV: onRemoval", ex); } } }; } protected CacheLoader<String, V> getDataLoader(){ return new CacheLoader<String, V>() { @Override public V load(String k) throws Exception { V value = wrapped.get(k); if (value != null) return wrapped.get(k); throw new NotInCachedException(); } }; } @Override public void put(String key, V value) { cache.put(key, value); } @Override public V get(String key) throws ExecutionException { try{ return cache.get(key); } catch (ExecutionException ex){ if (ex.getCause() instanceof NotInCachedException) { return null; } else { throw ex; } } } @Override public void remove(String key) { cache.invalidate(key); } @Override public boolean contains(String key) throws ExecutionException { return get(key) != null; } @Override public void shutdown() throws Exception { for (Map.Entry<String, V> entry: cache.asMap().entrySet()){ wrapped.put(entry.getKey(), entry.getValue()); } cache.invalidateAll(); } protected static class NotInCachedException extends Exception{} }