aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/measite/minidns/LRUCache.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/measite/minidns/LRUCache.java')
-rw-r--r--src/main/java/de/measite/minidns/LRUCache.java139
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;
+ }
+
+}