|
0
|
1 |
"Memcached cache backend" |
|
|
2 |
|
|
29
|
3 |
import time |
|
|
4 |
|
|
0
|
5 |
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError |
|
|
6 |
from django.utils.encoding import smart_unicode, smart_str |
|
|
7 |
|
|
|
8 |
try: |
|
|
9 |
import cmemcache as memcache |
|
29
|
10 |
import warnings |
|
|
11 |
warnings.warn( |
|
|
12 |
"Support for the 'cmemcache' library has been deprecated. Please use python-memcached instead.", |
|
|
13 |
PendingDeprecationWarning |
|
|
14 |
) |
|
0
|
15 |
except ImportError: |
|
|
16 |
try: |
|
|
17 |
import memcache |
|
|
18 |
except: |
|
|
19 |
raise InvalidCacheBackendError("Memcached cache backend requires either the 'memcache' or 'cmemcache' library") |
|
|
20 |
|
|
|
21 |
class CacheClass(BaseCache): |
|
|
22 |
def __init__(self, server, params): |
|
|
23 |
BaseCache.__init__(self, params) |
|
|
24 |
self._cache = memcache.Client(server.split(';')) |
|
|
25 |
|
|
29
|
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 |
|
|
0
|
42 |
def add(self, key, value, timeout=0): |
|
|
43 |
if isinstance(value, unicode): |
|
|
44 |
value = value.encode('utf-8') |
|
29
|
45 |
return self._cache.add(smart_str(key), value, self._get_memcache_timeout(timeout)) |
|
0
|
46 |
|
|
|
47 |
def get(self, key, default=None): |
|
|
48 |
val = self._cache.get(smart_str(key)) |
|
|
49 |
if val is None: |
|
|
50 |
return default |
|
29
|
51 |
return val |
|
0
|
52 |
|
|
|
53 |
def set(self, key, value, timeout=0): |
|
29
|
54 |
self._cache.set(smart_str(key), value, self._get_memcache_timeout(timeout)) |
|
0
|
55 |
|
|
|
56 |
def delete(self, key): |
|
|
57 |
self._cache.delete(smart_str(key)) |
|
|
58 |
|
|
|
59 |
def get_many(self, keys): |
|
|
60 |
return self._cache.get_multi(map(smart_str,keys)) |
|
|
61 |
|
|
|
62 |
def close(self, **kwargs): |
|
|
63 |
self._cache.disconnect_all() |
|
|
64 |
|
|
|
65 |
def incr(self, key, delta=1): |
|
29
|
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 |
|
0
|
78 |
|
|
|
79 |
def decr(self, key, delta=1): |
|
29
|
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() |