Skip to content

Commit c2a3806

Browse files
NH-2176 - one more concurrency issue, but not sure that will fix it.
1 parent d52d74a commit c2a3806

File tree

1 file changed

+23
-0
lines changed

1 file changed

+23
-0
lines changed

src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,9 @@ void IEnlistmentNotification.InDoubt(Enlistment enlistment)
170170

171171
private void ProcessSecondPhase(Enlistment enlistment, bool? success)
172172
{
173+
// In case of rollback, the prepare phase may have not be run, and we then need to lock as soon as possible.
174+
// There is no guarantee the second phase will be run before the completed event, doing that at both places.
175+
SafeLockSession();
173176
using (new SessionIdLoggingContext(_sessionImplementor.SessionId))
174177
{
175178
_logger.Debug(
@@ -195,6 +198,9 @@ private void ProcessSecondPhase(Enlistment enlistment, bool? success)
195198

196199
public void TransactionCompleted(object sender, TransactionEventArgs e)
197200
{
201+
// In case of rollback, the prepare phase may have not be run, and we then need to lock as soon as possible.
202+
// There is no guarantee the second phase will be run before the completed event, doing that at both places.
203+
SafeLockSession();
198204
e.Transaction.TransactionCompleted -= TransactionCompleted;
199205
// This event may execute before second phase, so we cannot try to get the success from second phase.
200206
// Using this event is required by example in case the prepare phase failed and called force rollback:
@@ -247,6 +253,23 @@ private void RunAfterTransactionActions(bool wasSuccessful)
247253
}
248254
}
249255

256+
/// <summary>
257+
/// Lock the session, but do not assume the context is not already disposed or concurrently disposing.
258+
/// </summary>
259+
private void SafeLockSession()
260+
{
261+
if (_isDisposed)
262+
return;
263+
try
264+
{
265+
_waitEvent.Reset();
266+
}
267+
catch
268+
{
269+
// Ignore, concurrently disposing, meaning it does not need to block anymore.
270+
}
271+
}
272+
250273
private volatile bool _isDisposed;
251274

252275
public void Dispose()

0 commit comments

Comments
 (0)