app/django/core/cache/backends/locmem.py
changeset 54 03e267d67478
child 323 ff1a9aa48cfd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/core/cache/backends/locmem.py	Fri Jul 18 18:22:23 2008 +0000
@@ -0,0 +1,127 @@
+"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)
+                except pickle.PickleError:
+                    pass
+        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()