view src/main/java/edu/harvard/iq/dataverse/util/LruCache.java @ 10:a50cf11e5178

Rewrite LGDataverse completely upgrading to dataverse4.0
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Tue, 08 Sep 2015 17:00:21 +0200
parents
children
line wrap: on
line source

package edu.harvard.iq.dataverse.util;

import java.util.LinkedHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * A thread-safe implementation of a capped-size cache, where the removal is done 
 * based on the "Least Recently Used" strategy.
 * This implementation allows some scenarios where the removed values are not the
 * least recently used, in order to provide better performance.
 * 
 * @author michael
 * @param <K> Class for the cache keys
 * @param <V> Class for the cache values
 */
public class LruCache<K,V> {
    private final LinkedHashMap<K, V> cache = new LinkedHashMap<>(10, 0.75f, true);
    private final ReentrantLock cacheLock = new ReentrantLock();
    private long maxSize = 128;
    
    /**
     * @param k The key to get
     * @return The value associated with {@code k}, or {@code null}, if there isn't any.
     */
    public V get( K k ) {
        try {
            cacheLock.lock();
            return cache.get(k);
        } finally { cacheLock.unlock(); }
    }
    
    /**
     * Associates {@code k} with {@code v}.
     * @param k the key
     * @param v the value
     * @return {@code v}, to allow method call chaining.
     */
    public V put( K k, V v ) {
        try {
            cacheLock.lock();
            cache.put(k, v);
            shrinkToMaxSize();
            return v;
        } finally { cacheLock.unlock(); }
    }

    public long size() {
        try {
            cacheLock.lock();
            return cache.size();
        } finally { cacheLock.unlock(); }
    }
        
    public long getMaxSize() {
        return maxSize;
    }

    public void setMaxSize(long maxSize) {
        if ( maxSize < 1 ) {
            throw new IllegalArgumentException("Max cache size can't be less than 1");
        }
        try {
            cacheLock.lock();
            this.maxSize = maxSize;
            shrinkToMaxSize();
        } finally { cacheLock.unlock(); }
    }
    
    public void invalidate() {
        try {
            cacheLock.lock();
            cache.clear();
        } finally { cacheLock.unlock(); }
    }
    
    public void invalidate( K k ) {
        try {
            cacheLock.lock();
            cache.remove(k);
        } finally { cacheLock.unlock(); }
    }
    
    private void shrinkToMaxSize() {
        while( cache.size() > getMaxSize() ) {
            cache.remove( cache.entrySet().iterator().next().getKey() );
        }
    }
}