PageRenderTime 36ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/django/core/cache/backends/memcached.py

https://github.com/Tippr/django
Python | 177 lines | 121 code | 28 blank | 28 comment | 18 complexity | 0e2ed4c624d2cbd9d493fbf1844f6213 MD5 | raw file
  1. "Memcached cache backend"
  2. import time
  3. from threading import local
  4. from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
  5. class BaseMemcachedCache(BaseCache):
  6. def __init__(self, server, params, library, value_not_found_exception):
  7. super(BaseMemcachedCache, self).__init__(params)
  8. if isinstance(server, basestring):
  9. self._servers = server.split(';')
  10. else:
  11. self._servers = server
  12. # The exception type to catch from the underlying library for a key
  13. # that was not found. This is a ValueError for python-memcache,
  14. # pylibmc.NotFound for pylibmc, and cmemcache will return None without
  15. # raising an exception.
  16. self.LibraryValueNotFoundException = value_not_found_exception
  17. self._lib = library
  18. self._options = params.get('OPTIONS', None)
  19. @property
  20. def _cache(self):
  21. """
  22. Implements transparent thread-safe access to a memcached client.
  23. """
  24. if getattr(self, '_client', None) is None:
  25. self._client = self._lib.Client(self._servers)
  26. return self._client
  27. def _get_memcache_timeout(self, timeout):
  28. """
  29. Memcached deals with long (> 30 days) timeouts in a special
  30. way. Call this function to obtain a safe value for your timeout.
  31. """
  32. timeout = timeout or self.default_timeout
  33. if timeout > 2592000: # 60*60*24*30, 30 days
  34. # See http://code.google.com/p/memcached/wiki/FAQ
  35. # "You can set expire times up to 30 days in the future. After that
  36. # memcached interprets it as a date, and will expire the item after
  37. # said date. This is a simple (but obscure) mechanic."
  38. #
  39. # This means that we have to switch to absolute timestamps.
  40. timeout += int(time.time())
  41. return int(timeout)
  42. def add(self, key, value, timeout=0, version=None):
  43. key = self.make_key(key, version=version)
  44. return self._cache.add(key, value, self._get_memcache_timeout(timeout))
  45. def get(self, key, default=None, version=None):
  46. key = self.make_key(key, version=version)
  47. val = self._cache.get(key)
  48. if val is None:
  49. return default
  50. return val
  51. def set(self, key, value, timeout=0, version=None):
  52. key = self.make_key(key, version=version)
  53. self._cache.set(key, value, self._get_memcache_timeout(timeout))
  54. def delete(self, key, version=None):
  55. key = self.make_key(key, version=version)
  56. self._cache.delete(key)
  57. def get_many(self, keys, version=None):
  58. new_keys = map(lambda x: self.make_key(x, version=version), keys)
  59. ret = self._cache.get_multi(new_keys)
  60. if ret:
  61. _ = {}
  62. m = dict(zip(new_keys, keys))
  63. for k, v in ret.items():
  64. _[m[k]] = v
  65. ret = _
  66. return ret
  67. def close(self, **kwargs):
  68. self._cache.disconnect_all()
  69. def incr(self, key, delta=1, version=None):
  70. key = self.make_key(key, version=version)
  71. try:
  72. val = self._cache.incr(key, delta)
  73. # python-memcache responds to incr on non-existent keys by
  74. # raising a ValueError, pylibmc by raising a pylibmc.NotFound
  75. # and Cmemcache returns None. In all cases,
  76. # we should raise a ValueError though.
  77. except self.LibraryValueNotFoundException:
  78. val = None
  79. if val is None:
  80. raise ValueError("Key '%s' not found" % key)
  81. return val
  82. def decr(self, key, delta=1, version=None):
  83. key = self.make_key(key, version=version)
  84. try:
  85. val = self._cache.decr(key, delta)
  86. # python-memcache responds to incr on non-existent keys by
  87. # raising a ValueError, pylibmc by raising a pylibmc.NotFound
  88. # and Cmemcache returns None. In all cases,
  89. # we should raise a ValueError though.
  90. except self.LibraryValueNotFoundException:
  91. val = None
  92. if val is None:
  93. raise ValueError("Key '%s' not found" % key)
  94. return val
  95. def set_many(self, data, timeout=0, version=None):
  96. safe_data = {}
  97. for key, value in data.items():
  98. key = self.make_key(key, version=version)
  99. safe_data[key] = value
  100. self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout))
  101. def delete_many(self, keys, version=None):
  102. l = lambda x: self.make_key(x, version=version)
  103. self._cache.delete_multi(map(l, keys))
  104. def clear(self):
  105. self._cache.flush_all()
  106. class CacheClass(BaseMemcachedCache):
  107. def __init__(self, server, params):
  108. import warnings
  109. warnings.warn(
  110. "memcached.CacheClass has been split into memcached.MemcachedCache and memcached.PyLibMCCache. Please update your cache backend setting.",
  111. PendingDeprecationWarning
  112. )
  113. try:
  114. import memcache
  115. except:
  116. raise InvalidCacheBackendError(
  117. "Memcached cache backend requires either the 'memcache' or 'cmemcache' library"
  118. )
  119. super(CacheClass, self).__init__(server, params,
  120. library=memcache,
  121. value_not_found_exception=ValueError)
  122. class MemcachedCache(BaseMemcachedCache):
  123. "An implementation of a cache binding using python-memcached"
  124. def __init__(self, server, params):
  125. import memcache
  126. super(MemcachedCache, self).__init__(server, params,
  127. library=memcache,
  128. value_not_found_exception=ValueError)
  129. class PyLibMCCache(BaseMemcachedCache):
  130. "An implementation of a cache binding using pylibmc"
  131. def __init__(self, server, params):
  132. import pylibmc
  133. self._local = local()
  134. super(PyLibMCCache, self).__init__(server, params,
  135. library=pylibmc,
  136. value_not_found_exception=pylibmc.NotFound)
  137. @property
  138. def _cache(self):
  139. # PylibMC uses cache options as the 'behaviors' attribute.
  140. # It also needs to use threadlocals, because some versions of
  141. # PylibMC don't play well with the GIL.
  142. client = getattr(self._local, 'client', None)
  143. if client:
  144. return client
  145. client = self._lib.Client(self._servers)
  146. if self._options:
  147. client.behaviors = self._options
  148. self._local.client = client
  149. return client