Skip to content

Commit bc8abe3

Browse files
committed
Fixed django#16358 - Made memcache backend delete old value on a failure to set.
Default Memcached configuration allows for a maximum object of 1MB and will fail to set the key if it is too large. The key will be deleted from memcached if it fails to be set. This is needed to avoid an issue with cache_db session backend using the old value stored in memcached, instead of the newer value stored in the database.
1 parent bfb11b9 commit bc8abe3

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

Diff for: django/core/cache/backends/memcached.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ def get(self, key, default=None, version=None):
8686

8787
def set(self, key, value, timeout=DEFAULT_TIMEOUT, version=None):
8888
key = self.make_key(key, version=version)
89-
self._cache.set(key, value, self.get_backend_timeout(timeout))
89+
if not self._cache.set(key, value, self.get_backend_timeout(timeout)):
90+
# make sure the key doesn't keep its old value in case of failure to set (memcached's 1MB limit)
91+
self._cache.delete(key)
9092

9193
def delete(self, key, version=None):
9294
key = self.make_key(key, version=version)

Diff for: docs/releases/1.8.txt

+4
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,10 @@ Miscellaneous
729729

730730
.. _universal newlines: http://www.python.org/dev/peps/pep-0278
731731

732+
* The Memcached cache backends ``MemcachedCache`` and ``PyLibMCCache`` will
733+
delete a key if ``set()`` fails. This is necessary to ensure the ``cache_db``
734+
session store always fetches the most current session data.
735+
732736
.. _deprecated-features-1.8:
733737

734738
Features deprecated in 1.8

Diff for: tests/cache/tests.py

+18
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,24 @@ def test_zero_cull(self):
11331133
# culling isn't implemented, memcached deals with it.
11341134
pass
11351135

1136+
def test_memcached_deletes_key_on_failed_set(self):
1137+
# By default memcached allows objects up to 1MB. For the cache_db session
1138+
# backend to always use the current session, memcached needs to delete
1139+
# the old key if it fails to set.
1140+
# pylibmc doesn't seem to have SERVER_MAX_VALUE_LENGTH as far as I can
1141+
# tell from a quick check of its source code. This is falling back to
1142+
# the default value exposed by python-memcached on my system.
1143+
max_value_length = getattr(cache._lib, 'SERVER_MAX_VALUE_LENGTH', 1048576)
1144+
1145+
cache.set('small_value', 'a')
1146+
self.assertEqual(cache.get('small_value'), 'a')
1147+
1148+
large_value = 'a' * (max_value_length + 1)
1149+
cache.set('small_value', large_value)
1150+
# small_value should be deleted, or set if configured to accept larger values
1151+
value = cache.get('small_value')
1152+
self.assertTrue(value is None or value == large_value)
1153+
11361154

11371155
@override_settings(CACHES=caches_setting_for_tests(
11381156
BACKEND='django.core.cache.backends.filebased.FileBasedCache',

0 commit comments

Comments
 (0)