Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed #11569 -- Wrapped DatabaseCache._base_set in an atomic block.

The atomic block provides a clean rollback to a savepoint on failed writes.

The ticket reported a race condition which I don't know how to test.
  • Loading branch information...
commit 1b12e248ea556789e994caa8d3849f4de6a9096e 1 parent faabf36
@aaugustin aaugustin authored
Showing with 15 additions and 14 deletions.
  1. +15 −14 django/core/cache/backends/db.py
View
29 django/core/cache/backends/db.py
@@ -10,7 +10,7 @@
from django.conf import settings
from django.core.cache.backends.base import BaseCache
-from django.db import connections, router, DatabaseError
+from django.db import connections, transaction, router, DatabaseError
from django.utils import timezone, six
from django.utils.encoding import force_bytes
@@ -26,7 +26,7 @@ def __init__(self, table):
self.model_name = 'cacheentry'
self.verbose_name = 'cache entry'
self.verbose_name_plural = 'cache entries'
- self.object_name = 'CacheEntry'
+ self.object_name = 'CacheEntry'
self.abstract = False
self.managed = True
self.proxy = False
@@ -108,19 +108,20 @@ def _base_set(self, mode, key, value, timeout=None):
# string, not bytes. Refs #19274.
if six.PY3:
b64encoded = b64encoded.decode('latin1')
- cursor.execute("SELECT cache_key, expires FROM %s "
- "WHERE cache_key = %%s" % table, [key])
try:
- result = cursor.fetchone()
- if result and (mode == 'set' or
- (mode == 'add' and result[1] < now)):
- cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
- "WHERE cache_key = %%s" % table,
- [b64encoded, connections[db].ops.value_to_db_datetime(exp), key])
- else:
- cursor.execute("INSERT INTO %s (cache_key, value, expires) "
- "VALUES (%%s, %%s, %%s)" % table,
- [key, b64encoded, connections[db].ops.value_to_db_datetime(exp)])
+ with transaction.atomic_if_autocommit(using=db):
+ cursor.execute("SELECT cache_key, expires FROM %s "
+ "WHERE cache_key = %%s" % table, [key])
+ result = cursor.fetchone()
+ exp = connections[db].ops.value_to_db_datetime(exp)
+ if result and (mode == 'set' or (mode == 'add' and result[1] < now)):
+ cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
+ "WHERE cache_key = %%s" % table,
+ [b64encoded, exp, key])
+ else:
+ cursor.execute("INSERT INTO %s (cache_key, value, expires) "
+ "VALUES (%%s, %%s, %%s)" % table,
+ [key, b64encoded, exp])
except DatabaseError:
# To be threadsafe, updates/inserts are allowed to fail silently
return False
Please sign in to comment.
Something went wrong with that request. Please try again.