org.mapdb.Caches Maven / Gradle / Ivy
The newest version!
package org.mapdb; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.Random; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * Contains various instance cache implementations */ public final class Caches { private Caches(){} /** * Least Recently Used cache. * If cache is full it removes less used items to make a space */ public static class LRU extends EngineWrapper { protected LongMap
orWeakReference
* Items can be removed from cache by Garbage Collector if * * @author Jan Kotek */ public static class WeakSoftRef extends EngineWrapper implements Engine { protected final ReentrantLock[] locks = new ReentrantLock[CC.CONCURRENCY]; { for(int i=0;iextends WeakReference implements CacheItem { final long recid; public CacheWeakItem(A referent, ReferenceQueue q, long recid) { super(referent, q); this.recid = recid; } @Override public long getRecid() { return recid; } } protected static final class CacheSoftItem extends SoftReference implements CacheItem { final long recid; public CacheSoftItem(A referent, ReferenceQueue q, long recid) { super(referent, q); this.recid = recid; } @Override public long getRecid() { return recid; } } @SuppressWarnings("rawtypes") protected ReferenceQueue queue = new ReferenceQueue(); protected Thread queueThread = new Thread("MapDB GC collector"){ @Override public void run(){ runRefQueue(); } }; protected LongConcurrentHashMap items = new LongConcurrentHashMap (); final protected boolean useWeakRef; public WeakSoftRef(Engine engine, boolean useWeakRef){ super(engine); this.useWeakRef = useWeakRef; queueThread.setDaemon(true); queueThread.start(); } /** Collects items from GC and removes them from cache */ protected void runRefQueue(){ try{ final ReferenceQueue> queue = this.queue; if(queue == null)return; final LongConcurrentHashMap items = this.items; while(true){ CacheItem item = (CacheItem) queue.remove(); items.remove(item.getRecid(), item); if(Thread.interrupted()) return; } }catch(InterruptedException e){ //this is expected, so just silently exit thread } } @Override public long put(A value, Serializer serializer) { long recid = getWrappedEngine().put(value, serializer); ReferenceQueue q = checkClosed(queue); LongConcurrentHashMap items2 = checkClosed(items); CacheItem item = useWeakRef? new CacheWeakItem(value, q, recid) : new CacheSoftItem(value, q, recid); final Lock lock = locks[Store.lockPos(recid)]; lock.lock(); try{ items2.put(recid,item); }finally{ lock.unlock(); } return recid; } @SuppressWarnings("unchecked") @Override public A get(long recid, Serializer serializer) { LongConcurrentHashMap items2 = checkClosed(items); CacheItem item = items2.get(recid); if(item!=null){ Object o = item.get(); if(o == null) items2.remove(recid); else{ return (A) o; } } Engine engine = getWrappedEngine(); final Lock lock = locks[Store.lockPos(recid)]; lock.lock(); try{ Object value = engine.get(recid, serializer); if(value!=null){ ReferenceQueue q = checkClosed(queue); item = useWeakRef? new CacheWeakItem(value, q, recid) : new CacheSoftItem(value, q, recid); items2.put(recid,item); } return (A) value; }finally{ lock.unlock(); } } @Override public void update(long recid, A value, Serializer serializer) { Engine engine = getWrappedEngine(); ReferenceQueue q = checkClosed(queue); LongConcurrentHashMap items2 = checkClosed(items); CacheItem item = useWeakRef? new CacheWeakItem(value, q, recid) : new CacheSoftItem(value, q, recid); final Lock lock = locks[Store.lockPos(recid)]; lock.lock(); try{ items2.put(recid,item); engine.update(recid, value, serializer); }finally { lock.unlock(); } } @Override public void delete(long recid, Serializer serializer){ Engine engine = getWrappedEngine(); LongMap items2 = checkClosed(items); final Lock lock = locks[Store.lockPos(recid)]; lock.lock(); try{ items2.remove(recid); engine.delete(recid,serializer); }finally { lock.unlock(); } } @Override public boolean compareAndSwap(long recid, A expectedOldValue, A newValue, Serializer serializer) { Engine engine = getWrappedEngine(); LongMap items2 = checkClosed(items); ReferenceQueue q = checkClosed(queue); final Lock lock = locks[Store.lockPos(recid)]; lock.lock(); try{ CacheItem item = items2.get(recid); Object oldValue = item==null? null: item.get() ; if(item!=null && item.getRecid() == recid && (oldValue == expectedOldValue || (oldValue!=null && oldValue.equals(expectedOldValue)))){ //found matching entry in cache, so just update and return true items2.put(recid,useWeakRef? new CacheWeakItem(newValue, q, recid) : new CacheSoftItem(newValue, q, recid)); engine.update(recid, newValue, serializer); return true; }else{ boolean ret = engine.compareAndSwap(recid, expectedOldValue, newValue, serializer); if(ret){ items2.put(recid,useWeakRef? new CacheWeakItem(newValue, q, recid) : new CacheSoftItem(newValue, q, recid)); } return ret; } }finally { lock.unlock(); } } @Override public void close() { super.close(); items = null; queue = null; if (queueThread != null) { queueThread.interrupt(); queueThread = null; } } @Override public void rollback() { items.clear(); super.rollback(); } @Override public void clearCache() { items.clear(); super.clearCache(); } } /** * Cache created objects using hard reference. * It checks free memory every N operations (1024*10). If free memory is bellow 75% it clears the cache * * @author Jan Kotek */ public static class HardRef extends LRU { final static int CHECK_EVERY_N = 10000; int counter = 0; public HardRef(Engine engine, int initialCapacity) { super(engine, new LongConcurrentHashMap (initialCapacity)); } @Override public A get(long recid, Serializer serializer) { checkFreeMem(); return super.get(recid, serializer); } private void checkFreeMem() { if((counter++)%CHECK_EVERY_N==0 ){ Runtime r = Runtime.getRuntime(); long max = r.maxMemory(); if(max == Long.MAX_VALUE) return; double free = r.freeMemory(); double total = r.totalMemory(); //We believe that free refers to total not max. //Increasing heap size to max would increase to max free = free + (max-total); //TODO logging // if(CC.LOG_TRACE) // Utils.LOG.fine("DBCache: freemem = " +free + " = "+(free/max)+"%"); if(free<1e7 || free*4 void update(long recid, A value, Serializer serializer) { checkFreeMem(); super.update(recid, value, serializer); } @Override public void delete(long recid, Serializer serializer){ checkFreeMem(); super.delete(recid,serializer); } @Override public boolean compareAndSwap(long recid, A expectedOldValue, A newValue, Serializer serializer) { checkFreeMem(); return super.compareAndSwap(recid, expectedOldValue, newValue, serializer); } } }
© 2015 - 2025 Weber Informatics LLC | Privacy Policy