Skip to content

Commit dfa3d02

Browse files
committed
Some refactoring
- AllocateParameterAndReplacer method returns back its responsibility declared in name - Checking for ability to cache query is moved to method that caches query - No two calls for queryTarget.GetType(), it is cached when AllocateParameterAndReplacer method is called, since the method called only when caching is needed we can use cached type later on in IsQueryCacheable method - all structs allowed in closure type
1 parent 5b32fc4 commit dfa3d02

File tree

1 file changed

+40
-23
lines changed

1 file changed

+40
-23
lines changed

Orm/Xtensive.Orm/Orm/Internals/CompiledQueryRunner.cs

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,6 @@ namespace Xtensive.Orm.Internals
2121
{
2222
internal class CompiledQueryRunner
2323
{
24-
private static readonly Func<FieldInfo, IReadOnlySet<Type>, bool> IsFieldReadyToCache = (fieldInfo, supportedTypes) =>
25-
IsTypeCacheable(fieldInfo.FieldType, supportedTypes);
26-
2724
private readonly Domain domain;
2825
private readonly Session session;
2926
private readonly QueryEndpoint endpoint;
@@ -34,6 +31,7 @@ internal class CompiledQueryRunner
3431

3532
private Parameter queryParameter;
3633
private ExtendedExpressionReplacer queryParameterReplacer;
34+
private Type queryTargetType;
3735

3836
public QueryResult<TElement> ExecuteCompiled<TElement>(Func<QueryEndpoint, IQueryable<TElement>> query)
3937
{
@@ -114,24 +112,24 @@ private DelayedQuery<TElement> CreateDelayedSequenceQuery<TElement>(
114112
private ParameterizedQuery GetScalarQuery<TResult>(
115113
Func<QueryEndpoint, TResult> query, bool executeAsSideEffect, out TResult result)
116114
{
117-
var cacheable = AllocateParameterAndReplacer();
115+
AllocateParameterAndReplacer();
118116

119117
var parameterContext = new ParameterContext(outerContext);
120118
parameterContext.SetValue(queryParameter, queryTarget);
121119
var scope = new CompiledQueryProcessingScope(
122120
queryParameter, queryParameterReplacer, parameterContext, executeAsSideEffect);
121+
123122
using (scope.Enter()) {
124123
result = query.Invoke(endpoint);
125124
}
126125

127126
var parameterizedQuery = (ParameterizedQuery) scope.ParameterizedQuery;
128-
if (parameterizedQuery==null && queryTarget!=null) {
127+
if (parameterizedQuery == null && queryTarget != null) {
129128
throw new NotSupportedException(Strings.ExNonLinqCallsAreNotSupportedWithinQueryExecuteDelayed);
130129
}
131130

132-
if (cacheable) {
133-
PutCachedQuery(parameterizedQuery);
134-
}
131+
PutQueryToCacheIfAllowed(parameterizedQuery);
132+
135133
return parameterizedQuery;
136134
}
137135

@@ -143,29 +141,28 @@ private ParameterizedQuery GetSequenceQuery<TElement>(
143141
return parameterizedQuery;
144142
}
145143

146-
var cacheable = AllocateParameterAndReplacer();
144+
AllocateParameterAndReplacer();
147145
var scope = new CompiledQueryProcessingScope(queryParameter, queryParameterReplacer);
148146
using (scope.Enter()) {
149147
var result = query.Invoke(endpoint);
150148
var translatedQuery = endpoint.Provider.Translate(result.Expression);
151149
parameterizedQuery = (ParameterizedQuery) translatedQuery;
152150
}
153151

154-
if (cacheable) {
155-
PutCachedQuery(parameterizedQuery);
156-
}
152+
PutQueryToCacheIfAllowed(parameterizedQuery);
153+
157154
return parameterizedQuery;
158155
}
159156

160-
private bool AllocateParameterAndReplacer()
157+
private void AllocateParameterAndReplacer()
161158
{
162159
if (queryTarget == null) {
163160
queryParameter = null;
164161
queryParameterReplacer = new ExtendedExpressionReplacer(e => e);
165-
return true;
162+
return;
166163
}
167164

168-
var closureType = queryTarget.GetType();
165+
var closureType = queryTargetType = queryTarget.GetType();
169166
var parameterType = WellKnownOrmTypes.ParameterOfT.CachedMakeGenericType(closureType);
170167
var valueMemberInfo = parameterType.GetProperty(nameof(Parameter<object>.Value), closureType);
171168
queryParameter = (Parameter) System.Activator.CreateInstance(parameterType, "pClosure");
@@ -202,10 +199,24 @@ private bool AllocateParameterAndReplacer()
202199
}
203200
return null;
204201
});
202+
}
203+
204+
private bool IsQueryCacheable()
205+
{
206+
if (queryTargetType==null) {
207+
return true;
208+
}
205209

210+
if (!queryTargetType.IsClosure()) {
211+
return true;
212+
}
206213

207-
return !TypeHelper.IsClosure(closureType)
208-
|| closureType.GetFields().All(f => IsFieldReadyToCache(f, supportedTypes));
214+
foreach (var field in queryTargetType.GetFields()) {
215+
if (!IsTypeCacheable(field.FieldType, supportedTypes)) {
216+
return false;
217+
}
218+
}
219+
return true;
209220
}
210221

211222
private static bool IsTypeCacheable(Type type, IReadOnlySet<Type> supportedTypes)
@@ -240,10 +251,7 @@ private static bool IsTypeCacheable(Type type, IReadOnlySet<Type> supportedTypes
240251
TypeCode.Char => true,
241252
TypeCode.String => true,
242253
TypeCode.DateTime => true,
243-
TypeCode.Object => type1 == WellKnownTypes.Guid
244-
|| type1 == WellKnownTypes.TimeSpan
245-
|| type1 == WellKnownTypes.DateTimeOffset
246-
|| supportedTypes.Contains(type1),
254+
TypeCode.Object => type1.IsValueType,
247255
_ => false
248256
};
249257
}
@@ -252,8 +260,17 @@ private static bool IsTypeCacheable(Type type, IReadOnlySet<Type> supportedTypes
252260
private ParameterizedQuery GetCachedQuery() =>
253261
domain.QueryCache.TryGetItem(queryKey, true, out var item) ? item.Second : null;
254262

255-
private void PutCachedQuery(ParameterizedQuery parameterizedQuery) =>
256-
domain.QueryCache.Add(new Pair<object, ParameterizedQuery>(queryKey, parameterizedQuery));
263+
private void PutQueryToCacheIfAllowed(ParameterizedQuery parameterizedQuery) {
264+
if (IsQueryCacheable()) {
265+
domain.QueryCache.Add(new Pair<object, ParameterizedQuery>(queryKey, parameterizedQuery));
266+
}
267+
else {
268+
// no .resx used because it is hot path.
269+
if (OrmLog.IsLogged(Logging.LogLevel.Info))
270+
OrmLog.Info("Query can't be cached because closure type it has references to captures reference" +
271+
" type instances. This will lead to long-living objects in memory.");
272+
}
273+
}
257274

258275
private ParameterContext CreateParameterContext(ParameterizedQuery query)
259276
{

0 commit comments

Comments
 (0)