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.
129 lines
3.6 KiB
129 lines
3.6 KiB
"Thread-safe in-memory cache backend." |
|
|
|
import time |
|
try: |
|
import cPickle as pickle |
|
except ImportError: |
|
import pickle |
|
|
|
from django.core.cache.backends.base import BaseCache |
|
from django.utils.synch import RWLock |
|
|
|
class CacheClass(BaseCache): |
|
def __init__(self, _, params): |
|
BaseCache.__init__(self, params) |
|
self._cache = {} |
|
self._expire_info = {} |
|
|
|
max_entries = params.get('max_entries', 300) |
|
try: |
|
self._max_entries = int(max_entries) |
|
except (ValueError, TypeError): |
|
self._max_entries = 300 |
|
|
|
cull_frequency = params.get('cull_frequency', 3) |
|
try: |
|
self._cull_frequency = int(cull_frequency) |
|
except (ValueError, TypeError): |
|
self._cull_frequency = 3 |
|
|
|
self._lock = RWLock() |
|
|
|
def add(self, key, value, timeout=None): |
|
self._lock.writer_enters() |
|
try: |
|
exp = self._expire_info.get(key) |
|
if exp is None or exp <= time.time(): |
|
try: |
|
self._set(key, pickle.dumps(value), timeout) |
|
return True |
|
except pickle.PickleError: |
|
pass |
|
return False |
|
finally: |
|
self._lock.writer_leaves() |
|
|
|
def get(self, key, default=None): |
|
self._lock.reader_enters() |
|
try: |
|
exp = self._expire_info.get(key) |
|
if exp is None: |
|
return default |
|
elif exp > time.time(): |
|
try: |
|
return pickle.loads(self._cache[key]) |
|
except pickle.PickleError: |
|
return default |
|
finally: |
|
self._lock.reader_leaves() |
|
self._lock.writer_enters() |
|
try: |
|
del self._cache[key] |
|
del self._expire_info[key] |
|
return default |
|
finally: |
|
self._lock.writer_leaves() |
|
|
|
def _set(self, key, value, timeout=None): |
|
if len(self._cache) >= self._max_entries: |
|
self._cull() |
|
if timeout is None: |
|
timeout = self.default_timeout |
|
self._cache[key] = value |
|
self._expire_info[key] = time.time() + timeout |
|
|
|
def set(self, key, value, timeout=None): |
|
self._lock.writer_enters() |
|
# Python 2.3 and 2.4 don't allow combined try-except-finally blocks. |
|
try: |
|
try: |
|
self._set(key, pickle.dumps(value), timeout) |
|
except pickle.PickleError: |
|
pass |
|
finally: |
|
self._lock.writer_leaves() |
|
|
|
def has_key(self, key): |
|
self._lock.reader_enters() |
|
try: |
|
exp = self._expire_info.get(key) |
|
if exp is None: |
|
return False |
|
elif exp > time.time(): |
|
return True |
|
finally: |
|
self._lock.reader_leaves() |
|
|
|
self._lock.writer_enters() |
|
try: |
|
del self._cache[key] |
|
del self._expire_info[key] |
|
return False |
|
finally: |
|
self._lock.writer_leaves() |
|
|
|
def _cull(self): |
|
if self._cull_frequency == 0: |
|
self._cache.clear() |
|
self._expire_info.clear() |
|
else: |
|
doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0] |
|
for k in doomed: |
|
self._delete(k) |
|
|
|
def _delete(self, key): |
|
try: |
|
del self._cache[key] |
|
except KeyError: |
|
pass |
|
try: |
|
del self._expire_info[key] |
|
except KeyError: |
|
pass |
|
|
|
def delete(self, key): |
|
self._lock.writer_enters() |
|
try: |
|
self._delete(key) |
|
finally: |
|
self._lock.writer_leaves()
|
|
|