I think we would need the same concurrency protection yes. If not today, in the near
future.
On 10 mars 2015, at 15:53, Scott Marlow <smarlow(a)redhat.com>
wrote:
> On 03/10/2015 10:12 AM, Emmanuel Bernard wrote:
> So Gunnar, your workaround is fine today but will pose problems in the future if we
decide that onRollback for ErrorHandler needs access to the session somehow to be able to
compensate and undo the already executed operations:
> - a closed session will do us no good
> - there is a harder problem that Scott mentions below related to tx reaping in a
different thread
>
> Let’s try and find a solution for the first problem.
>
> @Scott, I think what happens is the following:
>
> - Hibernate registers a Sync when the EM is created (for the flush() callbacks and a
few other things)
> - Synchronization attached to the Hibernate Transaction objects are piggybacking on
that initial Sync attachement
> - Wildfly attach a “close session” Sync once it has the instance of EntityManager
> - according to your rules, the close session afterTransaction Sync is called before
the one Hibernate put
> - that explains why Gunnar finds an already closed Tx.
>
> But since Gunnar attaches its Sync when the Hibernate TransactionCoordinator creates
the Hibernate transaction, which is when the EM is created, I can’t explain why the
workaround works.
Because Gunnar initially registered the Sync, via [3]
javax.transaction.Transaction.registerSynchronization(Sync), which might be correct in
some non-WildFly environments where perhaps all Syncs are registered via [3] (as
non-interposed syncs). When Gunnar, switched to the Hibernate JtaPlatform mechanism for
registering the Sync, we then switched to an interposed Sync. I suspect that the
JtaPlatform sync registration is a good way to register the OGM, however, I have been told
that the *best* way is to register only one sync (to avoid ordering issues).
If OGM could register to share the existing Hibernate EM sync, we would have more control
over when the OGM sync is invoked and in which thread (application versus background tm
reaping thread).
Regarding the proposed "new proposal for tx timeout handling using transaction
DISASSOCIATING event notification" discussion and how that could impact OGM. We will
continue to run the interposed/non-interposed sync callbacks in whatever thread the TM,
calls them from (e.g. beforeCompletion may or may not be called from app thread,
afterCompletion will be called from either app thread, background reaping thread or
background communications thread). The reason is that certain resources need to be
cleaned up immediately from the Sync.afterCompletion(int status) call. Certain other
resources (like clearing managed entities from persistence context after a rollback), need
to be handled from either the application thread or a background thread after the
application thread is disassociated from the JTA transaction.
IMO, the OGM ErrorHandling/Compensation API probably needs to be aware of the same
concurrency requirements to avoid presenting the executed operations list, while the
application thread is still executing new operations (because it perhaps doesn't yet
know that the tx rolled back).
It would be good to know if OGM will also need the concurrency protection, so that any
new Hibernate 5.0 SPI can be used by OGM (e.g. currently the only need is to run the
Hibernate Session.clear when we know that the application thread is not actively using the
Session).
>
> Emmanuel
>
>> On 10 Mar 2015, at 14:39, Scott Marlow <smarlow(a)redhat.com> wrote:
>>
>> Hi Gunnar,
>>
>> Yes, this behaviour is expected since you registered an non-interposed
>> synchronization. For what purpose are you registering the transaction
>> synchronization? I would like to be aware of the synchronizations that
>> we register in WildFly.
>>
>> The non-interposed sync beforeCompletion callback are invoked first,
>> then the interposed sync beforeCompletion calls, then the interposed
>> afterCompletion(int status) calls and finally, the non-interposed
>> afterCompletion(int status) calls.
>>
>> The Synchronizations that are registered via the
>>
javax.transaction.TransactionSynchronizationRegistry.registerInterposedSynchronization(Synchronization)
>> [2] are interposed.
>>
>> Synchronizations that are registered via the
>> javax.transaction.Transaction.registerSynchronization(Synchronization)
>> [3] are non-interposed.
>>
>> In WildFly, the transaction manager uses the registration order within
>> the interposed/non-interposed group. Before completion syncs (within
>> their respective group), are run in registration order. After
>> completion syncs (within their respective group), are run in reverse
>> registration order.
>>
>> I believe that your workaround, mentioned below, of using
>> JtaPlatform#registerSynchronization() on WildFly, is registering your
>> synchronization as interposed via the TransactionSynchronizationRegistry
>> [2]. There might be a way to register a sync callback at the Hibernate
>> session level (which would also run as interposed sync on WildFly).
>>
>> Not sure if you saw my email yesterday to Hibernate-dev ml. You should
>> be aware that the afterCompletion(int status) callback, may be called
>> from a non-application thread when the WildFly tm reaper handles tx
>> timeout (this can happen while the application thread is still invoking
>> calls on the Hibernate session). Because the Hibernate session is not
>> thread safe, we need to ensure that the Hibernate session
>> afterCompletion(int status) callback does not mutate the Hibernate
>> session (e.g. calling session.clear() what status == rolled back).
>>
>> Scott
>>
>> [2]
>>
http://docs.oracle.com/javaee/5/api/javax/transaction/TransactionSynchron...
>>
>> [3]
>>
http://docs.oracle.com/javaee/5/api/javax/transaction/Transaction.html#re...
>>
>>> On 03/10/2015 09:03 AM, Gunnar Morling wrote:
>>> Hi,
>>>
>>> I'm trying to perform a specific action upon transaction rollback.
>>>
>>> Assuming this could be done using a custom
>>> javax.transaction.Synchronization, I tried to register a synchronization as
>>> follows:
>>>
>>> TransactionImplementor transaction = ...; // e.g. a CMTTransaction
>>> transaction.registerSynchronization( new MySync() );
>>>
>>> And indeed beforeCompletion() is invoked as expected. But afterCompletion()
>>> never is. I debugged this a bit on WildFly and observed the following:
>>>
>>> * Hibernate ORM registers RegisteredSynchronization with JTA.
>>> RegisteredSynchronization manages (indirectly, through
>>> TransactionCoordinator, SynchronizationRegistry etc.) those
>>> synchronizations added through o.h.t.Transaction.registerSynchronization()
>>> * WildFly (specifically, TransactionUtil [1]) registers its own
>>> SessionSynchronization
>>> for closing the entity manager/session
>>>
>>> Now that second synchronization is called first, closing the session. Upon
>>> SessionImpl#close(), the SynchronizationRegistry is cleared. Then when
>>> afterComplection() is called on RegisteredSynchronization afterwards, any
>>> previously registered delegate synchronizations are gone already and thus
>>> do not get invoked.
>>>
>>> I believe I found a workaround for my case by registering my
>>> synchronization through JtaPlatform#registerSynchronization() (which
>>> registers it with the actual JTA transaction).
>>>
>>> My questions are:
>>>
>>> * Is this behaviour expected?
>>> * Is the work-around of doing the registration via JtaPlatform viable or
>>> are there any drawbacks which I'm not aware of?
>>>
>>> Thanks,
>>>
>>> --Gunnar
>>>
>>> [1]
>>>
https://github.com/wildfly/wildfly/blob/master/jpa/src/main/java/org/jbos...
>>> _______________________________________________
>>> hibernate-dev mailing list
>>> hibernate-dev(a)lists.jboss.org
>>>
https://lists.jboss.org/mailman/listinfo/hibernate-dev
>> _______________________________________________
>> hibernate-dev mailing list
>> hibernate-dev(a)lists.jboss.org
>>
https://lists.jboss.org/mailman/listinfo/hibernate-dev
>