mirror of https://github.com/webbukkit/dynmap.git
187 lines
5.5 KiB
Java
187 lines
5.5 KiB
Java
package org.dynmap.bukkit.helper;
|
|
|
|
import java.lang.ref.Reference;
|
|
import java.lang.ref.ReferenceQueue;
|
|
import java.lang.ref.WeakReference;
|
|
import java.lang.ref.SoftReference;
|
|
import java.util.IdentityHashMap;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.Map;
|
|
|
|
import org.dynmap.utils.DynIntHashMap;
|
|
import org.dynmap.bukkit.helper.AbstractMapChunkCache.Snapshot;
|
|
|
|
public class SnapshotCache {
|
|
|
|
public static SnapshotCache sscache;
|
|
|
|
public static class SnapshotRec {
|
|
public Snapshot ss;
|
|
public long inhabitedTicks;
|
|
public DynIntHashMap tileData;
|
|
};
|
|
|
|
private CacheHashMap snapcache;
|
|
private ReferenceQueue<SnapshotRec> refqueue;
|
|
private long cache_attempts;
|
|
private long cache_success;
|
|
private boolean softref;
|
|
|
|
private static class CacheRec {
|
|
Reference<SnapshotRec> ref;
|
|
boolean hasbiome;
|
|
boolean hasrawbiome;
|
|
boolean hasblockdata;
|
|
boolean hashighesty;
|
|
}
|
|
|
|
@SuppressWarnings("serial")
|
|
public class CacheHashMap extends LinkedHashMap<String, CacheRec> {
|
|
private int limit;
|
|
private IdentityHashMap<Reference<SnapshotRec>, String> reverselookup;
|
|
|
|
public CacheHashMap(int lim) {
|
|
super(16, (float)0.75, true);
|
|
limit = lim;
|
|
reverselookup = new IdentityHashMap<Reference<SnapshotRec>, String>();
|
|
}
|
|
protected boolean removeEldestEntry(Map.Entry<String, CacheRec> last) {
|
|
boolean remove = (size() >= limit);
|
|
if(remove) {
|
|
reverselookup.remove(last.getValue().ref);
|
|
}
|
|
return remove;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create snapshot cache
|
|
*/
|
|
public SnapshotCache(int max_size, boolean softref) {
|
|
snapcache = new CacheHashMap(max_size);
|
|
refqueue = new ReferenceQueue<SnapshotRec>();
|
|
this.softref = softref;
|
|
}
|
|
private String getKey(String w, int cx, int cz) {
|
|
return w + ":" + cx + ":" + cz;
|
|
}
|
|
/**
|
|
* Invalidate cached snapshot, if in cache
|
|
*/
|
|
public void invalidateSnapshot(String w, int x, int y, int z) {
|
|
String key = getKey(w, x>>4, z>>4);
|
|
CacheRec rec = snapcache.remove(key);
|
|
if(rec != null) {
|
|
snapcache.reverselookup.remove(rec.ref);
|
|
rec.ref.clear();
|
|
}
|
|
//processRefQueue();
|
|
}
|
|
/**
|
|
* Invalidate cached snapshot, if in cache
|
|
*/
|
|
public void invalidateSnapshot(String w, int x0, int y0, int z0, int x1, int y1, int z1) {
|
|
for(int xx = (x0>>4); xx <= (x1>>4); xx++) {
|
|
for(int zz = (z0>>4); zz <= (z1>>4); zz++) {
|
|
String key = getKey(w, xx, zz);
|
|
CacheRec rec = snapcache.remove(key);
|
|
if(rec != null) {
|
|
snapcache.reverselookup.remove(rec.ref);
|
|
rec.ref.clear();
|
|
}
|
|
}
|
|
}
|
|
//processRefQueue();
|
|
}
|
|
/**
|
|
* Look for chunk snapshot in cache
|
|
*/
|
|
public SnapshotRec getSnapshot(String w, int chunkx, int chunkz,
|
|
boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) {
|
|
String key = getKey(w, chunkx, chunkz);
|
|
processRefQueue();
|
|
SnapshotRec ss = null;
|
|
CacheRec rec = snapcache.get(key);
|
|
if(rec != null) {
|
|
ss = rec.ref.get();
|
|
if(ss == null) {
|
|
snapcache.reverselookup.remove(rec.ref);
|
|
snapcache.remove(key);
|
|
}
|
|
}
|
|
if(ss != null) {
|
|
if((blockdata && (!rec.hasblockdata)) ||
|
|
(biome && (!rec.hasbiome)) ||
|
|
(biomeraw && (!rec.hasrawbiome)) ||
|
|
(highesty && (!rec.hashighesty))) {
|
|
ss = null;
|
|
}
|
|
}
|
|
cache_attempts++;
|
|
if(ss != null) cache_success++;
|
|
|
|
return ss;
|
|
}
|
|
/**
|
|
* Add chunk snapshot to cache
|
|
*/
|
|
public void putSnapshot(String w, int chunkx, int chunkz, SnapshotRec ss,
|
|
boolean blockdata, boolean biome, boolean biomeraw, boolean highesty) {
|
|
String key = getKey(w, chunkx, chunkz);
|
|
processRefQueue();
|
|
CacheRec rec = new CacheRec();
|
|
rec.hasblockdata = blockdata;
|
|
rec.hasbiome = biome;
|
|
rec.hasrawbiome = biomeraw;
|
|
rec.hashighesty = highesty;
|
|
if (softref)
|
|
rec.ref = new SoftReference<SnapshotRec>(ss, refqueue);
|
|
else
|
|
rec.ref = new WeakReference<SnapshotRec>(ss, refqueue);
|
|
CacheRec prevrec = snapcache.put(key, rec);
|
|
if(prevrec != null) {
|
|
snapcache.reverselookup.remove(prevrec.ref);
|
|
}
|
|
snapcache.reverselookup.put(rec.ref, key);
|
|
}
|
|
/**
|
|
* Process reference queue
|
|
*/
|
|
private void processRefQueue() {
|
|
Reference<? extends SnapshotRec> ref;
|
|
while((ref = refqueue.poll()) != null) {
|
|
String k = snapcache.reverselookup.remove(ref);
|
|
if(k != null) {
|
|
snapcache.remove(k);
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Get hit rate (percent)
|
|
*/
|
|
public double getHitRate() {
|
|
if(cache_attempts > 0) {
|
|
return (100.0*cache_success)/(double)cache_attempts;
|
|
}
|
|
return 0.0;
|
|
}
|
|
/**
|
|
* Reset cache stats
|
|
*/
|
|
public void resetStats() {
|
|
cache_attempts = cache_success = 0;
|
|
}
|
|
/**
|
|
* Cleanup
|
|
*/
|
|
public void cleanup() {
|
|
if(snapcache != null) {
|
|
snapcache.clear();
|
|
snapcache.reverselookup.clear();
|
|
snapcache.reverselookup = null;
|
|
snapcache = null;
|
|
}
|
|
}
|
|
}
|
|
|