1# -*- coding: utf-8 -*- 2from time import time 3try: 4 import cPickle as pickle 5except ImportError: # pragma: no cover 6 import pickle 7 8from cachelib.base import BaseCache 9 10 11class SimpleCache(BaseCache): 12 13 """Simple memory cache for single process environments. This class exists 14 mainly for the development server and is not 100% thread safe. It tries 15 to use as many atomic operations as possible and no locks for simplicity 16 but it could happen under heavy load that keys are added multiple times. 17 18 :param threshold: the maximum number of items the cache stores before 19 it starts deleting some. 20 :param default_timeout: the default timeout that is used if no timeout is 21 specified on :meth:`~BaseCache.set`. A timeout of 22 0 indicates that the cache never expires. 23 """ 24 25 def __init__(self, threshold=500, default_timeout=300): 26 BaseCache.__init__(self, default_timeout) 27 self._cache = {} 28 self.clear = self._cache.clear 29 self._threshold = threshold 30 31 def _prune(self): 32 if len(self._cache) > self._threshold: 33 now = time() 34 toremove = [] 35 for idx, (key, (expires, _)) in enumerate(self._cache.items()): 36 if (expires != 0 and expires <= now) or idx % 3 == 0: 37 toremove.append(key) 38 for key in toremove: 39 self._cache.pop(key, None) 40 41 def _normalize_timeout(self, timeout): 42 timeout = BaseCache._normalize_timeout(self, timeout) 43 if timeout > 0: 44 timeout = time() + timeout 45 return timeout 46 47 def get(self, key): 48 try: 49 expires, value = self._cache[key] 50 if expires == 0 or expires > time(): 51 return pickle.loads(value) 52 except (KeyError, pickle.PickleError): 53 return None 54 55 def set(self, key, value, timeout=None): 56 expires = self._normalize_timeout(timeout) 57 self._prune() 58 self._cache[key] = (expires, pickle.dumps(value, 59 pickle.HIGHEST_PROTOCOL)) 60 return True 61 62 def add(self, key, value, timeout=None): 63 expires = self._normalize_timeout(timeout) 64 self._prune() 65 item = (expires, pickle.dumps(value, 66 pickle.HIGHEST_PROTOCOL)) 67 if key in self._cache: 68 return False 69 self._cache.setdefault(key, item) 70 return True 71 72 def delete(self, key): 73 return self._cache.pop(key, None) is not None 74 75 def has(self, key): 76 try: 77 expires, value = self._cache[key] 78 return expires == 0 or expires > time() 79 except KeyError: 80 return False 81