Django

Code

Ticket #2705 (new)

Opened 4 years ago

Last modified 2 months ago

[patch] Add optional FOR UPDATE clause to QuerySets

Reported by: Hawkeye Assigned to: anonymous
Milestone: Component: Database layer (models, ORM)
Version: SVN Keywords:
Cc: mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com, physicsnick@gmail.com, meticulos.slacker@gmail.com, forest Triage Stage: Accepted
Has patch: 1 Needs documentation: 0
Needs tests: 0 Patch needs improvement: 1

Description

SQL supports the "FOR UPDATE" clause for SELECT statements to allow for pre-emptive locking. The addition of for_update() for use with get() database operations would greatly enhance Django's transaction support.

As articulated by Michael Radziej on django-users:

   something = models.Something.get(id=333).for_update() 
   # --> django issues: SELECT * FROM something FOR UPDATE 
   something.count +=1 
   something.save() 
   # --> django issues: UPDATE SOMETHING SET ... 

Suggesting EITHER:

  • for_update method to extend all 'get'-like statements
  • get_for_update to supplement other 'get'-like statements

Attachments

for_update.diff (1.5 kB) - added by Hawkeye on 09/13/06 07:15:17.
select_for_update.patch (8.3 kB) - added by Collin Grady <cgrady@the-magi.us> on 03/27/07 18:34:56.
improvement on same idea, supports backend-specific syntax
select_for_update_r7188.patch (4.7 kB) - added by KBS on 03/01/08 18:54:15.
updated patch that works against r7188 of trunk
for_update_7477.patch (4.1 kB) - added by sakyamuni on 04/27/08 13:48:46.
patch against 7477
for_update_7509.patch (5.9 kB) - added by sakyamuni on 04/29/08 19:13:26.
Updated patch to include test / documentation, please review as I have not submitted tests/documentation before
for_update_7510.patch (6.2 kB) - added by sakyamuni on 04/30/08 02:18:40.
Corrected bug in test, modified documentation
for_update_7510.2.patch (6.2 kB) - added by sakyamuni on 04/30/08 18:55:56.
minor documentation changes
for_update_7513.patch (6.2 kB) - added by kbs on 05/04/08 10:26:55.
should work now with sqlite
for_update_7513.2.patch (7.9 kB) - added by sakyamuni on 05/04/08 21:18:26.
Added NOWAIT support (raises exception with mysql), included KBS'es fix to get sqlite to work
for_update_8031.2.patch (7.9 kB) - added by anih on 07/21/08 15:11:14.
patch against r8031
for_update_1.0.patch (8.1 kB) - added by jdemoor on 09/10/08 11:53:19.
Updated patch for Django 1.0, several fixes, tested with Postgres and SQLite.
for_update_1.0.2.patch (8.1 kB) - added by jdemoor on 09/13/08 03:07:21.
Fixed MySQL bug.
for_update-1.0.1.diff (18.7 kB) - added by jdemoor on 11/17/08 06:32:06.
Patch against Django 1.0.1
for_update-1.0.1-v2.diff (18.7 kB) - added by anih on 11/21/08 08:14:46.
with all
for_update-1.0.1-v3.diff (19.5 kB) - added by ikelly on 02/25/09 19:34:36.
Added support for oracle backend
for_update_9962.diff (12.6 kB) - added by anih on 03/03/09 07:05:54.
for update patch with transaction.commit_unless_managed() inside select_for_update()
for_update_9962.v2.diff (19.6 kB) - added by anih on 03/03/09 13:30:27.
in last patch i forget include new files
for_update_9975.diff (19.6 kB) - added by jdemoor on 03/05/09 06:32:43.
Fixed bug in tests.
for_update_11366.diff (12.7 kB) - added by anih on 07/29/09 03:25:41.
for update patch do 1.1
for_update_11366_cdestigter.diff (12.1 kB) - added by cdestigter on 12/16/09 16:01:26.
remove unnecessary/broken changes to django/db/models/base.py

Change History

09/12/06 11:20:39 changed by mir@noris.de

My original proposal was grossly defect (it just meant to illustrate the idea).

What I really meant was adding for_update() as a method to QuerySet?, returning a QuerySet? (like filter, distinct, etc.)

So, the example should of course be the other way around:

something = models.Something.objects.for_update().get(id=333)

or, easier to understand,

something = models.Something.objects.filter(id=333).for_update().get()

09/13/06 07:15:17 changed by Hawkeye

  • attachment for_update.diff added.

09/13/06 07:16:17 changed by Hawkeye

  • summary changed from Add optional FOR UPDATE clause to 'get' database operations to [patch] Add optional FOR UPDATE clause to 'get' database operations.

I'm attaching a patch that provides the functionality:

something = models.Something.objects.filter(id=333).for_update().get()

Obviously, it could appear at different locations in the chain.

Comments welcome!

09/13/06 07:17:09 changed by Hawkeye

  • summary changed from [patch] Add optional FOR UPDATE clause to 'get' database operations to [patch] Add optional FOR UPDATE clause to QuerySets.

03/27/07 18:34:56 changed by Collin Grady <cgrady@the-magi.us>

  • attachment select_for_update.patch added.

improvement on same idea, supports backend-specific syntax

03/27/07 18:37:25 changed by Collin Grady <cgrady@the-magi.us>

  • cc changed from mir@noris.de to mir@noris.de, cgrady@the-magi.us.

I had this same idea last night, and wrote up a patch similar to this, but with support for db-specific syntax - for example MS SQL uses 'WITH (UPDLOCK, HOLDLOCK)' from what I could see, whereas sqlite doesn't support it at all, so it's ignored there to prevent errors (though that could be changed if it's the wrong way to go about it)

03/27/07 20:44:26 changed by mtredinnick

  • stage changed from Unreviewed to Design decision needed.

This isn't a bad feature, although I'm not sure I like the API without being able to put my finger on the exact reason -- nevermind, though, that can be sorted out later and it may be that I just haven't become used to it yet.

Wanted to drop in a note to say "yes, it's worth implementing", but "stop posting patches", because this will go in after the QuerySet refactorisation.

Moving to "design decision needed" so that we remember to think about the API at the right moment.

06/25/07 15:05:50 changed by anonymous

  • cc changed from mir@noris.de, cgrady@the-magi.us to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com.

07/13/07 05:48:47 changed by Vic

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua.

12/02/07 13:34:00 changed by jacob

  • stage changed from Design decision needed to Someday/Maybe.

12/02/07 13:40:04 changed by jacob

  • stage changed from Someday/Maybe to Accepted.

03/01/08 18:53:28 changed by KBS

Here is an updated patch which I got working with r7188 of trunk.

It solved this problem I was having with concurrently incrementing a model field: http://dpaste.com/37397/

Now I simply do to lock row and retreive data in mysql. vote = Votes.object.select_for_update().get_or_create(name='xx')[0]

Note: you could get deadlock if you do not save and commit transaction, and on mysql, this only works on innodb tables, and maybe clusters.

03/01/08 18:54:15 changed by KBS

  • attachment select_for_update_r7188.patch added.

updated patch that works against r7188 of trunk

(follow-up: ↓ 14 ) 04/16/08 15:43:45 changed by anonymous

bump, i realy need this feature, could someone say what is this feature status?

04/16/08 15:44:44 changed by anonymous

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net.

04/18/08 16:06:46 changed by anonymous

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com.

(in reply to: ↑ 11 ) 04/27/08 00:35:50 changed by ubernostrum

Replying to anonymous:

bump, i realy need this feature, could someone say what is this feature status?

Please don't do this; posting a comment for no other reason than to try to "bump" a ticket is rude, and your question was already answered by Malcolm's comment about what needs to happen with this patch.

04/27/08 13:48:46 changed by sakyamuni

  • attachment for_update_7477.patch added.

patch against 7477

04/27/08 13:51:49 changed by sakyamuni

I just updated KBS'es patch to work against the trunk.

Thanks.

04/27/08 14:25:23 changed by anonymous

  • needs_docs set to 1.
  • version set to SVN.
  • needs_tests set to 1.

04/29/08 19:13:26 changed by sakyamuni

  • attachment for_update_7509.patch added.

Updated patch to include test / documentation, please review as I have not submitted tests/documentation before

04/30/08 02:18:40 changed by sakyamuni

  • attachment for_update_7510.patch added.

Corrected bug in test, modified documentation

04/30/08 18:55:56 changed by sakyamuni

  • attachment for_update_7510.2.patch added.

minor documentation changes

05/04/08 10:26:55 changed by kbs

  • attachment for_update_7513.patch added.

should work now with sqlite

05/04/08 21:18:26 changed by sakyamuni

  • attachment for_update_7513.2.patch added.

Added NOWAIT support (raises exception with mysql), included KBS'es fix to get sqlite to work

05/04/08 21:19:51 changed by sakyamuni <x@y.com>

Also note that with for_update_7513.2.patch, I improved the tests such that it tries to commit after locking with for_update()

05/26/08 05:59:09 changed by LI Daobing <lidaobing@gmail.com>

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com.

06/14/08 22:57:24 changed by cgrady

  • needs_docs deleted.

07/10/08 11:52:28 changed by anonymous

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com.

07/21/08 15:11:14 changed by anih

  • attachment for_update_8031.2.patch added.

patch against r8031

07/25/08 10:15:29 changed by wallenfe

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com to mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com.

(follow-up: ↓ 23 ) 07/25/08 10:47:10 changed by wallenfe

Will this patch be included in the 1.0 release?

(in reply to: ↑ 22 ) 07/25/08 20:09:57 changed by russellm

Replying to wallenfe:

Will this patch be included in the 1.0 release?

No. The canonical list of v1.0 features is the Version One features wiki page. This ticket is not mentioned there, so it won't be included.

07/25/08 20:11:07 changed by cgrady

  • cc changed from mir@noris.de, cgrady@the-magi.us, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com.

08/02/08 06:54:05 changed by anih

hmm its small patch without any backwards-incompatible changes and its working, so maybe worth to be commited?

08/18/08 06:01:34 changed by mrts

  • milestone set to post-1.0.

As of now, targeting to post 1.0. Could go into 1.0-maybe as well.

09/10/08 11:53:19 changed by jdemoor

  • attachment for_update_1.0.patch added.

Updated patch for Django 1.0, several fixes, tested with Postgres and SQLite.

09/11/08 08:03:49 changed by spaetz

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de.

tested on mysql. django 1.0 plus patch for_update_1.0.patch posted in comment above:

Exception Value: type object 'BaseDatabaseWrapper?' has no attribute 'for_update_sql' Exception Location: django-1.0_for_update/django/db/backends/mysql/base.py in for_update_sql, line 146

09/13/08 03:07:21 changed by jdemoor

  • attachment for_update_1.0.2.patch added.

Fixed MySQL bug.

11/17/08 06:32:06 changed by jdemoor

  • attachment for_update-1.0.1.diff added.

Patch against Django 1.0.1

11/17/08 06:37:44 changed by jdemoor

  • needs_tests deleted.

I attached a new patch with these changes:

  • backend-agnostic exceptions for deadlocks and locking failures
  • a decorator to retry deadlocked views
  • select_for_update() does nothing when the backend doesn't support it; the same goes for the nowait argument with MySQL (there used to be a NotImplementedError?)
  • updated documentation
  • comprehensive tests

The patch is against Django 1.0.1 and is tested on Python 2.5.

11/21/08 07:47:01 changed by ramiro

  • needs_better_patch set to 1.

Latest patch (for_update-1.0.1.diff) has this in django/db/models/sql/query.py:30

_all__ = ['Query', 'BaseQuery', 'LockNotAvailable']

a leading "_" is missing.

11/21/08 08:14:46 changed by anih

  • attachment for_update-1.0.1-v2.diff added.

with all

02/25/09 13:51:44 changed by

  • milestone deleted.

Milestone post-1.0 deleted

02/25/09 17:59:21 changed by anih

Could anyone specify what is need to add this patch to trunk?

02/25/09 18:56:00 changed by ikelly

For starters, somebody needs to update the patch so that it applies cleanly to trunk. A patch against 1.0.1 is not useful, since this feature will never be included in any 1.0.X release.

We also need to add support for the Oracle backend...actually, I think I'll work on that now.

02/25/09 19:34:36 changed by ikelly

  • attachment for_update-1.0.1-v3.diff added.

Added support for oracle backend

(follow-up: ↓ 38 ) 02/25/09 20:04:08 changed by ikelly

I made a small change to handle_deadlocks so that the transaction is automatically rolled back when a deadlock is detected and no retries are left. The reason for this is that in Oracle, the second thread in the test was still waiting for the first thread to rollback even after the first thread had been joined and presumably had its resources cleaned up. The alternative would be to leave it as is and recommend the user to always rollback whenever a DeadlockError? is raised, but I'm not thrilled with that: one might expect to be able to ignore the DeadlockError? and have the deadlock be fully resolved.

I'll also be checking on the cx_Oracle mailing list whether this behavior is intended.

On a related note, I'm not sure that having handle_deadlocks retry the view should be the default behavior -- anything done in middleware and not already committed would be rolled back as well and not retried.

02/27/09 03:21:10 changed by anonymous

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org.

03/01/09 03:16:34 changed by liangent

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com.

it seems there's a problem... if i used .select_for_update(), but didn't do UPDATE django doesn't know it needs to commit when automatic commit is required, for example, .managed(False) or something in middleware/transaction.py (when a view returns)

maybe, it should be marked as dirty when invoking .select_for_update()?

(follow-up: ↓ 37 ) 03/03/09 03:57:51 changed by liangent

another problem...

                transaction.managed(True)
                transaction.set_dirty() # see comment above
                s = S.objects.select_for_update().filter(s='Q').order_by('pk')
                try:
                    t = s[0]
                except IndexError:
                    transaction.managed(False)
                    time.sleep(2000)
                    continue # there's a 'for' outside
                t.s = 'A'
                t.g = G.objects.get(pk=1)
                t.save(force_update=True) # mark
                transaction.managed(False)

in that marked line, if i don't specify force_update=True, it will do an INSERT, which will cause an IntegrityError. IntegrityError: (1062, "Duplicate entry '11' for key 1")

03/03/09 07:05:54 changed by anih

  • attachment for_update_9962.diff added.

for update patch with transaction.commit_unless_managed() inside select_for_update()

(in reply to: ↑ 36 ; follow-up: ↓ 41 ) 03/03/09 07:11:53 changed by anih

Replying to liangent:

in that marked line, if i don't specify force_update=True, it will do an INSERT, which will cause an IntegrityError. IntegrityError: (1062, "Duplicate entry '11' for key 1")

i try to reproduce this problem but without success, could you paste model file and separate some test?

i send patch to trunk version with transaction.commit_unless_managed() inside select_for_update() (django/db/models/query.py)

i dont have oracle to make some tests, but im using this patch with postgresql for about 1/2 year

(in reply to: ↑ 33 ; follow-up: ↓ 39 ) 03/03/09 12:53:16 changed by ikelly

Replying to ikelly:

I made a small change to handle_deadlocks so that the transaction is automatically rolled back when a deadlock is detected and no retries are left. The reason for this is that in Oracle, the second thread in the test was still waiting for the first thread to rollback even after the first thread had been joined and presumably had its resources cleaned up. The alternative would be to leave it as is and recommend the user to always rollback whenever a DeadlockError? is raised, but I'm not thrilled with that: one might expect to be able to ignore the DeadlockError? and have the deadlock be fully resolved. I'll also be checking on the cx_Oracle mailing list whether this behavior is intended.

Update: I'm having a heck of a time nailing down exactly what's going on with this hang issue. It reliably occurs when using the oracle backend, but outside of Django I can't reproduce it at all; the connection does get properly cleaned up when the deadlocked thread exits. About the only thing I've managed to determine is that if I run del connection.connection when exiting the test threads, then the issue does not occur and the tests pass. What I can't figure out is why this is necessary.

03/03/09 13:30:27 changed by anih

  • attachment for_update_9962.v2.diff added.

in last patch i forget include new files

(in reply to: ↑ 38 ) 03/03/09 13:58:45 changed by anih

Replying to ikelly:

Update: I'm having a heck of a time nailing down exactly what's going on with this hang issue. It reliably occurs when using the oracle backend, but outside of Django I can't reproduce it at all; the connection does get properly cleaned up when the deadlocked thread exits. About the only thing I've managed to determine is that if I run del connection.connection when exiting the test threads, then the issue does not occur and the tests pass. What I can't figure out is why this is necessary.

maybe problem is related with that select_for_update didnt set transaction dirty? new patch have this corected(i think)

(follow-up: ↓ 42 ) 03/03/09 15:16:59 changed by ikelly

I've found the problem -- turns out it has nothing to do with Oracle. It's Python bug 1868 combined with setting DEBUG=True in the settings file; I had that set in my oracle test settings file, but not in my postgres or mysql files. With DEBUG=True set, the cursor gets wrapped in a CursorDebugWrapper, which has a finally clause in its execute method that accesses an attribute of the ConnectionWrapper object, triggering the bug.

I don't think this is likely to be a major issue outside of the test suite, so I wouldn't object to moving the rollback in handle_deadlock back to its original location, as long as we do something in the test to make sure it doesn't hang.

Also, I think select_for_update is the wrong place to set the transaction dirty. That needs to happen when the query is run, not when the queryset is constructed, which is not necessarily the same time.

(in reply to: ↑ 37 ; follow-up: ↓ 43 ) 03/03/09 23:08:42 changed by liangent

Replying to anih:

Replying to liangent:

in that marked line, if i don't specify force_update=True, it will do an INSERT, which will cause an IntegrityError. IntegrityError: (1062, "Duplicate entry '11' for key 1")

i try to reproduce this problem but without success, could you paste model file and separate some test? i send patch to trunk version with transaction.commit_unless_managed() inside select_for_update() (django/db/models/query.py) i dont have oracle to make some tests, but im using this patch with postgresql for about 1/2 year

(note: 1. 'key 1' is the primary key; 2. i'm using mysql: 5.0.67-0ubuntu6)

i think it has nothing to do with the models.

as i know, django try to SELECT a row when we're going to .save() to know if the row exists. however, because i used SELECT FOR UPDATE, mysql locked the row, and django cannot find it with SELECT, so django decides to INSERT. since the field 'id' in object 't' has been set and value is assigned to an existing row ('t' was got from a SELECT FOR UPDATE), an IntegrityError is raised.

(in reply to: ↑ 40 ) 03/03/09 23:10:46 changed by liangent

Replying to ikelly:

I've found the problem -- turns out it has nothing to do with Oracle. It's Python bug 1868 combined with setting DEBUG=True in the settings file; I had that set in my oracle test settings file, but not in my postgres or mysql files. With DEBUG=True set, the cursor gets wrapped in a CursorDebugWrapper, which has a finally clause in its execute method that accesses an attribute of the ConnectionWrapper object, triggering the bug. I don't think this is likely to be a major issue outside of the test suite, so I wouldn't object to moving the rollback in handle_deadlock back to its original location, as long as we do something in the test to make sure it doesn't hang. Also, I think select_for_update is the wrong place to set the transaction dirty. That needs to happen when the query is run, not when the queryset is constructed, which is not necessarily the same time.

anyhow, transaction should be set dirty after SELECT FOR UPDATE was executed.

(in reply to: ↑ 41 ; follow-up: ↓ 44 ) 03/04/09 01:31:30 changed by anih

Replying to liangent:

Replying to anih: (note: 1. 'key 1' is the primary key; 2. i'm using mysql: 5.0.67-0ubuntu6) i think it has nothing to do with the models. as i know, django try to SELECT a row when we're going to .save() to know if the row exists. however, because i used SELECT FOR UPDATE, mysql locked the row, and django cannot find it with SELECT, so django decides to INSERT. since the field 'id' in object 't' has been set and value is assigned to an existing row ('t' was got from a SELECT FOR UPDATE), an IntegrityError is raised.

problem is how mysql treats rows select with for update statment: http://www.mysqlperformanceblog.com/2006/08/06/select-lock-in-share-mode-and-for-update/

(in reply to: ↑ 43 ) 03/04/09 08:11:56 changed by liangent

Replying to anih:

Replying to liangent:

Replying to anih: (note: 1. 'key 1' is the primary key; 2. i'm using mysql: 5.0.67-0ubuntu6) i think it has nothing to do with the models. as i know, django try to SELECT a row when we're going to .save() to know if the row exists. however, because i used SELECT FOR UPDATE, mysql locked the row, and django cannot find it with SELECT, so django decides to INSERT. since the field 'id' in object 't' has been set and value is assigned to an existing row ('t' was got from a SELECT FOR UPDATE), an IntegrityError is raised.

problem is how mysql treats rows select with for update statment: http://www.mysqlperformanceblog.com/2006/08/06/select-lock-in-share-mode-and-for-update/

i think django should deal with it and have an identical invoking interface between different DBs.

03/04/09 08:36:20 changed by anih

i see two solutions:

1. in documentation put information about this problem and workaround with force_update=True

2. we can propagate information about using select_for_update to models object and when we check if row exist add for update to this "select count()"

i dont now if second solution is ok

maybe we need set stage "design decision needed" for this ticket?

03/04/09 23:40:03 changed by liangent

1. will SELECT COUNT() FOR UPDATE lock more rows? i'm not sure

2. or we can save whether an instance was selected by .select_for_update() in that instance?

03/05/09 06:32:43 changed by jdemoor

  • attachment for_update_9975.diff added.

Fixed bug in tests.

03/05/09 06:36:17 changed by jdemoor

The tests were failing because of

view1 = handle_deadlocks(max_retries=max_retries)(transaction.commit_manually(view1))

which is now

view1 = transaction.commit_manually(handle_deadlocks(max_retries=max_retries)(view1))

This will have to go in the documentation.

03/12/09 15:23:22 changed by xmm

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com.
  • needs_better_patch deleted.
  • has_patch deleted.

03/12/09 15:33:33 changed by xmm

  • needs_better_patch set to 1.
  • has_patch set to 1.

Sorry, some options switched off. Maybe it is important. PS: Has added myself in the CC-field since I consider important this patch.

05/08/09 15:32:47 changed by sfllaw

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com.

07/29/09 03:25:41 changed by anih

  • attachment for_update_11366.diff added.

for update patch do 1.1

08/13/09 09:11:28 changed by physicsnick

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com, physicsnick@gmail.com.

09/19/09 08:43:35 changed by meticulos_slacker

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com, physicsnick@gmail.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com, physicsnick@gmail.com, meticulos.slacker@gmail.com.

09/28/09 10:58:01 changed by physicsnick

Hey guys, just a warning here: the latest patch, for_update_11366, adds a print statement to db/models/base.py which causes mod_wsgi to panic because access to stdout is restricted. Seems to work well otherwise.

10/05/09 12:35:16 changed by anonymous

  • owner changed from nobody to anonymous.

12/16/09 16:01:26 changed by cdestigter

  • attachment for_update_11366_cdestigter.diff added.

remove unnecessary/broken changes to django/db/models/base.py

12/16/09 16:02:19 changed by cdestigter

new patch solves a bunch of test failures and gets rid of the offending print statement.

02/02/10 20:24:58 changed by forest

  • cc changed from mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com, physicsnick@gmail.com, meticulos.slacker@gmail.com to mir@noris.de, rajeev.sebastian@gmail.com, vic@stream.net.ua, sebastian@e-ti.net, justin.fiore@gmail.com, lidaobing@gmail.com, jdemoor@gmail.com, wallenfe@gmail.com, sebastian@sspaeth.de, jdi@l4x.org, liangent@gmail.com, xmm.dev@gmail.com, simon@akoha.com, physicsnick@gmail.com, meticulos.slacker@gmail.com, forest.

02/03/10 11:12:45 changed by forest

I believe that transaction.set_dirty should be called when acquiring the row lock. The transaction must be rolled back or committed for the lock to be released. TransactionMiddleware? won't do this unless the transaction is marked as dirty.


Add/Change #2705 ([patch] Add optional FOR UPDATE clause to QuerySets)




Change Properties
Action