aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/measite/minidns/LRUCache.java
blob: 6b9bbdc1f1b512feb1aaa5b1170c430122648fd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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 + (capacity + 3) / 4 + 2, 11), 0.75f, true)
            {
                @Override
                protected boolean removeEldestEntry(
                        Entry<Question, DNSMessage> eldest) {
                    return size() > capacity;
                }
            };
    }

    /**
     * Create a new LRUCache with given capacity.
     * @param capacity The capacity of this cache.
     */
    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;
    }

}