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.

locmem.py 4.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. "Thread-safe in-memory cache backend."
  2. import pickle
  3. import time
  4. from collections import OrderedDict
  5. from threading import Lock
  6. from django.core.cache.backends.base import DEFAULT_TIMEOUT, BaseCache
  7. # Global in-memory store of cache data. Keyed by name, to provide
  8. # multiple named local memory caches.
  9. _caches = {}
  10. _expire_info = {}
  11. _locks = {}
  12. class LocMemCache(BaseCache):
  13. pickle_protocol = pickle.HIGHEST_PROTOCOL
  14. def __init__(self, name, params):
  15. super().__init__(params)
  16. self._cache = _caches.setdefault(name, OrderedDict())
  17. self._expire_info = _expire_info.setdefault(name, {})
  18. self._lock = _locks.setdefault(name, Lock())
  19. def add(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
  20. key = self.make_key(key, version=version)
  21. self.validate_key(key)
  22. pickled = pickle.dumps(value, self.pickle_protocol)
  23. with self._lock:
  24. if self._has_expired(key):
  25. self._set(key, pickled, timeout)
  26. return True
  27. return False
  28. def get(self, key, default=None, version=None):
  29. key = self.make_key(key, version=version)
  30. self.validate_key(key)
  31. with self._lock:
  32. if self._has_expired(key):
  33. self._delete(key)
  34. return default
  35. pickled = self._cache[key]
  36. self._cache.move_to_end(key, last=False)
  37. return pickle.loads(pickled)
  38. def _set(self, key, value, timeout=DEFAULT_TIMEOUT):
  39. if len(self._cache) >= self._max_entries:
  40. self._cull()
  41. self._cache[key] = value
  42. self._cache.move_to_end(key, last=False)
  43. self._expire_info[key] = self.get_backend_timeout(timeout)
  44. def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
  45. key = self.make_key(key, version=version)
  46. self.validate_key(key)
  47. pickled = pickle.dumps(value, self.pickle_protocol)
  48. with self._lock:
  49. self._set(key, pickled, timeout)
  50. def touch(self, key, timeout=DEFAULT_TIMEOUT, version=None):
  51. key = self.make_key(key, version=version)
  52. with self._lock:
  53. if self._has_expired(key):
  54. return False
  55. self._expire_info[key] = self.get_backend_timeout(timeout)
  56. return True
  57. def incr(self, key, delta=1, version=None):
  58. key = self.make_key(key, version=version)
  59. self.validate_key(key)
  60. with self._lock:
  61. if self._has_expired(key):
  62. self._delete(key)
  63. raise ValueError("Key '%s' not found" % key)
  64. pickled = self._cache[key]
  65. value = pickle.loads(pickled)
  66. new_value = value + delta
  67. pickled = pickle.dumps(new_value, self.pickle_protocol)
  68. self._cache[key] = pickled
  69. self._cache.move_to_end(key, last=False)
  70. return new_value
  71. def has_key(self, key, version=None):
  72. key = self.make_key(key, version=version)
  73. self.validate_key(key)
  74. with self._lock:
  75. if self._has_expired(key):
  76. self._delete(key)
  77. return False
  78. return True
  79. def _has_expired(self, key):
  80. exp = self._expire_info.get(key, -1)
  81. return exp is not None and exp <= time.time()
  82. def _cull(self):
  83. if self._cull_frequency == 0:
  84. self._cache.clear()
  85. self._expire_info.clear()
  86. else:
  87. count = len(self._cache) // self._cull_frequency
  88. for i in range(count):
  89. key, _ = self._cache.popitem()
  90. del self._expire_info[key]
  91. def _delete(self, key):
  92. try:
  93. del self._cache[key]
  94. del self._expire_info[key]
  95. except KeyError:
  96. pass
  97. def delete(self, key, version=None):
  98. key = self.make_key(key, version=version)
  99. self.validate_key(key)
  100. with self._lock:
  101. self._delete(key)
  102. def clear(self):
  103. with self._lock:
  104. self._cache.clear()
  105. self._expire_info.clear()