On 06/02/2011 01:41 PM, Scott Marlow wrote:
My understanding of "Too late in the game", would be
attempting to
register the sync after commit has been called to start ending the
transaction.
That's not quite right and indeed the trouble we're seeing stems from
Synchronizations that (indirectly) register other Synchronizations from
within beforeCompletion i.e. at a point in time after commit() is called
by the app or container and the transaction manager has thus begun tx
termination processing, of which beforeCompletion calls are one of the
early parts.
Since the tx is technically still active during beforeCompletion, it is
legitimate for beforeCompletions to call registerSynchronization or
registerInterposedSynchronization. Prior to the introduction of the
latter method in JTA 1.1 that was the end of the story - newly
registered Syncs just got tacked onto the end of the pending list and
the beforeCompletion phase continued to run until no new ones were
registered. Registration order determined call order, although that's
not a JTA requirement, just an impl detail.
With JTA 1.1 there is now a spec defined partial order for
Synchronizations which differs from registration order, so in some cases
we can't simply tack newly registered ones onto the list - we're passed
the point at which we would call them and so we reject the registration.
A beforeCompletion can only register a Sync only if it would be ordered
after the one that's currently executing. Technically this is true even
within Sync types, but it only manifests as a problem between types
(interposed/non-interposed) as we take care of the ordering between
instances of the same type internally in the tx code - you can't
override that bit through the JTA api.
So, the rule for activity in beforeCompletion is:
- a Sync registered via registerSynchronization may call either
registerSynchronization or registerInterposedSynchronization.
- a Sync registered via registerInterposedSynchronization may call
only registerInterposedSynchronization.
Thus hibernate (interposed) can't call the JCA (non-interposed) to get a
db connection. But it could call registerInterposedSynchronization,
which is basically why there is now a more to convert everything that it
may call to use interposed syncs. That escalation may not necessarily
be the best long term move, as it leaves you with a problem if you wind
up needing a yet tighter defined ordering equivalent to
registerInterposedInterposed...
Jonathan.
Note from Jonathan Halliday about the same:
"
per the JTA spec, interposed Synchronizations must be called after
non-interposed ones. Since hibernate is using interposed
Synchronizations, the tx has already passed the point at which it can
call non-interposed Synchronizations. Therefore it does not allow them
to be registered, on the basis that there needs to be some way to spot
that they are not going to get called, otherwise you'd spend hours
scratching your head and wondering why the Synchronization was not
getting invoked. There is a corner case where you don't give a toss
about beforeCompletion and want the Synchronization only for
afterCompletion, but there is no way in the API to indicate that so we
play it safe and disallow uniformly.
--
Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod
Street, Windsor, Berkshire, SI4 1TE, United Kingdom.
Registered in UK and Wales under Company Registration No. 3798903
Directors: Michael Cunningham (USA), Charlie Peters (USA), Matt Parsons
(USA) and Brendan Lane (Ireland).