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

Somehow a mismatch in the ShapedCommandContext entries resulting in KeyNotFoundException #7863

Closed
NinoFloris opened this issue Mar 13, 2017 · 4 comments
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Milestone

Comments

@NinoFloris
Copy link

NinoFloris commented Mar 13, 2017

Error Message:
 System.Collections.Generic.KeyNotFoundException : The given key was not present in the dictionary.
Stack Trace:
   at System.ThrowHelper.ThrowKeyNotFoundException()
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Microsoft.EntityFrameworkCore.Query.Internal.ShaperCommandContext.CommandCacheKey.Equals(Object obj)
   at System.Collections.Generic.ObjectEqualityComparer`1.Equals(T x, T y)
   at System.Collections.Concurrent.ConcurrentDictionary`2.TryAddInternal(TKey key, Int32 hashcode, TValue value, Boolean updateIfExists, Boolean acquireLock, TValue& resultingValue)
   at System.Collections.Concurrent.ConcurrentDictionary`2.TryAdd(TKey key, TValue value)
   at Microsoft.EntityFrameworkCore.Query.Internal.ShaperCommandContext.GetRelationalCommand(IReadOnlyDictionary`2 parameters)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable.Enumerator.BufferlessMoveNext(Boolean buffer)
   at Microsoft.EntityFrameworkCore.Query.QueryMethodProvider.GetResult[TResult](IEnumerable`1 valueBuffers)
   at lambda_method(Closure , QueryContext )
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass20_0`1.<CompileQueryCore>b__0(QueryContext qc)
   at System.Linq.Queryable.Count[TSource](IQueryable`1 source)
   at Roadrunner.Authorization.Authorizers.Authorizer`1.IsAuthorized(Boolean doAction) in /#PATH#/Authorizers/Authorizer.cs:line 65
   at Roadrunner.Authorization.Authorizers.Authorizer`1.Act() in /#PATH#/Authorizers/Authorizer.cs:line 38
   at Roadrunner.Features.PageRelations.Delete.Handler.<Handle>d__7.MoveNext() in /#PATH#/PageRelations/Delete.cs:line 60
--- End of stack trace from previous location where exception was thrown ---

This check does not do a ContainsKey before trying to access the key in the other cache entry:

foreach (var parameterValue in _parameterValues)
{
    var value = parameterValue.Value;
    var otherValue = other._parameterValues[parameterValue.Key];
...

https://github.com/aspnet/EntityFramework/blob/f386095005e46ea3aa4d677e4439cdac113dbfb1/src/EFCore.Relational/Query/Internal/ShaperCommandContext.cs#L44

Steps to reproduce

It requires a few tries to reproduce as it's non deterministic due to the cache entries needing to get in there in the right order.

I don't know how the ShapedCommandContext works, when a new one is constructed or how only this one has mismatching arguments but I hope you can shed some light on this

Further technical details

EF Core version: dev
Database Provider: Npgsql
Operating system: OSX
IDE: VSCode dotnet cli 1.0 tooling

@NinoFloris
Copy link
Author

I'd think this is quite a problem. We don't know if we release an alteration of this code (that doesn't crash EF) that it will not show up in production under load in any other way. Basically somewhere the underlying model is broken in a way that is quite scary.

Please at least give some response, any at all is better than this complete silence.

Mind you the reproduction of this issue is 100% within a few tries so this is not some sort of heisenbug you should just ignore

/cc @ajcvickers

@ajcvickers
Copy link
Member

@NinoFloris We triage issues multiple times per week. This issue was filed after our first triage this week and our second one for this week is today. We will assign someone to investigate at that time. However, from looking at the info above, I suspect we are going to need more information to be able to reproduce it. A simplified complete project or code listing would be ideal. If that's not possible, then at least some information about what your model looks like and what queries are being executed.

@NinoFloris
Copy link
Author

NinoFloris commented Mar 22, 2017

It took us a while to pinpoint the exact cause but this is the smallest we can get :)

https://gist.github.com/NinoFloris/2c91585c047050e00e388e94edc09a98

dotnet new console with package:

<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="1.1.0-*" />

@NinoFloris
Copy link
Author

So how does this problem actually manifest?

I definitely know it is an expression visiting problem but where I would have to look then is unknown terrain for me.

I presume there is an expression visitor that decides that the nested function should be visited.
Then another visitor goes and finds all the parameters used in the expression tree and adds them to the ShaperCommandContext? Then my question is, how and by what piece of code are these two different queries incorrectly conflated?

Is there a visitor that decides query shape equality? E.g. same where's, from, joins, projection and other expression bits but fails to take into account the argument names when they are not db parameters?

So as I've asked in my first post already:

I don't know how the ShapedCommandContext works, when a new one is constructed or how only this one has mismatching arguments but I hope you can shed some light on this

I do really like to know the answer to:
How does EF select the ShaperCommandContext to share between queries?

My educated guess is that is where it fails to take into account a nuance around nested functions that cannot be translated to sql with respect to their arguments not being db parameters, therefore failing to distinguish they are different queries.

@ajcvickers ajcvickers modified the milestones: 2.0.0-preview1, 2.0.0 Apr 19, 2017
anpete added a commit that referenced this issue Jun 26, 2017
…sulting in KeyNotFoundException

- Found an edge case where we can extract different parameters during parameterization but end up with a single query in query cache.
@anpete anpete closed this as completed in 8a27fa2 Jun 27, 2017
@anpete anpete added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Jun 27, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests

3 participants