📄 cache.java
字号:
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)package org.xbill.DNS;import java.io.*;import java.util.*;/** * A cache of DNS records. The cache obeys TTLs, so items are purged after * their validity period is complete. Negative answers are cached, to * avoid repeated failed DNS queries. The credibility of each RRset is * maintained, so that more credible records replace less credible records, * and lookups can specify the minimum credibility of data they are requesting. * @see RRset * @see Credibility * * @author Brian Wellington */public class Cache {private interface Element { public boolean expired(); public int compareCredibility(int cred); public int getType();}private static intlimitExpire(long ttl, long maxttl) { if (maxttl >= 0 && maxttl < ttl) ttl = maxttl; int expire = (int)((System.currentTimeMillis() / 1000) + ttl); if (expire < 0 || expire > Integer.MAX_VALUE) return Integer.MAX_VALUE; return expire;}private static class CacheRRset extends RRset implements Element { int credibility; int expire; public CacheRRset(Record rec, int cred, long maxttl) { super(); this.credibility = cred; this.expire = limitExpire(rec.getTTL(), maxttl); addRR(rec); } public CacheRRset(RRset rrset, int cred, long maxttl) { super(rrset); this.credibility = cred; this.expire = limitExpire(rrset.getTTL(), maxttl); } public final boolean expired() { int now = (int)(System.currentTimeMillis() / 1000); return (now >= expire); } public final int compareCredibility(int cred) { return credibility - cred; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append(super.toString()); sb.append(" cl = "); sb.append(credibility); return sb.toString(); }}private static class NegativeElement implements Element { int type; Name name; SOARecord soa; int credibility; int expire; public NegativeElement(Name name, int type, SOARecord soa, int cred, long maxttl) { this.name = name; this.type = type; this.soa = soa; long cttl = 0; if (soa != null) cttl = soa.getMinimum(); this.credibility = cred; this.expire = limitExpire(cttl, maxttl); } public int getType() { return type; } public final boolean expired() { int now = (int)(System.currentTimeMillis() / 1000); return (now >= expire); } public final int compareCredibility(int cred) { return credibility - cred; } public String toString() { StringBuffer sb = new StringBuffer(); if (type == 0) sb.append("NXDOMAIN " + name); else sb.append("NXRRSET " + name + " " + Type.string(type)); sb.append(" cl = "); sb.append(credibility); return sb.toString(); }}private static class CacheMap extends LinkedHashMap { private int maxsize = -1; CacheMap(int maxsize) { super(16, (float) 0.75, true); this.maxsize = maxsize; } int getMaxSize() { return maxsize; } void setMaxSize(int maxsize) { /* * Note that this doesn't shrink the size of the map if * the maximum size is lowered, but it should shrink as * entries expire. */ this.maxsize = maxsize; } protected boolean removeEldestEntry(Map.Entry eldest) { return maxsize >= 0 && size() > maxsize; }}private CacheMap data;private int maxncache = -1;private int maxcache = -1;private int dclass;private static final int defaultMaxEntries = 50000;/** * Creates an empty Cache * * @param dclass The DNS class of this cache * @see DClass */publicCache(int dclass) { this.dclass = dclass; data = new CacheMap(defaultMaxEntries);}/** * Creates an empty Cache for class IN. * @see DClass */publicCache() { this(DClass.IN);}/** * Creates a Cache which initially contains all records in the specified file. */publicCache(String file) throws IOException { data = new CacheMap(defaultMaxEntries); Master m = new Master(file); Record record; while ((record = m.nextRecord()) != null) addRecord(record, Credibility.HINT, m);}private synchronized ObjectexactName(Name name) { return data.get(name);}private synchronized voidremoveName(Name name) { data.remove(name);}private synchronized Element []allElements(Object types) { if (types instanceof List) { List typelist = (List) types; int size = typelist.size(); return (Element []) typelist.toArray(new Element[size]); } else { Element set = (Element) types; return new Element[] {set}; }}private synchronized ElementoneElement(Name name, Object types, int type, int minCred) { Element found = null; if (type == Type.ANY) throw new IllegalArgumentException("oneElement(ANY)"); if (types instanceof List) { List list = (List) types; for (int i = 0; i < list.size(); i++) { Element set = (Element) list.get(i); if (set.getType() == type) { found = set; break; } } } else { Element set = (Element) types; if (set.getType() == type) found = set; } if (found == null) return null; if (found.expired()) { removeElement(name, type); return null; } if (found.compareCredibility(minCred) < 0) return null; return found;}private synchronized ElementfindElement(Name name, int type, int minCred) { Object types = exactName(name); if (types == null) return null; return oneElement(name, types, type, minCred);}private synchronized voidaddElement(Name name, Element element) { Object types = data.get(name); if (types == null) { data.put(name, element); return; } int type = element.getType(); if (types instanceof List) { List list = (List) types; for (int i = 0; i < list.size(); i++) { Element elt = (Element) list.get(i); if (elt.getType() == type) { list.set(i, element); return; } } list.add(element); } else { Element elt = (Element) types; if (elt.getType() == type) data.put(name, element); else { LinkedList list = new LinkedList(); list.add(elt); list.add(element); data.put(name, list); } }}private synchronized voidremoveElement(Name name, int type) { Object types = data.get(name); if (types == null) { return; } if (types instanceof List) { List list = (List) types; for (int i = 0; i < list.size(); i++) { Element elt = (Element) list.get(i); if (elt.getType() == type) { list.remove(i); if (list.size() == 0) data.remove(name); return; } } } else { Element elt = (Element) types; if (elt.getType() != type) return; data.remove(name); }}/** Empties the Cache. */public synchronized voidclearCache() { data.clear();}/** * Adds a record to the Cache. * @param r The record to be added * @param cred The credibility of the record * @param o The source of the record (this could be a Message, for example) * @see Record */public synchronized voidaddRecord(Record r, int cred, Object o) { Name name = r.getName(); int type = r.getRRsetType(); if (!Type.isRR(type)) return; Element element = findElement(name, type, cred); if (element == null) { CacheRRset crrset = new CacheRRset(r, cred, maxcache); addRRset(crrset, cred); } else if (element.compareCredibility(cred) == 0) { if (element instanceof CacheRRset) { CacheRRset crrset = (CacheRRset) element; crrset.addRR(r); } }}/** * Adds an RRset to the Cache. * @param rrset The RRset to be added * @param cred The credibility of these records * @see RRset */public synchronized voidaddRRset(RRset rrset, int cred) { long ttl = rrset.getTTL(); Name name = rrset.getName(); int type = rrset.getType(); Element element = findElement(name, type, 0); if (ttl == 0) { if (element != null && element.compareCredibility(cred) <= 0) removeElement(name, type); } else { if (element != null && element.compareCredibility(cred) <= 0) element = null; if (element == null) { CacheRRset crrset; if (rrset instanceof CacheRRset) crrset = (CacheRRset) rrset; else crrset = new CacheRRset(rrset, cred, maxcache); addElement(name, crrset); } }}/** * Adds a negative entry to the Cache. * @param name The name of the negative entry * @param type The type of the negative entry * @param soa The SOA record to add to the negative cache entry, or null. * The negative cache ttl is derived from the SOA. * @param cred The credibility of the negative entry */public synchronized voidaddNegative(Name name, int type, SOARecord soa, int cred) { long ttl = 0; if (soa != null) ttl = soa.getTTL(); Element element = findElement(name, type, 0); if (ttl == 0) { if (element != null && element.compareCredibility(cred) <= 0) removeElement(name, type); } else { if (element != null && element.compareCredibility(cred) <= 0) element = null; if (element == null) addElement(name, new NegativeElement(name, type, soa, cred, maxncache)); }}/** * Finds all matching sets or something that causes the lookup to stop. */protected synchronized SetResponselookup(Name name, int type, int minCred) { int labels; int tlabels; Element element; CacheRRset crrset; Name tname; Object types; SetResponse sr; labels = name.labels(); for (tlabels = labels; tlabels >= 1; tlabels--) { boolean isRoot = (tlabels == 1); boolean isExact = (tlabels == labels); if (isRoot) tname = Name.root; else if (isExact) tname = name; else tname = new Name(name, labels - tlabels); types = data.get(tname); if (types == null)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -