class SafeSimpleCache(BaseCache): """Simple memory cache for multi process environments. :param threshold: the maximum number of items the cache stores before it starts deleting some. :param default_timeout: the default timeout that is used if no timeout is specified on :meth:`~BaseCache.set`. :param pickle: Allows disabling of automatic pickle action if you're just storing basic python objects. """ def __init__(self, threshold=500, default_timeout=300, pickle=True): BaseCache.__init__(self, default_timeout) self._cache = {} self._threshold = threshold self._pickle = pickle self._lock = RWLock() def _serial(self, val): if self._pickle: return pickle.dumps(val, pickle.HIGHEST_PROTOCOL) return val def _deserial(self, val): if self._pickle: return pickle.loads(val) return val def clear(self): with self._lock.writer(): self._cache.clear() return True def _prune(self): with self._lock.reader(): length = len(self._cache) if length > self._threshold: now = time() with self._lock.writer(): for idx, (key, (expires, _)) in enumerate(self._cache.items()): if expires <= now or idx % 3 == 0: self._cache.pop(key, None) def get(self, key): try: with self._lock.reader(): expires, value = self._cache[key] if expires > time(): return self._deserial(value) except (KeyError, pickle.PickleError): return None def set(self, key, value, timeout=None): if timeout is None: timeout = self.default_timeout self._prune() new_key = (time() + timeout, self._serial(value)) with self._lock.writer(): self._cache[key] = new_key return True def add(self, key, value, timeout=None): if timeout is None: timeout = self.default_timeout self._prune() with self._lock.reader(): if key in self._cache: return False item = (time() + timeout, self._serial(value)) with self._lock.writer(): self._cache.setdefault(key, item) return True def delete(self, key): with self._lock.writer(): return self._cache.pop(key, None) is not None