--- a/web/lib/django/core/cache/backends/memcached.py Wed May 19 17:43:59 2010 +0200
+++ b/web/lib/django/core/cache/backends/memcached.py Tue May 25 02:43:45 2010 +0200
@@ -1,10 +1,17 @@
"Memcached cache backend"
+import time
+
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
from django.utils.encoding import smart_unicode, smart_str
try:
import cmemcache as memcache
+ import warnings
+ warnings.warn(
+ "Support for the 'cmemcache' library has been deprecated. Please use python-memcached instead.",
+ PendingDeprecationWarning
+ )
except ImportError:
try:
import memcache
@@ -16,25 +23,35 @@
BaseCache.__init__(self, params)
self._cache = memcache.Client(server.split(';'))
+ def _get_memcache_timeout(self, timeout):
+ """
+ Memcached deals with long (> 30 days) timeouts in a special
+ way. Call this function to obtain a safe value for your timeout.
+ """
+ timeout = timeout or self.default_timeout
+ if timeout > 2592000: # 60*60*24*30, 30 days
+ # See http://code.google.com/p/memcached/wiki/FAQ
+ # "You can set expire times up to 30 days in the future. After that
+ # memcached interprets it as a date, and will expire the item after
+ # said date. This is a simple (but obscure) mechanic."
+ #
+ # This means that we have to switch to absolute timestamps.
+ timeout += int(time.time())
+ return timeout
+
def add(self, key, value, timeout=0):
if isinstance(value, unicode):
value = value.encode('utf-8')
- return self._cache.add(smart_str(key), value, timeout or self.default_timeout)
+ return self._cache.add(smart_str(key), value, self._get_memcache_timeout(timeout))
def get(self, key, default=None):
val = self._cache.get(smart_str(key))
if val is None:
return default
- else:
- if isinstance(val, basestring):
- return smart_unicode(val)
- else:
- return val
+ return val
def set(self, key, value, timeout=0):
- if isinstance(value, unicode):
- value = value.encode('utf-8')
- self._cache.set(smart_str(key), value, timeout or self.default_timeout)
+ self._cache.set(smart_str(key), value, self._get_memcache_timeout(timeout))
def delete(self, key):
self._cache.delete(smart_str(key))
@@ -46,7 +63,42 @@
self._cache.disconnect_all()
def incr(self, key, delta=1):
- return self._cache.incr(key, delta)
+ try:
+ val = self._cache.incr(key, delta)
+
+ # python-memcache responds to incr on non-existent keys by
+ # raising a ValueError. Cmemcache returns None. In both
+ # cases, we should raise a ValueError though.
+ except ValueError:
+ val = None
+ if val is None:
+ raise ValueError("Key '%s' not found" % key)
+
+ return val
def decr(self, key, delta=1):
- return self._cache.decr(key, delta)
+ try:
+ val = self._cache.decr(key, delta)
+
+ # python-memcache responds to decr on non-existent keys by
+ # raising a ValueError. Cmemcache returns None. In both
+ # cases, we should raise a ValueError though.
+ except ValueError:
+ val = None
+ if val is None:
+ raise ValueError("Key '%s' not found" % key)
+ return val
+
+ def set_many(self, data, timeout=0):
+ safe_data = {}
+ for key, value in data.items():
+ if isinstance(value, unicode):
+ value = value.encode('utf-8')
+ safe_data[smart_str(key)] = value
+ self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout))
+
+ def delete_many(self, keys):
+ self._cache.delete_multi(map(smart_str, keys))
+
+ def clear(self):
+ self._cache.flush_all()