1 "Memcached cache backend" |
1 "Memcached cache backend" |
|
2 |
|
3 import time |
2 |
4 |
3 from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError |
5 from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError |
4 from django.utils.encoding import smart_unicode, smart_str |
6 from django.utils.encoding import smart_unicode, smart_str |
5 |
7 |
6 try: |
8 try: |
7 import cmemcache as memcache |
9 import cmemcache as memcache |
|
10 import warnings |
|
11 warnings.warn( |
|
12 "Support for the 'cmemcache' library has been deprecated. Please use python-memcached instead.", |
|
13 PendingDeprecationWarning |
|
14 ) |
8 except ImportError: |
15 except ImportError: |
9 try: |
16 try: |
10 import memcache |
17 import memcache |
11 except: |
18 except: |
12 raise InvalidCacheBackendError("Memcached cache backend requires either the 'memcache' or 'cmemcache' library") |
19 raise InvalidCacheBackendError("Memcached cache backend requires either the 'memcache' or 'cmemcache' library") |
14 class CacheClass(BaseCache): |
21 class CacheClass(BaseCache): |
15 def __init__(self, server, params): |
22 def __init__(self, server, params): |
16 BaseCache.__init__(self, params) |
23 BaseCache.__init__(self, params) |
17 self._cache = memcache.Client(server.split(';')) |
24 self._cache = memcache.Client(server.split(';')) |
18 |
25 |
|
26 def _get_memcache_timeout(self, timeout): |
|
27 """ |
|
28 Memcached deals with long (> 30 days) timeouts in a special |
|
29 way. Call this function to obtain a safe value for your timeout. |
|
30 """ |
|
31 timeout = timeout or self.default_timeout |
|
32 if timeout > 2592000: # 60*60*24*30, 30 days |
|
33 # See http://code.google.com/p/memcached/wiki/FAQ |
|
34 # "You can set expire times up to 30 days in the future. After that |
|
35 # memcached interprets it as a date, and will expire the item after |
|
36 # said date. This is a simple (but obscure) mechanic." |
|
37 # |
|
38 # This means that we have to switch to absolute timestamps. |
|
39 timeout += int(time.time()) |
|
40 return timeout |
|
41 |
19 def add(self, key, value, timeout=0): |
42 def add(self, key, value, timeout=0): |
20 if isinstance(value, unicode): |
43 if isinstance(value, unicode): |
21 value = value.encode('utf-8') |
44 value = value.encode('utf-8') |
22 return self._cache.add(smart_str(key), value, timeout or self.default_timeout) |
45 return self._cache.add(smart_str(key), value, self._get_memcache_timeout(timeout)) |
23 |
46 |
24 def get(self, key, default=None): |
47 def get(self, key, default=None): |
25 val = self._cache.get(smart_str(key)) |
48 val = self._cache.get(smart_str(key)) |
26 if val is None: |
49 if val is None: |
27 return default |
50 return default |
28 else: |
51 return val |
29 if isinstance(val, basestring): |
|
30 return smart_unicode(val) |
|
31 else: |
|
32 return val |
|
33 |
52 |
34 def set(self, key, value, timeout=0): |
53 def set(self, key, value, timeout=0): |
35 if isinstance(value, unicode): |
54 self._cache.set(smart_str(key), value, self._get_memcache_timeout(timeout)) |
36 value = value.encode('utf-8') |
|
37 self._cache.set(smart_str(key), value, timeout or self.default_timeout) |
|
38 |
55 |
39 def delete(self, key): |
56 def delete(self, key): |
40 self._cache.delete(smart_str(key)) |
57 self._cache.delete(smart_str(key)) |
41 |
58 |
42 def get_many(self, keys): |
59 def get_many(self, keys): |
44 |
61 |
45 def close(self, **kwargs): |
62 def close(self, **kwargs): |
46 self._cache.disconnect_all() |
63 self._cache.disconnect_all() |
47 |
64 |
48 def incr(self, key, delta=1): |
65 def incr(self, key, delta=1): |
49 return self._cache.incr(key, delta) |
66 try: |
|
67 val = self._cache.incr(key, delta) |
|
68 |
|
69 # python-memcache responds to incr on non-existent keys by |
|
70 # raising a ValueError. Cmemcache returns None. In both |
|
71 # cases, we should raise a ValueError though. |
|
72 except ValueError: |
|
73 val = None |
|
74 if val is None: |
|
75 raise ValueError("Key '%s' not found" % key) |
|
76 |
|
77 return val |
50 |
78 |
51 def decr(self, key, delta=1): |
79 def decr(self, key, delta=1): |
52 return self._cache.decr(key, delta) |
80 try: |
|
81 val = self._cache.decr(key, delta) |
|
82 |
|
83 # python-memcache responds to decr on non-existent keys by |
|
84 # raising a ValueError. Cmemcache returns None. In both |
|
85 # cases, we should raise a ValueError though. |
|
86 except ValueError: |
|
87 val = None |
|
88 if val is None: |
|
89 raise ValueError("Key '%s' not found" % key) |
|
90 return val |
|
91 |
|
92 def set_many(self, data, timeout=0): |
|
93 safe_data = {} |
|
94 for key, value in data.items(): |
|
95 if isinstance(value, unicode): |
|
96 value = value.encode('utf-8') |
|
97 safe_data[smart_str(key)] = value |
|
98 self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout)) |
|
99 |
|
100 def delete_many(self, keys): |
|
101 self._cache.delete_multi(map(smart_str, keys)) |
|
102 |
|
103 def clear(self): |
|
104 self._cache.flush_all() |