Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix dependent transaction failure #2197

Merged
merged 6 commits into from
Sep 5, 2019

Conversation

fredericDelaporte
Copy link
Member

Fix #2172

This is a regression of NH5.0, causing dependent transactions to be unusable.
The trouble with dependent transactions is, they are usually disposed of before completing the actual transaction.
This causes a bug in NHibernate transaction context when checking for the transaction status. It fortunately uses a clone for this, but due to a bug where the status may still be active while the transaction is rollbacked, it does also check the original transaction, and currently assumes that if it is disposed, the transaction is no more active.
This is not true with dependent transactions.
(Well actually the check method just yield null to tell it does not know, but then the code calling it do the "not active" path.)

Since this PR targets 5.2.x, I will delay releasing 5.2.6.
If merged, this PR should be back-ported down to 5.0.x

@fredericDelaporte fredericDelaporte added this to the 5.2.6 milestone Aug 24, 2019
@@ -285,16 +285,17 @@ protected virtual void Unlock()
{
// Cloned transaction is not disposed "unexpectedly", its status is accessible till context disposal.
var status = EnlistedTransaction.TransactionInformation.Status;
if (status != TransactionStatus.Active)
if (status != TransactionStatus.Active || _preparing)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The trouble with dependent transactions occurs in the prepare phase, where we are sure the transaction is not (yet) roll-backed.
This way of dodging that trouble looks like one more crutch in this dreaded system transaction management. But I have seen no better.

(Checking the original transaction concrete type is unreliable, because a DependentTransaction own Clone method will not yield another DependentTransaction, but a Transaction. Moreover, knowing it is a dependent transaction will anyway not help knowing whether the transaction is still actually active or not.)

@@ -236,7 +236,7 @@ public virtual void Wait()
// Remove the block then throw.
Unlock();
throw new HibernateException(
"Synchronization timeout for transaction completion. Either raise {Cfg.Environment.SystemTransactionCompletionLockTimeout}, or this may be a bug in NHibernate.");
$"Synchronization timeout for transaction completion. Either raise {Cfg.Environment.SystemTransactionCompletionLockTimeout}, or this may be a bug in NHibernate.");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trivial bug fix by the way. I do not think it is even worth a mention in commit.

@fredericDelaporte fredericDelaporte changed the title Fix dependent transaction failure WIP - Fix dependent transaction failure Aug 25, 2019
@fredericDelaporte

This comment has been minimized.

@fredericDelaporte fredericDelaporte changed the title WIP - Fix dependent transaction failure Fix dependent transaction failure Aug 25, 2019
var currentTransaction = System.Transactions.Transaction.Current;
if (!ReferenceEquals(currentTransaction, _originalTransaction) &&
currentTransaction == EnlistedTransaction)
return currentTransaction.TransactionInformation.Status;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows chaining multiple dependent transaction usage of the same original transaction on the same session. This means this use case will works with some exception handling, which hurts performances.
But dodging theses exceptions for this dependent case would require to check the current transaction first (instead of trying the original one), which would introduce another exception handling for more regular cases than dependent transaction or rollback.

Fix chaining dependent transaction usage on the same session
@fredericDelaporte
Copy link
Member Author

It seems we are getting an async test trouble. Fiddling with Transaction.Current in an async context along with distributed transactions (which introduces actual thread changes) does not work well. Especially, it looks like the finally cannot set to null Current for the original execution context, causing teardown and subsequent tests to fail.
So I am going to commit an async ignore change for these tests.

using NHibernate.Test.TransactionTest;
using NUnit.Framework;

using sysTran = System.Transactions;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont' like this much.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I will revert.
I did that due to otherwise having to specify the full namespace everywhere before "sysTran" Transaction because of the conflict with NHibernate Transaction namespace, and I then rather shorten the namespace prefixing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants