Skip to content

Commit ee1c8dd

Browse files
authored
Optimize multiple dereferences in PrefetchManager (#185)
* Optimize multiple dereferences in `PrefetchManager` * Optimize GetParameterValue()
1 parent 7efcee4 commit ee1c8dd

File tree

4 files changed

+50
-60
lines changed

4 files changed

+50
-60
lines changed

Orm/Xtensive.Orm/Orm/Internals/Prefetch/EntityContainer.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ internal abstract class EntityContainer
3636

3737
public void AddColumns(IEnumerable<ColumnInfo> candidateColumns)
3838
{
39-
if (columns == null)
40-
columns = new SortedDictionary<int, ColumnInfo>();
39+
columns ??= new SortedDictionary<int, ColumnInfo>();
4140
if (PrefetchHelper.AddColumns(candidateColumns, columns, Type) && ColumnIndexesToBeLoaded != null)
4241
ColumnIndexesToBeLoaded = null;
4342
}

Orm/Xtensive.Orm/Orm/Internals/Prefetch/PrefetchHelper.cs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,18 @@ public static IReadOnlyList<PrefetchFieldDescriptor> GetCachedDescriptorsForFiel
3434
public static bool? TryGetExactKeyType(Key key, PrefetchManager manager, out TypeInfo type)
3535
{
3636
type = null;
37-
if (!key.TypeReference.Type.IsLeaf) {
37+
var keyTypeReferenceType = key.TypeReference.Type;
38+
if (!keyTypeReferenceType.IsLeaf) {
3839
var cachedKey = key;
39-
EntityState state;
40-
if (!manager.TryGetTupleOfNonRemovedEntity(ref cachedKey, out state))
40+
if (!manager.TryGetTupleOfNonRemovedEntity(ref cachedKey, out var state))
4141
return null;
4242
if (cachedKey.HasExactType) {
4343
type = cachedKey.TypeReference.Type;
4444
return true;
4545
}
4646
return false;
4747
}
48-
type = key.TypeReference.Type;
48+
type = keyTypeReferenceType;
4949
return true;
5050
}
5151

@@ -61,12 +61,17 @@ public static bool AddColumns(IEnumerable<ColumnInfo> candidateColumns,
6161
SortedDictionary<int, ColumnInfo> columns, TypeInfo type)
6262
{
6363
var result = false;
64+
var typeIsInterface = type.IsInterface;
65+
var typeFields = type.Fields;
66+
var typeFieldMap = type.FieldMap;
6467
foreach (var column in candidateColumns) {
6568
result = true;
66-
if (type.IsInterface == column.Field.DeclaringType.IsInterface)
67-
columns[type.Fields[column.Field.Name].MappingInfo.Offset] = column;
68-
else if (column.Field.DeclaringType.IsInterface)
69-
columns[type.FieldMap[column.Field].MappingInfo.Offset] = column;
69+
var columnField = column.Field;
70+
var columnIsInterface = columnField.DeclaringType.IsInterface;
71+
if (typeIsInterface == columnIsInterface)
72+
columns[typeFields[columnField.Name].MappingInfo.Offset] = column;
73+
else if (columnIsInterface)
74+
columns[typeFieldMap[columnField].MappingInfo.Offset] = column;
7075
else
7176
throw new InvalidOperationException();
7277
}
@@ -83,4 +88,4 @@ public static List<int> GetColumnsToBeLoaded(SortedDictionary<int, ColumnInfo> u
8388
return result;
8489
}
8590
}
86-
}
91+
}

Orm/Xtensive.Orm/Orm/Internals/Prefetch/PrefetchManager.cs

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,7 @@ public bool Equals(RootContainerCacheKey other)
3434
return Equals(other.type, type) && Equals(other.descriptors, descriptors);
3535
}
3636

37-
public override bool Equals(object obj)
38-
{
39-
if (obj is null) {
40-
return false;
41-
}
42-
if (obj.GetType() != typeof (RootContainerCacheKey)) {
43-
return false;
44-
}
45-
return Equals((RootContainerCacheKey) obj);
46-
}
37+
public override bool Equals(object obj) => obj is RootContainerCacheKey other && Equals(other);
4738

4839
public override int GetHashCode() => hashCode;
4940

@@ -126,20 +117,21 @@ private async ValueTask<StrongReferenceContainer> Prefetch(
126117

127118
var selectedFields = descriptors;
128119
var currentType = type;
120+
var currentKeyTypeReferenceType = currentKey.TypeReference.Type;
129121
var isKeyTypeExact = currentKey.HasExactType
130-
|| currentKey.TypeReference.Type.IsLeaf
131-
|| currentKey.TypeReference.Type == type;
122+
|| currentKeyTypeReferenceType.IsLeaf
123+
|| currentKeyTypeReferenceType == type;
132124
if (isKeyTypeExact) {
133-
currentType = currentKey.TypeReference.Type;
125+
currentType = currentKeyTypeReferenceType;
134126
EnsureAllFieldsBelongToSpecifiedType(descriptors, currentType);
135127
}
136128
else {
137129
ArgumentValidator.EnsureArgumentNotNull(currentType, "type");
138130
EnsureAllFieldsBelongToSpecifiedType(descriptors, currentType);
139-
_ = SetUpContainers(currentKey, currentKey.TypeReference.Type,
140-
PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, currentKey.TypeReference.Type),
131+
_ = SetUpContainers(currentKey, currentKeyTypeReferenceType,
132+
PrefetchHelper.GetCachedDescriptorsForFieldsLoadedByDefault(session.Domain, currentKeyTypeReferenceType),
141133
true, ownerState, true);
142-
var hierarchyRoot = currentKey.TypeReference.Type;
134+
var hierarchyRoot = currentKeyTypeReferenceType;
143135
selectedFields = descriptors
144136
.Where(descriptor => descriptor.Field.DeclaringType != hierarchyRoot)
145137
.ToList();
@@ -215,16 +207,15 @@ public GraphContainer SetUpContainers(Key key, TypeInfo type,
215207
{
216208
var result = GetGraphContainer(key, type, exactType);
217209
var areAnyColumns = false;
218-
var haveColumnsBeenSet = canUseCache
219-
? TrySetCachedColumnIndexes(result, descriptors, state)
220-
: false;
210+
var haveColumnsBeenSet = canUseCache && TrySetCachedColumnIndexes(result, descriptors, state);
221211

222212
foreach (var descriptor in descriptors) {
223-
if (descriptor.Field.IsEntity && descriptor.FetchFieldsOfReferencedEntity && !type.IsAuxiliary) {
213+
var descriptorField = descriptor.Field;
214+
if (descriptorField.IsEntity && descriptor.FetchFieldsOfReferencedEntity && !type.IsAuxiliary) {
224215
areAnyColumns = true;
225216
result.RegisterReferencedEntityContainer(state, descriptor);
226217
}
227-
else if (descriptor.Field.IsEntitySet) {
218+
else if (descriptorField.IsEntitySet) {
228219
result.RegisterEntitySetTask(state, descriptor);
229220
}
230221
else {
@@ -281,21 +272,18 @@ public void GetCachedColumnIndexes(TypeInfo type,
281272

282273
private static void EnsureKeyTypeCorrespondsToSpecifiedType(Key key, TypeInfo type)
283274
{
284-
if (type == null || key.TypeReference.Type == type) {
275+
var keyTypeReferenceType = key.TypeReference.Type;
276+
if (type == null || keyTypeReferenceType == type) {
285277
return;
286278
}
287279

288-
if (!key.TypeReference.Type.IsInterface && !type.IsInterface) {
289-
if (key.TypeReference.Type.Hierarchy == type.Hierarchy) {
280+
if (!keyTypeReferenceType.IsInterface && !type.IsInterface) {
281+
if (keyTypeReferenceType.Hierarchy == type.Hierarchy) {
290282
return;
291283
}
292-
else {
293-
throw new ArgumentException(Strings.ExSpecifiedTypeHierarchyIsDifferentFromKeyHierarchy);
294-
}
295284
}
296-
297-
if (type.AllInterfaces.Contains(key.TypeReference.Type)
298-
|| key.TypeReference.Type.AllInterfaces.Contains(type)) {
285+
else if (type.AllInterfaces.Contains(keyTypeReferenceType)
286+
|| keyTypeReferenceType.AllInterfaces.Contains(type)) {
299287
return;
300288
}
301289

@@ -304,9 +292,10 @@ private static void EnsureKeyTypeCorrespondsToSpecifiedType(Key key, TypeInfo ty
304292

305293
private static void EnsureAllFieldsBelongToSpecifiedType(IReadOnlyList<PrefetchFieldDescriptor> descriptors, TypeInfo type)
306294
{
307-
for (var i = 0; i < descriptors.Count; i++) {
295+
var typeUnderlyingType = type.UnderlyingType;
296+
for (int i = 0, count = descriptors.Count; i < count; i++) {
308297
var declaringType = descriptors[i].Field.DeclaringType;
309-
if (type != declaringType && !declaringType.UnderlyingType.IsAssignableFrom(type.UnderlyingType)) {
298+
if (type != declaringType && !declaringType.UnderlyingType.IsAssignableFrom(typeUnderlyingType)) {
310299
throw new InvalidOperationException(
311300
string.Format(Strings.ExFieldXIsNotDeclaredInTypeYOrInOneOfItsAncestors, descriptors[i].Field, type));
312301
}
@@ -317,17 +306,13 @@ private GraphContainer GetGraphContainer(Key key, TypeInfo type, bool exactType)
317306
graphContainers.GetValueOrDefault((key, type))
318307
?? (graphContainers[(key, type)] = new GraphContainer(key, type, exactType, this));
319308

320-
private static IEnumerable<ColumnInfo> ExtractColumns(IEnumerable<PrefetchFieldDescriptor> descriptors)
321-
{
322-
foreach (var descriptor in descriptors) {
323-
var columns = descriptor.Field.IsStructure && !descriptor.FetchLazyFields
324-
? descriptor.Field.Columns.Where(column => !column.Field.IsLazyLoad)
325-
: descriptor.Field.Columns;
326-
foreach (var column in columns) {
327-
yield return column;
328-
}
329-
}
330-
}
309+
private static IEnumerable<ColumnInfo> ExtractColumns(IEnumerable<PrefetchFieldDescriptor> descriptors) =>
310+
descriptors.SelectMany(static descriptor => {
311+
var descriptorField = descriptor.Field;
312+
return descriptorField.IsStructure && !descriptor.FetchLazyFields
313+
? descriptorField.Columns.Where(static column => !column.Field.IsLazyLoad)
314+
: descriptorField.Columns;
315+
});
331316

332317
private bool TrySetCachedColumnIndexes(
333318
GraphContainer container, IEnumerable<PrefetchFieldDescriptor> descriptors, EntityState state)
@@ -357,4 +342,4 @@ public PrefetchManager(Session session)
357342
ColumnIndexesCacheSize, cacheEntry => cacheEntry.Key);
358343
}
359344
}
360-
}
345+
}

Orm/Xtensive.Orm/Orm/Providers/CommandProcessing/CommandFactory.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,14 @@ private static object GetParameterValue(QueryParameterBinding binding, Parameter
201201

202202
private object GetParameterValue(SqlPersistTask task, PersistParameterBinding binding)
203203
{
204+
var fieldIndex = binding.FieldIndex;
204205
switch (binding.BindingType) {
205-
case PersistParameterBindingType.Regular when task.Tuple != null:
206-
return task.Tuple.GetValueOrDefault(binding.FieldIndex);
207-
case PersistParameterBindingType.Regular when task.Tuples != null:
208-
return task.Tuples[binding.RowIndex].GetValueOrDefault(binding.FieldIndex);
206+
case PersistParameterBindingType.Regular when task.Tuple is { } tuple:
207+
return tuple.GetValueOrDefault(fieldIndex);
208+
case PersistParameterBindingType.Regular when task.Tuples is { } tuples:
209+
return tuples[binding.RowIndex].GetValueOrDefault(fieldIndex);
209210
case PersistParameterBindingType.VersionFilter:
210-
return task.OriginalTuple.GetValueOrDefault(binding.FieldIndex);
211+
return task.OriginalTuple.GetValueOrDefault(fieldIndex);
211212
default:
212213
throw new ArgumentOutOfRangeException("binding.Source");
213214
}

0 commit comments

Comments
 (0)