Fixed #12399 -- Added handling for memcache timeouts longer than 30 days. Thanks to houdinihound for the report, and gciotta for the patch.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@12408 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
be57541af1
commit
75ab212d12
|
@ -1,5 +1,7 @@
|
||||||
"Memcached cache backend"
|
"Memcached cache backend"
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError
|
||||||
from django.utils.encoding import smart_unicode, smart_str
|
from django.utils.encoding import smart_unicode, smart_str
|
||||||
|
|
||||||
|
@ -16,10 +18,26 @@ class CacheClass(BaseCache):
|
||||||
BaseCache.__init__(self, params)
|
BaseCache.__init__(self, params)
|
||||||
self._cache = memcache.Client(server.split(';'))
|
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):
|
def add(self, key, value, timeout=0):
|
||||||
if isinstance(value, unicode):
|
if isinstance(value, unicode):
|
||||||
value = value.encode('utf-8')
|
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):
|
def get(self, key, default=None):
|
||||||
val = self._cache.get(smart_str(key))
|
val = self._cache.get(smart_str(key))
|
||||||
|
@ -34,7 +52,7 @@ class CacheClass(BaseCache):
|
||||||
def set(self, key, value, timeout=0):
|
def set(self, key, value, timeout=0):
|
||||||
if isinstance(value, unicode):
|
if isinstance(value, unicode):
|
||||||
value = value.encode('utf-8')
|
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):
|
def delete(self, key):
|
||||||
self._cache.delete(smart_str(key))
|
self._cache.delete(smart_str(key))
|
||||||
|
@ -78,7 +96,7 @@ class CacheClass(BaseCache):
|
||||||
if isinstance(value, unicode):
|
if isinstance(value, unicode):
|
||||||
value = value.encode('utf-8')
|
value = value.encode('utf-8')
|
||||||
safe_data[smart_str(key)] = value
|
safe_data[smart_str(key)] = value
|
||||||
self._cache.set_multi(safe_data, timeout or self.default_timeout)
|
self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout))
|
||||||
|
|
||||||
def delete_many(self, keys):
|
def delete_many(self, keys):
|
||||||
self._cache.delete_multi(map(smart_str, keys))
|
self._cache.delete_multi(map(smart_str, keys))
|
||||||
|
|
|
@ -324,6 +324,22 @@ class BaseCacheTests(object):
|
||||||
self.assertEqual(self.cache.get("key1"), None)
|
self.assertEqual(self.cache.get("key1"), None)
|
||||||
self.assertEqual(self.cache.get("key2"), None)
|
self.assertEqual(self.cache.get("key2"), None)
|
||||||
|
|
||||||
|
def test_long_timeout(self):
|
||||||
|
'''
|
||||||
|
Using a timeout greater than 30 days makes memcached think
|
||||||
|
it is an absolute expiration timestamp instead of a relative
|
||||||
|
offset. Test that we honour this convention. Refs #12399.
|
||||||
|
'''
|
||||||
|
self.cache.set('key1', 'eggs', 60*60*24*30 + 1) #30 days + 1 second
|
||||||
|
self.assertEqual(self.cache.get('key1'), 'eggs')
|
||||||
|
|
||||||
|
self.cache.add('key2', 'ham', 60*60*24*30 + 1)
|
||||||
|
self.assertEqual(self.cache.get('key2'), 'ham')
|
||||||
|
|
||||||
|
self.cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, 60*60*24*30 + 1)
|
||||||
|
self.assertEqual(self.cache.get('key3'), 'sausage')
|
||||||
|
self.assertEqual(self.cache.get('key4'), 'lobster bisque')
|
||||||
|
|
||||||
class DBCacheTests(unittest.TestCase, BaseCacheTests):
|
class DBCacheTests(unittest.TestCase, BaseCacheTests):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
management.call_command('createcachetable', 'test_cache_table', verbosity=0, interactive=False)
|
management.call_command('createcachetable', 'test_cache_table', verbosity=0, interactive=False)
|
||||||
|
|
Loading…
Reference in New Issue