Ticket #6124: locmem.py

File locmem.py, 4.0 KB (added by Luke Loeffler <lukerl@…>, 16 years ago)
Line 
1"Thread-safe in-memory cache backend."
2
3import time
4try:
5 import cPickle as pickle
6except ImportError:
7 import pickle
8
9from django.core.cache.backends.base import BaseCache
10from django.utils.synch import RWLock
11
12class CacheClass(BaseCache):
13 def __init__(self, _, params):
14 BaseCache.__init__(self, params)
15 self._cache = {}
16 self._expire_info = {}
17
18 if "nopickle" in params and params["nopickle"] == "True":
19 self.nopickle = True
20 else:
21 self.nopickle = False
22
23 max_entries = params.get('max_entries', 300)
24 try:
25 self._max_entries = int(max_entries)
26 except (ValueError, TypeError):
27 self._max_entries = 300
28
29 cull_frequency = params.get('cull_frequency', 3)
30 try:
31 self._cull_frequency = int(cull_frequency)
32 except (ValueError, TypeError):
33 self._cull_frequency = 3
34
35 self._lock = RWLock()
36
37 def _add(self, key, value, timeout=None):
38 if len(self._cache) >= self._max_entries:
39 self._cull()
40 if timeout is None:
41 timeout = self.default_timeout
42 if key not in self._cache.keys():
43 self._cache[key] = value
44 self._expire_info[key] = time.time() + timeout
45
46 def add(self, key, value, timeout=None):
47 self._lock.writer_enters()
48 # Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
49 try:
50 try:
51 self._add(key, pickle.dumps(value), timeout)
52 except pickle.PickleError:
53 pass
54 finally:
55 self._lock.writer_leaves()
56
57 def get(self, key, default=None):
58 should_delete = False
59 self._lock.reader_enters()
60 try:
61 now = time.time()
62 exp = self._expire_info.get(key)
63 if exp is None:
64 return default
65 elif exp < now:
66 should_delete = True
67 else:
68 if self.nopickle:
69 return self._cache[key]
70 else:
71 try:
72 return pickle.loads(self._cache[key])
73 except pickle.PickleError:
74 return default
75 finally:
76 self._lock.reader_leaves()
77 if should_delete:
78 self._lock.writer_enters()
79 try:
80 del self._cache[key]
81 del self._expire_info[key]
82 return default
83 finally:
84 self._lock.writer_leaves()
85
86 def _set(self, key, value, timeout=None):
87 if len(self._cache) >= self._max_entries:
88 self._cull()
89 if timeout is None:
90 timeout = self.default_timeout
91 self._cache[key] = value
92 self._expire_info[key] = time.time() + timeout
93
94 def set(self, key, value, timeout=None):
95 self._lock.writer_enters()
96 # Python 2.3 and 2.4 don't allow combined try-except-finally blocks.
97 try:
98 if self.nopickle:
99 self._set(key, value, timeout)
100 else:
101 try:
102 self._set(key, pickle.dumps(value), timeout)
103 except pickle.PickleError:
104 pass
105 finally:
106 self._lock.writer_leaves()
107
108 def has_key(self, key):
109 return key in self._cache
110
111 def _cull(self):
112 if self._cull_frequency == 0:
113 self._cache.clear()
114 self._expire_info.clear()
115 else:
116 doomed = [k for (i, k) in enumerate(self._cache) if i % self._cull_frequency == 0]
117 for k in doomed:
118 self.delete(k)
119
120 def _delete(self, key):
121 try:
122 del self._cache[key]
123 except KeyError:
124 pass
125 try:
126 del self._expire_info[key]
127 except KeyError:
128 pass
129
130 def delete(self, key):
131 self._lock.writer_enters()
132 try:
133 self._delete(key)
134 finally:
135 self._lock.writer_leaves()
Back to Top