Commit 1b12e248 authored by Aymeric Augustin's avatar Aymeric Augustin
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.
parent faabf361
Loading
Loading
Loading
Loading
+15 −14
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@ except ImportError:

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

@@ -108,19 +108,20 @@ class DatabaseCache(BaseDatabaseCache):
        # string, not bytes. Refs #19274.
        if six.PY3:
            b64encoded = b64encoded.decode('latin1')
        try:
            with transaction.atomic_if_autocommit(using=db):
                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)):
                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, connections[db].ops.value_to_db_datetime(exp), key])
                                   [b64encoded, 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)])
                                   [key, b64encoded, exp])
        except DatabaseError:
            # To be threadsafe, updates/inserts are allowed to fail silently
            return False