Skip to content

Commit 62bbba5

Browse files
authored
Optimize PersistRequest (#353)
* Optimize `PersistRequest` * Remove using
1 parent e4c5d27 commit 62bbba5

File tree

12 files changed

+89
-124
lines changed

12 files changed

+89
-124
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public virtual IEnumerable<CommandPart> CreatePersistParts(SqlPersistTask task,
5454
var result = new List<CommandPart>(task.RequestSequence.Count);
5555
int parameterIndex = 0;
5656
foreach (var request in task.RequestSequence) {
57-
var compilationResult = request.GetCompiledStatement();
57+
var compilationResult = request.CompiledStatement;
5858
var configuration = shareStorageNodesOverNodes
5959
? new SqlPostCompilerConfiguration(nodeConfiguration.GetDatabaseMapping(), nodeConfiguration.GetSchemaMapping())
6060
: new SqlPostCompilerConfiguration();

Orm/Xtensive.Orm/Orm/Providers/CommandProcessing/SqlPersistTask.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public sealed class SqlPersistTask : SqlTask
2626
/// <summary>
2727
/// Requests to execute.
2828
/// </summary>
29-
public readonly IReadOnlyCollection<PersistRequest> RequestSequence;
29+
public readonly IReadOnlyCollection<PreparedPersistRequest> RequestSequence;
3030

3131
/// <summary>
3232
/// A tuple that stores changed column values.
@@ -57,38 +57,38 @@ public override void ProcessWith(ISqlTaskProcessor processor, CommandProcessorCo
5757

5858
// Constructors
5959

60-
public SqlPersistTask(PersistRequest request, Tuple tuple = null)
60+
public SqlPersistTask(PreparedPersistRequest request, Tuple tuple = null)
6161
{
62-
RequestSequence = new PersistRequest[1] { request };
62+
RequestSequence = [request];
6363
Tuple = tuple;
6464
}
6565

66-
public SqlPersistTask(PersistRequest request, IReadOnlyList<Tuple> tuples)
66+
public SqlPersistTask(PreparedPersistRequest request, IReadOnlyList<Tuple> tuples)
6767
{
68-
RequestSequence = new PersistRequest[1] { request };
68+
RequestSequence = [request];
6969
Tuples = tuples;
7070
}
7171

7272
[Obsolete]
73-
public SqlPersistTask(Key key, IEnumerable<PersistRequest> requestSequence, Tuple tuple)
74-
: this(key, (requestSequence as IReadOnlyCollection<PersistRequest>)?? requestSequence.ToList(), tuple)
73+
public SqlPersistTask(Key key, IEnumerable<PreparedPersistRequest> requestSequence, Tuple tuple)
74+
: this(key, (requestSequence as IReadOnlyCollection<PreparedPersistRequest>)?? requestSequence.ToList(), tuple)
7575
{
7676
}
7777

7878
[Obsolete]
79-
public SqlPersistTask(Key key, IEnumerable<PersistRequest> requestSequence, Tuple tuple, Tuple originalTuple, bool validateRowCount)
80-
: this(key, (requestSequence as IReadOnlyCollection<PersistRequest>) ?? requestSequence.ToList(), tuple, originalTuple, validateRowCount)
79+
public SqlPersistTask(Key key, IEnumerable<PreparedPersistRequest> requestSequence, Tuple tuple, Tuple originalTuple, bool validateRowCount)
80+
: this(key, (requestSequence as IReadOnlyCollection<PreparedPersistRequest>) ?? requestSequence.ToList(), tuple, originalTuple, validateRowCount)
8181
{
8282
}
8383

84-
public SqlPersistTask(Key key, IReadOnlyCollection<PersistRequest> requestSequence, Tuple tuple)
84+
public SqlPersistTask(Key key, IReadOnlyCollection<PreparedPersistRequest> requestSequence, Tuple tuple)
8585
{
8686
EntityKey = key;
8787
RequestSequence = requestSequence;
8888
Tuple = tuple;
8989
}
9090

91-
public SqlPersistTask(Key key, IReadOnlyCollection<PersistRequest> requestSequence, Tuple tuple, Tuple originalTuple, bool validateRowCount)
91+
public SqlPersistTask(Key key, IReadOnlyCollection<PreparedPersistRequest> requestSequence, Tuple tuple, Tuple originalTuple, bool validateRowCount)
9292
{
9393
EntityKey = key;
9494
RequestSequence = requestSequence;

Orm/Xtensive.Orm/Orm/Providers/Interfaces/IPersistDescriptors.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ public interface IPersistDescriptor
1313
/// <summary>
1414
/// Request to store data.
1515
/// </summary>
16-
PersistRequest StoreRequest { get; }
16+
PreparedPersistRequest StoreRequest { get; }
1717

1818
/// <summary>
1919
/// Request to clear data.
2020
/// </summary>
21-
PersistRequest ClearRequest { get; }
21+
PreparedPersistRequest ClearRequest { get; }
2222
}
2323

2424
public interface IMultiRecordPersistDescriptor : IPersistDescriptor
@@ -28,22 +28,22 @@ public interface IMultiRecordPersistDescriptor : IPersistDescriptor
2828
/// protion can't be stored by neither <see cref="StoreBigBatchRequest"/>
2929
/// nor <see cref="StoreSmallBatchRequest"/>.
3030
/// </summary>
31-
Lazy<PersistRequest> StoreSingleRecordRequest { get { return new Lazy<PersistRequest>(StoreRequest); } }
31+
Lazy<PreparedPersistRequest> StoreSingleRecordRequest => new(StoreRequest);
3232

3333
/// <summary>
3434
/// Request that stores smaller portion of data at a time.
3535
/// The request is used when data can't be stored with <see cref="StoreBigBatchRequest"/>
3636
/// due to smaller size. When data portion size becomes smaller than the reqired by
3737
/// this request the <see cref="StoreSingleRecordRequest"/> will be used.
3838
/// </summary>
39-
Lazy<PersistRequest> StoreSmallBatchRequest { get; }
39+
Lazy<PreparedPersistRequest> StoreSmallBatchRequest { get; }
4040

4141
/// <summary>
4242
/// Request that stores big portion of data at a time. The request is used
4343
/// unless data portion is smaller than the request can store, in this case
4444
/// <see cref="StoreSmallBatchRequest"/> or even <see cref="StoreSingleRecordRequest" />
4545
/// will be used.
4646
/// </summary>
47-
Lazy<PersistRequest> StoreBigBatchRequest { get; }
47+
Lazy<PreparedPersistRequest> StoreBigBatchRequest { get; }
4848
}
4949
}

Orm/Xtensive.Orm/Orm/Providers/Persister.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,8 @@ private SqlPersistTask CreateRemoveTask(PersistAction action, bool validateVersi
9393
}
9494
}
9595

96-
private IReadOnlyCollection<PersistRequest> GetOrBuildRequest(StorageNode node, PersistRequestBuilderTask task)
97-
{
98-
var cache = node.PersistRequestCache;
99-
if (cache.TryGetValue(task, out var result))
100-
return result;
101-
result = requestBuilder.Build(node, task);
102-
return cache.TryAdd(task, result) ? result : cache[task];
103-
}
96+
private IReadOnlyCollection<PreparedPersistRequest> GetOrBuildRequest(StorageNode node, PersistRequestBuilderTask task) =>
97+
node.PersistRequestCache.GetOrAdd(task, static (t, x) => x.requestBuilder.Build(x.node, t), (requestBuilder, node));
10498

10599
#endregion
106100

Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequest.cs

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,59 +4,49 @@
44
// Created by: Dmitri Maximov
55
// Created: 2008.08.22
66

7-
using System;
8-
using System.Collections.Generic;
97
using Xtensive.Core;
108
using Xtensive.Orm.Configuration;
119
using Xtensive.Sql;
1210
using Xtensive.Sql.Compiler;
1311

14-
namespace Xtensive.Orm.Providers
15-
{
16-
/// <summary>
17-
/// Modification (INSERT, UPDATE, DELETE) request.
18-
/// </summary>
19-
public sealed class PersistRequest
20-
{
21-
private static readonly IReadOnlySet<PersistParameterBinding> EmptyBindings = new HashSet<PersistParameterBinding>();
12+
namespace Xtensive.Orm.Providers;
2213

23-
private readonly StorageDriver driver;
14+
public record struct PreparedPersistRequest(
15+
SqlCompilationResult CompiledStatement,
16+
IReadOnlyCollection<PersistParameterBinding> ParameterBindings
17+
);
2418

25-
private SqlCompilationResult compiledStatement;
19+
/// <summary>
20+
/// Modification (INSERT, UPDATE, DELETE) request.
21+
/// </summary>
22+
public readonly struct PersistRequest
23+
{
24+
private static readonly IReadOnlySet<PersistParameterBinding> EmptyBindings = new HashSet<PersistParameterBinding>();
2625

27-
public SqlStatement Statement { get; private set; }
26+
private readonly StorageDriver driver;
2827

29-
public ISqlCompileUnit CompileUnit { get; private set; }
28+
public SqlStatement Statement { get; }
3029

31-
public IReadOnlyCollection<PersistParameterBinding> ParameterBindings { get; }
30+
public ISqlCompileUnit CompileUnit { get; }
3231

33-
public SqlCompilationResult GetCompiledStatement() =>
34-
compiledStatement ?? throw new InvalidOperationException(Strings.ExRequestIsNotPrepared);
32+
public IReadOnlyCollection<PersistParameterBinding> ParameterBindings { get; }
3533

36-
public void Prepare()
37-
{
38-
if (compiledStatement != null)
39-
return;
40-
compiledStatement = driver.Compile(CompileUnit);
41-
CompileUnit = null;
42-
Statement = null;
43-
}
34+
public PreparedPersistRequest Prepare() => new(driver.Compile(CompileUnit), ParameterBindings);
4435

45-
// Constructors
36+
// Constructors
4637

47-
public PersistRequest(
48-
StorageDriver driver, SqlStatement statement, IReadOnlySet<PersistParameterBinding> parameterBindings)
49-
{
50-
ArgumentNullException.ThrowIfNull(driver);
51-
ArgumentNullException.ThrowIfNull(statement);
38+
public PersistRequest(
39+
StorageDriver driver, SqlStatement statement, IReadOnlySet<PersistParameterBinding> parameterBindings)
40+
{
41+
ArgumentNullException.ThrowIfNull(driver);
42+
ArgumentNullException.ThrowIfNull(statement);
5243

53-
var compileUnit = statement as ISqlCompileUnit
54-
?? throw new ArgumentException("Statement is not ISqlCompileUnit");
44+
var compileUnit = statement as ISqlCompileUnit
45+
?? throw new ArgumentException("Statement is not ISqlCompileUnit");
5546

56-
this.driver = driver;
57-
Statement = statement;
58-
CompileUnit = compileUnit;
59-
ParameterBindings = parameterBindings ?? EmptyBindings;
60-
}
47+
this.driver = driver;
48+
Statement = statement;
49+
CompileUnit = compileUnit;
50+
ParameterBindings = parameterBindings ?? EmptyBindings;
6151
}
6252
}

Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestBuilder.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public class PersistRequestBuilder : DomainBoundHandler
2424
private ProviderInfo providerInfo;
2525
private StorageDriver driver;
2626

27-
internal IReadOnlyList<PersistRequest> Build(StorageNode node, PersistRequestBuilderTask task)
27+
internal IReadOnlyList<PreparedPersistRequest> Build(StorageNode node, PersistRequestBuilderTask task)
2828
{
2929
var context = new PersistRequestBuilderContext(task, node.Mapping, node.Configuration);
3030
List<PersistRequest> result;
@@ -52,15 +52,10 @@ internal IReadOnlyList<PersistRequest> Build(StorageNode node, PersistRequestBui
5252
bindings.UnionWith(request.ParameterBindings);
5353
}
5454
var batchRequest = new PersistRequest(driver, batch, bindings);
55-
batchRequest.Prepare();
56-
return new List<PersistRequest> { batchRequest }.AsSafeWrapper();
55+
return [batchRequest.Prepare()];
5756
}
5857

59-
foreach (var item in result) {
60-
item.Prepare();
61-
}
62-
63-
return result.AsSafeWrapper();
58+
return result.Select(request => request.Prepare()).ToArray();
6459
}
6560

6661
protected virtual List<PersistRequest> BuildInsertRequest(in PersistRequestBuilderContext context)

Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestBuilderTask.cs

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
// Created by: Dmitri Maximov
55
// Created: 2008.08.29
66

7-
using System;
87
using System.Collections;
98
using Xtensive.Orm.Model;
109

@@ -13,52 +12,46 @@ namespace Xtensive.Orm.Providers
1312
/// <summary>
1413
/// A task for <see cref="PersistRequestBuilder"/>.
1514
/// </summary>
16-
public sealed class PersistRequestBuilderTask
15+
public sealed class PersistRequestBuilderTask : IEquatable<PersistRequestBuilderTask>
1716
{
1817
private readonly int hashCode;
1918

2019
/// <summary>
2120
/// Gets the type.
2221
/// </summary>
23-
public TypeInfo Type { get; private set; }
22+
public TypeInfo Type { get; }
2423

2524
/// <summary>
2625
/// Gets the field map that describes updated fields.
2726
/// </summary>
28-
public BitArray ChangedFields { get; private set; }
27+
public BitArray ChangedFields { get; }
2928

3029
/// <summary>
3130
/// Gets the field map that describes available (fetched) fields.
3231
/// </summary>
33-
public BitArray AvailableFields { get; private set; }
32+
public BitArray AvailableFields { get; }
3433

3534
/// <summary>
3635
/// Gets the <see cref="PersistRequestKind"/>.
3736
/// </summary>
38-
public PersistRequestKind Kind { get; private set; }
37+
public PersistRequestKind Kind { get; }
3938

4039
/// <summary>
4140
/// Gets flag indicating if validation should be performed.
4241
/// </summary>
43-
public bool ValidateVersion { get; private set; }
42+
public bool ValidateVersion { get; }
43+
44+
public bool Equals(PersistRequestBuilderTask other) =>
45+
ReferenceEquals(this, other)
46+
|| other is not null
47+
&& Type == other.Type
48+
&& Kind == other.Kind
49+
&& ValidateVersion == other.ValidateVersion
50+
&& CompareBits(AvailableFields, other.AvailableFields)
51+
&& CompareBits(ChangedFields, other.ChangedFields);
4452

4553
/// <inheritdoc/>
46-
public override bool Equals(object obj)
47-
{
48-
if (ReferenceEquals(this, obj))
49-
return true;
50-
if (obj is PersistRequestBuilderTask other) {
51-
if (Type != other.Type)
52-
return false;
53-
if (Kind != other.Kind)
54-
return false;
55-
if (ValidateVersion != other.ValidateVersion)
56-
return false;
57-
return CompareBits(AvailableFields, other.AvailableFields)
58-
&& CompareBits(ChangedFields, other.ChangedFields);
59-
}
60-
return false;
61-
}
54+
public override bool Equals(object obj) => obj is PersistRequestBuilderTask other && Equals(other);
6255

6356
/// <inheritdoc/>
6457
public override int GetHashCode() => hashCode;
@@ -78,11 +71,11 @@ private int HashBits(BitArray bits)
7871

7972
private bool CompareBits(BitArray left, BitArray right)
8073
{
81-
if (left==null && right==null)
74+
if (left == null && right == null)
8275
return true;
83-
if (left!=null && right!=null && left.Count==right.Count) {
84-
for (var i = 0; i < left.Count; i++)
85-
if (left[i]!=right[i])
76+
if (left != null && right != null && left.Count == right.Count) {
77+
for (int i = 0, n = left.Count; i < n; i++)
78+
if (left[i] != right[i])
8679
return false;
8780
return true;
8881
}

Orm/Xtensive.Orm/Orm/Providers/Requests/PersistRequestKind.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Xtensive.Orm.Providers
99
/// <summary>
1010
/// Kinds of <see cref="PersistRequest"/>.
1111
/// </summary>
12-
public enum PersistRequestKind
12+
public enum PersistRequestKind : sbyte
1313
{
1414
/// <summary>
1515
/// Insert request.
@@ -26,4 +26,4 @@ public enum PersistRequestKind
2626
/// </summary>
2727
Update = 0,
2828
}
29-
}
29+
}

Orm/Xtensive.Orm/Orm/Providers/TemporaryTables/TemporaryTableDescriptor.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,37 @@ public sealed class TemporaryTableDescriptor : IMultiRecordPersistDescriptor
4141
/// <summary>
4242
/// Gets or sets the persist request used to store batched data in temporary table.
4343
/// </summary>
44-
public Lazy<PersistRequest> LazyLevel1BatchStoreRequest { get; set; }
44+
public Lazy<PreparedPersistRequest> LazyLevel1BatchStoreRequest { get; set; }
4545

4646
/// <summary>
4747
/// Gets or sets the persist request used to store batched data in temporary table.
4848
/// </summary>
49-
public Lazy<PersistRequest> LazyLevel2BatchStoreRequest { get; set; }
49+
public Lazy<PreparedPersistRequest> LazyLevel2BatchStoreRequest { get; set; }
5050

5151
/// <summary>
5252
/// Gets or sets the persist request used to store data in temporary table.
5353
/// </summary>
54-
public Lazy<PersistRequest> StoreSingleRecordRequest { get; set; }
54+
public Lazy<PreparedPersistRequest> StoreSingleRecordRequest { get; set; }
5555

5656
/// <summary>
5757
/// Gets or sets the persist request used to store batched data in temporary table.
5858
/// </summary>
59-
public Lazy<PersistRequest> StoreSmallBatchRequest { get; set; }
59+
public Lazy<PreparedPersistRequest> StoreSmallBatchRequest { get; set; }
6060

6161
/// <summary>
6262
/// Gets or sets the persist request used to store batched data in temporary table.
6363
/// </summary>
64-
public Lazy<PersistRequest> StoreBigBatchRequest { get; set; }
64+
public Lazy<PreparedPersistRequest> StoreBigBatchRequest { get; set; }
6565

6666
/// <summary>
6767
/// Gets the persist request used to store data in temporary table.
6868
/// </summary>
69-
PersistRequest IPersistDescriptor.StoreRequest => StoreSingleRecordRequest.Value;
69+
PreparedPersistRequest IPersistDescriptor.StoreRequest => StoreSingleRecordRequest.Value;
7070

7171
/// <summary>
7272
/// Gets or sets the clear reqest used to delete all data from temporary table.
7373
/// </summary>
74-
public PersistRequest ClearRequest { get; set; }
74+
public PreparedPersistRequest ClearRequest { get; set; }
7575

7676
/// <summary>
7777
/// Gets or sets the query statement associated with this table descriptor.

0 commit comments

Comments
 (0)