org.snapscript.common.CopyOnWriteCache Maven / Gradle / Ivy
package org.snapscript.common;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class CopyOnWriteCache implements Cache {
private volatile MapUpdater updater;
private volatile Map cache;
public CopyOnWriteCache() {
this(16);
}
public CopyOnWriteCache(int size) {
this(16, 0.5f);
}
public CopyOnWriteCache(int size, float density) {
this.updater = new MapUpdater(size, density);
this.cache = new HashMap();
}
@Override
public Set keySet() {
return cache.keySet();
}
@Override
public V take(K key) {
return updater.take(key);
}
@Override
public V fetch(K key) {
return cache.get(key);
}
@Override
public boolean isEmpty() {
return cache.isEmpty();
}
@Override
public boolean contains(K key) {
return cache.containsKey(key);
}
@Override
public void cache(K key, V value) {
updater.cache(key, value);
}
@Override
public void clear() {
updater.clear();
}
@Override
public int size() {
return cache.size();
}
private class MapUpdater {
private final Map empty;
private final float density;
private final int size;
public MapUpdater(int size, float density) {
this.empty = new HashMap();
this.density = density;
this.size = size;
}
public synchronized void cache(K key, V value) {
V existing = cache.get(key);
if(existing != value) { // reduce churn
Map copy = new HashMap(size, density);
copy.putAll(cache);
copy.put(key, value);
cache = copy;
}
}
public synchronized V take(K key) {
V existing = cache.get(key);
if(existing != null) {
Map copy = new HashMap(size, density);
copy.putAll(cache);
copy.remove(key);
cache = copy;
}
return existing;
}
public synchronized void clear() {
cache = empty;
}
}
}