Skip to content
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

Caching access to virtual properties #24775

Merged
merged 5 commits into from
Apr 28, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -172,17 +172,18 @@ public bool MoveNext()

if (hasNext)
{
var resultContext = _resultCoordinator.ResultContext;
Copy link
Member

Choose a reason for hiding this comment

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

Single ResultContext is read-only on SingleQueryResultCoordinator, we could cache it as a field on SingleQueryingEnumerable rather than doing it on each MoveNext, no?

Copy link
Contributor

Choose a reason for hiding this comment

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

Should we just make our result coordinators sealed and non-virtual properties? They are public and overridable because of pub-ternal philosophy. It it is hurting perf then I don't think it is worth sticking to it.

Copy link
Member

Choose a reason for hiding this comment

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

Sure, we can go that way too. Though we're accessing some other virtual properties in MoveNext which we should probably cache (DbDataReader, CancellationToken), so we'd go down the caching route anyway...

Copy link
Member

Choose a reason for hiding this comment

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

We should make members on QueryContext and derived classes non-virtual too.

Copy link
Member

Choose a reason for hiding this comment

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

@AndriySvyryd yeah.. I pushed a commit which at least caches QueryContext.Context so it doesn't get recalculated all the time.

while (true)
{
_resultCoordinator.ResultReady = true;
_resultCoordinator.HasNext = null;
Current = _shaper(
_relationalQueryContext, _dataReader!.DbDataReader, _resultCoordinator.ResultContext,
_relationalQueryContext, _dataReader!.DbDataReader, resultContext,
roji marked this conversation as resolved.
Show resolved Hide resolved
_resultCoordinator);
if (_resultCoordinator.ResultReady)
{
// We generated a result so null out previously stored values
_resultCoordinator.ResultContext.Values = null;
resultContext.Values = null;
break;
}

Expand All @@ -192,7 +193,7 @@ public bool MoveNext()
// Enumeration has ended, materialize last element
_resultCoordinator.ResultReady = true;
Current = _shaper(
_relationalQueryContext, _dataReader.DbDataReader, _resultCoordinator.ResultContext,
_relationalQueryContext, _dataReader.DbDataReader, resultContext,
_resultCoordinator);

break;
Expand Down Expand Up @@ -313,17 +314,18 @@ await _relationalQueryContext.ExecutionStrategyFactory.Create()

if (hasNext)
{
var resultContext = _resultCoordinator.ResultContext;
while (true)
{
_resultCoordinator.ResultReady = true;
_resultCoordinator.HasNext = null;
Current = _shaper(
_relationalQueryContext, _dataReader!.DbDataReader, _resultCoordinator.ResultContext,
_relationalQueryContext, _dataReader!.DbDataReader, resultContext,
_resultCoordinator);
if (_resultCoordinator.ResultReady)
{
// We generated a result so null out previously stored values
_resultCoordinator.ResultContext.Values = null;
resultContext.Values = null;
break;
}

Expand All @@ -333,7 +335,7 @@ await _relationalQueryContext.ExecutionStrategyFactory.Create()
// Enumeration has ended, materialize last element
_resultCoordinator.ResultReady = true;
Current = _shaper(
_relationalQueryContext, _dataReader.DbDataReader, _resultCoordinator.ResultContext,
_relationalQueryContext, _dataReader.DbDataReader, resultContext,
_resultCoordinator);

break;
Expand Down
11 changes: 6 additions & 5 deletions src/EFCore/DbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -723,11 +723,12 @@ void IDbContextPoolable.SetLease(DbContextLease lease)
Check.DebugAssert(
_configurationSnapshot.DeleteOrphansTiming.HasValue, "!configurationSnapshot.DeleteOrphansTiming.HasValue");

ChangeTracker.AutoDetectChangesEnabled = _configurationSnapshot.AutoDetectChangesEnabled.Value;
ChangeTracker.QueryTrackingBehavior = _configurationSnapshot.QueryTrackingBehavior.Value;
ChangeTracker.LazyLoadingEnabled = _configurationSnapshot.LazyLoadingEnabled.Value;
ChangeTracker.CascadeDeleteTiming = _configurationSnapshot.CascadeDeleteTiming.Value;
ChangeTracker.DeleteOrphansTiming = _configurationSnapshot.DeleteOrphansTiming.Value;
var changeTracker = ChangeTracker;
changeTracker.AutoDetectChangesEnabled = _configurationSnapshot.AutoDetectChangesEnabled.Value;
changeTracker.QueryTrackingBehavior = _configurationSnapshot.QueryTrackingBehavior.Value;
changeTracker.LazyLoadingEnabled = _configurationSnapshot.LazyLoadingEnabled.Value;
changeTracker.CascadeDeleteTiming = _configurationSnapshot.CascadeDeleteTiming.Value;
changeTracker.DeleteOrphansTiming = _configurationSnapshot.DeleteOrphansTiming.Value;
}
else
{
Expand Down