You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// WARNING: This test case makes use of reflection resulting in failures if internals change, but reflection was needed to allow for simulation.
23
+
// This test simulates a heavy load on the QueryPlanCache by making it use a SoftLimitMRUCache instance with a size of 1 instead of the default of 128.
24
+
// Since this cache moves the most recently used query plans to the top, pushing down the less used query plans until they are removed from the cache,
25
+
// the smaller the size of the cache the sooner the query plans will be dropped, making it easier to simulate the problem.
26
+
//
27
+
// What is the exact problem:
28
+
// -> When executing a LINQ query that has a contains with only one element in the collection the same queryExpression string is generated by 2 different types
29
+
// of IQueryExpression, the 'NHibernate.Impl.ExpandedQueryExpression' and the 'NHibernate.Linq.NhLinqExpression' and that key is used to store a query plan
30
+
// in the QueryPlanCache if a query plan is requested and not found in the cache.
31
+
// -> The 'NHibernate.Linq.NhLinqExpression' is typically added during the DefaultQueryProvider.PrepareQuery and the 'NHibernate.Impl.ExpandedQueryExpression'
32
+
// less likely during the execution of the LINQ query
33
+
// -> Unfortunately the PrepareQuery is casting the returned query plan's QueryExpression to a NhLinqExpression, which it assumes will always be the case, but this
34
+
// is not true in a heavy loaded environment where the cache entries are constantly moving when other queries are being executed at the same time.
35
+
// -> If you look at the following method inside the DefaultQueryProvider class, then you'll see that by drilling down in the PrepareQuery and in the ExecuteQuery, that
36
+
// both operations are actually requesting the query plan from the QueryPlanCache at some point
37
+
// public virtual object Execute(Expression expression)
38
+
// {
39
+
// IQuery query;
40
+
// NhLinqExpression nhQuery;
41
+
// NhLinqExpression nhLinqExpression = PrepareQuery(expression, out query, out nhQuery);
// When they are requesting the corresponding query plan according to the QueryExpression's key the PrepareQuery assumes it will get back a NhLinqExpression, while it
46
+
// is perfectly possible that the corresponding query plan has a QueryExpression of type ExpandedQueryExpression that has been added during the ExecuteQuery because
47
+
// when a request was made for the query plan during the execution, the load on the cache has put the query plan with a QueryExpression of type NhLinqExpression and with
48
+
// the same key somewhere at the bottom of the MRU cache and it might even have been removed from the cache, resulting in adding a query plan with a QueryExpression value
49
+
// of type ExpandedQueryExpression. When the same LINQ query is executed afterwards, it will go through the PrepareQuery again, assuming that what is returned is a
50
+
// NhLinqExpression, while in reality it is an ExpandedQueryExpression, resulting in a cast exception. This problem might even go away due to the same load, pushing out
51
+
// the cached query plan with a QueryExpression of ExpandedQueryExpression and have a NhLinqExpression added back again during the next Prepare.
52
+
//
53
+
// So this test will simulate the pushing out by clearing the cache as long as the QueryExpression of the query plan is NhLinqExpression, once it is an ExpandedQueryExpression
54
+
// it will stop clearing the cache, and the exception will occur, resulting in a failure of the test.
55
+
// The test will pass once all LINQ expression are executed (1000 max) and no exception occured
56
+
57
+
varcache=newSoftLimitMRUCache(1);
58
+
59
+
varqueryPlanCacheType=typeof(QueryPlanCache);
60
+
61
+
// get the planCache field on the QueryPlanCache and overwrite it with the restricted cache
0 commit comments