OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.names.test -*- | |
2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
3 # See LICENSE for details. | |
4 | |
5 | |
6 import time | |
7 | |
8 from zope.interface import implements | |
9 | |
10 from twisted.names import dns | |
11 from twisted.python import failure, log | |
12 from twisted.internet import interfaces, defer | |
13 | |
14 import common | |
15 | |
16 class CacheResolver(common.ResolverBase): | |
17 """A resolver that serves records from a local, memory cache.""" | |
18 | |
19 implements(interfaces.IResolver) | |
20 | |
21 cache = None | |
22 | |
23 def __init__(self, cache = None, verbose = 0): | |
24 common.ResolverBase.__init__(self) | |
25 | |
26 if cache is None: | |
27 cache = {} | |
28 self.cache = cache | |
29 self.verbose = verbose | |
30 self.cancel = {} | |
31 | |
32 | |
33 def __setstate__(self, state): | |
34 self.__dict__ = state | |
35 | |
36 now = time.time() | |
37 for (k, (when, (ans, add, ns))) in self.cache.items(): | |
38 diff = now - when | |
39 for rec in ans + add + ns: | |
40 if rec.ttl < diff: | |
41 del self.cache[k] | |
42 break | |
43 | |
44 | |
45 def __getstate__(self): | |
46 for c in self.cancel.values(): | |
47 c.cancel() | |
48 self.cancel.clear() | |
49 return self.__dict__ | |
50 | |
51 | |
52 def _lookup(self, name, cls, type, timeout): | |
53 now = time.time() | |
54 q = dns.Query(name, type, cls) | |
55 try: | |
56 when, (ans, auth, add) = self.cache[q] | |
57 except KeyError: | |
58 if self.verbose > 1: | |
59 log.msg('Cache miss for ' + repr(name)) | |
60 return defer.fail(failure.Failure(dns.DomainError(name))) | |
61 else: | |
62 if self.verbose: | |
63 log.msg('Cache hit for ' + repr(name)) | |
64 diff = now - when | |
65 return defer.succeed(( | |
66 [dns.RRHeader(str(r.name), r.type, r.cls, r.ttl - diff, r.payloa
d) for r in ans], | |
67 [dns.RRHeader(str(r.name), r.type, r.cls, r.ttl - diff, r.payloa
d) for r in auth], | |
68 [dns.RRHeader(str(r.name), r.type, r.cls, r.ttl - diff, r.payloa
d) for r in add] | |
69 )) | |
70 | |
71 | |
72 def lookupAllRecords(self, name, timeout = None): | |
73 return defer.fail(failure.Failure(dns.DomainError(name))) | |
74 | |
75 | |
76 def cacheResult(self, query, payload): | |
77 if self.verbose > 1: | |
78 log.msg('Adding %r to cache' % query) | |
79 | |
80 self.cache[query] = (time.time(), payload) | |
81 | |
82 if self.cancel.has_key(query): | |
83 self.cancel[query].cancel() | |
84 | |
85 s = list(payload[0]) + list(payload[1]) + list(payload[2]) | |
86 m = s[0].ttl | |
87 for r in s: | |
88 m = min(m, r.ttl) | |
89 | |
90 from twisted.internet import reactor | |
91 self.cancel[query] = reactor.callLater(m, self.clearEntry, query) | |
92 | |
93 | |
94 def clearEntry(self, query): | |
95 del self.cache[query] | |
96 del self.cancel[query] | |
OLD | NEW |