Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
Aymeric Augustin authored March 11, 2013

Showing 1 changed file with 15 additions and 14 deletions. Show diff stats Hide diff stats

  1. 29  django/core/cache/backends/db.py
29  django/core/cache/backends/db.py
@@ -10,7 +10,7 @@
10 10
 
11 11
 from django.conf import settings
12 12
 from django.core.cache.backends.base import BaseCache
13  
-from django.db import connections, router, DatabaseError
  13
+from django.db import connections, transaction, router, DatabaseError
14 14
 from django.utils import timezone, six
15 15
 from django.utils.encoding import force_bytes
16 16
 
@@ -26,7 +26,7 @@ def __init__(self, table):
26 26
         self.model_name = 'cacheentry'
27 27
         self.verbose_name = 'cache entry'
28 28
         self.verbose_name_plural = 'cache entries'
29  
-        self.object_name =  'CacheEntry'
  29
+        self.object_name = 'CacheEntry'
30 30
         self.abstract = False
31 31
         self.managed = True
32 32
         self.proxy = False
@@ -108,19 +108,20 @@ def _base_set(self, mode, key, value, timeout=None):
108 108
         # string, not bytes. Refs #19274.
109 109
         if six.PY3:
110 110
             b64encoded = b64encoded.decode('latin1')
111  
-        cursor.execute("SELECT cache_key, expires FROM %s "
112  
-                       "WHERE cache_key = %%s" % table, [key])
113 111
         try:
114  
-            result = cursor.fetchone()
115  
-            if result and (mode == 'set' or
116  
-                    (mode == 'add' and result[1] < now)):
117  
-                cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
118  
-                               "WHERE cache_key = %%s" % table,
119  
-                               [b64encoded, connections[db].ops.value_to_db_datetime(exp), key])
120  
-            else:
121  
-                cursor.execute("INSERT INTO %s (cache_key, value, expires) "
122  
-                               "VALUES (%%s, %%s, %%s)" % table,
123  
-                               [key, b64encoded, connections[db].ops.value_to_db_datetime(exp)])
  112
+            with transaction.atomic_if_autocommit(using=db):
  113
+                cursor.execute("SELECT cache_key, expires FROM %s "
  114
+                               "WHERE cache_key = %%s" % table, [key])
  115
+                result = cursor.fetchone()
  116
+                exp = connections[db].ops.value_to_db_datetime(exp)
  117
+                if result and (mode == 'set' or (mode == 'add' and result[1] < now)):
  118
+                    cursor.execute("UPDATE %s SET value = %%s, expires = %%s "
  119
+                                   "WHERE cache_key = %%s" % table,
  120
+                                   [b64encoded, exp, key])
  121
+                else:
  122
+                    cursor.execute("INSERT INTO %s (cache_key, value, expires) "
  123
+                                   "VALUES (%%s, %%s, %%s)" % table,
  124
+                                   [key, b64encoded, exp])
124 125
         except DatabaseError:
125 126
             # To be threadsafe, updates/inserts are allowed to fail silently
126 127
             return False

0 notes on commit 1b12e24

Please sign in to comment.
Something went wrong with that request. Please try again.