Skip to content

Commit 4b783e3

Browse files
committed
Improving snapshot applying rows performances
1 parent ed9a1c6 commit 4b783e3

File tree

3 files changed

+79
-18
lines changed

3 files changed

+79
-18
lines changed

Projects/Dotmim.Sync.Core/Batch/BatchInfo.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace Dotmim.Sync.Batch
1717
[DataContract(Name = "bi"), Serializable]
1818
public class BatchInfo
1919
{
20-
20+
2121
/// <summary>
2222
/// Ctor for serializer
2323
/// </summary>
@@ -94,7 +94,7 @@ public BatchInfo(bool isInMemory, SyncSet inSchema, string rootDirectory = null,
9494
/// <summary>
9595
/// Gets or Sets the Serialization Factory Key used to serialize this batch info (if not in memory)
9696
/// </summary>
97-
[DataMember(Name = "ser", IsRequired = false, EmitDefaultValue =false, Order = 6)]
97+
[DataMember(Name = "ser", IsRequired = false, EmitDefaultValue = false, Order = 6)]
9898
public string SerializerFactoryKey { get; set; }
9999

100100

@@ -174,7 +174,7 @@ public bool HasData(string tableName, string schemaName)
174174
return false;
175175
}
176176

177-
public async IAsyncEnumerable<SyncTable> GetTableAsync(string tableName, string schemaName, ISerializerFactory serializerFactory = default, BaseOrchestrator orchestrator = null)
177+
public async IAsyncEnumerable<(SyncTable SyncTable, BatchPartInfo BatchPartInfo)> GetTableAsync(string tableName, string schemaName, ISerializerFactory serializerFactory = default, BaseOrchestrator orchestrator = null)
178178
{
179179
if (this.SanitizedSchema == null)
180180
throw new NullReferenceException("Batch info schema should not be null");
@@ -186,7 +186,7 @@ public async IAsyncEnumerable<SyncTable> GetTableAsync(string tableName, string
186186
this.SerializerFactoryKey = null;
187187

188188
if (this.InMemoryData != null && this.InMemoryData.HasTables)
189-
yield return this.InMemoryData.Tables[tableName, schemaName];
189+
yield return (this.InMemoryData.Tables[tableName, schemaName], null);
190190
}
191191
else
192192
{
@@ -208,13 +208,13 @@ public async IAsyncEnumerable<SyncTable> GetTableAsync(string tableName, string
208208

209209
if (batchTable != null)
210210
{
211-
yield return batchTable;
211+
yield return (batchTable, batchPartinInfo);
212212

213213
// We may need this same BatchPartInfo for another table,
214214
// but we dispose it anyway, because memory can be quickly a bottleneck
215215
// if batchpartinfos are resident in memory
216-
batchPartinInfo.Data.Dispose();
217-
batchPartinInfo.Data = null;
216+
//batchPartinInfo.Data.Dispose();
217+
//batchPartinInfo.Data = null;
218218
}
219219
}
220220
}

Projects/Dotmim.Sync.Core/Orchestrators/BaseOrchestrator.ApplyChanges.cs

+65-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Dotmim.Sync.Builders;
1+
using Dotmim.Sync.Batch;
2+
using Dotmim.Sync.Builders;
23
using Dotmim.Sync.Enumerations;
34
using Microsoft.Extensions.Logging;
45
using System;
@@ -38,6 +39,9 @@ public abstract partial class BaseOrchestrator
3839

3940
var schemaTables = message.Schema.Tables.SortByDependencies(tab => tab.GetRelations().Select(r => r.GetParentTable()));
4041

42+
// contains list of table that have been done
43+
var doneTables = new List<SyncTable>();
44+
4145
// Disable check constraints
4246
// Because Sqlite does not support "PRAGMA foreign_keys=OFF" Inside a transaction
4347
// Report this disabling constraints brefore opening a transaction
@@ -59,17 +63,27 @@ public abstract partial class BaseOrchestrator
5963
// 1) Applying Inserts and Updates. Apply in table order
6064
// -----------------------------------------------------
6165
if (hasChanges)
66+
{
67+
doneTables.Clear();
6268
foreach (var table in schemaTables)
63-
await this.InternalApplyTableChangesAsync(context, table, message, connection,
69+
{
70+
await this.InternalApplyTableChangesAsync(context, table, message, doneTables, connection,
6471
transaction, DataRowState.Modified, changesApplied, cancellationToken, progress).ConfigureAwait(false);
72+
}
73+
}
6574

6675
// -----------------------------------------------------
6776
// 2) Applying Deletes. Do not apply deletes if we are in a new database
6877
// -----------------------------------------------------
6978
if (!message.IsNew && hasChanges)
79+
{
80+
doneTables.Clear();
7081
foreach (var table in schemaTables.Reverse())
71-
await this.InternalApplyTableChangesAsync(context, table, message, connection,
82+
{
83+
await this.InternalApplyTableChangesAsync(context, table, message, doneTables, connection,
7284
transaction, DataRowState.Deleted, changesApplied, cancellationToken, progress).ConfigureAwait(false);
85+
}
86+
}
7387

7488
// Re enable check constraints
7589
if (message.DisableConstraintsOnApplyChanges)
@@ -216,7 +230,7 @@ private async Task<bool> InternalApplyConflictUpdateAsync(SyncContext context, D
216230
/// <summary>
217231
/// Apply changes internal method for one type of query: Insert, Update or Delete for every batch from a table
218232
/// </summary>
219-
private async Task InternalApplyTableChangesAsync(SyncContext context, SyncTable schemaTable, MessageApplyChanges message,
233+
private async Task InternalApplyTableChangesAsync(SyncContext context, SyncTable schemaTable, MessageApplyChanges message, List<SyncTable> doneTables,
220234
DbConnection connection, DbTransaction transaction, DataRowState applyType, DatabaseChangesApplied changesApplied,
221235
CancellationToken cancellationToken, IProgress<ProgressArgs> progress)
222236
{
@@ -250,12 +264,19 @@ private async Task InternalApplyTableChangesAsync(SyncContext context, SyncTable
250264
var enumerableOfTables = message.Changes.GetTableAsync(schemaTable.TableName, schemaTable.SchemaName, message.SerializerFactory, this);
251265
var enumeratorOfTable = enumerableOfTables.GetAsyncEnumerator();
252266

267+
// List of batchpartinfos during the iteration
268+
var batchPartinfos = new List<BatchPartInfo>();
269+
253270
// getting the table to be applied
254271
// we may have multiple batch files, so we can have multipe sync tables with the same name
255272
// We can say that dmTable may be contained in several files
256273
while (await enumeratorOfTable.MoveNextAsync())
257274
{
258-
var syncTable = enumeratorOfTable.Current;
275+
var syncTable = enumeratorOfTable.Current.SyncTable;
276+
277+
// add curent batch part info
278+
if (enumeratorOfTable.Current.BatchPartInfo != null)
279+
batchPartinfos.Add(enumeratorOfTable.Current.BatchPartInfo);
259280

260281
if (syncTable == null || syncTable.Rows == null || syncTable.Rows.Count == 0)
261282
continue;
@@ -334,8 +355,46 @@ private async Task InternalApplyTableChangesAsync(SyncContext context, SyncTable
334355
await this.InterceptAsync(tableChangesBatchAppliedArgs, cancellationToken).ConfigureAwait(false);
335356
this.ReportProgress(context, progress, tableChangesBatchAppliedArgs, connection, transaction);
336357
}
358+
359+
}
360+
361+
// table processeed
362+
// we can add it to the list of done tables
363+
doneTables.Add(schemaTable);
364+
365+
// Let's see if we can close the batchpartinfo
366+
// we can close it if all the tables contains in the bpiTables are already processed
367+
foreach (var batchPartinInfo in batchPartinfos)
368+
{
369+
var isDoneTable = false;
370+
// for each table in the current file
371+
foreach (var batchPartTableInfo in batchPartinInfo.Tables)
372+
{
373+
// check if all tables in batch part info are done
374+
isDoneTable = doneTables.Any(doneTable =>
375+
{
376+
var sc = SyncGlobalization.DataSourceStringComparison;
377+
var innerTableSchemaName = string.IsNullOrEmpty(doneTable.SchemaName) ? string.Empty : doneTable.SchemaName;
378+
var batchPartTableSchemaName = string.IsNullOrEmpty(batchPartTableInfo.SchemaName) ? string.Empty : batchPartTableInfo.SchemaName;
379+
return string.Equals(doneTable.TableName, batchPartTableInfo.TableName, sc) && string.Equals(innerTableSchemaName, batchPartTableSchemaName);
380+
});
381+
382+
// the current table is not done yet, don't need to continue to iterate
383+
// over the other tables information
384+
if (!isDoneTable)
385+
break;
386+
387+
}
388+
389+
if (isDoneTable)
390+
{
391+
batchPartinInfo.Data.Dispose();
392+
batchPartinInfo.Data = null;
393+
}
337394
}
338395

396+
397+
339398
// Report the overall changes applied for the current table
340399
if (tableChangesApplied != null)
341400
{
@@ -387,7 +446,7 @@ private async Task InternalApplyTableChangesAsync(SyncContext context, SyncTable
387446
// Get command
388447
var command = await syncAdapter.GetCommandAsync(dbCommandType, connection, transaction);
389448

390-
if (command == null) return (0,0);
449+
if (command == null) return (0, 0);
391450

392451
// Launch any interceptor if available
393452
var args = new TableChangesBatchApplyingArgs(context, changesTable, applyType, command, connection, transaction);

Projects/Dotmim.Sync.Core/Set/SyncTable.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,13 @@ protected virtual void Dispose(bool cleanup)
148148
/// </summary>
149149
public SyncTable Clone()
150150
{
151-
var clone = new SyncTable();
152-
clone.OriginalProvider = this.OriginalProvider;
153-
clone.SchemaName = this.SchemaName;
154-
clone.SyncDirection = this.SyncDirection;
155-
clone.TableName = this.TableName;
151+
var clone = new SyncTable
152+
{
153+
OriginalProvider = this.OriginalProvider,
154+
SchemaName = this.SchemaName,
155+
SyncDirection = this.SyncDirection,
156+
TableName = this.TableName
157+
};
156158

157159
foreach (var c in this.Columns)
158160
clone.Columns.Add(c.Clone());

0 commit comments

Comments
 (0)