-
Notifications
You must be signed in to change notification settings - Fork 934
Fix some NRE in work isolation and connection handling #2337
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,6 @@ | |
using NHibernate.Engine; | ||
using NHibernate.Engine.Transaction; | ||
using NHibernate.Exceptions; | ||
using NHibernate.Impl; | ||
|
||
namespace NHibernate.Transaction | ||
{ | ||
|
@@ -42,33 +41,24 @@ async Task InternalExecuteWorkInIsolationAsync() | |
|
||
DbConnection connection = null; | ||
DbTransaction trans = null; | ||
// bool wasAutoCommit = false; | ||
try | ||
{ | ||
// We make an exception for SQLite and use the session's connection, | ||
// since SQLite only allows one connection to the database. | ||
if (session.Factory.Dialect is SQLiteDialect) | ||
connection = session.Connection; | ||
else | ||
connection = await (session.Factory.ConnectionProvider.GetConnectionAsync(cancellationToken)).ConfigureAwait(false); | ||
connection = session.Factory.Dialect is SQLiteDialect | ||
? session.Connection | ||
: await (session.Factory.ConnectionProvider.GetConnectionAsync(cancellationToken)).ConfigureAwait(false); | ||
|
||
if (transacted) | ||
{ | ||
trans = connection.BeginTransaction(); | ||
// TODO NH: a way to read the autocommit state is needed | ||
//if (TransactionManager.GetAutoCommit(connection)) | ||
//{ | ||
// wasAutoCommit = true; | ||
// TransactionManager.SetAutoCommit(connection, false); | ||
//} | ||
} | ||
|
||
await (work.DoWorkAsync(connection, trans, cancellationToken)).ConfigureAwait(false); | ||
|
||
if (transacted) | ||
{ | ||
trans.Commit(); | ||
//TransactionManager.Commit(connection); | ||
} | ||
} | ||
catch (Exception t) | ||
|
@@ -84,49 +74,33 @@ async Task InternalExecuteWorkInIsolationAsync() | |
} | ||
catch (Exception ignore) | ||
{ | ||
isolaterLog.Debug(ignore, "Unable to rollback transaction"); | ||
_isolatorLog.Debug(ignore, "Unable to rollback transaction"); | ||
} | ||
|
||
if (t is HibernateException) | ||
{ | ||
throw; | ||
} | ||
else if (t is DbException) | ||
{ | ||
throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t, | ||
"error performing isolated work"); | ||
} | ||
else | ||
{ | ||
throw new HibernateException("error performing isolated work", t); | ||
} | ||
switch (t) | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another indentation glitch. |
||
case HibernateException _: | ||
throw; | ||
case DbException _: | ||
throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t, | ||
"error performing isolated work"); | ||
default: | ||
throw new HibernateException("error performing isolated work", t); | ||
} | ||
} | ||
} | ||
finally | ||
{ | ||
//if (transacted && wasAutoCommit) | ||
//{ | ||
// try | ||
// { | ||
// // TODO NH: reset autocommit | ||
// // TransactionManager.SetAutoCommit(connection, true); | ||
// } | ||
// catch (Exception) | ||
// { | ||
// log.Debug("was unable to reset connection back to auto-commit"); | ||
// } | ||
//} | ||
|
||
try | ||
{ | ||
trans?.Dispose(); | ||
} | ||
catch (Exception ignore) | ||
{ | ||
isolaterLog.Warn(ignore, "Unable to dispose transaction"); | ||
_isolatorLog.Warn(ignore, "Unable to dispose transaction"); | ||
} | ||
|
||
if (session.Factory.Dialect is SQLiteDialect == false) | ||
if (connection != null && session.Factory.Dialect is SQLiteDialect == false) | ||
session.Factory.ConnectionProvider.CloseConnection(connection); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,9 @@ public abstract partial class ConnectionProvider : IConnectionProvider | |
/// <param name="conn">The <see cref="DbConnection"/> to clean up.</param> | ||
public virtual void CloseConnection(DbConnection conn) | ||
{ | ||
if (conn == null) | ||
throw new ArgumentNullException(nameof(conn)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can choose to just exit instead of throwing. But since the case was clearly not supported, causing a NRE in the try then a second NRE in the catch, I consider the current code base is never meant to supply |
||
|
||
log.Debug("Closing connection"); | ||
try | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,7 +6,6 @@ | |
using NHibernate.Engine; | ||
using NHibernate.Engine.Transaction; | ||
using NHibernate.Exceptions; | ||
using NHibernate.Impl; | ||
|
||
namespace NHibernate.Transaction | ||
{ | ||
|
@@ -16,7 +15,7 @@ namespace NHibernate.Transaction | |
/// </summary> | ||
public partial class AdoNetTransactionFactory : ITransactionFactory | ||
{ | ||
private readonly INHibernateLogger isolaterLog = NHibernateLogger.For(typeof(ITransactionFactory)); | ||
private static readonly INHibernateLogger _isolatorLog = NHibernateLogger.For(typeof(ITransactionFactory)); | ||
|
||
/// <inheritdoc /> | ||
public virtual ITransaction CreateTransaction(ISessionImplementor session) | ||
|
@@ -52,33 +51,24 @@ public virtual void ExecuteWorkInIsolation(ISessionImplementor session, IIsolate | |
|
||
DbConnection connection = null; | ||
DbTransaction trans = null; | ||
// bool wasAutoCommit = false; | ||
try | ||
{ | ||
// We make an exception for SQLite and use the session's connection, | ||
// since SQLite only allows one connection to the database. | ||
if (session.Factory.Dialect is SQLiteDialect) | ||
connection = session.Connection; | ||
else | ||
connection = session.Factory.ConnectionProvider.GetConnection(); | ||
connection = session.Factory.Dialect is SQLiteDialect | ||
? session.Connection | ||
: session.Factory.ConnectionProvider.GetConnection(); | ||
|
||
if (transacted) | ||
{ | ||
trans = connection.BeginTransaction(); | ||
// TODO NH: a way to read the autocommit state is needed | ||
//if (TransactionManager.GetAutoCommit(connection)) | ||
//{ | ||
// wasAutoCommit = true; | ||
// TransactionManager.SetAutoCommit(connection, false); | ||
//} | ||
} | ||
|
||
work.DoWork(connection, trans); | ||
|
||
if (transacted) | ||
{ | ||
trans.Commit(); | ||
//TransactionManager.Commit(connection); | ||
} | ||
} | ||
catch (Exception t) | ||
|
@@ -94,49 +84,33 @@ public virtual void ExecuteWorkInIsolation(ISessionImplementor session, IIsolate | |
} | ||
catch (Exception ignore) | ||
{ | ||
isolaterLog.Debug(ignore, "Unable to rollback transaction"); | ||
_isolatorLog.Debug(ignore, "Unable to rollback transaction"); | ||
} | ||
|
||
if (t is HibernateException) | ||
switch (t) | ||
{ | ||
throw; | ||
} | ||
else if (t is DbException) | ||
{ | ||
throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t, | ||
"error performing isolated work"); | ||
} | ||
else | ||
{ | ||
throw new HibernateException("error performing isolated work", t); | ||
case HibernateException _: | ||
throw; | ||
case DbException _: | ||
throw ADOExceptionHelper.Convert(session.Factory.SQLExceptionConverter, t, | ||
"error performing isolated work"); | ||
default: | ||
throw new HibernateException("error performing isolated work", t); | ||
} | ||
} | ||
} | ||
finally | ||
{ | ||
//if (transacted && wasAutoCommit) | ||
//{ | ||
// try | ||
// { | ||
// // TODO NH: reset autocommit | ||
// // TransactionManager.SetAutoCommit(connection, true); | ||
// } | ||
// catch (Exception) | ||
// { | ||
// log.Debug("was unable to reset connection back to auto-commit"); | ||
// } | ||
//} | ||
|
||
try | ||
{ | ||
trans?.Dispose(); | ||
} | ||
catch (Exception ignore) | ||
{ | ||
isolaterLog.Warn(ignore, "Unable to dispose transaction"); | ||
_isolatorLog.Warn(ignore, "Unable to dispose transaction"); | ||
} | ||
|
||
if (session.Factory.Dialect is SQLiteDialect == false) | ||
if (connection != null && session.Factory.Dialect is SQLiteDialect == false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's some messy method here.... Additional null check doesn't make it better. May be instead move connection retrieving logic outside of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well maybe not.. That would change exception.. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At least this will no more swallow a connection opening failure. But yes, it is indeed better to put the connection opening out of the try. It has no sense being into it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well... Changing from NRE unrelated to the trouble to the bare exception is still better. Switching back. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've just realized that this exception never was wrapped (my main concern was that we changed existing behavior - but we didn't) and I really don't see any benefits in such wrappings (seems like some legacy practice). So maybe better again switch back? ) |
||
session.Factory.ConnectionProvider.CloseConnection(connection); | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have added a small cleanup commit.
Afaik, the auto-commit feature and the transaction manager are not ported into NHibernate, so those decade old comments and todo-s are unlikely to be done any time soon. They are just polluting the code in my view.