
net.anthavio.cache.impl.HeapMapCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hatatitla Show documentation
Show all versions of hatatitla Show documentation
Compact but tweakable REST client library you have been dreaming of
The newest version!
package net.anthavio.cache.impl;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import net.anthavio.cache.CacheBase;
import net.anthavio.cache.CacheEntry;
import net.anthavio.cache.CacheKeyProvider;
/**
*
* @author martin.vanek
*
*/
public class HeapMapCache extends CacheBase {
private static int counter;
private final TtlEvictingThread ttlEvictingThread;
private final Map> storage = new ConcurrentHashMap>();
public HeapMapCache(CacheKeyProvider keyProvider) {
this(keyProvider, 0, null);
}
public HeapMapCache(CacheKeyProvider keyProvider, int evictionInterval, TimeUnit evictionUnit) {
super("HeapMapCache " + ++counter, keyProvider); //We don't care much about name
if (evictionInterval > 0) {
ttlEvictingThread = new TtlEvictingThread(evictionInterval, evictionUnit);
ttlEvictingThread.start();
} else {
ttlEvictingThread = null;
}
}
@Override
protected CacheEntry doGet(String key) {
CacheEntry entry = this.storage.get(key);
if (entry == null) {
return null;
} else if (entry.getEvictAt() < System.currentTimeMillis()) {
//silly but true - don't return if it's expired
storage.remove(key);
return null;
} else {
return entry;
}
}
@Override
protected Boolean doSet(String key, CacheEntry entry) {
this.storage.put(key, entry);
return true;
}
@Override
protected Boolean doRemove(String key) {
CacheEntry entry = this.storage.remove(key);
return entry != null ? Boolean.TRUE : Boolean.FALSE;
}
@Override
public void removeAll() {
logger.debug("Cache clear");
this.storage.clear();
}
@Override
public void close() {
super.close();
if (ttlEvictingThread != null) {
ttlEvictingThread.keepGoing = false;
ttlEvictingThread.interrupt();
}
}
private class TtlEvictingThread extends Thread {
private final long interval;
private boolean keepGoing = true;
public TtlEvictingThread(int interval, TimeUnit unit) {
this.interval = unit.toMillis(interval);
if (this.interval < 1000) {
throw new IllegalArgumentException("Interval " + this.interval + " must be >= 1000 millis");
}
this.setName(HeapMapCache.this.getName() + "-reaper");
this.setDaemon(true);
}
@Override
public void run() {
while (keepGoing) {
try {
Thread.sleep(interval);
} catch (InterruptedException ix) {
if (keepGoing) {
logger.debug("TtlEvictingThread stopped from sleep");
return;
} else {
logger.warn("TtlEvictingThread interrupted but continue");
}
}
doEviction();
}
logger.debug("TtlEvictingThread stopped from work");
}
private void doEviction() {
long now = System.currentTimeMillis();
try {
//XXX beware of concurrent changes of storage
for (Entry> entry : storage.entrySet()) {
if (entry.getValue().getEvictAt() < now) {
storage.remove(entry.getKey());
}
}
} catch (Exception x) {
logger.warn("Exception during eviction", x);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy