Hi Erik, On 02/10/2015 03:30 PM, Erik Cederstrand wrote: > Den 10/02/2015 kl. 21.27 skrev Erik Cederstrand > <erik+li...@cederstrand.dk>: >> >> Running this in parallel in two processes on the same machine >> returns this after a while: >> >> Process A: [...] >> >> Process B: [...] Traceback (most recent call last): File "tmp.py", >> line 30, in <module> assert cache.add(key='foo', value='bar') >> AssertionError >> >> >> I don't see how this is possible when I'm using >> transaction.atomic(). > > Phew. This situation is actually possible since "Read Committed" is > the default isolation level in PostgreSQL, which means that > non-repeatable reads are possible within a transaction.
Yes, that's what I said :-) > My code relies on isolation level "Serializable" for a cache.get() > followed by cache.add() to be reliable, but Django uses the default > from PostgreSQL. I don't think you need full Serializable, Repeatable Read should be sufficient. Serializable is dangerous, has a tendency to cause deadlocks (as I think you've discovered). Even with Repeatable Read, you'll need be a bit careful about any long-running processes that might hold open a transaction. > The isolation level is supposed to be configurable with the > 'isolation_level' setting in OPTIONS > (https://docs.djangoproject.com/en/1.7/ref/databases/#isolation-level). > Except it doesn't work because > django/db/backends/postgresql_psycopg2/base.py::_set_isolation_level() > is never called anywhere, AFAICS. But `self.connection.set_isolation_level()` is called in `_set_autocommit()`, and that should be sufficient. (The `_set_isolation_level()` method is dead code in 1.7 and has since been removed, but what really matters is that `self.connection.set_isolation_level()` is called.) > I tried disabling autocommit (the docs are wrong BTW, > https://docs.djangoproject.com/en/1.7/ref/databases/#autocommit-mode > says to put it in OPTIONS, but django/db/backends/__init__.py (line > 123) looks at settings_dict['AUTOCOMMIT'], not in OPTIONS) OPTIONS['autocommit'] has been ignored since Django 1.6, as the docs you linked clearly state: "This configuration is ignored and can be safely removed." You're looking for https://docs.djangoproject.com/en/1.7/ref/settings/#autocommit instead. (It would be good for the former to have a link to the latter, though.) and > hacking postgresql_psycopg2/base.py::_set_autocommit() to call > _set_isolation_level(), but now process A blocks process B entirely, > even when process A is outside the atomic() context manager. > > Has anyone got isolation_level "Serializable" to work in Django 1.7? I strongly recommend against using the Serializable isolation level, or turning off autocommit mode. The transaction.atomic() API will not work correctly or predictably with autocommit turned off. See https://docs.djangoproject.com/en/1.7/topics/db/transactions/#deactivate-transaction-management You could switch to Repeatable Read (but leave AUTOCOMMIT on). Or (what I would probably do) you could leave the isolation level at the default (since it's the default for Django, some parts of Django, such as QuerySet.get_or_create(), may not work correctly under a different isolation level) and simply update your locking logic to guard against that race condition (if the add fails, assume that another process has grabbed the lock in the interim). Carl -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com. To post to this group, send email to django-users@googlegroups.com. Visit this group at http://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/54DA8A07.9020704%40oddbird.net. For more options, visit https://groups.google.com/d/optout.
signature.asc
Description: OpenPGP digital signature