Code

Ticket #5632: dbmultithreaded2.diff

File dbmultithreaded2.diff, 5.9 KB (added by teepark, 6 years ago)
Line 
1Index: django/db/models/base.py
2===================================================================
3--- django/db/models/base.py    (revision 7364)
4+++ django/db/models/base.py    (working copy)
5@@ -6,7 +6,7 @@
6 from django.db.models.fields.related import OneToOneRel, ManyToOneRel
7 from django.db.models.query import delete_objects
8 from django.db.models.options import Options, AdminOptions
9-from django.db import connection, transaction
10+from django.db import connection, transaction, mutex
11 from django.db.models import signals
12 from django.db.models.loading import register_models, get_model
13 from django.dispatch import dispatcher
14@@ -275,6 +275,7 @@
15         dispatcher.send(signal=signals.post_save, sender=self.__class__,
16                         instance=self, created=(not record_exists), raw=raw)
17 
18+    save = mutex(save)
19     save.alters_data = True
20 
21     def validate(self):
22@@ -334,6 +335,7 @@
23         # Actually delete the objects
24         delete_objects(seen_objs)
25 
26+    delete = mutex(delete)
27     delete.alters_data = True
28 
29     def _get_FIELD_display(self, field):
30Index: django/db/models/fields/related.py
31===================================================================
32--- django/db/models/fields/related.py  (revision 7364)
33+++ django/db/models/fields/related.py  (working copy)
34@@ -1,4 +1,4 @@
35-from django.db import connection, transaction
36+from django.db import connection, transaction, mutex
37 from django.db.models import signals, get_model
38 from django.db.models.fields import AutoField, Field, IntegerField, PositiveIntegerField, PositiveSmallIntegerField, get_ul_class
39 from django.db.models.related import RelatedObject
40@@ -254,12 +254,14 @@
41                 for obj in objs:
42                     setattr(obj, rel_field.name, instance)
43                     obj.save()
44+            add = mutex(add)
45             add.alters_data = True
46 
47             def create(self, **kwargs):
48                 new_obj = self.model(**kwargs)
49                 self.add(new_obj)
50                 return new_obj
51+            create = mutex(create)
52             create.alters_data = True
53 
54             # remove() and clear() are only provided if the ForeignKey can have a value of null.
55@@ -273,12 +275,14 @@
56                             obj.save()
57                         else:
58                             raise rel_field.rel.to.DoesNotExist, "%r is not related to %r." % (obj, instance)
59+                remove = mutex(remove)
60                 remove.alters_data = True
61 
62                 def clear(self):
63                     for obj in self.all():
64                         setattr(obj, rel_field.name, None)
65                         obj.save()
66+                clear = mutex(clear)
67                 clear.alters_data = True
68 
69         manager = RelatedManager()
70@@ -325,6 +329,7 @@
71             # If this is a symmetrical m2m relation to self, add the mirror entry in the m2m table
72             if self.symmetrical:
73                 self._add_items(self.target_col_name, self.source_col_name, *objs)
74+        add = mutex(add)
75         add.alters_data = True
76 
77         def remove(self, *objs):
78@@ -333,6 +338,7 @@
79             # If this is a symmetrical m2m relation to self, remove the mirror entry in the m2m table
80             if self.symmetrical:
81                 self._remove_items(self.target_col_name, self.source_col_name, *objs)
82+        remove = mutex(remove)
83         remove.alters_data = True
84 
85         def clear(self):
86@@ -341,6 +347,7 @@
87             # If this is a symmetrical m2m relation to self, clear the mirror entry in the m2m table
88             if self.symmetrical:
89                 self._clear_items(self.target_col_name)
90+        clear = mutex(clear)
91         clear.alters_data = True
92 
93         def create(self, **kwargs):
94@@ -348,6 +355,7 @@
95             new_obj.save()
96             self.add(new_obj)
97             return new_obj
98+        create = mutex(create)
99         create.alters_data = True
100 
101         def _add_items(self, source_col_name, target_col_name, *objs):
102Index: django/db/models/query.py
103===================================================================
104--- django/db/models/query.py   (revision 7364)
105+++ django/db/models/query.py   (working copy)
106@@ -1,5 +1,5 @@
107 from django.conf import settings
108-from django.db import connection, transaction, IntegrityError
109+from django.db import connection, transaction, IntegrityError, mutex
110 from django.db.models.fields import DateField, FieldDoesNotExist
111 from django.db.models import signals, loading
112 from django.dispatch import dispatcher
113@@ -273,6 +273,7 @@
114         obj = self.model(**kwargs)
115         obj.save()
116         return obj
117+    create = mutex(create)
118 
119     def get_or_create(self, **kwargs):
120         """
121@@ -293,6 +294,7 @@
122                 return obj, True
123             except IntegrityError, e:
124                 return self.get(**kwargs), False
125+    get_or_create = mutex(get_or_create)
126 
127     def latest(self, field_name=None):
128         """
129@@ -354,6 +356,7 @@
130 
131         # Clear the result cache, in case this QuerySet gets reused.
132         self._result_cache = None
133+    delete = mutex(delete)
134     delete.alters_data = True
135 
136     ##################################################
137Index: django/db/__init__.py
138===================================================================
139--- django/db/__init__.py       (revision 7364)
140+++ django/db/__init__.py       (working copy)
141@@ -1,4 +1,5 @@
142 import os
143+import threading
144 from django.conf import settings
145 from django.core import signals
146 from django.core.exceptions import ImproperlyConfigured
147@@ -68,3 +69,17 @@
148     from django.db import transaction
149     transaction.rollback_unless_managed()
150 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)
151+
152+# Decorate data-modifying db functions to use a threading.RLock
153+__lock = threading.RLock()
154+def mutex(func):
155+    def decorated(*args, **kwargs):
156+        __lock.acquire()
157+        try:
158+            func(*args, **kwargs)
159+        except:
160+            __lock.release()
161+            raise
162+        __lock.release()
163+    return decorated
164+