6
6
using NHibernate . AdoNet ;
7
7
using NHibernate . Engine ;
8
8
using NHibernate . Engine . Transaction ;
9
- using NHibernate . Impl ;
10
9
using NHibernate . Util ;
11
10
12
11
namespace NHibernate . Transaction
@@ -186,6 +185,7 @@ public class SystemTransactionContext : ITransactionContext, IEnlistmentNotifica
186
185
private readonly System . Transactions . Transaction _originalTransaction ;
187
186
private readonly ManualResetEventSlim _lock = new ManualResetEventSlim ( true ) ;
188
187
private volatile bool _needCompletionLocking = true ;
188
+ private bool _preparing ;
189
189
// Required for not locking the completion phase itself when locking session usages from concurrent threads.
190
190
private static readonly AsyncLocal < bool > _bypassLock = new AsyncLocal < bool > ( ) ;
191
191
private readonly int _systemTransactionCompletionLockTimeout ;
@@ -236,7 +236,7 @@ public virtual void Wait()
236
236
// Remove the block then throw.
237
237
Unlock ( ) ;
238
238
throw new HibernateException (
239
- "Synchronization timeout for transaction completion. Either raise {Cfg.Environment.SystemTransactionCompletionLockTimeout}, or this may be a bug in NHibernate." ) ;
239
+ $ "Synchronization timeout for transaction completion. Either raise { Cfg . Environment . SystemTransactionCompletionLockTimeout } , or this may be a bug in NHibernate.") ;
240
240
}
241
241
catch ( HibernateException )
242
242
{
@@ -285,16 +285,17 @@ protected virtual void Unlock()
285
285
{
286
286
// Cloned transaction is not disposed "unexpectedly", its status is accessible till context disposal.
287
287
var status = EnlistedTransaction . TransactionInformation . Status ;
288
- if ( status != TransactionStatus . Active )
288
+ if ( status != TransactionStatus . Active || _preparing )
289
289
return status ;
290
290
291
- // The clone status can be out of date when active, check the original one (which could be disposed if
292
- // the clone is out of date).
291
+ // The clone status can be out of date when active and not in prepare phase, in case of rollback.
292
+ // In such case the original transaction is already disposed, and trying to check its status will
293
+ // trigger a dispose exception.
293
294
return _originalTransaction . TransactionInformation . Status ;
294
295
}
295
296
catch ( ObjectDisposedException ode )
296
297
{
297
- _logger . Warn ( ode , "Enlisted transaction status was wrongly active, original transaction being already disposed. Will assume neither active nor committed." ) ;
298
+ _logger . Warn ( ode , "Enlisted transaction status is maybe wrongly active, original transaction being already disposed. Will assume neither active nor committed." ) ;
298
299
return null ;
299
300
}
300
301
}
@@ -310,6 +311,7 @@ protected virtual void Unlock()
310
311
/// <param name="preparingEnlistment">The object for notifying the prepare phase outcome.</param>
311
312
public virtual void Prepare ( PreparingEnlistment preparingEnlistment )
312
313
{
314
+ _preparing = true ;
313
315
using ( _session . BeginContext ( ) )
314
316
{
315
317
try
@@ -343,10 +345,12 @@ public virtual void Prepare(PreparingEnlistment preparingEnlistment)
343
345
Lock ( ) ;
344
346
345
347
_logger . Debug ( "Prepared for system transaction" ) ;
348
+ _preparing = false ;
346
349
preparingEnlistment . Prepared ( ) ;
347
350
}
348
351
catch ( Exception exception )
349
352
{
353
+ _preparing = false ;
350
354
_logger . Error ( exception , "System transaction prepare phase failed" ) ;
351
355
try
352
356
{
@@ -404,7 +408,7 @@ protected virtual void ProcessSecondPhase(Enlistment enlistment, bool? success)
404
408
/// <summary>
405
409
/// Handle the transaction completion. Notify <see cref="ConnectionManager"/> of the end of the
406
410
/// transaction. Notify end of transaction to the session and to <see cref="ConnectionManager.DependentSessions"/>
407
- /// if any. Close sessions requiring it then cleanup transaction contextes and then <see cref="Unlock"/> blocked
411
+ /// if any. Close sessions requiring it then cleanup transaction contexts and then <see cref="Unlock"/> blocked
408
412
/// threads.
409
413
/// </summary>
410
414
/// <param name="isCommitted"><see langword="true"/> if the transaction is committed, <see langword="false"/>
0 commit comments