Skip to content

Commit f2283c9

Browse files
committed
Add cache of root method call expressions
For every Query.All<T> one .MakeGenericMethod required and the result is only visited. The same root expressions are re-used many times during domain lifetime The number of items in the cache is finite and limit is the number of entities and interfaces in domain model (auxilary types included). In future we may change type of cache from concurrent dictionary to LRU cache and limit it to have only hot query roots represented
1 parent 3789b53 commit f2283c9

File tree

5 files changed

+15
-13
lines changed

5 files changed

+15
-13
lines changed

Orm/Xtensive.Orm/Orm/Domain.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ public static Domain Demand()
125125

126126
internal ICache<Key, Key> KeyCache { get; private set; }
127127

128+
internal ConcurrentDictionary<Type, System.Linq.Expressions.MethodCallExpression> RootCallExpressionsCache { get; private set; }
129+
128130
internal object UpgradeContextCookie { get; private set; }
129131

130132
internal SqlConnection SingleConnection { get; private set; }
@@ -423,6 +425,7 @@ internal Domain(DomainConfiguration configuration, object upgradeContextCookie,
423425
PrefetchFieldDescriptorCache = new ConcurrentDictionary<TypeInfo, ReadOnlyList<PrefetchFieldDescriptor>>();
424426
KeyCache = new LruCache<Key, Key>(Configuration.KeyCacheSize, k => k);
425427
QueryCache = new FastConcurrentLruCache<object, Pair<object, ParameterizedQuery>>(Configuration.QueryCacheSize, k => k.First);
428+
RootCallExpressionsCache = new ConcurrentDictionary<Type, System.Linq.Expressions.MethodCallExpression>();
426429
PrefetchActionMap = new Dictionary<TypeInfo, Action<SessionHandler, IEnumerable<Key>>>();
427430
Extensions = new ExtensionCollection();
428431
UpgradeContextCookie = upgradeContextCookie;

Orm/Xtensive.Orm/Orm/EntitySet{T}.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,14 +225,14 @@ public Expression Expression
225225
/// <inheritdoc/>
226226
protected sealed override Func<QueryEndpoint,Int64> GetItemCountQueryDelegate(FieldInfo field)
227227
{
228-
return qe => GetItemsQuery(qe, field).LongCount();
228+
return qe => GetItemsQuery(qe, field, this.Session.Domain).LongCount();
229229
}
230230

231-
private static IQueryable<TItem> GetItemsQuery(QueryEndpoint qe, FieldInfo field)
231+
private static IQueryable<TItem> GetItemsQuery(QueryEndpoint qe, FieldInfo field, Domain domain)
232232
{
233233
var owner = Expression.Property(Expression.Constant(ownerParameter), ownerParameter.GetType()
234234
.GetProperty("Value", WellKnownOrmTypes.Entity));
235-
var queryExpression = QueryHelper.CreateEntitySetQuery(owner, field);
235+
var queryExpression = QueryHelper.CreateEntitySetQuery(owner, field, domain);
236236
return qe.Provider.CreateQuery<TItem>(queryExpression);
237237
}
238238

Orm/Xtensive.Orm/Orm/Linq/QueryHelper.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,9 @@ public static Expression<Func<Tuple, bool>> BuildFilterLambda(int startIndex, IR
6363
return FastExpression.Lambda<Func<Tuple, bool>>(filterExpression, TupleParameter);
6464
}
6565

66-
private static Expression CreateEntityQuery(Type elementType)
66+
private static Expression CreateEntityQuery(Type elementType, Domain domain)
6767
{
68-
var queryAll = WellKnownMembers.Query.All.MakeGenericMethod(elementType);
69-
return Expression.Call(null, queryAll);
68+
return domain.RootCallExpressionsCache.GetOrAdd(elementType, (t) => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(elementType)));
7069
}
7170

7271
public static bool IsDirectEntitySetQuery(Expression entitySet)
@@ -106,7 +105,7 @@ public static Expression CreateDirectEntitySetQuery(EntitySetBase entitySet)
106105
return Expression.Convert(Expression.Call(Expression.Constant(owner),indexers.Single(), new []{Expression.Constant(entitySet.Field.Name)}), entitySet.Field.ValueType);
107106
}
108107

109-
public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo field)
108+
public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo field, Domain domain)
110109
{
111110
if (!field.IsDynamicallyDefined && !field.UnderlyingProperty.PropertyType.IsOfGenericType(WellKnownOrmTypes.EntitySetOfT)) {
112111
throw Exceptions.InternalError(Strings.ExFieldMustBeOfEntitySetType, OrmLog.Instance);
@@ -131,7 +130,7 @@ public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo
131130
);
132131
return Expression.Call(
133132
WellKnownMembers.Queryable.Where.MakeGenericMethod(elementType),
134-
CreateEntityQuery(elementType),
133+
CreateEntityQuery(elementType, domain),
135134
FastExpression.Lambda(whereExpression, whereParameter)
136135
);
137136
}
@@ -156,7 +155,7 @@ public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo
156155

157156
var outerQuery = Expression.Call(
158157
WellKnownMembers.Queryable.Where.MakeGenericMethod(connectorType),
159-
CreateEntityQuery(connectorType),
158+
CreateEntityQuery(connectorType, domain),
160159
FastExpression.Lambda(filterExpression, filterParameter)
161160
);
162161

@@ -168,7 +167,7 @@ public static Expression CreateEntitySetQuery(Expression ownerEntity, FieldInfo
168167
var innerSelector = FastExpression.Lambda(innerSelectorParameter, innerSelectorParameter);
169168
var resultSelector = FastExpression.Lambda(innerSelectorParameter, outerSelectorParameter, innerSelectorParameter);
170169

171-
var innerQuery = CreateEntityQuery(elementType);
170+
var innerQuery = CreateEntityQuery(elementType, domain);
172171
var joinMethodInfo = WellKnownMembers.Queryable.Join
173172
.MakeGenericMethod(new[] {
174173
connectorType,

Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1657,7 +1657,7 @@ private ProjectionExpression VisitSequence(Expression sequenceExpression, Expres
16571657
.Model
16581658
.Types[memberAccess.Expression.Type]
16591659
.Fields[context.Domain.Handlers.NameBuilder.BuildFieldName(propertyInfo)];
1660-
sequenceExpression = QueryHelper.CreateEntitySetQuery(memberAccess.Expression, field);
1660+
sequenceExpression = QueryHelper.CreateEntitySetQuery(memberAccess.Expression, field, context.Domain);
16611661
}
16621662
}
16631663
}
@@ -1684,7 +1684,7 @@ private ProjectionExpression VisitSequence(Expression sequenceExpression, Expres
16841684
if (visitedExpression.IsEntitySetExpression()) {
16851685
var entitySetExpression = (EntitySetExpression) visitedExpression;
16861686
var entitySetQuery =
1687-
QueryHelper.CreateEntitySetQuery((Expression) entitySetExpression.Owner, entitySetExpression.Field);
1687+
QueryHelper.CreateEntitySetQuery((Expression) entitySetExpression.Owner, entitySetExpression.Field, context.Domain);
16881688
result = (ProjectionExpression) Visit(entitySetQuery);
16891689
}
16901690

Orm/Xtensive.Orm/Orm/QueryEndpoint.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -938,7 +938,7 @@ private Expression BuildRootExpression(Type elementType)
938938
{
939939
return RootBuilder!=null
940940
? RootBuilder.BuildRootExpression(elementType)
941-
: Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(elementType));
941+
: session.Domain.RootCallExpressionsCache.GetOrAdd(elementType, (t) => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(t)));
942942
}
943943

944944
#endregion

0 commit comments

Comments
 (0)