Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cache.py 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. # -*- test-case-name: twisted.names.test -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. An in-memory caching resolver.
  6. """
  7. from twisted.internet import defer
  8. from twisted.names import common, dns
  9. from twisted.python import failure, log
  10. class CacheResolver(common.ResolverBase):
  11. """
  12. A resolver that serves records from a local, memory cache.
  13. @ivar _reactor: A provider of L{interfaces.IReactorTime}.
  14. """
  15. cache = None
  16. def __init__(self, cache=None, verbose=0, reactor=None):
  17. common.ResolverBase.__init__(self)
  18. self.cache = {}
  19. self.verbose = verbose
  20. self.cancel = {}
  21. if reactor is None:
  22. from twisted.internet import reactor
  23. self._reactor = reactor
  24. if cache:
  25. for query, (seconds, payload) in cache.items():
  26. self.cacheResult(query, payload, seconds)
  27. def __setstate__(self, state):
  28. self.__dict__ = state
  29. now = self._reactor.seconds()
  30. for (k, (when, (ans, add, ns))) in self.cache.items():
  31. diff = now - when
  32. for rec in ans + add + ns:
  33. if rec.ttl < diff:
  34. del self.cache[k]
  35. break
  36. def __getstate__(self):
  37. for c in self.cancel.values():
  38. c.cancel()
  39. self.cancel.clear()
  40. return self.__dict__
  41. def _lookup(self, name, cls, type, timeout):
  42. now = self._reactor.seconds()
  43. q = dns.Query(name, type, cls)
  44. try:
  45. when, (ans, auth, add) = self.cache[q]
  46. except KeyError:
  47. if self.verbose > 1:
  48. log.msg("Cache miss for " + repr(name))
  49. return defer.fail(failure.Failure(dns.DomainError(name)))
  50. else:
  51. if self.verbose:
  52. log.msg("Cache hit for " + repr(name))
  53. diff = now - when
  54. try:
  55. result = (
  56. [
  57. dns.RRHeader(
  58. r.name.name, r.type, r.cls, r.ttl - diff, r.payload
  59. )
  60. for r in ans
  61. ],
  62. [
  63. dns.RRHeader(
  64. r.name.name, r.type, r.cls, r.ttl - diff, r.payload
  65. )
  66. for r in auth
  67. ],
  68. [
  69. dns.RRHeader(
  70. r.name.name, r.type, r.cls, r.ttl - diff, r.payload
  71. )
  72. for r in add
  73. ],
  74. )
  75. except ValueError:
  76. return defer.fail(failure.Failure(dns.DomainError(name)))
  77. else:
  78. return defer.succeed(result)
  79. def lookupAllRecords(self, name, timeout=None):
  80. return defer.fail(failure.Failure(dns.DomainError(name)))
  81. def cacheResult(self, query, payload, cacheTime=None):
  82. """
  83. Cache a DNS entry.
  84. @param query: a L{dns.Query} instance.
  85. @param payload: a 3-tuple of lists of L{dns.RRHeader} records, the
  86. matching result of the query (answers, authority and additional).
  87. @param cacheTime: The time (seconds since epoch) at which the entry is
  88. considered to have been added to the cache. If L{None} is given,
  89. the current time is used.
  90. """
  91. if self.verbose > 1:
  92. log.msg("Adding %r to cache" % query)
  93. self.cache[query] = (cacheTime or self._reactor.seconds(), payload)
  94. if query in self.cancel:
  95. self.cancel[query].cancel()
  96. s = list(payload[0]) + list(payload[1]) + list(payload[2])
  97. if s:
  98. m = s[0].ttl
  99. for r in s:
  100. m = min(m, r.ttl)
  101. else:
  102. m = 0
  103. self.cancel[query] = self._reactor.callLater(m, self.clearEntry, query)
  104. def clearEntry(self, query):
  105. del self.cache[query]
  106. del self.cancel[query]