Skip to content

Commit 51d471c

Browse files
committed
Better memory usage
1 parent 4f3959e commit 51d471c

5 files changed

Lines changed: 82 additions & 35 deletions

File tree

Orm/Xtensive.Orm/Orm/Building/Builders/StorageMappingBuilder.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ private readonly Dictionary<MappingRequest, MappingResult> mappingCache
7474
= new Dictionary<MappingRequest,MappingResult>();
7575

7676
private readonly bool verbose;
77-
private readonly List<MappingRule> mappingRules;
77+
private readonly MappingRule[] mappingRules;
7878
private readonly string defaultDatabase;
7979
private readonly string defaultSchema;
8080

@@ -138,12 +138,16 @@ private static bool RuleMatch(MappingRule rule, Type type)
138138
private StorageMappingBuilder(BuildingContext context)
139139
{
140140
this.context = context;
141+
var configuration = context.Configuration;
141142

142143
// Adding a special catch-all rule that maps all types to default schema/database.
143-
144-
mappingRules = context.Configuration.MappingRules
145-
.Concat(Enumerable.Repeat(new MappingRule(null, null, null, null), 1))
146-
.ToList();
144+
if (configuration.MappingRules.Count == 0)
145+
mappingRules = new[] { new MappingRule(null, null, null, null) };
146+
else {
147+
mappingRules = new MappingRule[context.Configuration.MappingRules.Count + 1];
148+
configuration.MappingRules.CopyTo(mappingRules, 0);
149+
mappingRules[^1] = new MappingRule(null, null, null, null);
150+
}
147151

148152
defaultDatabase = context.Configuration.DefaultDatabase ?? string.Empty;
149153
defaultSchema = context.Configuration.DefaultSchema ?? string.Empty;

Orm/Xtensive.Orm/Orm/Linq/Expressions/Visitors/IncludeFilterMappingGatherer.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,9 @@ public MappingEntry(LambdaExpression calculatedColumn)
4242

4343
public static MappingEntry[] Gather(Expression filterExpression, Expression filterDataTuple, ApplyParameter filteredTuple, int columnCount)
4444
{
45-
var mapping = Enumerable.Repeat((MappingEntry) null, columnCount).ToArray();
45+
var mapping = new MappingEntry[columnCount];
46+
System.Array.Fill(mapping, null);
47+
4648
var visitor = new IncludeFilterMappingGatherer(filterDataTuple, filteredTuple, mapping);
4749
_ = visitor.Visit(filterExpression);
4850
if (mapping.Contains(null)) {

Orm/Xtensive.Orm/Orm/Linq/Materialization/ExpressionMaterializer.cs

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace Xtensive.Orm.Linq.Materialization
2727
internal class ExpressionMaterializer : PersistentExpressionVisitor
2828
{
2929
private const string RootQueryTagsPrefix = "Root query tags ->";
30-
30+
private const int NumberOfItemsOnStack = 64;
3131
private static readonly MethodInfo BuildPersistentTupleMethod = typeof(ExpressionMaterializer).GetMethod(nameof(BuildPersistentTuple), BindingFlags.NonPublic | BindingFlags.Static);
3232
private static readonly MethodInfo GetTupleSegmentMethod = typeof(ExpressionMaterializer).GetMethod(nameof(GetTupleSegment), BindingFlags.NonPublic | BindingFlags.Static);
3333
private static readonly MethodInfo GetParameterValueMethod = WellKnownOrmTypes.ParameterContext.GetMethod(nameof(ParameterContext.GetValue));
@@ -246,12 +246,29 @@ protected override Expression VisitStructureFieldExpression(StructureFieldExpres
246246
if (expression.Owner == null) {
247247
var typeInfo = expression.PersistentType;
248248
var tuplePrototype = typeInfo.TuplePrototype;
249-
var mappingInfo = expression.Fields
249+
250+
var mappingSequence = expression.Fields
250251
.OfExactlyFieldExpression()
251252
.OrderBy(static f => f.Field.MappingInfo.Offset)
252253
.Select(static f => new Pair<int>(f.Field.MappingInfo.Offset, f.Mapping.Offset))
253-
.Distinct()
254-
.ToArray();
254+
.Distinct();
255+
256+
Pair<int>[] mappingInfo;
257+
if (expression.Fields.Count > NumberOfItemsOnStack * 2) {
258+
mappingInfo = mappingSequence.ToArray();
259+
}
260+
else {
261+
Span<Pair<int>> mappingInfoSpan = (expression.Fields.Count < NumberOfItemsOnStack)
262+
? stackalloc Pair<int>[expression.Fields.Count]
263+
: new Pair<int>[expression.Fields.Count];
264+
265+
int actualCount = 0;
266+
foreach (var map in mappingSequence) {
267+
mappingInfoSpan[actualCount++] = map;
268+
}
269+
270+
mappingInfo = mappingInfoSpan.Slice(0, actualCount).ToArray();
271+
}
255272

256273
var columnMap = MaterializationHelper.CreateSingleSourceMap(tuplePrototype.Count, mappingInfo);
257274

@@ -294,12 +311,29 @@ protected override Expression VisitStructureExpression(StructureExpression expre
294311

295312
var typeInfo = expression.PersistentType;
296313
var tuplePrototype = typeInfo.TuplePrototype;
297-
var mappingInfo = expression.Fields
314+
315+
var mappingSequence = expression.Fields
298316
.OfExactlyFieldExpression()
299317
.OrderBy(static f => f.Field.MappingInfo.Offset)
300318
.Select(static f => new Pair<int>(f.Field.MappingInfo.Offset, f.Mapping.Offset))
301-
.Distinct()
302-
.ToArray();
319+
.Distinct();
320+
321+
Pair<int>[] mappingInfo;
322+
if (expression.Fields.Count > NumberOfItemsOnStack * 2) {
323+
mappingInfo = mappingSequence.ToArray();
324+
}
325+
else {
326+
Span<Pair<int>> mappingInfoSpan = (expression.Fields.Count < NumberOfItemsOnStack)
327+
? stackalloc Pair<int>[expression.Fields.Count]
328+
: new Pair<int>[expression.Fields.Count];
329+
330+
int actualCount = 0;
331+
foreach (var map in mappingSequence) {
332+
mappingInfoSpan[actualCount++] = map;
333+
}
334+
335+
mappingInfo = mappingInfoSpan.Slice(0, actualCount).ToArray();
336+
}
303337

304338
var columnMap = MaterializationHelper.CreateSingleSourceMap(tuplePrototype.Count, mappingInfo);
305339

@@ -358,12 +392,28 @@ private Expression CreateEntity(IEntityExpression expression, Expression tupleEx
358392
var typeIdField = expression.Fields.SingleOrDefault(f => f.Name == WellKnown.TypeIdFieldName);
359393
var typeIdIndex = typeIdField == null ? -1 : typeIdField.Mapping.Offset;
360394

361-
var mappingInfo = expression.Fields
395+
var mappingSequence = expression.Fields
362396
.OfExactlyFieldExpression()
363397
.OrderBy(static f => f.Field.MappingInfo.Offset)
364398
.Select(static f => new Pair<int>(f.Field.MappingInfo.Offset, f.Mapping.Offset))
365-
.Distinct()
366-
.ToArray();
399+
.Distinct();
400+
401+
Pair<int>[] mappingInfo;
402+
if (expression.Fields.Count > NumberOfItemsOnStack * 4) {
403+
mappingInfo = mappingSequence.ToArray();
404+
}
405+
else {
406+
Span<Pair<int>> mappingInfoSpan = (expression.Fields.Count < NumberOfItemsOnStack)
407+
? stackalloc Pair<int>[expression.Fields.Count]
408+
: new Pair<int>[expression.Fields.Count];
409+
410+
int actualCount = 0;
411+
foreach (var map in mappingSequence) {
412+
mappingInfoSpan[actualCount++] = map;
413+
}
414+
415+
mappingInfo = mappingInfoSpan.Slice(0, actualCount).ToArray();
416+
}
367417

368418
var isMaterializedExpression = Expression.Call(
369419
itemMaterializationContextParameter,

Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,8 @@ private static ProjectionExpression Optimize(ProjectionExpression origin)
8989
if (usedColumns.Count == 0)
9090
usedColumns.Add(0);
9191
if (usedColumns.Count < origin.ItemProjector.DataSource.Header.Length) {
92-
var usedColumnsArray = usedColumns.ToArray();
93-
var resultProvider = new SelectProvider(originProvider, usedColumnsArray);
94-
var itemProjector = origin.ItemProjector.Remap(resultProvider, usedColumnsArray);
92+
var resultProvider = new SelectProvider(originProvider, usedColumns);
93+
var itemProjector = origin.ItemProjector.Remap(resultProvider, usedColumns);
9594
var result = origin.ApplyItemProjector(itemProjector);
9695
return result;
9796
}

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

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,9 @@ private ProjectionExpression VisitCast(Expression source, Type targetType, Type
356356
var recordSet = projection.ItemProjector.DataSource;
357357
var targetTypeInfo = context.Model.Types[targetType];
358358
var sourceTypeInfo = context.Model.Types[sourceType];
359-
var map = Enumerable.Repeat(-1, recordSet.Header.Columns.Count).ToArray();
359+
var map = new int[recordSet.Header.Columns.Count];
360+
Array.Fill(map, -1);
361+
360362
var targetFieldIndex = 0;
361363
var targetFields = targetTypeInfo.Fields.Where(f => f.IsPrimitive);
362364
foreach (var targetField in targetFields) {
@@ -1571,22 +1573,12 @@ private Expression VisitSetOperations(Expression outerSource, Expression innerSo
15711573

15721574
var outerItemProjector = outer.ItemProjector.RemoveOwner();
15731575
var innerItemProjector = inner.ItemProjector.RemoveOwner();
1574-
var outerColumnList = outerItemProjector.GetColumns(ColumnExtractionModes.Distinct).ToList();
1575-
var innerColumnList = innerItemProjector.GetColumns(ColumnExtractionModes.Distinct).ToList();
1576-
1577-
int[] outerColumns, innerColumns;
1578-
if (!outerColumnList.Except(innerColumnList).Any() && outerColumnList.Count == innerColumnList.Count) {
1579-
var outerColumnListCopy = outerColumnList.ToArray();
1580-
Array.Sort(outerColumnListCopy);
1581-
outerColumns = outerColumnListCopy;
1576+
var outerColumns = outerItemProjector.GetColumns(ColumnExtractionModes.Distinct).ToArray();
1577+
var innerColumns = innerItemProjector.GetColumns(ColumnExtractionModes.Distinct).ToArray();
15821578

1583-
var innerColumnListCopy = innerColumnList.ToArray();
1584-
Array.Sort(innerColumnListCopy);
1585-
innerColumns = innerColumnListCopy;
1586-
}
1587-
else {
1588-
outerColumns = outerColumnList.ToArray();
1589-
innerColumns = innerColumnList.ToArray();
1579+
if (!outerColumns.Except(innerColumns).Any() && outerColumns.Length == innerColumns.Length) {
1580+
Array.Sort(outerColumns);
1581+
Array.Sort(innerColumns);
15901582
}
15911583

15921584
var outerRecordSet = ShouldWrapDataSourceWithSelect(outerItemProjector, outerColumns)

0 commit comments

Comments
 (0)