
com.jaeksoft.searchlib.cache.LRUCache Maven / Gradle / Ivy
/**
* License Agreement for OpenSearchServer
*
* Copyright (C) 2008-2015 Emmanuel Keller / Jaeksoft
*
* http://www.open-search-server.com
*
* This file is part of OpenSearchServer.
*
* OpenSearchServer is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenSearchServer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenSearchServer.
* If not, see .
**/
package com.jaeksoft.searchlib.cache;
import java.io.PrintWriter;
import java.text.NumberFormat;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import com.jaeksoft.searchlib.util.ReadWriteLock;
import com.jaeksoft.searchlib.util.StringUtils;
import com.jaeksoft.searchlib.util.Timer;
public abstract class LRUCache> {
final private ReadWriteLock rwl = new ReadWriteLock();
private TreeMap cacheMap;
private EvictionQueue evictionQueue;
private final String name;
private int maxSize;
private long evictions;
private long lookups;
private long hits;
private long inserts;
private class EvictionQueue extends LinkedHashMap {
/**
*
*/
private static final long serialVersionUID = 2876891913920705107L;
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
if (size() <= maxSize)
return false;
cacheMap.remove(eldest.getKey());
evictions++;
return true;
}
}
protected LRUCache(String name, int maxSize) {
this.name = name;
this.evictions = 0;
this.lookups = 0;
this.inserts = 0;
this.hits = 0;
this.maxSize = 0;
this.cacheMap = null;
this.evictionQueue = null;
setMaxSize_noLock(maxSize);
}
private void setMaxSize_noLock(int newMaxSize) {
if (newMaxSize == maxSize)
return;
if (newMaxSize == 0) {
clear_nolock();
cacheMap = null;
evictionQueue = null;
} else {
if (newMaxSize < maxSize) {
cacheMap = null;
evictionQueue = null;
}
if (cacheMap == null)
cacheMap = new TreeMap();
if (evictionQueue == null)
evictionQueue = new EvictionQueue();
}
maxSize = newMaxSize;
}
public void setMaxSize(int newMaxSize) {
rwl.w.lock();
try {
setMaxSize_noLock(newMaxSize);
} finally {
rwl.w.unlock();
}
}
final protected K getAndPromote(final K newItem) {
rwl.w.lock();
try {
if (cacheMap == null)
return newItem;
lookups++;
K prevItem = cacheMap.get(newItem);
if (prevItem != null) {
evictionQueue.remove(prevItem);
evictionQueue.put(prevItem, prevItem);
hits++;
return prevItem;
}
evictionQueue.put(newItem, newItem);
cacheMap.put(newItem, newItem);
inserts++;
return newItem;
} finally {
rwl.w.unlock();
}
}
final public void put(final K item) {
rwl.w.lock();
try {
if (cacheMap == null)
return;
evictionQueue.put(item, item);
cacheMap.put(item, item);
inserts++;
} finally {
rwl.w.unlock();
}
}
final public boolean remove(final K key) {
rwl.w.lock();
try {
if (cacheMap == null)
return false;
K item1 = cacheMap.remove(key);
K item2 = evictionQueue.remove(key);
if (item1 == null && item2 == null)
return false;
evictions++;
return true;
} finally {
rwl.w.unlock();
}
}
public K getAndJoin(K item, Timer timer) throws Exception {
item = getAndPromote(item);
item.join(timer);
return item;
}
final private void clear_nolock() {
if (cacheMap != null)
cacheMap.clear();
if (evictionQueue != null)
evictionQueue.clear();
}
final public void clear() {
rwl.w.lock();
try {
clear_nolock();
} finally {
rwl.w.unlock();
}
}
@Override
final public String toString() {
rwl.r.lock();
try {
return StringUtils
.fastConcat(
name,
" - Size: ",
cacheMap == null ? 0 : Integer.toString(cacheMap
.size()),
'/',
evictionQueue == null ? 0 : Integer
.toString(evictionQueue.size())
+ " - MaxSize: ",
Integer.toString(maxSize), " - Lookup: ", Long
.toString(lookups), " - Insert: ", Long
.toString(inserts), " HitRatio: ",
getHitRatioPercent());
} finally {
rwl.r.unlock();
}
}
final public void xmlInfo(PrintWriter writer) {
rwl.r.lock();
try {
float hitRatio = getHitRatio();
writer.println("");
writer.println(" ");
} finally {
rwl.r.unlock();
}
}
final public String getName() {
rwl.r.lock();
try {
return name;
} finally {
rwl.r.unlock();
}
}
final public int getSize() {
rwl.r.lock();
try {
return cacheMap == null ? 0 : cacheMap.size();
} finally {
rwl.r.unlock();
}
}
final public int getMaxSize() {
rwl.r.lock();
try {
return maxSize;
} finally {
rwl.r.unlock();
}
}
final public long getEvictions() {
rwl.r.lock();
try {
return evictions;
} finally {
rwl.r.unlock();
}
}
final public long getLookups() {
rwl.r.lock();
try {
return lookups;
} finally {
rwl.r.unlock();
}
}
final public long getHits() {
rwl.r.lock();
try {
return hits;
} finally {
rwl.r.unlock();
}
}
final public long getInserts() {
rwl.r.lock();
try {
return inserts;
} finally {
rwl.r.unlock();
}
}
final public float getHitRatio() {
rwl.r.lock();
try {
if (hits > 0 && lookups > 0)
return (float) (((float) hits) / ((float) lookups));
else
return 0;
} finally {
rwl.r.unlock();
}
}
final public String getHitRatioPercent() {
return NumberFormat.getPercentInstance().format(getHitRatio());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy