Skip to content

Commit ea9c39a

Browse files
hazzikfredericDelaporte
authored andcommitted
NH-4034 - realigning transaction management with Hibernate
* Hibernate calls statistics between action queue and interceptor * Hibernate calls children AfterCompletion at the end. * Hibernate calls ConnectionManager.AfterTransaction outside of a SessionImpl.AfterTransactionCompletion * Call dependant sessions AfterTransactionCompletion * Flush dependent sessions * Hibernate does not call AfterTransactionBegin for dependent transactions (but should) * Hibernate does not restrict calling interceptors on dependant sessions * Move flush into beforeTransactionCompetion method * Add call to AfterTransactionBegin on dependent sessions * Move using(sessionImplementor.ConnectionManager.FlushingFromDtcTransaction) outside of a loop.
1 parent bfbd264 commit ea9c39a

File tree

8 files changed

+73
-85
lines changed

8 files changed

+73
-85
lines changed

src/NHibernate.Test/SystemTransactions/TransactionFixture.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public void FlushFromTransactionAppliesToDisposedSharingSession()
6161
}
6262
}
6363

64-
Assert.That(flushOrder, Is.EqualTo(new[] { 1, 2, 3, 0 }));
64+
Assert.That(flushOrder, Is.EqualTo(new[] { 0, 1, 2, 3 }));
6565

6666
using (var s = OpenSession())
6767
using (var t = s.BeginTransaction())
@@ -96,7 +96,7 @@ public void FlushFromTransactionAppliesToSharingSession()
9696
}
9797
}
9898

99-
Assert.That(flushOrder, Is.EqualTo(new[] { 1, 2, 3, 0 }));
99+
Assert.That(flushOrder, Is.EqualTo(new[] { 0, 1, 2, 3 }));
100100

101101
using (var s = OpenSession())
102102
using (var t = s.BeginTransaction())

src/NHibernate.Test/TransactionTest/TransactionFixture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ public void FlushFromTransactionAppliesToSharingSession()
163163
}
164164
}
165165

166-
Assert.That(flushOrder, Is.EqualTo(new[] { 1, 2, 3, 0 }));
166+
Assert.That(flushOrder, Is.EqualTo(new[] { 0, 1, 2, 3 }));
167167

168168
using (var s = OpenSession())
169169
using (var t = s.BeginTransaction())

src/NHibernate/Engine/ISessionImplementor.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ public interface ISessionImplementor
186186
/// </summary>
187187
void BeforeTransactionCompletion(ITransaction tx);
188188

189+
/// <summary>
190+
///
191+
/// </summary>
192+
void FlushBeforeTransactionCompletion();
193+
189194
/// <summary>
190195
/// Notify the session that the transaction completed, so we no longer own the old locks.
191196
/// (Also we should release cache softlocks). May be called multiple times during the transaction

src/NHibernate/Impl/AbstractSessionImpl.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ public virtual IList List(CriteriaImpl criteria)
152152
public abstract IEntityPersister GetEntityPersister(string entityName, object obj);
153153
public abstract void AfterTransactionBegin(ITransaction tx);
154154
public abstract void BeforeTransactionCompletion(ITransaction tx);
155+
public abstract void FlushBeforeTransactionCompletion();
155156
public abstract void AfterTransactionCompletion(bool successful, ITransaction tx);
156157
public abstract object GetContextEntityIdentifier(object obj);
157158
public abstract object Instantiate(string clazz, object id);
@@ -430,6 +431,7 @@ protected void AfterOperation(bool success)
430431
if (!ConnectionManager.IsInActiveTransaction)
431432
{
432433
ConnectionManager.AfterNonTransactionalQuery(success);
434+
ConnectionManager.AfterTransaction();
433435
AfterTransactionCompletion(success, null);
434436
}
435437
}

src/NHibernate/Impl/SessionImpl.cs

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -317,41 +317,27 @@ public DbConnection Close()
317317
/// </summary>
318318
public override void AfterTransactionCompletion(bool success, ITransaction tx)
319319
{
320-
if (!_transactionCoordinatorShared)
321-
foreach (var dependentSession in ConnectionManager.DependentSessions)
322-
{
323-
dependentSession.AfterTransactionCompletion(success, tx);
324-
}
325-
326320
using (new SessionIdLoggingContext(SessionId))
327321
{
328322
log.Debug("transaction completion");
323+
324+
persistenceContext.AfterTransactionCompletion();
325+
actionQueue.AfterTransactionCompletion(success);
326+
329327
if (Factory.Statistics.IsStatisticsEnabled)
330328
{
331329
Factory.StatisticsImplementor.EndTransaction(success);
332330
}
333331

334-
// Let the originating session notify the connection manager
335-
if (!_transactionCoordinatorShared)
332+
try
336333
{
337-
connectionManager.AfterTransaction();
334+
Interceptor.AfterTransactionCompletion(tx);
338335
}
339-
340-
persistenceContext.AfterTransactionCompletion();
341-
actionQueue.AfterTransactionCompletion(success);
342-
if (!_transactionCoordinatorShared || Interceptor != ConnectionManager.Session.Interceptor)
336+
catch (Exception t)
343337
{
344-
try
345-
{
346-
Interceptor.AfterTransactionCompletion(tx);
347-
}
348-
catch (Exception t)
349-
{
350-
log.Error("exception in interceptor afterTransactionCompletion()", t);
351-
}
338+
log.Error("exception in interceptor afterTransactionCompletion()", t);
352339
}
353340

354-
355341
//if (autoClear)
356342
// Clear();
357343
}
@@ -2104,48 +2090,39 @@ public override void AfterTransactionBegin(ITransaction tx)
21042090
using (new SessionIdLoggingContext(SessionId))
21052091
{
21062092
CheckAndUpdateSessionStatus();
2107-
2108-
if (!_transactionCoordinatorShared || Interceptor != ConnectionManager.Session.Interceptor)
2109-
{
2110-
Interceptor.AfterTransactionBegin(tx);
2111-
}
2093+
Interceptor.AfterTransactionBegin(tx);
21122094
}
2113-
2114-
if (!_transactionCoordinatorShared)
2115-
foreach (var dependentSession in ConnectionManager.DependentSessions)
2116-
{
2117-
dependentSession.AfterTransactionBegin(tx);
2118-
}
21192095
}
21202096

21212097
public override void BeforeTransactionCompletion(ITransaction tx)
21222098
{
2123-
if (!_transactionCoordinatorShared)
2124-
foreach (var dependentSession in ConnectionManager.DependentSessions)
2125-
{
2126-
dependentSession.BeforeTransactionCompletion(tx);
2127-
}
2128-
21292099
using (new SessionIdLoggingContext(SessionId))
21302100
{
21312101
log.Debug("before transaction completion");
2102+
FlushBeforeTransactionCompletion();
21322103
actionQueue.BeforeTransactionCompletion();
2133-
if (!_transactionCoordinatorShared || Interceptor != ConnectionManager.Session.Interceptor)
2104+
try
21342105
{
2135-
try
2136-
{
2137-
Interceptor.BeforeTransactionCompletion(tx);
2138-
}
2139-
catch (Exception e)
2140-
{
2141-
log.Error("exception in interceptor BeforeTransactionCompletion()", e);
2106+
Interceptor.BeforeTransactionCompletion(tx);
2107+
}
2108+
catch (Exception e)
2109+
{
2110+
log.Error("exception in interceptor BeforeTransactionCompletion()", e);
21422111

2143-
throw;
2144-
}
2112+
throw;
21452113
}
21462114
}
21472115
}
21482116

2117+
public override void FlushBeforeTransactionCompletion()
2118+
{
2119+
using (new SessionIdLoggingContext(SessionId))
2120+
{
2121+
if (FlushMode != FlushMode.Manual)
2122+
Flush();
2123+
}
2124+
}
2125+
21492126
public ISession SetBatchSize(int batchSize)
21502127
{
21512128
Batcher.BatchSize = batchSize;

src/NHibernate/Impl/StatelessSessionImpl.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ namespace NHibernate.Impl
2727
public class StatelessSessionImpl : AbstractSessionImpl, IStatelessSession
2828
{
2929
private static readonly IInternalLogger log = LoggerProvider.LoggerFor(typeof(StatelessSessionImpl));
30+
3031
[NonSerialized]
3132
private readonly ConnectionManager connectionManager;
33+
3234
[NonSerialized]
3335
private readonly StatefulPersistenceContext temporaryPersistenceContext;
3436

@@ -179,7 +181,7 @@ public override void List(CriteriaImpl criteria, IList results)
179181
temporaryPersistenceContext.Clear();
180182
}
181183
}
182-
184+
183185
public override IEnumerable Enumerable(IQueryExpression queryExpression, QueryParameters queryParameters)
184186
{
185187
throw new NotImplementedException();
@@ -216,16 +218,22 @@ public override void AfterTransactionBegin(ITransaction tx)
216218

217219
public override void BeforeTransactionCompletion(ITransaction tx)
218220
{
221+
FlushBeforeTransactionCompletion();
219222
}
220223

221-
public override void AfterTransactionCompletion(bool successful, ITransaction tx)
224+
public override void FlushBeforeTransactionCompletion()
222225
{
223226
using (new SessionIdLoggingContext(SessionId))
224227
{
225-
connectionManager.AfterTransaction();
228+
if (FlushMode != FlushMode.Manual)
229+
Flush();
226230
}
227231
}
228232

233+
public override void AfterTransactionCompletion(bool successful, ITransaction tx)
234+
{
235+
}
236+
229237
public override object GetContextEntityIdentifier(object obj)
230238
{
231239
CheckAndUpdateSessionStatus();
@@ -838,6 +846,7 @@ public ITransaction BeginTransaction(IsolationLevel isolationLevel)
838846
#endregion
839847

840848
#region IDisposable Members
849+
841850
private bool _isAlreadyDisposed;
842851

843852
/// <summary>

src/NHibernate/Transaction/AdoNetWithDistributedTransactionFactory.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
4848
logger.DebugFormat("enlisted into DTC transaction: {0}",
4949
transactionContext.AmbientTransation.IsolationLevel);
5050
session.AfterTransactionBegin(null);
51+
foreach (var dependentSession in session.ConnectionManager.DependentSessions)
52+
dependentSession.AfterTransactionBegin(null);
5153

5254
TransactionCompletedEventHandler handler = null;
5355

@@ -67,7 +69,11 @@ public void EnlistInDistributedTransactionIfNeeded(ISessionImplementor session)
6769
{
6870
logger.Warn("Completed transaction was disposed, assuming transaction rollback", ode);
6971
}
72+
session.ConnectionManager.AfterTransaction();
7073
session.AfterTransactionCompletion(wasSuccessful, null);
74+
foreach (var dependentSession in session.ConnectionManager.DependentSessions)
75+
dependentSession.AfterTransactionCompletion(wasSuccessful, null);
76+
7177
Cleanup(session);
7278
}
7379

@@ -140,29 +146,19 @@ void IEnlistmentNotification.Prepare(PreparingEnlistment preparingEnlistment)
140146
{
141147
using (var tx = new TransactionScope(AmbientTransation))
142148
{
143-
sessionImplementor.BeforeTransactionCompletion(null);
144149
if (sessionImplementor.ConnectionManager.IsConnected)
145150
{
146151
using (sessionImplementor.ConnectionManager.FlushingFromDtcTransaction)
147152
{
153+
sessionImplementor.BeforeTransactionCompletion(null);
148154
foreach (var dependentSession in sessionImplementor.ConnectionManager.DependentSessions)
149-
{
150-
if (dependentSession.FlushMode != FlushMode.Manual)
151-
{
152-
logger.DebugFormat("[session-id={0}] Flushing from Dtc Transaction", dependentSession.SessionId);
153-
dependentSession.Flush();
154-
}
155-
}
156-
if (sessionImplementor.FlushMode != FlushMode.Manual)
157-
{
158-
logger.DebugFormat("[session-id={0}] Flushing from Dtc Transaction", sessionImplementor.SessionId);
159-
sessionImplementor.Flush();
160-
}
155+
dependentSession.BeforeTransactionCompletion(null);
156+
157+
logger.Debug("prepared for DTC transaction");
158+
159+
tx.Complete();
161160
}
162161
}
163-
logger.Debug("prepared for DTC transaction");
164-
165-
tx.Complete();
166162
}
167163
preparingEnlistment.Prepared();
168164
}
@@ -202,7 +198,10 @@ void IEnlistmentNotification.InDoubt(Enlistment enlistment)
202198
{
203199
using (new SessionIdLoggingContext(sessionImplementor.SessionId))
204200
{
201+
sessionImplementor.ConnectionManager.AfterTransaction();
205202
sessionImplementor.AfterTransactionCompletion(false, null);
203+
foreach (var dependentSession in sessionImplementor.ConnectionManager.DependentSessions)
204+
dependentSession.AfterTransactionCompletion(false, null);
206205
logger.Debug("DTC transaction is in doubt");
207206
enlistment.Done();
208207
IsInActiveTransaction = false;
@@ -225,4 +224,4 @@ public class DependentContext : ITransactionContext
225224
public void Dispose() { }
226225
}
227226
}
228-
}
227+
}

src/NHibernate/Transaction/AdoTransaction.cs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,15 +154,21 @@ public void Begin(IsolationLevel isolationLevel)
154154
rolledBack = false;
155155

156156
session.AfterTransactionBegin(this);
157+
foreach (var dependentSession in session.ConnectionManager.DependentSessions)
158+
dependentSession.AfterTransactionBegin(this);
157159
}
158160
}
159161

160162
private void AfterTransactionCompletion(bool successful)
161163
{
162164
using (new SessionIdLoggingContext(sessionId))
163165
{
166+
session.ConnectionManager.AfterTransaction();
164167
session.AfterTransactionCompletion(successful, this);
165168
NotifyLocalSynchsAfterTransactionCompletion(successful);
169+
foreach (var dependentSession in session.ConnectionManager.DependentSessions)
170+
dependentSession.AfterTransactionCompletion(successful, this);
171+
166172
session = null;
167173
begun = false;
168174
}
@@ -186,20 +192,10 @@ public void Commit()
186192

187193
log.Debug("Start Commit");
188194

189-
foreach (var dependentSession in session.ConnectionManager.DependentSessions)
190-
{
191-
if (dependentSession.FlushMode != FlushMode.Manual)
192-
{
193-
dependentSession.Flush();
194-
}
195-
}
196-
if (session.FlushMode != FlushMode.Manual)
197-
{
198-
session.Flush();
199-
}
200-
201-
NotifyLocalSynchsBeforeTransactionCompletion();
202195
session.BeforeTransactionCompletion(this);
196+
NotifyLocalSynchsBeforeTransactionCompletion();
197+
foreach (var dependentSession in session.ConnectionManager.DependentSessions)
198+
dependentSession.BeforeTransactionCompletion(this);
203199

204200
try
205201
{

0 commit comments

Comments
 (0)