From 16c3522981d0964fcaffdf18259d083898bce3ab Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Wed, 3 Nov 2010 05:32:13 -0500 Subject: [PATCH 01/17] Obtain the memcache timeout after adding the herd timeout so values near 30 days work correctly --- newcache.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/newcache.py b/newcache.py index 1a26e17..5b77bc6 100644 --- a/newcache.py +++ b/newcache.py @@ -124,8 +124,10 @@ def add(self, key, value, timeout=None, herd=True): # If the user chooses to use the herd mechanism, then encode some # timestamp information into the object to be persisted into memcached if herd and timeout != 0: + if timeout is None: + timeout = self.default_timeout packed = self._pack_value(value, timeout) - real_timeout = (self._get_memcache_timeout(timeout) + + real_timeout = self._get_memcache_timeout(timeout + CACHE_HERD_TIMEOUT) else: packed = value @@ -154,8 +156,10 @@ def set(self, key, value, timeout=None, herd=True): # If the user chooses to use the herd mechanism, then encode some # timestamp information into the object to be persisted into memcached if herd and timeout != 0: + if timeout is None: + timeout = self.default_timeout packed = self._pack_value(value, timeout) - real_timeout = (self._get_memcache_timeout(timeout) + + real_timeout = self._get_memcache_timeout(timeout + CACHE_HERD_TIMEOUT) else: packed = value @@ -228,4 +232,4 @@ def delete_many(self, keys): self._cache.delete_multi(map(key_func, keys)) def clear(self): - self._cache.flush_all() \ No newline at end of file + self._cache.flush_all() From 26df38b5ca8fdbb448efa9cf1a118e7892cd4300 Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Wed, 17 Nov 2010 17:26:47 -0600 Subject: [PATCH 02/17] Remove incr and decr functions to fallback to BaseCache's naive implementations that unpack the stored integers instead of incrementing the tuple --- newcache.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/newcache.py b/newcache.py index 5b77bc6..c8e8f56 100644 --- a/newcache.py +++ b/newcache.py @@ -206,18 +206,6 @@ def get_many(self, keys): def close(self, **kwargs): self._cache.disconnect_all() - - def incr(self, key, delta=1): - try: - return self._cache.incr(key_func(key), delta) - except NotFoundError: - raise ValueError("Key '%s' not found" % (key,)) - - def decr(self, key, delta=1): - try: - return self._cache.decr(key_func(key), delta) - except NotFoundError: - raise ValueError("Key '%s' not found" % (key,)) def set_many(self, data, timeout=None, herd=True): if herd and timeout != 0: From e43330a2551527b584c8eb58e060755a648830a4 Mon Sep 17 00:00:00 2001 From: Daniel Rust Date: Mon, 2 May 2011 22:10:38 +0000 Subject: [PATCH 03/17] Added optional version param to the CacheClass's get() method to fix errors encountered when running the latest django (1.3) --- newcache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newcache.py b/newcache.py index 1a26e17..f14a9af 100644 --- a/newcache.py +++ b/newcache.py @@ -132,7 +132,7 @@ def add(self, key, value, timeout=None, herd=True): real_timeout = self._get_memcache_timeout(timeout) return self._cache.add(key_func(key), packed, real_timeout) - def get(self, key, default=None): + def get(self, key, default=None, version=None): encoded_key = key_func(key) packed = self._cache.get(encoded_key) if packed is None: From b5254f8090864a786cd823bf56b6988f77d8da3d Mon Sep 17 00:00:00 2001 From: Niran Babalola Date: Thu, 15 Sep 2011 11:03:46 -0500 Subject: [PATCH 04/17] Allow arbitrary kwargs in cache methods so they can be more future-proof --- newcache.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/newcache.py b/newcache.py index c8e8f56..4044634 100644 --- a/newcache.py +++ b/newcache.py @@ -120,7 +120,7 @@ def _get_memcache_timeout(self, timeout): timeout += int(time.time()) return timeout - def add(self, key, value, timeout=None, herd=True): + def add(self, key, value, timeout=None, herd=True, **kwargs): # If the user chooses to use the herd mechanism, then encode some # timestamp information into the object to be persisted into memcached if herd and timeout != 0: @@ -134,7 +134,7 @@ def add(self, key, value, timeout=None, herd=True): real_timeout = self._get_memcache_timeout(timeout) return self._cache.add(key_func(key), packed, real_timeout) - def get(self, key, default=None): + def get(self, key, default=None, **kwargs): encoded_key = key_func(key) packed = self._cache.get(encoded_key) if packed is None: @@ -152,7 +152,7 @@ def get(self, key, default=None): return val - def set(self, key, value, timeout=None, herd=True): + def set(self, key, value, timeout=None, herd=True, **kwargs): # If the user chooses to use the herd mechanism, then encode some # timestamp information into the object to be persisted into memcached if herd and timeout != 0: @@ -166,10 +166,10 @@ def set(self, key, value, timeout=None, herd=True): real_timeout = self._get_memcache_timeout(timeout) return self._cache.set(key_func(key), packed, real_timeout) - def delete(self, key): + def delete(self, key, **kwargs): self._cache.delete(key_func(key)) - def get_many(self, keys): + def get_many(self, keys, **kwargs): # First, map all of the keys through our key function rvals = map(key_func, keys) @@ -207,7 +207,7 @@ def get_many(self, keys): def close(self, **kwargs): self._cache.disconnect_all() - def set_many(self, data, timeout=None, herd=True): + def set_many(self, data, timeout=None, herd=True, **kwargs): if herd and timeout != 0: safe_data = dict(((key_func(k), self._pack_value(v, timeout)) for k, v in data.iteritems())) @@ -216,8 +216,8 @@ def set_many(self, data, timeout=None, herd=True): (key_func(k), v) for k, v in data.iteritems())) self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout)) - def delete_many(self, keys): + def delete_many(self, keys, **kwargs): self._cache.delete_multi(map(key_func, keys)) - def clear(self): + def clear(self, **kwargs): self._cache.flush_all() From 6a1f4ea00e4bd9cb1e2e7d3d2c9edde782125409 Mon Sep 17 00:00:00 2001 From: Joe Hillenbrand Date: Tue, 11 Oct 2011 12:33:09 -0700 Subject: [PATCH 05/17] Changed version number for setup.py --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 6783f8d..5df7375 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup -VERSION = '0.2.4' +VERSION = '0.2.4-1' setup( name='django-newcache', @@ -25,4 +25,4 @@ ], zip_safe=False, py_modules=['newcache'], -) \ No newline at end of file +) From 6afd04d4456835aa07202ef8e5f34776e30fe177 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Tue, 21 Feb 2012 14:39:08 -0500 Subject: [PATCH 06/17] =?UTF-8?q?Added=20support=20for=20pylibmc=20compres?= =?UTF-8?q?sion=20=C3=A0=20la=20jbalogh/django-pylibmc.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- newcache.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/newcache.py b/newcache.py index 1a26e17..357ae5b 100644 --- a/newcache.py +++ b/newcache.py @@ -36,6 +36,10 @@ CACHE_KEY_MODULE = getattr(settings, 'CACHE_KEY_MODULE', 'newcache') CACHE_HERD_TIMEOUT = getattr(settings, 'CACHE_HERD_TIMEOUT', 60) +MIN_COMPRESS = getattr(settings, 'PYLIBMC_MIN_COMPRESS_LEN', 0) # Disabled +if MIN_COMPRESS > 0 and not pylibmc.support_compression: + MIN_COMPRESS = 0 + class Marker(object): pass @@ -130,7 +134,7 @@ def add(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.add(key_func(key), packed, real_timeout) + return self._cache.add(key_func(key), packed, real_timeout, MIN_COMPRESSION) def get(self, key, default=None): encoded_key = key_func(key) @@ -160,7 +164,7 @@ def set(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.set(key_func(key), packed, real_timeout) + return self._cache.set(key_func(key), packed, real_timeout, MIN_COMPRESSINO) def delete(self, key): self._cache.delete(key_func(key)) From d23c001da8a16244f4ce7fd000ba76e356b43874 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Tue, 21 Feb 2012 14:41:10 -0500 Subject: [PATCH 07/17] Fixed mismatched variable name; changed to CACHE_MIN_COMPRESS for consistency. --- newcache.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/newcache.py b/newcache.py index 357ae5b..f7bc598 100644 --- a/newcache.py +++ b/newcache.py @@ -36,9 +36,9 @@ CACHE_KEY_MODULE = getattr(settings, 'CACHE_KEY_MODULE', 'newcache') CACHE_HERD_TIMEOUT = getattr(settings, 'CACHE_HERD_TIMEOUT', 60) -MIN_COMPRESS = getattr(settings, 'PYLIBMC_MIN_COMPRESS_LEN', 0) # Disabled -if MIN_COMPRESS > 0 and not pylibmc.support_compression: - MIN_COMPRESS = 0 +CACHE_MIN_COMPRESS = getattr(settings, 'PYLIBMC_MIN_COMPRESS_LEN', 0) # Disabled +if CACHE_MIN_COMPRESS > 0 and not pylibmc.support_compression: + CACHE_MIN_COMPRESS = 0 class Marker(object): pass @@ -134,7 +134,7 @@ def add(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.add(key_func(key), packed, real_timeout, MIN_COMPRESSION) + return self._cache.add(key_func(key), packed, real_timeout, CACHE_MIN_COMPRESS) def get(self, key, default=None): encoded_key = key_func(key) @@ -164,7 +164,7 @@ def set(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.set(key_func(key), packed, real_timeout, MIN_COMPRESSINO) + return self._cache.set(key_func(key), packed, real_timeout, CACHE_MIN_COMPRESS) def delete(self, key): self._cache.delete(key_func(key)) From 02e46b52cbf685bf2b2971ee9477963a36723bf8 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Tue, 21 Feb 2012 14:46:40 -0500 Subject: [PATCH 08/17] pylibmc is imported as memcache --- newcache.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/newcache.py b/newcache.py index f7bc598..d749c6b 100644 --- a/newcache.py +++ b/newcache.py @@ -37,7 +37,7 @@ CACHE_HERD_TIMEOUT = getattr(settings, 'CACHE_HERD_TIMEOUT', 60) CACHE_MIN_COMPRESS = getattr(settings, 'PYLIBMC_MIN_COMPRESS_LEN', 0) # Disabled -if CACHE_MIN_COMPRESS > 0 and not pylibmc.support_compression: +if CACHE_MIN_COMPRESS > 0 and not memcache.support_compression: CACHE_MIN_COMPRESS = 0 class Marker(object): From a840e4f47b2d4c00dbaedc782360f01933789a60 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Tue, 21 Feb 2012 14:49:17 -0500 Subject: [PATCH 09/17] Only pass compression argument if using_pylibmc is True. --- newcache.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/newcache.py b/newcache.py index d749c6b..ef250cf 100644 --- a/newcache.py +++ b/newcache.py @@ -134,7 +134,10 @@ def add(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.add(key_func(key), packed, real_timeout, CACHE_MIN_COMPRESS) + args = [key_func(key), packed, real_timeout] + if using_pylibmc is True: + args.append(CACHE_MIN_COMPRESS) + return self._cache.add(*args) def get(self, key, default=None): encoded_key = key_func(key) @@ -164,7 +167,10 @@ def set(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.set(key_func(key), packed, real_timeout, CACHE_MIN_COMPRESS) + args = [key_func(key), packed, real_timeout] + if using_pylibmc is True: + args.append(CACHE_MIN_COMPRESS) + return self._cache.set(*args) def delete(self, key): self._cache.delete(key_func(key)) From c767f1d3d62da705fcc869d89345343dcf71038c Mon Sep 17 00:00:00 2001 From: Guillermo Siliceo Trueba Date: Tue, 19 Jun 2012 13:03:58 -0500 Subject: [PATCH 10/17] Add client support for username and password --- newcache.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/newcache.py b/newcache.py index 1a26e17..2d73b11 100644 --- a/newcache.py +++ b/newcache.py @@ -1,6 +1,7 @@ "Modified memcached cache backend" import time +import os from threading import local @@ -52,10 +53,12 @@ def get_key(key): class CacheClass(BaseCache): - def __init__(self, server, params): + def __init__(self, server, params, username=None, password=None): super(CacheClass, self).__init__(params) self._servers = server.split(';') - self._use_binary = bool(params.get('binary')) + self._use_binary = bool(params.get('BINARY')) + self._username = os.environ.get('MEMCACHE_USERNAME', username) + self._password = os.environ.get('MEMCACHE_PASSWORD', password) self._local = local() @property @@ -69,9 +72,11 @@ def _cache(self): # Use binary mode if it's both supported and requested if using_pylibmc and self._use_binary: - client = memcache.Client(self._servers, binary=True) + client = memcache.Client(self._servers, binary=True, + username=self._username, password=self._password) else: - client = memcache.Client(self._servers) + client = memcache.Client(self._servers, + username=self._username, password=self._password) # If we're using pylibmc, set the behaviors according to settings if using_pylibmc: From 1eb09614e94eaf0b607a1b610fc6ce96b3fda764 Mon Sep 17 00:00:00 2001 From: Kris Bandurski Date: Mon, 15 Jul 2013 13:52:49 +0100 Subject: [PATCH 11/17] HOTFIX: Support lists of servers. --- newcache.py | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/newcache.py b/newcache.py index 1a26e17..0a4694f 100644 --- a/newcache.py +++ b/newcache.py @@ -5,6 +5,7 @@ from threading import local from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError +from django.utils import six from django.utils.hashcompat import sha_constructor from django.utils.encoding import smart_str from django.conf import settings @@ -24,7 +25,7 @@ import memcache NotFoundError = ValueError except ImportError: - raise InvalidCacheBackendError('Memcached cache backend requires ' + + raise InvalidCacheBackendError('Memcached cache backend requires ' + 'either the "pylibmc" or "memcache" library') # Flavor is used amongst multiple apps to differentiate the "flavor" of the @@ -54,10 +55,15 @@ class CacheClass(BaseCache): def __init__(self, server, params): super(CacheClass, self).__init__(params) - self._servers = server.split(';') + + if isinstance(server, six.string_types): + self._servers = server.split(';') + else: + self._servers = server + self._use_binary = bool(params.get('binary')) self._local = local() - + @property def _cache(self): """ @@ -66,17 +72,17 @@ def _cache(self): client = getattr(self._local, 'client', None) if client: return client - + # Use binary mode if it's both supported and requested if using_pylibmc and self._use_binary: client = memcache.Client(self._servers, binary=True) else: client = memcache.Client(self._servers) - + # If we're using pylibmc, set the behaviors according to settings if using_pylibmc: client.behaviors = CACHE_BEHAVIORS - + self._local.client = client return client @@ -87,7 +93,7 @@ def _pack_value(self, value, timeout): """ herd_timeout = (timeout or self.default_timeout) + int(time.time()) return (MARKER, value, herd_timeout) - + def _unpack_value(self, value, default=None): """ Unpacks a value and returns a tuple whose first element is the value, @@ -137,9 +143,9 @@ def get(self, key, default=None): packed = self._cache.get(encoded_key) if packed is None: return default - + val, refresh = self._unpack_value(packed) - + # If the cache has expired according to the embedded timeout, then # shove it back into the cache for a while, but act as if it was a # cache miss. @@ -147,7 +153,7 @@ def get(self, key, default=None): self._cache.set(encoded_key, val, self._get_memcache_timeout(CACHE_HERD_TIMEOUT)) return default - + return val def set(self, key, value, timeout=None, herd=True): @@ -168,36 +174,36 @@ def delete(self, key): def get_many(self, keys): # First, map all of the keys through our key function rvals = map(key_func, keys) - + packed_resp = self._cache.get_multi(rvals) - + resp = {} reinsert = {} - + for key, packed in packed_resp.iteritems(): # If it was a miss, treat it as a miss to our response & continue if packed is None: resp[key] = packed continue - + val, refresh = self._unpack_value(packed) if refresh: reinsert[key] = val resp[key] = None else: resp[key] = val - + # If there are values to re-insert for a short period of time, then do # so now. if reinsert: self._cache.set_multi(reinsert, self._get_memcache_timeout(CACHE_HERD_TIMEOUT)) - + # Build a reverse map of encoded keys to the original keys, so that # the returned dict's keys are what users expect (in that they match # what the user originally entered) reverse = dict(zip(rvals, keys)) - + return dict(((reverse[k], v) for k, v in resp.iteritems())) def close(self, **kwargs): @@ -214,7 +220,7 @@ def decr(self, key, delta=1): return self._cache.decr(key_func(key), delta) except NotFoundError: raise ValueError("Key '%s' not found" % (key,)) - + def set_many(self, data, timeout=None, herd=True): if herd and timeout != 0: safe_data = dict(((key_func(k), self._pack_value(v, timeout)) @@ -223,9 +229,9 @@ def set_many(self, data, timeout=None, herd=True): safe_data = dict(( (key_func(k), v) for k, v in data.iteritems())) self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout)) - + def delete_many(self, keys): self._cache.delete_multi(map(key_func, keys)) - + def clear(self): - self._cache.flush_all() \ No newline at end of file + self._cache.flush_all() From 362cc06f1c68c9568d9c0c3bb34f7f5f2af3c6ff Mon Sep 17 00:00:00 2001 From: svartalf Date: Thu, 31 Oct 2013 15:30:01 +0900 Subject: [PATCH 12/17] Deprecated django.utils.hashcompat.sha_constructor removal --- newcache.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/newcache.py b/newcache.py index f14a9af..08963e4 100644 --- a/newcache.py +++ b/newcache.py @@ -1,11 +1,10 @@ "Modified memcached cache backend" import time - +import hashlib from threading import local from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError -from django.utils.hashcompat import sha_constructor from django.utils.encoding import smart_str from django.conf import settings @@ -45,7 +44,7 @@ def get_key(key): """ Returns a hashed, versioned, flavored version of the string that was input. """ - hashed = sha_constructor(smart_str(key)).hexdigest() + hashed = hashlib.sha1(smart_str(key)).hexdigest() return ''.join((FLAVOR, '-', CACHE_VERSION, '-', hashed)) key_func = importlib.import_module(CACHE_KEY_MODULE).get_key From df9f45b329cffde17676ae0f085e324d8879c165 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Sun, 9 Feb 2014 07:44:34 -0500 Subject: [PATCH 13/17] Upped version. --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 6783f8d..792447c 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup -VERSION = '0.2.4' +VERSION = '0.2.5' setup( name='django-newcache', @@ -25,4 +25,4 @@ ], zip_safe=False, py_modules=['newcache'], -) \ No newline at end of file +) From 25d0a53808d2837c1000f9851d8565711a316d35 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Sun, 9 Feb 2014 10:38:59 -0500 Subject: [PATCH 14/17] Django doesn't include hashcompat anymore. --- newcache.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/newcache.py b/newcache.py index ef250cf..f21b73e 100644 --- a/newcache.py +++ b/newcache.py @@ -2,10 +2,10 @@ import time +from hashlib import sha1 as sha_constructor from threading import local from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError -from django.utils.hashcompat import sha_constructor from django.utils.encoding import smart_str from django.conf import settings @@ -238,4 +238,4 @@ def delete_many(self, keys): self._cache.delete_multi(map(key_func, keys)) def clear(self): - self._cache.flush_all() \ No newline at end of file + self._cache.flush_all() From b11e5447c9e64787775189767d591d3720e63300 Mon Sep 17 00:00:00 2001 From: Josh Ourisman Date: Sun, 9 Feb 2014 10:40:01 -0500 Subject: [PATCH 15/17] Upped version. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 792447c..ca15e1d 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup -VERSION = '0.2.5' +VERSION = '0.2.6' setup( name='django-newcache', From 450b06853288ae0a10a1064d99bc0d95113a3e4b Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov work Date: Wed, 6 Apr 2016 10:52:39 +0600 Subject: [PATCH 16/17] add compatibility with django 1.6 --- newcache.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/newcache.py b/newcache.py index 1a26e17..4541bfe 100644 --- a/newcache.py +++ b/newcache.py @@ -5,7 +5,10 @@ from threading import local from django.core.cache.backends.base import BaseCache, InvalidCacheBackendError -from django.utils.hashcompat import sha_constructor +try: + from hashlib import sha1 as sha_constructor +except ImportError: + from django.utils.hashcompat import sha_constructor from django.utils.encoding import smart_str from django.conf import settings @@ -228,4 +231,4 @@ def delete_many(self, keys): self._cache.delete_multi(map(key_func, keys)) def clear(self): - self._cache.flush_all() \ No newline at end of file + self._cache.flush_all() From 87c744dbed8d59b72cf77f53b7e401d21561adcb Mon Sep 17 00:00:00 2001 From: Dmitry Kosolapov work Date: Fri, 6 May 2016 16:27:35 +0600 Subject: [PATCH 17/17] compability with django=1.6 --- newcache.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/newcache.py b/newcache.py index 4541bfe..706e50d 100644 --- a/newcache.py +++ b/newcache.py @@ -44,12 +44,12 @@ class Marker(object): MARKER = Marker() -def get_key(key): +def get_key(key, version=None): """ Returns a hashed, versioned, flavored version of the string that was input. """ hashed = sha_constructor(smart_str(key)).hexdigest() - return ''.join((FLAVOR, '-', CACHE_VERSION, '-', hashed)) + return ''.join((FLAVOR, '-', CACHE_VERSION, '-', hashed, version if version is not None else '')) key_func = importlib.import_module(CACHE_KEY_MODULE).get_key @@ -123,7 +123,7 @@ def _get_memcache_timeout(self, timeout): timeout += int(time.time()) return timeout - def add(self, key, value, timeout=None, herd=True): + def add(self, key, value, timeout=None, herd=True, version=None): # If the user chooses to use the herd mechanism, then encode some # timestamp information into the object to be persisted into memcached if herd and timeout != 0: @@ -133,10 +133,10 @@ def add(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.add(key_func(key), packed, real_timeout) + return self._cache.add(key_func(key, version), packed, real_timeout) - def get(self, key, default=None): - encoded_key = key_func(key) + def get(self, key, default=None, version=None): + encoded_key = key_func(key, version) packed = self._cache.get(encoded_key) if packed is None: return default @@ -153,7 +153,7 @@ def get(self, key, default=None): return val - def set(self, key, value, timeout=None, herd=True): + def set(self, key, value, timeout=None, herd=True, version=None): # If the user chooses to use the herd mechanism, then encode some # timestamp information into the object to be persisted into memcached if herd and timeout != 0: @@ -163,14 +163,14 @@ def set(self, key, value, timeout=None, herd=True): else: packed = value real_timeout = self._get_memcache_timeout(timeout) - return self._cache.set(key_func(key), packed, real_timeout) + return self._cache.set(key_func(key, version), packed, real_timeout) - def delete(self, key): - self._cache.delete(key_func(key)) + def delete(self, key, version=None): + self._cache.delete(key_func(key, version)) - def get_many(self, keys): + def get_many(self, keys, version=None): # First, map all of the keys through our key function - rvals = map(key_func, keys) + rvals = [key_func(k, version) for k in keys] packed_resp = self._cache.get_multi(rvals) @@ -206,9 +206,9 @@ def get_many(self, keys): def close(self, **kwargs): self._cache.disconnect_all() - def incr(self, key, delta=1): + def incr(self, key, delta=1, version=None): try: - return self._cache.incr(key_func(key), delta) + return self._cache.incr(key_func(key, version), delta) except NotFoundError: raise ValueError("Key '%s' not found" % (key,)) @@ -218,17 +218,17 @@ def decr(self, key, delta=1): except NotFoundError: raise ValueError("Key '%s' not found" % (key,)) - def set_many(self, data, timeout=None, herd=True): + def set_many(self, data, timeout=None, herd=True, version=None): if herd and timeout != 0: - safe_data = dict(((key_func(k), self._pack_value(v, timeout)) + safe_data = dict(((key_func(k, version), self._pack_value(v, timeout)) for k, v in data.iteritems())) else: safe_data = dict(( - (key_func(k), v) for k, v in data.iteritems())) + (key_func(k, version), v) for k, v in data.iteritems())) self._cache.set_multi(safe_data, self._get_memcache_timeout(timeout)) - def delete_many(self, keys): - self._cache.delete_multi(map(key_func, keys)) + def delete_many(self, keys, version=None): + self._cache.delete_multi([key_func(k, version) for k in keys]) def clear(self): self._cache.flush_all()