#23576: ORM delete strategy can lead to race conditions inside a transaction
-------------------------------------+-------------------------------------
     Reporter:  jdufresne            |                    Owner:  nobody
         Type:  Uncategorized        |                   Status:  new
    Component:  Database layer       |                  Version:  1.7
  (models, ORM)                      |               Resolution:
     Severity:  Normal               |             Triage Stage:
     Keywords:                       |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------
Changes (by jdufresne):

 * needs_better_patch:   => 0
 * needs_tests:   => 0
 * needs_docs:   => 0


Comment:

 I have created a minimal test case:
 https://github.com/jdufresne/djtest-23576 I'd be happy to answer any
 questions about the test case if anything requires explanation. The
 waiting on `stdin` is to simulate a view with a long running process
 inside a transaction.

 To run the test, run `$ python test.py` from the project root directory.
 (As it is a race condition it may take more than one try.)

 The test runs in a management command instead of a HTTP view in order to
 easily trigger the race using multiple processes, but the principle is the
 same. Imagine the command is the view and each process is an HTTP request.
 Upon running the test and triggering the error I get the following
 traceback:

 {{{
 Traceback (most recent call last):
   File "manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/core/management/__init__.py", line 385, in
 execute_from_command_line
     utility.execute()
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/core/management/__init__.py", line 377, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/core/management/base.py", line 288, in run_from_argv
     self.execute(*args, **options.__dict__)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/core/management/base.py", line 338, in execute
     output = self.handle(*args, **options)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/core/management/base.py", line 533, in handle
     return self.handle_noargs(**options)
   File "/home/jon/djtest/myproj/myapp/management/commands/mytest.py", line
 13, in handle_noargs
     C(a=A.objects.get(name='foo'), b=B.objects.get(name='bar'))
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/models/manager.py", line 92, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/models/query.py", line 409, in bulk_create
     self._batched_insert(objs_without_pk, fields, batch_size)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/models/query.py", line 938, in _batched_insert
     using=self.db)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/models/manager.py", line 92, in manager_method
     return getattr(self.get_queryset(), name)(*args, **kwargs)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/models/query.py", line 921, in _insert
     return query.get_compiler(using=using).execute_sql(return_id)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/models/sql/compiler.py", line 920, in execute_sql
     cursor.execute(sql, params)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/backends/utils.py", line 81, in execute
     return super(CursorDebugWrapper, self).execute(sql, params)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/backends/utils.py", line 65, in execute
     return self.cursor.execute(sql, params)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/utils.py", line 94, in __exit__
     six.reraise(dj_exc_type, dj_exc_value, traceback)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/backends/utils.py", line 65, in execute
     return self.cursor.execute(sql, params)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/django/db/backends/mysql/base.py", line 128, in execute
     return self.cursor.execute(query, args)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/MySQLdb/cursors.py", line 205, in execute
     self.errorhandler(self, exc, value)
   File "/home/jon/djtest/venv/lib/python2.7/site-
 packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
     raise errorclass, errorvalue
 django.db.utils.IntegrityError: (1062, "Duplicate entry '1-1' for key
 'a_id'")
 }}}

--
Ticket URL: <https://code.djangoproject.com/ticket/23576#comment:1>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/067.eaf7a2cf38a9abaf68bc38a3f1c30585%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to