[Tim Peters]
>> ...
>> OTOH, if we view the after-commit hook as running at the very start of
>> "the next" transaction, the implementation becomes harder to picture
>> (although the edge case semantics become clearer:  the after-commit
>> hooks run "in" a well-defined transaction then).

[Dieter Maurer]
> But it would give very strange semantics:
>   A transactions has something at its beginning, it knows nothing
>   about -- and this is committed or aborted depending on the
>   fate of this transaction.
>   Bound to result in big surprises...

Yes, it's unattractive.  I have to say that "has something at its beginning"
is too strong, the truth is more that it _may_ have something transactional
at its beginning, depending entirely on what the after-commit hooks do.
Non-transactional "something"s are irrelevant.

Is the other way more attractive?  Running after-commit hooks "at the end"
of the current transaction has the same kinds of problems:

    Then a transaction may have something transactional at its end
    that's silently ignored.

For example, call addBeforeCommitHook() from an after-commit hook, and the
new hook will simply be thrown away uncalled.

Worse, modify a persistent object from an after-commit hook, and that
object's data manager will join a Transaction object (the still-current
Transaction object!) that simply vanishes shortly after.  The damage that
follows could be spectacular:

- tpc_finish marks the Connection as needing to join a Transaction,
  and clears the Connection's list of modified objects.

- The after-commit hooks run, and one of them loads and modifies an
  object from the Connection.

- The Connection joins the current transaction (still the same one!),
  and marks itself as being joined to a transaction.

- The current Transaction object vanishes.

- The Connection won't join the next transaction, because it believes
  it's already joined (before the introduction of after-commit hooks,
  joining a transaction was always followed by a commit or abort of
  that transaction, but not anymore).

- As a result, no modifications to _any_ objects loaded from that
  Connection during the next transaction (including the object modified
  by the after-commit hook) will persist when the next transaction

I'd say that's surprising too ;-)

There's no problem either way if users swear not to do "anything
transactional" in after-commit hooks.  It's unattractive to leave that to
good intentions and/or luck, and I don't see an easy way for either approach
to _prevent_ "something transactional" from happening while an after-commit
hook is running.

In fact I suspect we already have similar possible problems stemming from
afterCompletion() ISynchronizer methods, but so far nobody (other than
ZODB's own Connection) appears to be using those.

I suppose a Transaction could abort() itself "just in case" after
after-commit hooks ran.  Then transactional changes made by after-commit
hooks would be (silently) lost -- but wouldn't screw up the next transaction
(which would again start with a clean slate).

For more information about ZODB, see the ZODB Wiki:

ZODB-Dev mailing list  -  ZODB-Dev@zope.org

Reply via email to