Skip to content

NH-3606 - open a stateless session from a session #1520

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 9 commits into from
Mar 11, 2018

Conversation

fredericDelaporte
Copy link
Member

@@ -173,6 +173,35 @@ public void FlushFromTransactionAppliesToSharingSession()
}
}

[Test]
public void FlushFromTransactionAppliesToSharingStatelessSession()
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 not added the equivalent test in system transaction, because the "flush from transaction completion" feature is basically broken with stateless sessions. A stateless session accumulates changes as a pending batched command, bound to the current connection. When flushing from a system transaction, this means the command has to execute from the NHibernate enlisted resource prepare phase, potentially after (or concurrently to) its connection own prepare phase.

@hazzik
Copy link
Member

hazzik commented Jan 22, 2018

Maybe it's better to move duplicated code into AbstractSessionImpl?

@fredericDelaporte
Copy link
Member Author

fredericDelaporte commented Jan 22, 2018

I have to check how impactful it would be. Especially if this results in moving connectionManager to the base class.

@fredericDelaporte
Copy link
Member Author

Maybe it's better to move duplicated code into AbstractSessionImpl?

Done. This causes less changes than what I was expecting. I have still done it in multiple commits in order to allow dropping the last ones if preferring less changes.

/// A session is considered connected if there is a <see cref="DbConnection"/> (regardless
/// of its state) or if the field <c>connect</c> is true. Meaning that it will connect
/// at the next operation that requires a connection.
/// </remarks>
Copy link
Member Author

Choose a reason for hiding this comment

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

This property concrete implementation being put in common, I have taken the more complete xml documentation.

public ITransactionContext TransactionContext
{
get; set;
}

private bool isAlreadyDisposed;

private static readonly INHibernateLogger logger = NHibernateLogger.For(typeof(AbstractSessionImpl));
private static readonly INHibernateLogger Log = NHibernateLogger.For(typeof(AbstractSessionImpl));
Copy link
Member Author

Choose a reason for hiding this comment

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

It was unused. With the code moves, it is now used, and renamed by the way.

this,
options.UserSuppliedConnection,
options.SessionConnectionReleaseMode,
Interceptor,
Copy link
Member Author

Choose a reason for hiding this comment

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

Overridden in stateless for always returning EmptyInterceptor, so equivalent to previous code in stateless, which was creating the connection manager with EmptyInterceptor.

ConnectionManager = new ConnectionManager(
this,
options.UserSuppliedConnection,
options.SessionConnectionReleaseMode,
Copy link
Member Author

Choose a reason for hiding this comment

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

In stateless option, always return AfterTransaction, so equivalent to previous code in stateless.

public abstract IBatcher Batcher { get; }
// 6.0 TODO: remove virtual.
/// <inheritdoc />
public virtual IBatcher Batcher
Copy link
Member Author

Choose a reason for hiding this comment

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

Since it was abstract, and since AbstractSessionImpl was public, it would be a breaking change to not allow it to be overridden. But there are nor reason to keep it virtual, thus the TODO for 6.0. The same applies to a bunch of other properties later in this file.

public abstract bool TransactionInProgress { get; }
// 6.0 TODO: remove virtual.
/// <inheritdoc />
public virtual bool TransactionInProgress => ConnectionManager.IsInActiveTransaction;
Copy link
Member Author

Choose a reason for hiding this comment

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

In stateless, this was Transaction.IsActive instead. It looks to me as an undue discrepancy. I have removed this discrepancy. But it was not having much impact, since this is an unused ISessionImplementor property. Its documentation backs my change further:

/// <summary>
/// Does this <c>ISession</c> have an active NHibernate transaction
/// or is there a system transaction in progress in which the session is enlisted?
/// </summary>

@@ -218,19 +256,24 @@ public virtual IQuery GetNamedSQLQuery(string name)
}
}

// 6.0 TODO: remove virtual from below properties.
/// <inheritdoc />
public virtual ConnectionManager ConnectionManager { get; protected set; }
Copy link
Member Author

Choose a reason for hiding this comment

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

Serialization of SessionImpl constrains to have the setter. Otherwise we should explicitly implement serialization in this base class too. (Which theoretically would imply explicitly implementing it in stateless too, but stateless serialization seems to me already broken.)

Copy link
Member

Choose a reason for hiding this comment

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

Changing this to an automatic property makes it serializable while it was marked as [NonSerialized] before (in StatelessSession).

Copy link
Member Author

@fredericDelaporte fredericDelaporte Jan 23, 2018

Choose a reason for hiding this comment

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

If we were willing to fix serialization for stateless, we would need to serialize it. Not having it serializable is a bug. Since we need to serialize it for SessionImpl, better reflect that fact. This anyway changes nothing for stateless, since it cannot be deserialized to an usable object currently.

@@ -28,9 +25,6 @@ public partial class StatelessSessionImpl : AbstractSessionImpl, IStatelessSessi
{
private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(StatelessSessionImpl));

[NonSerialized]
private readonly ConnectionManager connectionManager;
Copy link
Member Author

@fredericDelaporte fredericDelaporte Jan 22, 2018

Choose a reason for hiding this comment

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

A deserialized session without a connection manager is quite useless. I guess no-one serializes stateless sessions, or maybe we have a bug logged somewhere about it. Anyway, it does not even have a default constructor or a deserialization constructor, so it can only fail deserializing.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, we have a bug.

@hazzik
Copy link
Member

hazzik commented Jan 22, 2018

I was thinking about this myself, and made a conclusion that StatelessSession is (was always) not serializable. Eg, the connectionManager property would always be null after deserialization.

@@ -218,19 +256,24 @@ public virtual IQuery GetNamedSQLQuery(string name)
}
}

// 6.0 TODO: remove virtual from below properties.
/// <inheritdoc />
public virtual ConnectionManager ConnectionManager { get; protected set; }
Copy link
Member

Choose a reason for hiding this comment

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

Changing this to an automatic property makes it serializable while it was marked as [NonSerialized] before (in StatelessSession).

/// <summary>Get the current NHibernate transaction.</summary>
public ITransaction Transaction => ConnectionManager.Transaction;

protected bool TransactionCoordinatorShared { get; }
Copy link
Member

Choose a reason for hiding this comment

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

In other places it's called "IsTransactionCoordinatorShared". Changing it to an automatic property makes the field serializable, while it was marked as [NonSerialized] before.

Copy link
Member Author

@fredericDelaporte fredericDelaporte Jan 23, 2018

Choose a reason for hiding this comment

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

Yes, but no, and without any importance currently, that is why I have not really bothered.

For SessionImpl, serialization is explicitly done, causing fields from the base class to be serialized only if handled explicitly. It is not in SessionImpl. Anyway, if it was serialized, it would not change anything, because GetObjectData throws if it is not false, so a value other than the default one for its type would not be serialized.

For stateless, well, it could be now serialized, if the stateless was actually serializable, which is still not I believe. Stateless should implement serialization the same way than SessionImpl, meaning choosing itself what it serialize and if it can be serialized.

Update: I do not think that we should switch away from an automatic property just for being able to signal it is not serialized, while its serialization or non-serialization cannot have any impact currently.

@@ -28,9 +25,6 @@ public partial class StatelessSessionImpl : AbstractSessionImpl, IStatelessSessi
{
private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(StatelessSessionImpl));

[NonSerialized]
private readonly ConnectionManager connectionManager;
Copy link
Member

Choose a reason for hiding this comment

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

Yes, we have a bug.

@fredericDelaporte
Copy link
Member Author

Rebased.

@fredericDelaporte fredericDelaporte merged commit dce4d02 into nhibernate:master Mar 11, 2018
@fredericDelaporte fredericDelaporte deleted the NH-3606 branch March 11, 2018 23:38
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.

2 participants