Skip to content

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

Merged
merged 2 commits into from
Mar 27, 2020

Conversation

fredericDelaporte
Copy link
Member

Fixes #2336

@fredericDelaporte fredericDelaporte added this to the 5.3 milestone Mar 22, 2020
@@ -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));
Copy link
Member Author

Choose a reason for hiding this comment

The 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 null to this method, so it looks better to throw.

@@ -136,7 +136,7 @@ public virtual void ExecuteWorkInIsolation(ISessionImplementor session, IIsolate
isolaterLog.Warn(ignore, "Unable to dispose transaction");
}

if (session.Factory.Dialect is SQLiteDialect == false)
if (connection != null && session.Factory.Dialect is SQLiteDialect == false)
Copy link
Member

Choose a reason for hiding this comment

The 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 try block?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well maybe not.. That would change exception..

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member Author

Choose a reason for hiding this comment

The 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.
But yes, it loses the HibernateException encapsulation.

Switching back.

Copy link
Member

Choose a reason for hiding this comment

The 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? )

DbTransaction trans = null;
// bool wasAutoCommit = false;
Copy link
Member Author

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.

// We make an exception for SQLite and use the session's connection,
// since SQLite only allows one connection to the database.
var connection = session.Factory.Dialect is SQLiteDialect
? session.Connection
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maca88, small indentation glitch here with async generator, that you may be interested to look into. Nothing important, it is just for polishing it if you wish.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #2363.

throw new HibernateException("error performing isolated work", t);
}
switch (t)
{
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another indentation glitch.

@fredericDelaporte
Copy link
Member Author

Back to initial change, forced push to remove fixup noise.

bahusoid
bahusoid previously approved these changes Mar 24, 2020
Copy link
Member

@bahusoid bahusoid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to have connection opening be outside of try block but feel free to keep it as is

@@ -16,7 +15,7 @@ namespace NHibernate.Transaction
/// </summary>
public partial class AdoNetTransactionFactory : ITransactionFactory
{
private readonly INHibernateLogger isolaterLog = NHibernateLogger.For(typeof(ITransactionFactory));
private readonly INHibernateLogger _isolatorLog = NHibernateLogger.For(typeof(ITransactionFactory));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't it be static?

@@ -136,7 +136,7 @@ public virtual void ExecuteWorkInIsolation(ISessionImplementor session, IIsolate
isolaterLog.Warn(ignore, "Unable to dispose transaction");
}

if (session.Factory.Dialect is SQLiteDialect == false)
if (connection != null && session.Factory.Dialect is SQLiteDialect == false)
Copy link
Member

Choose a reason for hiding this comment

The 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? )

@fredericDelaporte
Copy link
Member Author

Yes it could not be wrapped since the finally was failing with NRE.
But this is the usual practice of NHibernate: wrap DB exceptions into NHibernateException. That is why when you have signaled the wrapping would not be done, I have reverted even though the wrapping for this case was failing previously.
For consistency, I think we should have this wrapping. So when fixing bugs in this very wrapping, we should not by-pass it.

@bahusoid
Copy link
Member

For consistency, I think we should have this wrapping.

I'm very suspicious that OpenSession connection opening problems would be wrapped in HibernateException. So this consistency is not obvious to me and IMHO code looks cleaner without those wrappings but well use your judging here...

@fredericDelaporte
Copy link
Member Author

I have amended the cleanup commit for switching the logger to static.

@fredericDelaporte
Copy link
Member Author

fredericDelaporte commented Mar 24, 2020

OpenSession does not have to, it does not open the connection. The connection is lazily opened.
If respecting best practices, the connection will be opened by starting a transaction, by this code in AdoTransaction:

try
{
	trans = session.Factory.ConnectionProvider.Driver.BeginTransaction(isolationLevel, session.Connection);
}
catch (HibernateException)
{
	// Don't wrap HibernateExceptions
	throw;
}
catch (Exception e)
{
	log.Error(e, "Begin transaction failed");
	throw new TransactionException("Begin failed with SQL exception", e);
}

@bahusoid
Copy link
Member

OpenSession does not have to, it does not open the connection

Ok.. Bad example. But I meant I'm pretty sure that many session methods wouldn't wrap such issue in HibernateException.

@fredericDelaporte fredericDelaporte merged commit e7ba6ac into nhibernate:master Mar 27, 2020
@fredericDelaporte fredericDelaporte deleted the FixSomeNre branch March 27, 2020 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Intermittent null reference exception on CloseConnection
3 participants