On 29 touko, 01:07, Chris Conover <clc...@gmail.com> wrote:
> Adding commit_unless_managed() before the get() seems to fix the problem.
> Looking at it locally, the Gearman worker starts a transactions and just
> calls commit when the processing is done, over and over, never starting a
> new transaction. That combined with REPEATABLE-READ seems to be the culprit.
>
> My next step was going to be to set the isolation level to READ-COMMITTED
> which would probably have fixed it as well.  Thought I'm not sure how that
> would have affected performance.
>
> Will the changes to transactions in 1.6 possibly address this issue so I
> can remove the commit_unless_managed() call? It looks like the major change
> is using the underlying database's autocommit mode rather than emulating it
> in the ORM. I suppose I'll have to test...

The thing is Django didn't even emulate the autocommit mode in pre 1.6
versions. The behavior in 1.5 is this:
  1. Any query will start a transaction (unless of course you are
already in transaction)
  2. An ORM write will commit after the write is done (but not
rollback on exception!)
  3. Any other write will not commit

This is changed to:
  1. Any query will happen in autocommit mode - that is there are no
user-visible transactions.
  2. Some ORM write operations are wrapped in transaction (unless
already in transaction). Again, this is not user visible. Reason is
that for example multitable save() should be atomic.

That is, in 1.6 the mode is autocommit with some extra protection for
certain ORM write operations.

Another significant change: In pre 1.6 you can enter transaction block
by @commit_on_success. All queries inside the block will be part of
the same transaction. The name should be treated literally. If you
nest commit_on_success decorators you might get surprising behavior:
with commit_on_success: # Starts a transaction
    with commit_on_success: # Uses the same transaction
        obj.save()
    # Second commit_on_success commits on success. Note however that
the first commit_on_success started the transaction.
    otherobj.save()
    raise Exception("what happens?")

End situation is that obj.save() was committed, otherobj.save()
wasn't. A new transaction was started after the inner
commit_on_success block exited. In 99% of cases this isn't what was
wanted.

In 1.6 the code should be converted to:
with atomic: # Starts a transaction
    with atomic: # Creates a savepoint
        obj.save()
    # The savepoint is released
    otherobj.save()
    raise Exception

Now, the exception will cause a rollback of the transaction. Both obj
and otherobj save are rolled back.

All in all 1.6 transactions should be a lot easier to understand
(there isn't one unless you explicitly asked for a transaction), and
the atomic decorator is more powerful than commit_on_success.

I am not sure if you will need some form of commit in 1.6 before
the .get(). It depends on how the code is structured, and what does
start the problematic transaction. If the code uses some form of
explicit transaction control (commit_on_success, commit_manually) then
the autocommit behavior will not be in effect, and you will need
manual commit. If autocommit mode is in effect, things should just
work.

 - Anssi

-- 
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?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to