From: <fab...@us...> - 2009-05-14 06:41:15
|
Revision: 4298 http://nhibernate.svn.sourceforge.net/nhibernate/?rev=4298&view=rev Author: fabiomaulo Date: 2009-05-14 06:41:09 +0000 (Thu, 14 May 2009) Log Message: ----------- - Improved log to check Dtc possible problems - Fix NH-1769 (by Timo Rantanen) - added some test for Dtc Modified Paths: -------------- trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/DtcFailures/DtcFailuresFixture.cs Modified: trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-05-14 03:56:57 UTC (rev 4297) +++ trunk/nhibernate/src/NHibernate/Impl/AbstractSessionImpl.cs 2009-05-14 06:41:09 UTC (rev 4298) @@ -318,10 +318,13 @@ using (var tx = new TransactionScope(ambientTransation)) { BeforeTransactionCompletion(null); - if (FlushMode != FlushMode.Never) + if (FlushMode != FlushMode.Never && ConnectionManager.IsConnected) { using (ConnectionManager.FlushingFromDtcTransaction) + { + logger.Debug(string.Format("[session-id={0}] Flushing from Dtc Transaction", sessionId)); Flush(); + } } logger.Debug("prepared for DTC transaction"); @@ -333,7 +336,6 @@ { logger.Error("DTC transaction prepre phase failed", exception); preparingEnlistment.ForceRollback(exception); - } } } @@ -382,13 +384,21 @@ AfterTransactionBegin(null); ambientTransation.TransactionCompleted += delegate(object sender, TransactionEventArgs e) { - bool wasSuccessful = e.Transaction.TransactionInformation.Status - == TransactionStatus.Committed; - AfterTransactionCompletion(wasSuccessful, null); - if (shouldCloseSessionOnDtcTransactionCompleted) + bool wasSuccessful = false; + try { - Dispose(true); + wasSuccessful = e.Transaction.TransactionInformation.Status + == TransactionStatus.Committed; } + catch (ObjectDisposedException ode) + { + logger.Warn("Completed transaction was disposed.", ode); + } + AfterTransactionCompletion(wasSuccessful, null); + if (shouldCloseSessionOnDtcTransactionCompleted) + { + Dispose(true); + } ambientTransation = null; }; ambientTransation.EnlistVolatile(this, EnlistmentOptions.EnlistDuringPrepareRequired); Modified: trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-05-14 03:56:57 UTC (rev 4297) +++ trunk/nhibernate/src/NHibernate/Impl/SessionImpl.cs 2009-05-14 06:41:09 UTC (rev 4298) @@ -226,7 +226,7 @@ if (log.IsDebugEnabled) { - log.Debug("opened session at timestamp: " + timestamp); + log.Debug(string.Format("[session-id={0}]opened session at timestamp:{1}", sessionId, timestamp)); } CheckAndUpdateSessionStatus(); @@ -1655,7 +1655,7 @@ { using (new SessionIdLoggingContext(sessionId)) { - log.Debug("running ISession.Dispose()"); + log.Debug(string.Format("[session-id={0}]running ISession.Dispose()",sessionId)); if (TakingPartInDtcTransaction) { shouldCloseSessionOnDtcTransactionCompleted = true; @@ -1684,6 +1684,8 @@ return; } + log.Debug(string.Format("[session-id={0}]executing real Dispose({1})", sessionId, isDisposing)); + // free managed resources that are being managed by the session if we // know this call came through Dispose() if (isDisposing && !IsClosed) Modified: trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/DtcFailures/DtcFailuresFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/DtcFailures/DtcFailuresFixture.cs 2009-05-14 03:56:57 UTC (rev 4297) +++ trunk/nhibernate/src/NHibernate.Test/NHSpecificTest/DtcFailures/DtcFailuresFixture.cs 2009-05-14 06:41:09 UTC (rev 4298) @@ -2,6 +2,8 @@ using System.Collections; using System.Threading; using System.Transactions; +using log4net; +using log4net.Repository.Hierarchy; using NUnit.Framework; namespace NHibernate.Test.NHSpecificTest.DtcFailures @@ -9,9 +11,11 @@ [TestFixture] public class DtcFailuresFixture : TestCase { + private static readonly ILog log = LogManager.GetLogger(typeof(DtcFailuresFixture)); + protected override IList Mappings { - get { return new string[] {"NHSpecificTest.DtcFailures.Mappings.hbm.xml"}; } + get { return new[] {"NHSpecificTest.DtcFailures.Mappings.hbm.xml"}; } } protected override string MappingsAssembly @@ -51,7 +55,7 @@ using (ISession s = sessions.OpenSession()) { new ForceEscalationToDistributedTx(true); //will rollback tx - s.Save(new Person {CreatedAt = DateTime.Today}); + s.Save(new Person { CreatedAt = DateTime.Today }); tx.Complete(); } @@ -67,6 +71,151 @@ } [Test] + [Description("Another action inside the transaction do the rollBack outside nh-session-scope.")] + public void RollbackOutsideNh() + { + try + { + using (var txscope = new TransactionScope()) + { + using (ISession s = sessions.OpenSession()) + { + var person = new Person { CreatedAt = DateTime.Now }; + s.Save(person); + } + new ForceEscalationToDistributedTx(true); //will rollback tx + + txscope.Complete(); + } + + log.DebugFormat("Transaction fail."); + Assert.Fail("Expected tx abort"); + } + catch (TransactionAbortedException) + { + log.DebugFormat("Transaction aborted."); + } + } + + [Test] + [Description("rollback inside nh-session-scope should not commit save and the transaction should be aborted.")] + public void TransactionInsertWithRollBackTask() + { + try + { + using (var txscope = new TransactionScope()) + { + using (ISession s = sessions.OpenSession()) + { + var person = new Person {CreatedAt = DateTime.Now}; + s.Save(person); + new ForceEscalationToDistributedTx(true); //will rollback tx + person.CreatedAt = DateTime.Now; + s.Update(person); + } + txscope.Complete(); + } + log.DebugFormat("Transaction fail."); + Assert.Fail("Expected tx abort"); + } + catch (TransactionAbortedException) + { + log.DebugFormat("Transaction aborted."); + } + } + + [Test, Ignore("Not fixed.")] + [Description(@"Two session in two txscope +(without an explicit NH transaction and without an explicit flush) +and with a rollback in the second dtc and a ForceRollback outside nh-session-scope.")] + public void TransactionInsertLoadWithRollBackTask() + { + object savedId; + using (var txscope = new TransactionScope()) + { + using (ISession s = sessions.OpenSession()) + { + var person = new Person {CreatedAt = DateTime.Now}; + savedId = s.Save(person); + } + txscope.Complete(); + } + try + { + using (var txscope = new TransactionScope()) + { + using (ISession s = sessions.OpenSession()) + { + var person = s.Get<Person>(savedId); + person.CreatedAt = DateTime.Now; + s.Update(person); + } + new ForceEscalationToDistributedTx(true); + + log.Debug("completing the tx scope"); + txscope.Complete(); + } + log.Debug("Transaction fail."); + Assert.Fail("Expected tx abort"); + } + catch (TransactionAbortedException) + { + log.Debug("Transaction aborted."); + } + finally + { + using (var txscope = new TransactionScope()) + { + using (ISession s = sessions.OpenSession()) + { + var person = s.Get<Person>(savedId); + s.Delete(person); + } + txscope.Complete(); + } + } + } + + private int totalCall; + + [Test, Explicit] + public void MultiThreadedTransaction() + { + // Test added for NH-1709 (trying to recreate the issue... without luck) + // If one thread break the test, you can see the result in the console. + ((Logger)log.Logger).Level = log4net.Core.Level.Debug; + var actions = new MultiThreadRunner<object>.ExecuteAction[] + { + delegate(object o) + { + Can_roll_back_transaction(); + totalCall++; + }, + delegate(object o) + { + RollbackOutsideNh(); + totalCall++; + }, + delegate(object o) + { + TransactionInsertWithRollBackTask(); + totalCall++; + }, + //delegate(object o) + // { + // TransactionInsertLoadWithRollBackTask(); + // totalCall++; + // }, + }; + var mtr = new MultiThreadRunner<object>(20, actions) + { + EndTimeout = 5000, TimeoutBetweenThreadStart = 5 + }; + mtr.Run(null); + log.DebugFormat("{0} calls", totalCall); + } + + [Test] public void CanDeleteItemInDtc() { object id; @@ -95,6 +244,26 @@ } } + [Test] + [Description("Open/Close a session inside a TransactionScope fails.")] + public void NH1744() + { + using (var tx = new TransactionScope()) + { + using (ISession s = sessions.OpenSession()) + { + s.Flush(); + } + + using (ISession s = sessions.OpenSession()) + { + s.Flush(); + } + + //and I always leave the transaction disposed without calling tx.Complete(), I let the database server to rollback all actions in this test. + } + } + public class ForceEscalationToDistributedTx : IEnlistmentNotification { private readonly bool shouldRollBack; @@ -114,6 +283,7 @@ Assert.AreNotEqual(thread, Thread.CurrentThread.ManagedThreadId); if (shouldRollBack) { + log.Debug(">>>>Force Rollback<<<<<"); preparingEnlistment.ForceRollback(); } else This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |