Skip to content

Commit b7a3374

Browse files
authored
Optimization: avoid double lookup in FieldMap (#224)
1 parent bc2d598 commit b7a3374

File tree

2 files changed

+53
-43
lines changed

2 files changed

+53
-43
lines changed

Orm/Xtensive.Orm/Orm/Building/Builders/TypeBuilder.cs

+30-32
Original file line numberDiff line numberDiff line change
@@ -58,39 +58,39 @@ public TypeInfo BuildType(TypeDef typeDef)
5858
typeInfo.TypeId = typeDef.StaticTypeId.Value;
5959
}
6060

61-
context.Model.Types.Add(typeInfo);
61+
var contextModelTypes = context.Model.Types;
62+
contextModelTypes.Add(typeInfo);
6263

6364
// Registering connections between type & its ancestors
64-
var node = context.DependencyGraph.TryGetNode(typeDef);
65-
if (node != null) {
66-
foreach (var edge in node.OutgoingEdges.Where(static e =>
67-
e.Kind is EdgeKind.Implementation or EdgeKind.Inheritance)) {
68-
var baseType = context.Model.Types[edge.Head.Value.UnderlyingType];
65+
if (context.DependencyGraph.TryGetNode(typeDef) is { } node) {
66+
foreach (var edge in node.OutgoingEdges.Where(static e => e.Kind is EdgeKind.Implementation or EdgeKind.Inheritance)) {
67+
var baseType = contextModelTypes[edge.Head.Value.UnderlyingType];
6968
switch (edge.Kind) {
7069
case EdgeKind.Inheritance:
71-
context.Model.Types.RegisterInheritance(baseType, typeInfo);
70+
contextModelTypes.RegisterInheritance(baseType, typeInfo);
7271
break;
7372
case EdgeKind.Implementation:
74-
context.Model.Types.RegisterImplementation(baseType, typeInfo);
73+
contextModelTypes.RegisterImplementation(baseType, typeInfo);
7574
break;
7675
}
7776
}
7877
}
7978

79+
var typeDefFields = typeDef.Fields;
8080
if (typeDef.IsEntity) {
8181
var hierarchyDef = context.ModelDef.FindHierarchy(typeDef);
8282

8383
// Is type a hierarchy root?
8484
if (typeInfo.UnderlyingType == hierarchyDef.Root.UnderlyingType) {
8585
foreach (var keyField in hierarchyDef.KeyFields) {
86-
var fieldInfo = BuildDeclaredField(typeInfo, typeDef.Fields[keyField.Name]);
86+
var fieldInfo = BuildDeclaredField(typeInfo, typeDefFields[keyField.Name]);
8787
fieldInfo.IsPrimaryKey = true;
8888
}
8989

9090
typeInfo.Hierarchy = BuildHierarchyInfo(typeInfo, hierarchyDef);
9191
}
9292
else {
93-
var root = context.Model.Types[hierarchyDef.Root.UnderlyingType];
93+
var root = contextModelTypes[hierarchyDef.Root.UnderlyingType];
9494
typeInfo.Hierarchy = root.Hierarchy;
9595
foreach (var fieldInfo in root.Fields.Where(static f => f.IsPrimaryKey && f.Parent == null)) {
9696
BuildInheritedField(typeInfo, fieldInfo);
@@ -100,7 +100,7 @@ public TypeInfo BuildType(TypeDef typeDef)
100100
else if (typeDef.IsInterface) {
101101
var hierarchyDef = context.ModelDef.FindHierarchy(typeDef.Implementors[0]);
102102
foreach (var keyField in hierarchyDef.KeyFields) {
103-
var fieldInfo = BuildDeclaredField(typeInfo, typeDef.Fields[keyField.Name]);
103+
var fieldInfo = BuildDeclaredField(typeInfo, typeDefFields[keyField.Name]);
104104
fieldInfo.IsPrimaryKey = true;
105105
}
106106
}
@@ -134,12 +134,15 @@ public void BuildTypeDiscriminatorMap(TypeDef typeDef, TypeInfo typeInfo)
134134

135135
public void BuildFields(TypeDef typeDef, TypeInfo typeInfo)
136136
{
137+
var typeDefFields = typeDef.Fields;
138+
var typeInfoFields = typeInfo.Fields;
139+
var typeInfoFieldMap = typeInfo.FieldMap;
137140
if (typeInfo.IsInterface) {
138141
var sourceFields = typeInfo.DirectInterfaces
139142
.SelectMany(static i => i.Fields)
140143
.Where(static f => !f.IsPrimaryKey && f.Parent == null);
141144
foreach (var srcField in sourceFields) {
142-
if (!typeInfo.Fields.Contains(srcField.Name)) {
145+
if (!typeInfoFields.Contains(srcField.Name)) {
143146
BuildInheritedField(typeInfo, srcField);
144147
}
145148
}
@@ -148,7 +151,7 @@ public void BuildFields(TypeDef typeDef, TypeInfo typeInfo)
148151
var ancestor = typeInfo.Ancestor;
149152
if (ancestor != null) {
150153
foreach (var srcField in ancestor.Fields.Where(static f => !f.IsPrimaryKey && f.Parent == null)) {
151-
if (typeDef.Fields.TryGetValue(srcField.Name, out var fieldDef)) {
154+
if (typeDefFields.TryGetValue(srcField.Name, out var fieldDef)) {
152155
if (fieldDef.UnderlyingProperty == null) {
153156
throw new DomainBuilderException(
154157
string.Format(Strings.ExFieldXIsAlreadyDefinedInTypeXOrItsAncestor, fieldDef.Name, typeInfo.Name));
@@ -168,13 +171,13 @@ public void BuildFields(TypeDef typeDef, TypeInfo typeInfo)
168171
}
169172

170173
foreach (var pair in ancestor.FieldMap) {
171-
typeInfo.FieldMap.Add(pair.Key, typeInfo.Fields[pair.Value.Name]);
174+
typeInfoFieldMap.Add(pair.Key, typeInfoFields[pair.Value.Name]);
172175
}
173176
}
174177
}
175178

176-
foreach (var fieldDef in typeDef.Fields) {
177-
if (typeInfo.Fields.TryGetValue(fieldDef.Name, out var field)) {
179+
foreach (var fieldDef in typeDefFields) {
180+
if (typeInfoFields.TryGetValue(fieldDef.Name, out var field)) {
178181
if (field.ValueType != fieldDef.ValueType) {
179182
throw new DomainBuilderException(
180183
string.Format(Strings.ExFieldXIsAlreadyDefinedInTypeXOrItsAncestor, fieldDef.Name, typeInfo.Name));
@@ -197,34 +200,28 @@ public void BuildFields(TypeDef typeDef, TypeInfo typeInfo)
197200

198201
private void BuildFieldMap(TypeInfo @interface, TypeInfo implementor)
199202
{
203+
var implementorFields = implementor.Fields;
204+
var implementorFieldMap = implementor.FieldMap;
200205
foreach (var field in @interface.Fields.Where(static f => f.IsDeclared)) {
201206
var explicitName = context.NameBuilder.BuildExplicitFieldName(field.DeclaringType, field.Name);
202-
if (implementor.Fields.TryGetValue(explicitName, out var implField)) {
207+
if (implementorFields.TryGetValue(explicitName, out var implField)) {
203208
implField.IsExplicit = true;
204209
}
205210
else {
206-
if (!implementor.Fields.TryGetValue(field.Name, out implField)) {
211+
if (!implementorFields.TryGetValue(field.Name, out implField)) {
207212
throw new DomainBuilderException(
208213
string.Format(Strings.TypeXDoesNotImplementYZField, implementor.Name, @interface.Name, field.Name));
209214
}
210215
}
211216

212217
implField.IsInterfaceImplementation = true;
213-
214-
if (!implementor.FieldMap.ContainsKey(field)) {
215-
implementor.FieldMap.Add(field, implField);
216-
}
217-
else {
218-
implementor.FieldMap.Override(field, implField);
219-
}
218+
implementorFieldMap.AddOrOverride(field, implField);
220219

221220
var declaringType = implField.DeclaringType;
222221
var declaringField = implField.DeclaringField;
223222
if (implField.IsInherited && declaringType.IsEntity) {
224223
declaringField.IsInterfaceImplementation = true;
225-
if (!declaringType.FieldMap.ContainsKey(field)) {
226-
declaringType.FieldMap.Add(field, declaringField);
227-
}
224+
declaringType.FieldMap.TryAdd(field, declaringField);
228225
}
229226
}
230227
}
@@ -235,11 +232,12 @@ private FieldInfo BuildDeclaredField(TypeInfo type, FieldDef fieldDef)
235232

236233
var validators = fieldDef.Validators;
237234

238-
if (fieldDef.IsStructure && DeclaresOnValidate(fieldDef.ValueType)) {
235+
var valueType = fieldDef.ValueType;
236+
if (fieldDef.IsStructure && DeclaresOnValidate(valueType)) {
239237
validators.Add(new StructureFieldValidator());
240238
}
241239

242-
if (fieldDef.IsEntitySet && DeclaresOnValidate(fieldDef.ValueType)) {
240+
if (fieldDef.IsEntitySet && DeclaresOnValidate(valueType)) {
243241
validators.Add(new EntitySetFieldValidator());
244242
}
245243

@@ -248,7 +246,7 @@ private FieldInfo BuildDeclaredField(TypeInfo type, FieldDef fieldDef)
248246
Name = fieldDef.Name,
249247
OriginalName = fieldDef.Name,
250248
MappingName = fieldDef.MappingName,
251-
ValueType = fieldDef.ValueType,
249+
ValueType = valueType,
252250
ItemType = fieldDef.ItemType,
253251
Length = fieldDef.Length,
254252
Scale = fieldDef.Scale,
@@ -642,4 +640,4 @@ public TypeBuilder(BuildingContext context)
642640
.ToDictionary(configuration => context.NameBuilder.BuildKeyGeneratorName(configuration));
643641
}
644642
}
645-
}
643+
}

Orm/Xtensive.Orm/Orm/Model/FieldMap.cs

+23-11
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,37 @@ public bool ContainsKey(FieldInfo interfaceField)
4646
return map.ContainsKey(interfaceField);
4747
}
4848

49-
public void Add(FieldInfo interfaceField, FieldInfo typeField)
49+
internal bool TryAdd(FieldInfo interfaceField, FieldInfo typeField)
5050
{
5151
EnsureNotLocked();
52-
map.Add(interfaceField, typeField);
52+
if (!map.TryAdd(interfaceField, typeField)) {
53+
return false;
54+
}
5355
if (reversedMap.TryGetValue(typeField, out var interfaceFields)) {
5456
interfaceFields.Add(interfaceField);
5557
}
56-
else
57-
reversedMap.Add(typeField, new HashSet<FieldInfo> {interfaceField});
58+
else {
59+
reversedMap.Add(typeField, new HashSet<FieldInfo> { interfaceField });
60+
}
61+
return true;
5862
}
5963

60-
public void Override(FieldInfo interfaceField, FieldInfo typeField)
64+
public void Add(FieldInfo interfaceField, FieldInfo typeField)
6165
{
62-
EnsureNotLocked();
63-
var oldTypeField = map[interfaceField];
64-
var interfaceFields = reversedMap[oldTypeField];
65-
map[interfaceField] = typeField;
66-
reversedMap.Remove(oldTypeField);
67-
reversedMap.Add(typeField, interfaceFields);
66+
if (!TryAdd(interfaceField, typeField)) {
67+
throw new ArgumentException("An element with the same key already exists");
68+
}
69+
}
70+
71+
public void AddOrOverride(FieldInfo interfaceField, FieldInfo typeField)
72+
{
73+
if (!TryAdd(interfaceField, typeField)) {
74+
var oldTypeField = map[interfaceField];
75+
var interfaceFields = reversedMap[oldTypeField];
76+
map[interfaceField] = typeField;
77+
reversedMap.Remove(oldTypeField);
78+
reversedMap.Add(typeField, interfaceFields);
79+
}
6880
}
6981

7082
public bool TryGetValue(FieldInfo interfaceField, out FieldInfo typeField)

0 commit comments

Comments
 (0)