summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/core/cache/backends/memcached.py4
-rw-r--r--docs/releases/1.8.txt4
-rw-r--r--tests/cache/tests.py18
3 files changed, 25 insertions, 1 deletions
diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py
index b32ab704ec..87f05f973b 100644
--- a/django/core/cache/backends/memcached.py
+++ b/django/core/cache/backends/memcached.py
@@ -86,7 +86,9 @@ class BaseMemcachedCache(six.with_metaclass(BaseMemcachedCacheMethods, BaseCache
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
key = self.make_key(key, version=version)
- self._cache.set(key, value, self.get_backend_timeout(timeout))
+ if not self._cache.set(key, value, self.get_backend_timeout(timeout)):
+ # make sure the key doesn't keep its old value in case of failure to set (memcached's 1MB limit)
+ self._cache.delete(key)
def delete(self, key, version=None):
key = self.make_key(key, version=version)
diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt
index d3232d8235..fec2e2b4bc 100644
--- a/docs/releases/1.8.txt
+++ b/docs/releases/1.8.txt
@@ -729,6 +729,10 @@ Miscellaneous
.. _universal newlines: http://www.python.org/dev/peps/pep-0278
+* The Memcached cache backends ``MemcachedCache`` and ``PyLibMCCache`` will
+ delete a key if ``set()`` fails. This is necessary to ensure the ``cache_db``
+ session store always fetches the most current session data.
+
.. _deprecated-features-1.8:
Features deprecated in 1.8
diff --git a/tests/cache/tests.py b/tests/cache/tests.py
index c7604f131e..9dfd7af15d 100644
--- a/tests/cache/tests.py
+++ b/tests/cache/tests.py
@@ -1133,6 +1133,24 @@ class MemcachedCacheTests(BaseCacheTests, TestCase):
# culling isn't implemented, memcached deals with it.
pass
+ def test_memcached_deletes_key_on_failed_set(self):
+ # By default memcached allows objects up to 1MB. For the cache_db session
+ # backend to always use the current session, memcached needs to delete
+ # the old key if it fails to set.
+ # pylibmc doesn't seem to have SERVER_MAX_VALUE_LENGTH as far as I can
+ # tell from a quick check of its source code. This is falling back to
+ # the default value exposed by python-memcached on my system.
+ max_value_length = getattr(cache._lib, 'SERVER_MAX_VALUE_LENGTH', 1048576)
+
+ cache.set('small_value', 'a')
+ self.assertEqual(cache.get('small_value'), 'a')
+
+ large_value = 'a' * (max_value_length + 1)
+ cache.set('small_value', large_value)
+ # small_value should be deleted, or set if configured to accept larger values
+ value = cache.get('small_value')
+ self.assertTrue(value is None or value == large_value)
+
@override_settings(CACHES=caches_setting_for_tests(
BACKEND='django.core.cache.backends.filebased.FileBasedCache',