diff options
Diffstat (limited to 'src/main/java/de/measite/minidns/LRUCache.java')
-rw-r--r-- | src/main/java/de/measite/minidns/LRUCache.java | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/src/main/java/de/measite/minidns/LRUCache.java b/src/main/java/de/measite/minidns/LRUCache.java new file mode 100644 index 00000000..132bf794 --- /dev/null +++ b/src/main/java/de/measite/minidns/LRUCache.java @@ -0,0 +1,139 @@ +package de.measite.minidns; + +import java.util.LinkedHashMap; +import java.util.Map.Entry; + +/** + * LRU based DNSCache backed by a LinkedHashMap. + */ +public class LRUCache implements DNSCache { + + /** + * Internal miss count. + */ + protected long missCount = 0l; + + /** + * Internal expire count (subset of misses that was caused by expire). + */ + protected long expireCount = 0l; + + /** + * Internal hit count. + */ + protected long hitCount = 0l; + + /** + * The internal capacity of the backend cache. + */ + protected int capacity; + + /** + * The upper bound of the ttl. All longer TTLs will be capped by this ttl. + */ + protected long maxTTL; + + /** + * The backend cache. + */ + protected LinkedHashMap<Question, DNSMessage> backend; + + /** + * Create a new LRUCache with given capacity and upper bound ttl. + * @param capacity The internal capacity. + * @param maxTTL The upper bound for any ttl. + */ + @SuppressWarnings("serial") + public LRUCache(final int capacity, final long maxTTL) { + this.capacity = capacity; + this.maxTTL = maxTTL; + backend = new LinkedHashMap<Question,DNSMessage>( + Math.min(capacity, 11), 0.75f, true) + { + @Override + protected boolean removeEldestEntry( + Entry<Question, DNSMessage> eldest) { + return size() > capacity; + } + }; + } + + /** + * Create a new LRUCache with given capacity. + * @param capacity + */ + public LRUCache(final int capacity) { + this(capacity, Long.MAX_VALUE); + } + + @Override + public synchronized void put(Question q, DNSMessage message) { + if (message.getReceiveTimestamp() <= 0l) { + return; + } + backend.put(q, message); + } + + @Override + public synchronized DNSMessage get(Question q) { + DNSMessage message = backend.get(q); + if (message == null) { + missCount++; + return null; + } + + long ttl = maxTTL; + for (Record r : message.getAnswers()) { + ttl = Math.min(ttl, r.ttl); + } + for (Record r : message.getAdditionalResourceRecords()) { + ttl = Math.min(ttl, r.ttl); + } + if (message.getReceiveTimestamp() + ttl > System.currentTimeMillis()) { + missCount++; + expireCount++; + backend.remove(q); + return null; + } else { + hitCount++; + return message; + } + } + + /** + * Clear all entries in this cache. + */ + public synchronized void clear() { + backend.clear(); + missCount = 0l; + hitCount = 0l; + expireCount = 0l; + } + + /** + * Get the miss count of this cache which is the number of fruitless + * get calls since this cache was last resetted. + * @return The number of cache misses. + */ + public long getMissCount() { + return missCount; + } + + /** + * The number of expires (cache hits that have had a ttl to low to be + * retrieved). + * @return The expire count. + */ + public long getExpireCount() { + return expireCount; + } + + /** + * The cache hit count (all sucessful calls to get). + * @return The hit count. + */ + public long getHitCount() { + return hitCount; + } + +} |