1 # -*- test-case-name: twisted.names.test -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
5 from zope.interface import implements
7 from twisted.names import dns, common
8 from twisted.python import failure, log
9 from twisted.internet import interfaces, defer
13 class CacheResolver(common.ResolverBase):
15 A resolver that serves records from a local, memory cache.
17 @ivar _reactor: A provider of L{interfaces.IReactorTime}.
20 implements(interfaces.IResolver)
24 def __init__(self, cache=None, verbose=0, reactor=None):
25 common.ResolverBase.__init__(self)
28 self.verbose = verbose
31 from twisted.internet import reactor
32 self._reactor = reactor
35 for query, (seconds, payload) in cache.items():
36 self.cacheResult(query, payload, seconds)
39 def __setstate__(self, state):
42 now = self._reactor.seconds()
43 for (k, (when, (ans, add, ns))) in self.cache.items():
45 for rec in ans + add + ns:
51 def __getstate__(self):
52 for c in self.cancel.values():
58 def _lookup(self, name, cls, type, timeout):
59 now = self._reactor.seconds()
60 q = dns.Query(name, type, cls)
62 when, (ans, auth, add) = self.cache[q]
65 log.msg('Cache miss for ' + repr(name))
66 return defer.fail(failure.Failure(dns.DomainError(name)))
69 log.msg('Cache hit for ' + repr(name))
71 return defer.succeed((
72 [dns.RRHeader(str(r.name), r.type, r.cls, max(0, r.ttl - diff), r.payload) for r in ans],
73 [dns.RRHeader(str(r.name), r.type, r.cls, max(0, r.ttl - diff), r.payload) for r in auth],
74 [dns.RRHeader(str(r.name), r.type, r.cls, max(0, r.ttl - diff), r.payload) for r in add]
78 def lookupAllRecords(self, name, timeout = None):
79 return defer.fail(failure.Failure(dns.DomainError(name)))
82 def cacheResult(self, query, payload, cacheTime=None):
86 @param query: a L{dns.Query} instance.
88 @param payload: a 3-tuple of lists of L{dns.RRHeader} records, the
89 matching result of the query (answers, authority and additional).
91 @param cacheTime: The time (seconds since epoch) at which the entry is
92 considered to have been added to the cache. If C{None} is given,
93 the current time is used.
96 log.msg('Adding %r to cache' % query)
98 self.cache[query] = (cacheTime or self._reactor.seconds(), payload)
100 if self.cancel.has_key(query):
101 self.cancel[query].cancel()
103 s = list(payload[0]) + list(payload[1]) + list(payload[2])
111 self.cancel[query] = self._reactor.callLater(m, self.clearEntry, query)
114 def clearEntry(self, query):
115 del self.cache[query]
116 del self.cancel[query]