All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.venky.cache.Cache Maven / Gradle / Ivy

There is a newer version: 1.18
Show newest version
package com.venky.cache;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import com.venky.core.checkpoint.Mergeable;
import com.venky.core.util.Bucket;
import com.venky.core.util.ObjectUtil;

public abstract class Cache implements Mergeable> , Serializable{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = -4801418262910565684L;
	public static final int MAX_ENTRIES_DEFAULT = 1000;
	public static final int MAX_ENTRIES_UNLIMITED = 0;
	public static final double PRUNE_FACTOR_DEFAULT = 0.8;
	private Bucket fakeTime = new Bucket(); 
			
	protected Cache(){
		this(MAX_ENTRIES_DEFAULT,PRUNE_FACTOR_DEFAULT);
	}
	
	private final int maxEntries ;
	private final double pruneFactor ;
	protected Cache(int maxEntries,double pruneFactor){
		this.maxEntries = maxEntries;
		this.pruneFactor = pruneFactor;
		if (this.pruneFactor > 1 || this.pruneFactor < 0 ){
			throw new IllegalArgumentException("Prune factor must be between 0.0 than 1.0");
		}
	}

	public void makeSpace(){
		if (maxEntries != MAX_ENTRIES_UNLIMITED && size() >= maxEntries){
			int numEntriesToRemove = (int)(size() * pruneFactor);
			if (numEntriesToRemove <= 0){
				return;
			}
			if (pruneFactor == 1){
				cacheMap.clear();
				accessTimeMap.clear();
				return;
			}
			SortedMap> keysAccessedByTime = new TreeMap>(); 
			for (K key : accessTimeMap.keySet()){
				Long time = accessTimeMap.get(key);
				List keys = keysAccessedByTime.get(time);
				if (keys == null){
					keys = new ArrayList();
					keysAccessedByTime.put(time, keys);
				}
				keys.add(key);
			}
			int numEntriesRemoved = 0;
			for (Long time: keysAccessedByTime.keySet()){//We will read in the order of being Accessed.
				for (K key : keysAccessedByTime.get(time)){
					cacheMap.remove(key);
					accessTimeMap.remove(key);
					numEntriesRemoved ++;
				}
				if (numEntriesRemoved >= numEntriesToRemove){
					break;
				}
			}
 		}
	}

	@SuppressWarnings("unchecked")
	public Cache clone(){
		try {
			Cache clone = (Cache)super.clone();
			clone.accessTimeMap = (HashMap)accessTimeMap.clone();
			clone.cacheMap = (HashMap)cacheMap.clone();
			for (K k :clone.cacheMap.keySet()){
				clone.cacheMap.put(k, ObjectUtil.clone(clone.get(k)));
			}
			return clone;
		} catch (CloneNotSupportedException e) {
			throw new RuntimeException(e);
		}
	}
	
	public void merge(Cache another){
		ObjectUtil.mergeValues(another.accessTimeMap,this.accessTimeMap);
		ObjectUtil.mergeValues(another.cacheMap,this.cacheMap);
	}
	public int size(){
		return cacheMap.size();
	}
	
	public Set keySet(){
		return cacheMap.keySet();
	}
	
	private HashMap cacheMap = new HashMap();
	private HashMap accessTimeMap = new HashMap();
	
	public V get(K key){
		V v = cacheMap.get(key);
		if (v == null && !cacheMap.containsKey(key)){
			synchronized (cacheMap) {
				v = cacheMap.get(key);
				if (v == null && !cacheMap.containsKey(key)){
					makeSpace();
					v = getValue(key);
					cacheMap.put(key, v);
				}
			}
		}
		fakeTime.increment();
		accessTimeMap.put(key, fakeTime.longValue());
		return v;
	}
	
	
	public void remove(K key){
		synchronized (cacheMap) {
			cacheMap.remove(key);
			accessTimeMap.remove(key);
		}
	}
	public void clear(){
		synchronized (cacheMap) {
			cacheMap.clear();
			accessTimeMap.clear();
		}
	}
	
	public void put(K key,V value){
		synchronized (cacheMap) {
			cacheMap.put(key, value);
			fakeTime.increment();
			accessTimeMap.put(key, fakeTime.longValue());
		}
	}
	
	protected abstract V getValue(K k);
	public Long accessTime(K k){
		return accessTimeMap.get(k);
	}
	
	public Collection values(){
		return cacheMap.values();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy