Skip to content

Commit 31dac53

Browse files
authored
Merge pull request #447 from DataObjects-NET/master-upgrade-small-imps
HintGenerator: small improvements
2 parents e0d4745 + 1a2bb5d commit 31dac53

File tree

2 files changed

+71
-94
lines changed

2 files changed

+71
-94
lines changed

ChangeLog/7.2.0-dev.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
[main] Changes of Persistent objects in events Persisted/TransactionCommitting/TransactionCommitted became prohibited to prevent possible loss of changes
2-
[postgresql] Server-side statement timeout handled as TimeoutException
2+
[main] Memory efficiency and performance improvements of upgrade process
3+
[postgresql] Server-side statement timeout handled as TimeoutException

Orm/Xtensive.Orm/Orm/Upgrade/Internals/HintGenerator.cs

Lines changed: 69 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -152,54 +152,33 @@ private void GenerateCopyColumnHint(CopyFieldHint hint)
152152
// searching for all required objects
153153
var targetTypeName = hint.TargetType.GetFullName();
154154
var targetType = currentModel.Types
155-
.SingleOrDefault(type => type.UnderlyingType.Equals(targetTypeName, StringComparison.Ordinal));
156-
if (targetType == null) {
157-
throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintTargetTypeNotFound, targetTypeName));
158-
}
155+
.SingleOrDefault(type => type.UnderlyingType.Equals(targetTypeName, StringComparison.Ordinal))
156+
?? throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintTargetTypeNotFound, targetTypeName));
159157

160158
var targetField = targetType.AllFields
161-
.SingleOrDefault(field => field.Name.Equals(hint.TargetField, StringComparison.Ordinal));
162-
if (targetField == null) {
163-
throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintTargetFieldNotFound, hint.TargetField));
164-
}
159+
.SingleOrDefault(field => field.Name.Equals(hint.TargetField, StringComparison.Ordinal))
160+
?? throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintTargetFieldNotFound, hint.TargetField));
165161

166-
var targetHierarchy = targetType.Hierarchy;
162+
var targetHierarchy = targetType.Hierarchy ?? throw TypeIsNotInHierarchy(targetTypeName);
167163

168164
var sourceTypeName = hint.SourceType;
169165
var sourceType = extractedModel.Types
170-
.SingleOrDefault(type => type.UnderlyingType.Equals(sourceTypeName, StringComparison.Ordinal));
171-
if (sourceType == null) {
172-
throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintSourceTypeNotFound, sourceTypeName));
173-
}
166+
.SingleOrDefault(type => type.UnderlyingType.Equals(sourceTypeName, StringComparison.Ordinal))
167+
?? throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintSourceTypeNotFound, sourceTypeName));
174168

175169
var sourceField = sourceType.AllFields
176-
.SingleOrDefault(field => field.Name.Equals(hint.SourceField, StringComparison.Ordinal));
177-
if (sourceField == null) {
178-
throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintSourceFieldNotFound, hint.SourceField));
179-
}
170+
.SingleOrDefault(field => field.Name.Equals(hint.SourceField, StringComparison.Ordinal))
171+
?? throw new InvalidOperationException(string.Format(Strings.ExUpgradeHintSourceFieldNotFound, hint.SourceField));
180172

181-
var sourceHierarchy = sourceType.Hierarchy;
182-
183-
// checking that types have hierarchies
184-
if (sourceHierarchy == null) {
185-
throw TypeIsNotInHierarchy(hint.SourceType);
186-
}
187-
188-
if (targetHierarchy == null) {
189-
throw TypeIsNotInHierarchy(targetTypeName);
190-
}
173+
var sourceHierarchy = sourceType.Hierarchy ?? throw TypeIsNotInHierarchy(hint.SourceType);
191174

192175
// building set of key columns
193-
var pairedKeyColumns = AssociateMappedKeyFields(sourceHierarchy, targetHierarchy);
194-
if (pairedKeyColumns == null) {
195-
throw KeysDoNotMatch(sourceTypeName, targetTypeName);
196-
}
176+
var pairedKeyColumns = AssociateMappedKeyFields(sourceHierarchy, targetHierarchy)
177+
?? throw KeysDoNotMatch(sourceTypeName, targetTypeName);
197178

198179
// building set of copied columns
199-
var pairedColumns = AssociateMappedFields(new Pair<StoredFieldInfo>(sourceField, targetField));
200-
if (pairedColumns == null) {
201-
throw FieldsDoNotMatch(sourceField, targetField);
202-
}
180+
var pairedColumns = AssociateMappedFields(new Pair<StoredFieldInfo>(sourceField, targetField))
181+
?? throw FieldsDoNotMatch(sourceField, targetField);
203182

204183
// building source/destination table/column names
205184
var targetTypes = GetAffectedMappedTypes(
@@ -238,22 +217,13 @@ private void GenerateRecordCleanupHints(List<StoredTypeInfo> removedTypes,
238217

239218
private void GenerateCleanupByPrimaryKeyHints(StoredTypeInfo removedType, CleanupInfo cleanupInfo)
240219
{
241-
IEnumerable<(StoredTypeInfo, IdentityPair)> typesToProcess;
242220
var hierarchy = removedType.Hierarchy;
243-
switch (hierarchy.InheritanceSchema) {
244-
case InheritanceSchema.ClassTable:
245-
typesToProcess = GetTypesToCleanForClassTable(removedType, cleanupInfo);
246-
break;
247-
case InheritanceSchema.SingleTable:
248-
typesToProcess = GetTypesToCleanForSingleTable(removedType, cleanupInfo);
249-
break;
250-
case InheritanceSchema.ConcreteTable:
251-
typesToProcess = GetTypesToCleanForConcreteTable(removedType, cleanupInfo);
252-
break;
253-
default:
254-
throw Exceptions.InternalError(string.Format(Strings.ExInheritanceSchemaIsInvalid, hierarchy.InheritanceSchema), UpgradeLog.Instance);
255-
}
256-
221+
var typesToProcess = hierarchy.InheritanceSchema switch {
222+
InheritanceSchema.ClassTable => GetTypesToCleanForClassTable(removedType, cleanupInfo),
223+
InheritanceSchema.SingleTable => GetTypesToCleanForSingleTable(removedType, cleanupInfo),
224+
InheritanceSchema.ConcreteTable => GetTypesToCleanForConcreteTable(removedType, cleanupInfo),
225+
_ => throw Exceptions.InternalError(string.Format(Strings.ExInheritanceSchemaIsInvalid, hierarchy.InheritanceSchema), UpgradeLog.Instance),
226+
};
257227
var deleteInfo = DataDeletionInfo.None;
258228
if ((cleanupInfo & CleanupInfo.TypeMovedToAnotherHierarchy) != 0)
259229
deleteInfo |= DataDeletionInfo.PostCopy;
@@ -283,8 +253,9 @@ private void GenerateCleanupByPrimaryKeyHints(StoredTypeInfo removedType, Cleanu
283253
return Array.Empty<(StoredTypeInfo, IdentityPair)>();
284254

285255
var capacity = (2 * removedType.AllAncestors.Length) + removedType.AllDescendants.Length + 1;
286-
var typesToProcess = new List<(StoredTypeInfo, IdentityPair)>(capacity);
287-
typesToProcess.Add((removedType, CreateIdentityPair(removedType, removedType)));
256+
var typesToProcess = new List<(StoredTypeInfo, IdentityPair)>(capacity) {
257+
(removedType, CreateIdentityPair(removedType, removedType))
258+
};
288259
foreach(var dType in removedType.AllDescendants) {
289260
typesToProcess.Add((removedType, CreateIdentityPair(removedType, removedType, dType.TypeId)));
290261
typesToProcess.Add((dType, null));
@@ -410,8 +381,8 @@ private void ClearAssociationForInterface(
410381
.Where(t => !t.IsInterface
411382
&& t.Fields.Any(f => f.IsInterfaceImplementation
412383
&& f.Name.Equals(field.Name, StringComparison.Ordinal)
413-
&& f.ValueType.Equals(field.ValueType, StringComparison.Ordinal)))
414-
.ToList();
384+
&& f.ValueType.Equals(field.ValueType, StringComparison.Ordinal)));
385+
415386
foreach (var candidate in candidates) {
416387
var inheritanceSchema = candidate.Hierarchy.InheritanceSchema;
417388
GenerateClearReferenceHints(
@@ -534,11 +505,9 @@ private void GenerateClearReferenceHint(
534505
.Fields
535506
: association.ReferencingField.Fields;
536507
var pairedIdentityFields = JoinFieldsByOriginalName(identityFieldsOfRemovedType, identityFieldsOfUpdatedType);
537-
var pairedIdentityColumns = AssociateMappedFields(pairedIdentityFields);
538-
if (pairedIdentityColumns == null) {
539-
throw new InvalidOperationException(
508+
var pairedIdentityColumns = AssociateMappedFields(pairedIdentityFields)
509+
?? throw new InvalidOperationException(
540510
string.Format(Strings.ExPairedIdentityColumnsForTypesXAndXNotFound, removedType, updatedType));
541-
}
542511

543512
var sourceTablePath = GetTablePath(updatedType);
544513
var identities = pairedIdentityColumns.SelectToList(pair =>
@@ -582,11 +551,8 @@ private void UpdateAffectedTables(RemoveTypeHint hint)
582551
{
583552
var affectedTables = new List<string>();
584553
var typeName = hint.Type;
585-
var storedType = extractedModel.Types
586-
.SingleOrDefault(type => type.UnderlyingType.Equals(typeName, StringComparison.Ordinal));
587-
if (storedType == null) {
588-
throw TypeNotFound(typeName);
589-
}
554+
var storedType = extractedModel.Types.SingleOrDefault(type => type.UnderlyingType.Equals(typeName, StringComparison.Ordinal))
555+
?? throw TypeNotFound(typeName);
590556

591557
var inheritanceSchema = storedType.Hierarchy.InheritanceSchema;
592558

@@ -612,17 +578,11 @@ private void UpdateAffectedTables(RemoveTypeHint hint)
612578
private void UpdateAffectedColumns(ChangeFieldTypeHint hint)
613579
{
614580
var currentTypeName = hint.Type.GetFullName();
615-
var currentType = currentModel.Types
616-
.SingleOrDefault(type => type.UnderlyingType.Equals(currentTypeName, StringComparison.Ordinal));
617-
if (currentType == null) {
618-
throw TypeNotFound(currentTypeName);
619-
}
581+
var currentType = currentModel.Types.SingleOrDefault(type => type.UnderlyingType.Equals(currentTypeName, StringComparison.Ordinal))
582+
?? throw TypeNotFound(currentTypeName);
620583

621-
var currentField = currentType.AllFields
622-
.SingleOrDefault(field => field.Name.Equals(hint.FieldName, StringComparison.Ordinal));
623-
if (currentField==null) {
624-
throw FieldNotFound(currentTypeName, hint.FieldName);
625-
}
584+
var currentField = currentType.AllFields.SingleOrDefault(field => field.Name.Equals(hint.FieldName, StringComparison.Ordinal))
585+
?? throw FieldNotFound(currentTypeName, hint.FieldName);
626586

627587
var affectedColumns = GetAffectedColumns(currentType, currentField);
628588
hint.AffectedColumns = affectedColumns.AsReadOnly();
@@ -635,26 +595,41 @@ private void UpdateAffectedColumns(RemoveFieldHint hint)
635595
}
636596

637597
var typeName = hint.Type;
638-
var storedType = extractedModel.Types
639-
.SingleOrDefault(type => type.UnderlyingType.Equals(typeName, StringComparison.Ordinal));
640-
if (storedType == null) {
641-
throw TypeNotFound(typeName);
642-
}
598+
var storedType = extractedModel.Types.SingleOrDefault(type => type.UnderlyingType.Equals(typeName, StringComparison.Ordinal))
599+
?? throw TypeNotFound(typeName);
643600

601+
const char dot = '.';
644602
StoredFieldInfo storedField = null;
645603
// Nested field, looks like a field of a structure
646-
if (hint.Field.Contains(".", StringComparison.Ordinal)) {
647-
var path = hint.Field.Split('.');
604+
if (hint.Field.Contains(dot, StringComparison.Ordinal)) {
648605
var fields = storedType.AllFields;
649-
var fieldName = string.Empty;
650-
for (var i = 0; i < path.Length; i++) {
651-
fieldName += string.IsNullOrEmpty(fieldName) ? path[i] : "." + path[i];
652-
var parameter = fieldName;
653-
storedField = fields.SingleOrDefault(field => field.Name.Equals(parameter, StringComparison.Ordinal));
654-
if (storedField == null) {
655-
throw FieldNotFound(typeName, hint.Field);
606+
var hintFieldName = hint.Field;
607+
var fieldNameAsSpan = hintFieldName.AsSpan();
608+
609+
var endOfName = hintFieldName.IndexOf(dot);
610+
while (endOfName < hintFieldName.Length) {
611+
ReadOnlySpan<char> slice;
612+
if (endOfName == -1) {
613+
endOfName = hintFieldName.Length;
614+
slice = fieldNameAsSpan[..endOfName];
615+
}
616+
else {
617+
slice = fieldNameAsSpan[..endOfName];
618+
endOfName = hintFieldName.IndexOf(dot, endOfName + 1);
619+
}
620+
StoredFieldInfo result = null;
621+
foreach (var f in fields) {
622+
if (f.Name.AsSpan().Equals(slice, StringComparison.Ordinal)) {
623+
if (result is null)
624+
result = f;
625+
else {
626+
result = null;
627+
break;
628+
}
629+
}
656630
}
657631

632+
storedField = result ?? throw FieldNotFound(typeName, hint.Field);
658633
fields = storedField.Fields;
659634
}
660635
}
@@ -770,17 +745,18 @@ private HashSet<StoredTypeInfo> GetConflictsByTable(IReadOnlyList<StoredTypeInfo
770745
// by table. Knowing that we basically cannot register table conflicts
771746
// on table basis, except for the case when root is conflict.
772747

773-
var capacity = currentModel.Types.Length - typeMapping.Count;
748+
var capacity = Math.Abs(currentModel.Types.Length - typeMapping.Count);
774749
var currentTables = new HashSet<string>(capacity, StringComparer.Ordinal);
775750
foreach (var newType in currentNonConnectorTypes.Where(t => !reverseTypeMapping.ContainsKey(t))) {
776751
if (newType.Hierarchy == null
777-
|| (newType.Hierarchy.InheritanceSchema == InheritanceSchema.SingleTable && !newType.IsHierarchyRoot))
752+
|| (newType.Hierarchy.InheritanceSchema == InheritanceSchema.SingleTable && !newType.IsHierarchyRoot)) {
778753
continue;
754+
}
779755
var key = $"{newType.MappingDatabase}.{newType.MappingSchema}.{newType.MappingName}";
780-
currentTables.Add(key);
756+
_ = currentTables.Add(key);
781757
}
782758

783-
var conflictsByTable = new HashSet<StoredTypeInfo>();
759+
var conflictsByTable = new HashSet<StoredTypeInfo>(suspiciousTypes.Count);
784760

785761
foreach (var rType in removedTypes) {
786762
var rTypeIdentifier = $"{rType.MappingDatabase}.{rType.MappingSchema}.{rType.MappingName}";
@@ -798,7 +774,7 @@ from type in extractedNonConnectorTypes
798774
where type.IsEntity && (!type.IsAbstract) && (!type.IsGeneric) && (!type.IsInterface)
799775
where IsRemoved(type)
800776
select type
801-
).ToList();
777+
).ToList(Math.Max(extractedNonConnectorTypes.Count / 10, 8));
802778

803779
bool IsRemoved(StoredTypeInfo type)
804780
{
@@ -813,7 +789,7 @@ from type in extractedNonConnectorTypes
813789
where type.IsEntity && (!type.IsAbstract) && (!type.IsGeneric) && (!type.IsInterface)
814790
where IsMovedToAnotherHierarchy(type)
815791
select type
816-
).ToList();
792+
).ToList(Math.Max(extractedNonConnectorTypes.Count / 10, 8));
817793

818794
bool IsMovedToAnotherHierarchy(StoredTypeInfo oldType)
819795
{

0 commit comments

Comments
 (0)