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.

base.py 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. "Base Cache class."
  2. import time
  3. import warnings
  4. from django.core.exceptions import ImproperlyConfigured
  5. from django.utils.module_loading import import_string
  6. class InvalidCacheBackendError(ImproperlyConfigured):
  7. pass
  8. class CacheKeyWarning(RuntimeWarning):
  9. pass
  10. # Stub class to ensure not passing in a `timeout` argument results in
  11. # the default timeout
  12. DEFAULT_TIMEOUT = object()
  13. # Memcached does not accept keys longer than this.
  14. MEMCACHE_MAX_KEY_LENGTH = 250
  15. def default_key_func(key, key_prefix, version):
  16. """
  17. Default function to generate keys.
  18. Construct the key used by all other methods. By default, prepend
  19. the `key_prefix'. KEY_FUNCTION can be used to specify an alternate
  20. function with custom key making behavior.
  21. """
  22. return '%s:%s:%s' % (key_prefix, version, key)
  23. def get_key_func(key_func):
  24. """
  25. Function to decide which key function to use.
  26. Default to ``default_key_func``.
  27. """
  28. if key_func is not None:
  29. if callable(key_func):
  30. return key_func
  31. else:
  32. return import_string(key_func)
  33. return default_key_func
  34. class BaseCache:
  35. def __init__(self, params):
  36. timeout = params.get('timeout', params.get('TIMEOUT', 300))
  37. if timeout is not None:
  38. try:
  39. timeout = int(timeout)
  40. except (ValueError, TypeError):
  41. timeout = 300
  42. self.default_timeout = timeout
  43. options = params.get('OPTIONS', {})
  44. max_entries = params.get('max_entries', options.get('MAX_ENTRIES', 300))
  45. try:
  46. self._max_entries = int(max_entries)
  47. except (ValueError, TypeError):
  48. self._max_entries = 300
  49. cull_frequency = params.get('cull_frequency', options.get('CULL_FREQUENCY', 3))
  50. try:
  51. self._cull_frequency = int(cull_frequency)
  52. except (ValueError, TypeError):
  53. self._cull_frequency = 3
  54. self.key_prefix = params.get('KEY_PREFIX', '')
  55. self.version = params.get('VERSION', 1)
  56. self.key_func = get_key_func(params.get('KEY_FUNCTION'))
  57. def get_backend_timeout(self, timeout=DEFAULT_TIMEOUT):
  58. """
  59. Return the timeout value usable by this backend based upon the provided
  60. timeout.
  61. """
  62. if timeout == DEFAULT_TIMEOUT:
  63. timeout = self.default_timeout
  64. elif timeout == 0:
  65. # ticket 21147 - avoid time.time() related precision issues
  66. timeout = -1
  67. return None if timeout is None else time.time() + timeout
  68. def make_key(self, key, version=None):
  69. """
  70. Construct the key used by all other methods. By default, use the
  71. key_func to generate a key (which, by default, prepends the
  72. `key_prefix' and 'version'). A different key function can be provided
  73. at the time of cache construction; alternatively, you can subclass the
  74. cache backend to provide custom key making behavior.
  75. """
  76. if version is None:
  77. version = self.version
  78. new_key = self.key_func(key, self.key_prefix, version)
  79. return new_key
  80. def add(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
  81. """
  82. Set a value in the cache if the key does not already exist. If
  83. timeout is given, use that timeout for the key; otherwise use the
  84. default cache timeout.
  85. Return True if the value was stored, False otherwise.
  86. """
  87. raise NotImplementedError('subclasses of BaseCache must provide an add() method')
  88. def get(self, key, default=None, version=None):
  89. """
  90. Fetch a given key from the cache. If the key does not exist, return
  91. default, which itself defaults to None.
  92. """
  93. raise NotImplementedError('subclasses of BaseCache must provide a get() method')
  94. def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
  95. """
  96. Set a value in the cache. If timeout is given, use that timeout for the
  97. key; otherwise use the default cache timeout.
  98. """
  99. raise NotImplementedError('subclasses of BaseCache must provide a set() method')
  100. def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):
  101. """
  102. Update the key's expiry time using timeout. Return True if successful
  103. or False if the key does not exist.
  104. """
  105. raise NotImplementedError('subclasses of BaseCache must provide a touch() method')
  106. def delete(self, key, version=None):
  107. """
  108. Delete a key from the cache, failing silently.
  109. """
  110. raise NotImplementedError('subclasses of BaseCache must provide a delete() method')
  111. def get_many(self, keys, version=None):
  112. """
  113. Fetch a bunch of keys from the cache. For certain backends (memcached,
  114. pgsql) this can be *much* faster when fetching multiple values.
  115. Return a dict mapping each key in keys to its value. If the given
  116. key is missing, it will be missing from the response dict.
  117. """
  118. d = {}
  119. for k in keys:
  120. val = self.get(k, version=version)
  121. if val is not None:
  122. d[k] = val
  123. return d
  124. def get_or_set(self, key, default, timeout=DEFAULT_TIMEOUT, version=None):
  125. """
  126. Fetch a given key from the cache. If the key does not exist,
  127. add the key and set it to the default value. The default value can
  128. also be any callable. If timeout is given, use that timeout for the
  129. key; otherwise use the default cache timeout.
  130. Return the value of the key stored or retrieved.
  131. """
  132. val = self.get(key, version=version)
  133. if val is None:
  134. if callable(default):
  135. default = default()
  136. if default is not None:
  137. self.add(key, default, timeout=timeout, version=version)
  138. # Fetch the value again to avoid a race condition if another
  139. # caller added a value between the first get() and the add()
  140. # above.
  141. return self.get(key, default, version=version)
  142. return val
  143. def has_key(self, key, version=None):
  144. """
  145. Return True if the key is in the cache and has not expired.
  146. """
  147. return self.get(key, version=version) is not None
  148. def incr(self, key, delta=1, version=None):
  149. """
  150. Add delta to value in the cache. If the key does not exist, raise a
  151. ValueError exception.
  152. """
  153. value = self.get(key, version=version)
  154. if value is None:
  155. raise ValueError("Key '%s' not found" % key)
  156. new_value = value + delta
  157. self.set(key, new_value, version=version)
  158. return new_value
  159. def decr(self, key, delta=1, version=None):
  160. """
  161. Subtract delta from value in the cache. If the key does not exist, raise
  162. a ValueError exception.
  163. """
  164. return self.incr(key, -delta, version=version)
  165. def __contains__(self, key):
  166. """
  167. Return True if the key is in the cache and has not expired.
  168. """
  169. # This is a separate method, rather than just a copy of has_key(),
  170. # so that it always has the same functionality as has_key(), even
  171. # if a subclass overrides it.
  172. return self.has_key(key)
  173. def set_many(self, data, timeout=DEFAULT_TIMEOUT, version=None):
  174. """
  175. Set a bunch of values in the cache at once from a dict of key/value
  176. pairs. For certain backends (memcached), this is much more efficient
  177. than calling set() multiple times.
  178. If timeout is given, use that timeout for the key; otherwise use the
  179. default cache timeout.
  180. On backends that support it, return a list of keys that failed
  181. insertion, or an empty list if all keys were inserted successfully.
  182. """
  183. for key, value in data.items():
  184. self.set(key, value, timeout=timeout, version=version)
  185. return []
  186. def delete_many(self, keys, version=None):
  187. """
  188. Delete a bunch of values in the cache at once. For certain backends
  189. (memcached), this is much more efficient than calling delete() multiple
  190. times.
  191. """
  192. for key in keys:
  193. self.delete(key, version=version)
  194. def clear(self):
  195. """Remove *all* values from the cache at once."""
  196. raise NotImplementedError('subclasses of BaseCache must provide a clear() method')
  197. def validate_key(self, key):
  198. """
  199. Warn about keys that would not be portable to the memcached
  200. backend. This encourages (but does not force) writing backend-portable
  201. cache code.
  202. """
  203. if len(key) > MEMCACHE_MAX_KEY_LENGTH:
  204. warnings.warn(
  205. 'Cache key will cause errors if used with memcached: %r '
  206. '(longer than %s)' % (key, MEMCACHE_MAX_KEY_LENGTH), CacheKeyWarning
  207. )
  208. for char in key:
  209. if ord(char) < 33 or ord(char) == 127:
  210. warnings.warn(
  211. 'Cache key contains characters that will cause errors if '
  212. 'used with memcached: %r' % key, CacheKeyWarning
  213. )
  214. break
  215. def incr_version(self, key, delta=1, version=None):
  216. """
  217. Add delta to the cache version for the supplied key. Return the new
  218. version.
  219. """
  220. if version is None:
  221. version = self.version
  222. value = self.get(key, version=version)
  223. if value is None:
  224. raise ValueError("Key '%s' not found" % key)
  225. self.set(key, value, version=version + delta)
  226. self.delete(key, version=version)
  227. return version + delta
  228. def decr_version(self, key, delta=1, version=None):
  229. """
  230. Subtract delta from the cache version for the supplied key. Return the
  231. new version.
  232. """
  233. return self.incr_version(key, -delta, version)
  234. def close(self, **kwargs):
  235. """Close the cache connection"""
  236. pass