@powersync/service-module-mssql 0.0.0-dev-20251128080741
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/LICENSE +67 -0
- package/README.md +3 -0
- package/ci/init-mssql.sql +50 -0
- package/dist/api/MSSQLRouteAPIAdapter.d.ts +21 -0
- package/dist/api/MSSQLRouteAPIAdapter.js +248 -0
- package/dist/api/MSSQLRouteAPIAdapter.js.map +1 -0
- package/dist/common/LSN.d.ts +37 -0
- package/dist/common/LSN.js +64 -0
- package/dist/common/LSN.js.map +1 -0
- package/dist/common/MSSQLSourceTable.d.ts +27 -0
- package/dist/common/MSSQLSourceTable.js +35 -0
- package/dist/common/MSSQLSourceTable.js.map +1 -0
- package/dist/common/MSSQLSourceTableCache.d.ts +14 -0
- package/dist/common/MSSQLSourceTableCache.js +28 -0
- package/dist/common/MSSQLSourceTableCache.js.map +1 -0
- package/dist/common/mssqls-to-sqlite.d.ts +18 -0
- package/dist/common/mssqls-to-sqlite.js +143 -0
- package/dist/common/mssqls-to-sqlite.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/module/MSSQLModule.d.ts +15 -0
- package/dist/module/MSSQLModule.js +68 -0
- package/dist/module/MSSQLModule.js.map +1 -0
- package/dist/replication/CDCPoller.d.ts +67 -0
- package/dist/replication/CDCPoller.js +188 -0
- package/dist/replication/CDCPoller.js.map +1 -0
- package/dist/replication/CDCReplicationJob.d.ts +17 -0
- package/dist/replication/CDCReplicationJob.js +76 -0
- package/dist/replication/CDCReplicationJob.js.map +1 -0
- package/dist/replication/CDCReplicator.d.ts +18 -0
- package/dist/replication/CDCReplicator.js +55 -0
- package/dist/replication/CDCReplicator.js.map +1 -0
- package/dist/replication/CDCStream.d.ts +106 -0
- package/dist/replication/CDCStream.js +539 -0
- package/dist/replication/CDCStream.js.map +1 -0
- package/dist/replication/MSSQLConnectionManager.d.ts +23 -0
- package/dist/replication/MSSQLConnectionManager.js +97 -0
- package/dist/replication/MSSQLConnectionManager.js.map +1 -0
- package/dist/replication/MSSQLConnectionManagerFactory.d.ts +10 -0
- package/dist/replication/MSSQLConnectionManagerFactory.js +28 -0
- package/dist/replication/MSSQLConnectionManagerFactory.js.map +1 -0
- package/dist/replication/MSSQLErrorRateLimiter.d.ts +10 -0
- package/dist/replication/MSSQLErrorRateLimiter.js +34 -0
- package/dist/replication/MSSQLErrorRateLimiter.js.map +1 -0
- package/dist/replication/MSSQLSnapshotQuery.d.ts +71 -0
- package/dist/replication/MSSQLSnapshotQuery.js +190 -0
- package/dist/replication/MSSQLSnapshotQuery.js.map +1 -0
- package/dist/types/mssql-data-types.d.ts +66 -0
- package/dist/types/mssql-data-types.js +62 -0
- package/dist/types/mssql-data-types.js.map +1 -0
- package/dist/types/types.d.ts +177 -0
- package/dist/types/types.js +141 -0
- package/dist/types/types.js.map +1 -0
- package/dist/utils/mssql.d.ts +80 -0
- package/dist/utils/mssql.js +329 -0
- package/dist/utils/mssql.js.map +1 -0
- package/dist/utils/schema.d.ts +21 -0
- package/dist/utils/schema.js +131 -0
- package/dist/utils/schema.js.map +1 -0
- package/package.json +51 -0
- package/src/api/MSSQLRouteAPIAdapter.ts +283 -0
- package/src/common/LSN.ts +77 -0
- package/src/common/MSSQLSourceTable.ts +54 -0
- package/src/common/MSSQLSourceTableCache.ts +36 -0
- package/src/common/mssqls-to-sqlite.ts +151 -0
- package/src/index.ts +1 -0
- package/src/module/MSSQLModule.ts +82 -0
- package/src/replication/CDCPoller.ts +247 -0
- package/src/replication/CDCReplicationJob.ts +87 -0
- package/src/replication/CDCReplicator.ts +70 -0
- package/src/replication/CDCStream.ts +691 -0
- package/src/replication/MSSQLConnectionManager.ts +113 -0
- package/src/replication/MSSQLConnectionManagerFactory.ts +33 -0
- package/src/replication/MSSQLErrorRateLimiter.ts +36 -0
- package/src/replication/MSSQLSnapshotQuery.ts +230 -0
- package/src/types/mssql-data-types.ts +79 -0
- package/src/types/types.ts +224 -0
- package/src/utils/mssql.ts +420 -0
- package/src/utils/schema.ts +172 -0
- package/test/src/CDCStream.test.ts +204 -0
- package/test/src/CDCStreamTestContext.ts +212 -0
- package/test/src/CDCStream_resumable_snapshot.test.ts +159 -0
- package/test/src/env.ts +11 -0
- package/test/src/mssql-to-sqlite.test.ts +474 -0
- package/test/src/setup.ts +12 -0
- package/test/src/util.ts +188 -0
- package/test/tsconfig.json +28 -0
- package/tsconfig.json +26 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
import { container, DatabaseConnectionError, ErrorCode, logger as defaultLogger, ReplicationAbortedError, ReplicationAssertionError, ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
2
|
+
import { getUuidReplicaIdentityBson, storage } from '@powersync/service-core';
|
|
3
|
+
import { ReplicationMetric } from '@powersync/service-types';
|
|
4
|
+
import { BatchedSnapshotQuery, IdSnapshotQuery, SimpleSnapshotQuery } from './MSSQLSnapshotQuery.js';
|
|
5
|
+
import { getReplicationIdentityColumns, getTablesFromPattern } from '../utils/schema.js';
|
|
6
|
+
import { checkSourceConfiguration, createCheckpoint, getCaptureInstance, getLatestLSN, getLatestReplicatedLSN, isIColumnMetadata, isTableEnabledForCDC, isWithinRetentionThreshold, toQualifiedTableName } from '../utils/mssql.js';
|
|
7
|
+
import sql from 'mssql';
|
|
8
|
+
import { CDCToSqliteRow, toSqliteInputRow } from '../common/mssqls-to-sqlite.js';
|
|
9
|
+
import { LSN } from '../common/LSN.js';
|
|
10
|
+
import { MSSQLSourceTable } from '../common/MSSQLSourceTable.js';
|
|
11
|
+
import { MSSQLSourceTableCache } from '../common/MSSQLSourceTableCache.js';
|
|
12
|
+
import { CDCPoller } from './CDCPoller.js';
|
|
13
|
+
export var SnapshotStatus;
|
|
14
|
+
(function (SnapshotStatus) {
|
|
15
|
+
SnapshotStatus["IN_PROGRESS"] = "in-progress";
|
|
16
|
+
SnapshotStatus["DONE"] = "done";
|
|
17
|
+
SnapshotStatus["RESTART_REQUIRED"] = "restart-required";
|
|
18
|
+
})(SnapshotStatus || (SnapshotStatus = {}));
|
|
19
|
+
export class CDCConfigurationError extends Error {
|
|
20
|
+
constructor(message) {
|
|
21
|
+
super(message);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Thrown when required updates in the CDC instance tables are no longer available
|
|
26
|
+
*
|
|
27
|
+
* Possible reasons:
|
|
28
|
+
* * Older data has been cleaned up due to exceeding the retention period.
|
|
29
|
+
* This can happen if PowerSync was stopped for a long period of time.
|
|
30
|
+
*/
|
|
31
|
+
export class CDCDataExpiredError extends DatabaseConnectionError {
|
|
32
|
+
constructor(message, cause) {
|
|
33
|
+
super(ErrorCode.PSYNC_S1500, message, cause);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class CDCStream {
|
|
37
|
+
options;
|
|
38
|
+
syncRules;
|
|
39
|
+
storage;
|
|
40
|
+
connections;
|
|
41
|
+
abortSignal;
|
|
42
|
+
logger;
|
|
43
|
+
tableCache = new MSSQLSourceTableCache();
|
|
44
|
+
/**
|
|
45
|
+
* Time of the oldest uncommitted change, according to the source db.
|
|
46
|
+
* This is used to determine the replication lag.
|
|
47
|
+
*/
|
|
48
|
+
oldestUncommittedChange = null;
|
|
49
|
+
/**
|
|
50
|
+
* Keep track of whether we have done a commit or keepalive yet.
|
|
51
|
+
* We can only compute replication lag if isStartingReplication == false, or oldestUncommittedChange is present.
|
|
52
|
+
*/
|
|
53
|
+
isStartingReplication = true;
|
|
54
|
+
constructor(options) {
|
|
55
|
+
this.options = options;
|
|
56
|
+
this.logger = options.logger ?? defaultLogger;
|
|
57
|
+
this.storage = options.storage;
|
|
58
|
+
this.syncRules = options.storage.getParsedSyncRules({ defaultSchema: options.connections.schema });
|
|
59
|
+
this.connections = options.connections;
|
|
60
|
+
this.abortSignal = options.abortSignal;
|
|
61
|
+
}
|
|
62
|
+
get metrics() {
|
|
63
|
+
return this.options.metrics;
|
|
64
|
+
}
|
|
65
|
+
get stopped() {
|
|
66
|
+
return this.abortSignal.aborted;
|
|
67
|
+
}
|
|
68
|
+
get defaultSchema() {
|
|
69
|
+
return this.connections.schema;
|
|
70
|
+
}
|
|
71
|
+
get groupId() {
|
|
72
|
+
return this.options.storage.group_id;
|
|
73
|
+
}
|
|
74
|
+
get connectionId() {
|
|
75
|
+
const { connectionId } = this.connections;
|
|
76
|
+
// Default to 1 if not set
|
|
77
|
+
if (!connectionId) {
|
|
78
|
+
return 1;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* This is often `"default"` (string) which will parse to `NaN`
|
|
82
|
+
*/
|
|
83
|
+
const parsed = Number.parseInt(connectionId);
|
|
84
|
+
if (isNaN(parsed)) {
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
return parsed;
|
|
88
|
+
}
|
|
89
|
+
get connectionTag() {
|
|
90
|
+
return this.connections.connectionTag;
|
|
91
|
+
}
|
|
92
|
+
get snapshotBatchSize() {
|
|
93
|
+
return this.options.snapshotBatchSize ?? 10_000;
|
|
94
|
+
}
|
|
95
|
+
async replicate() {
|
|
96
|
+
try {
|
|
97
|
+
await this.initReplication();
|
|
98
|
+
await this.streamChanges();
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
await this.storage.reportError(e);
|
|
102
|
+
throw e;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async populateTableCache() {
|
|
106
|
+
const sourceTables = this.syncRules.getSourceTables();
|
|
107
|
+
await this.storage.startBatch({
|
|
108
|
+
logger: this.logger,
|
|
109
|
+
zeroLSN: LSN.ZERO,
|
|
110
|
+
defaultSchema: this.defaultSchema,
|
|
111
|
+
storeCurrentData: true
|
|
112
|
+
}, async (batch) => {
|
|
113
|
+
for (let tablePattern of sourceTables) {
|
|
114
|
+
const tables = await this.getQualifiedTableNames(batch, tablePattern);
|
|
115
|
+
for (const table of tables) {
|
|
116
|
+
this.tableCache.set(table);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
async getQualifiedTableNames(batch, tablePattern) {
|
|
122
|
+
if (tablePattern.connectionTag != this.connections.connectionTag) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
const matchedTables = await getTablesFromPattern(this.connections, tablePattern);
|
|
126
|
+
const tables = [];
|
|
127
|
+
for (const matchedTable of matchedTables) {
|
|
128
|
+
const isEnabled = await isTableEnabledForCDC({
|
|
129
|
+
connectionManager: this.connections,
|
|
130
|
+
table: matchedTable.name,
|
|
131
|
+
schema: matchedTable.schema
|
|
132
|
+
});
|
|
133
|
+
if (!isEnabled) {
|
|
134
|
+
this.logger.info(`Skipping ${matchedTable.schema}.${matchedTable.name} - table is not enabled for CDC.`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
// TODO: Check RLS settings for table
|
|
138
|
+
const replicaIdColumns = await getReplicationIdentityColumns({
|
|
139
|
+
connectionManager: this.connections,
|
|
140
|
+
tableName: matchedTable.name,
|
|
141
|
+
schema: matchedTable.schema
|
|
142
|
+
});
|
|
143
|
+
const table = await this.processTable(batch, {
|
|
144
|
+
name: matchedTable.name,
|
|
145
|
+
schema: matchedTable.schema,
|
|
146
|
+
objectId: matchedTable.objectId,
|
|
147
|
+
replicaIdColumns: replicaIdColumns.columns
|
|
148
|
+
}, false);
|
|
149
|
+
tables.push(table);
|
|
150
|
+
}
|
|
151
|
+
return tables;
|
|
152
|
+
}
|
|
153
|
+
async processTable(batch, table, snapshot) {
|
|
154
|
+
if (!table.objectId && typeof table.objectId != 'number') {
|
|
155
|
+
throw new ReplicationAssertionError(`objectId expected, got ${typeof table.objectId}`);
|
|
156
|
+
}
|
|
157
|
+
const resolved = await this.storage.resolveTable({
|
|
158
|
+
group_id: this.groupId,
|
|
159
|
+
connection_id: this.connectionId,
|
|
160
|
+
connection_tag: this.connectionTag,
|
|
161
|
+
entity_descriptor: table,
|
|
162
|
+
sync_rules: this.syncRules
|
|
163
|
+
});
|
|
164
|
+
const captureInstance = await getCaptureInstance({
|
|
165
|
+
connectionManager: this.connections,
|
|
166
|
+
tableName: resolved.table.name,
|
|
167
|
+
schema: resolved.table.schema
|
|
168
|
+
});
|
|
169
|
+
if (!captureInstance) {
|
|
170
|
+
throw new ServiceAssertionError(`Missing capture instance for table ${toQualifiedTableName(resolved.table.schema, resolved.table.name)}`);
|
|
171
|
+
}
|
|
172
|
+
const resolvedTable = new MSSQLSourceTable({
|
|
173
|
+
sourceTable: resolved.table,
|
|
174
|
+
captureInstance: captureInstance
|
|
175
|
+
});
|
|
176
|
+
// Drop conflicting tables. This includes for example renamed tables.
|
|
177
|
+
await batch.drop(resolved.dropTables);
|
|
178
|
+
// Snapshot if:
|
|
179
|
+
// 1. Snapshot is requested (false for initial snapshot, since that process handles it elsewhere)
|
|
180
|
+
// 2. Snapshot is not already done, AND:
|
|
181
|
+
// 3. The table is used in sync rules.
|
|
182
|
+
const shouldSnapshot = snapshot && !resolved.table.snapshotComplete && resolved.table.syncAny;
|
|
183
|
+
if (shouldSnapshot) {
|
|
184
|
+
// Truncate this table in case a previous snapshot was interrupted.
|
|
185
|
+
await batch.truncate([resolved.table]);
|
|
186
|
+
// Start the snapshot inside a transaction.
|
|
187
|
+
try {
|
|
188
|
+
await this.snapshotTableInTx(batch, resolvedTable);
|
|
189
|
+
}
|
|
190
|
+
finally {
|
|
191
|
+
// TODO Cleanup?
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return resolvedTable;
|
|
195
|
+
}
|
|
196
|
+
async snapshotTableInTx(batch, table, limited) {
|
|
197
|
+
// Note: We use the "Read Committed" isolation level here, not snapshot isolation.
|
|
198
|
+
// The data may change during the transaction, but that is compensated for in the streaming
|
|
199
|
+
// replication afterward.
|
|
200
|
+
const transaction = await this.connections.createTransaction();
|
|
201
|
+
await transaction.begin(sql.ISOLATION_LEVEL.READ_COMMITTED);
|
|
202
|
+
try {
|
|
203
|
+
await this.snapshotTable(batch, transaction, table, limited);
|
|
204
|
+
// Get the current LSN.
|
|
205
|
+
// The data will only be consistent once incremental replication has passed that point.
|
|
206
|
+
// We have to get this LSN _after_ we have finished the table snapshot.
|
|
207
|
+
//
|
|
208
|
+
// There are basically two relevant LSNs here:
|
|
209
|
+
// A: PreSnapshot: The LSN before the snapshot starts.
|
|
210
|
+
// B: PostSnapshot: The LSN after the table snapshot is complete, which is what we get here.
|
|
211
|
+
// When we do the snapshot queries, the data that we get back for each batch could match the state
|
|
212
|
+
// anywhere between A and B. To actually have a consistent state on our side, we need to:
|
|
213
|
+
// 1. Complete the snapshot.
|
|
214
|
+
// 2. Wait until logical replication has caught up with all the changes between A and B.
|
|
215
|
+
// Calling `markSnapshotDone(LSN B)` covers that.
|
|
216
|
+
const postSnapshotLSN = await getLatestLSN(this.connections);
|
|
217
|
+
// Side note: A ROLLBACK would probably also be fine here, since we only read in this transaction.
|
|
218
|
+
await transaction.commit();
|
|
219
|
+
const [updatedSourceTable] = await batch.markSnapshotDone([table.sourceTable], postSnapshotLSN.toString());
|
|
220
|
+
this.tableCache.updateSourceTable(updatedSourceTable);
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
await transaction.rollback();
|
|
224
|
+
throw e;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async snapshotTable(batch, transaction, table, limited) {
|
|
228
|
+
let totalEstimatedCount = table.sourceTable.snapshotStatus?.totalEstimatedCount;
|
|
229
|
+
let replicatedCount = table.sourceTable.snapshotStatus?.replicatedCount ?? 0;
|
|
230
|
+
let lastCountTime = 0;
|
|
231
|
+
let query;
|
|
232
|
+
// We do streaming on two levels:
|
|
233
|
+
// 1. Coarse select from the entire table, stream rows 1 by one
|
|
234
|
+
// 2. Fine level: Stream batches of rows with each fetch call
|
|
235
|
+
if (limited) {
|
|
236
|
+
query = new IdSnapshotQuery(transaction, table, limited);
|
|
237
|
+
}
|
|
238
|
+
else if (BatchedSnapshotQuery.supports(table)) {
|
|
239
|
+
// Single primary key - we can use the primary key for chunking
|
|
240
|
+
const orderByKey = table.sourceTable.replicaIdColumns[0];
|
|
241
|
+
query = new BatchedSnapshotQuery(transaction, table, this.snapshotBatchSize, table.sourceTable.snapshotStatus?.lastKey ?? null);
|
|
242
|
+
if (table.sourceTable.snapshotStatus?.lastKey != null) {
|
|
243
|
+
this.logger.info(`Replicating ${table.toQualifiedName()} ${table.sourceTable.formatSnapshotProgress()} - resuming from ${orderByKey.name} > ${query.lastKey}`);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
this.logger.info(`Replicating ${table.toQualifiedName()} ${table.sourceTable.formatSnapshotProgress()} - resumable`);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
// Fallback case - query the entire table
|
|
251
|
+
this.logger.info(`Replicating ${table.toQualifiedName()} ${table.sourceTable.formatSnapshotProgress()} - not resumable`);
|
|
252
|
+
query = new SimpleSnapshotQuery(transaction, table);
|
|
253
|
+
replicatedCount = 0;
|
|
254
|
+
}
|
|
255
|
+
await query.initialize();
|
|
256
|
+
let hasRemainingData = true;
|
|
257
|
+
while (hasRemainingData) {
|
|
258
|
+
// Fetch 10k at a time.
|
|
259
|
+
// The balance here is between latency overhead per FETCH call,
|
|
260
|
+
// and not spending too much time on each FETCH call.
|
|
261
|
+
// We aim for a couple of seconds on each FETCH call.
|
|
262
|
+
let batchReplicatedCount = 0;
|
|
263
|
+
let columns = null;
|
|
264
|
+
const cursor = query.next();
|
|
265
|
+
for await (const result of cursor) {
|
|
266
|
+
if (columns == null && isIColumnMetadata(result)) {
|
|
267
|
+
columns = result;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
if (!columns) {
|
|
272
|
+
throw new ReplicationAssertionError(`Missing column metadata`);
|
|
273
|
+
}
|
|
274
|
+
const inputRow = toSqliteInputRow(result, columns);
|
|
275
|
+
const row = this.syncRules.applyRowContext(inputRow);
|
|
276
|
+
// This auto-flushes when the batch reaches its size limit
|
|
277
|
+
await batch.save({
|
|
278
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
279
|
+
sourceTable: table.sourceTable,
|
|
280
|
+
before: undefined,
|
|
281
|
+
beforeReplicaId: undefined,
|
|
282
|
+
after: row,
|
|
283
|
+
afterReplicaId: getUuidReplicaIdentityBson(row, table.sourceTable.replicaIdColumns)
|
|
284
|
+
});
|
|
285
|
+
replicatedCount++;
|
|
286
|
+
batchReplicatedCount++;
|
|
287
|
+
this.metrics.getCounter(ReplicationMetric.ROWS_REPLICATED).add(1);
|
|
288
|
+
}
|
|
289
|
+
this.touch();
|
|
290
|
+
}
|
|
291
|
+
// Important: flush before marking progress
|
|
292
|
+
await batch.flush();
|
|
293
|
+
if (limited == null) {
|
|
294
|
+
let lastKey;
|
|
295
|
+
if (query instanceof BatchedSnapshotQuery) {
|
|
296
|
+
lastKey = query.getLastKeySerialized();
|
|
297
|
+
}
|
|
298
|
+
if (lastCountTime < performance.now() - 10 * 60 * 1000) {
|
|
299
|
+
// Even though we're doing the snapshot inside a transaction, the transaction uses
|
|
300
|
+
// the default "Read Committed" isolation level. This means we can get new data
|
|
301
|
+
// within the transaction, so we re-estimate the count every 10 minutes when replicating
|
|
302
|
+
// large tables.
|
|
303
|
+
totalEstimatedCount = await this.estimatedCountNumber(table, transaction);
|
|
304
|
+
lastCountTime = performance.now();
|
|
305
|
+
}
|
|
306
|
+
const updatedSourceTable = await batch.updateTableProgress(table.sourceTable, {
|
|
307
|
+
lastKey: lastKey,
|
|
308
|
+
replicatedCount: replicatedCount,
|
|
309
|
+
totalEstimatedCount: totalEstimatedCount
|
|
310
|
+
});
|
|
311
|
+
this.tableCache.updateSourceTable(updatedSourceTable);
|
|
312
|
+
this.logger.info(`Replicating ${table.toQualifiedName()} ${table.sourceTable.formatSnapshotProgress()}`);
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
this.logger.info(`Replicating ${table.toQualifiedName()} ${replicatedCount}/${limited.length} for resnapshot`);
|
|
316
|
+
}
|
|
317
|
+
if (this.abortSignal.aborted) {
|
|
318
|
+
// We only abort after flushing
|
|
319
|
+
throw new ReplicationAbortedError(`Initial replication interrupted`);
|
|
320
|
+
}
|
|
321
|
+
// When the batch of rows is smaller than the requested batch size we know it is the final batch
|
|
322
|
+
if (batchReplicatedCount < this.snapshotBatchSize) {
|
|
323
|
+
hasRemainingData = false;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Estimate the number of rows in a table. This query uses partition stats view to get a fast estimate of the row count.
|
|
329
|
+
* This requires that the MSSQL DB user has the VIEW DATABASE PERFORMANCE STATE permission.
|
|
330
|
+
* @param table
|
|
331
|
+
* @param transaction
|
|
332
|
+
*/
|
|
333
|
+
async estimatedCountNumber(table, transaction) {
|
|
334
|
+
const request = transaction ? transaction.request() : await this.connections.createRequest();
|
|
335
|
+
const { recordset: result } = await request.query(`SELECT SUM(row_count) AS total_rows
|
|
336
|
+
FROM sys.dm_db_partition_stats
|
|
337
|
+
WHERE object_id = OBJECT_ID('${table.toQualifiedName()}')
|
|
338
|
+
AND index_id < 2;`);
|
|
339
|
+
return result[0].total_rows ?? -1;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Start initial replication.
|
|
343
|
+
*
|
|
344
|
+
* If (partial) replication was done before on this slot, this clears the state
|
|
345
|
+
* and starts again from scratch.
|
|
346
|
+
*/
|
|
347
|
+
async startInitialReplication(snapshotStatus) {
|
|
348
|
+
let { status, snapshotLSN } = snapshotStatus;
|
|
349
|
+
if (status === SnapshotStatus.RESTART_REQUIRED) {
|
|
350
|
+
this.logger.info(`Snapshot restart required, clearing state.`);
|
|
351
|
+
// This happens if the last replicated checkpoint LSN is no longer available in the CDC tables.
|
|
352
|
+
await this.storage.clear({ signal: this.abortSignal });
|
|
353
|
+
}
|
|
354
|
+
await this.storage.startBatch({
|
|
355
|
+
logger: this.logger,
|
|
356
|
+
zeroLSN: LSN.ZERO,
|
|
357
|
+
defaultSchema: this.defaultSchema,
|
|
358
|
+
storeCurrentData: false,
|
|
359
|
+
skipExistingRows: true
|
|
360
|
+
}, async (batch) => {
|
|
361
|
+
if (snapshotLSN == null) {
|
|
362
|
+
// First replication attempt - set the snapshot LSN to the current LSN before starting
|
|
363
|
+
snapshotLSN = (await getLatestReplicatedLSN(this.connections)).toString();
|
|
364
|
+
await batch.setResumeLsn(snapshotLSN);
|
|
365
|
+
const latestLSN = (await getLatestLSN(this.connections)).toString();
|
|
366
|
+
this.logger.info(`Marking snapshot at ${snapshotLSN}, Latest DB LSN ${latestLSN}.`);
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
this.logger.info(`Resuming snapshot at ${snapshotLSN}.`);
|
|
370
|
+
}
|
|
371
|
+
const tablesToSnapshot = [];
|
|
372
|
+
for (const table of this.tableCache.getAll()) {
|
|
373
|
+
if (table.sourceTable.snapshotComplete) {
|
|
374
|
+
this.logger.info(`Skipping table [${table.toQualifiedName()}] - snapshot already done.`);
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const count = await this.estimatedCountNumber(table);
|
|
378
|
+
const updatedSourceTable = await batch.updateTableProgress(table.sourceTable, {
|
|
379
|
+
totalEstimatedCount: count
|
|
380
|
+
});
|
|
381
|
+
this.tableCache.updateSourceTable(updatedSourceTable);
|
|
382
|
+
tablesToSnapshot.push(table);
|
|
383
|
+
this.logger.info(`To replicate: ${table.toQualifiedName()} ${table.sourceTable.formatSnapshotProgress()}`);
|
|
384
|
+
}
|
|
385
|
+
for (const table of tablesToSnapshot) {
|
|
386
|
+
await this.snapshotTableInTx(batch, table);
|
|
387
|
+
this.touch();
|
|
388
|
+
}
|
|
389
|
+
// This will not create a consistent checkpoint yet, but will persist the op.
|
|
390
|
+
// Actual checkpoint will be created when streaming replication caught up.
|
|
391
|
+
await batch.commit(snapshotLSN);
|
|
392
|
+
this.logger.info(`Snapshot done. Need to replicate from ${snapshotLSN} to ${batch.noCheckpointBeforeLsn} to be consistent`);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
async initReplication() {
|
|
396
|
+
const errors = await checkSourceConfiguration(this.connections);
|
|
397
|
+
if (errors.length > 0) {
|
|
398
|
+
throw new CDCConfigurationError(`CDC Configuration Errors: ${errors.join(', ')}`);
|
|
399
|
+
}
|
|
400
|
+
await this.populateTableCache();
|
|
401
|
+
const snapshotStatus = await this.checkSnapshotStatus();
|
|
402
|
+
if (snapshotStatus.status !== SnapshotStatus.DONE) {
|
|
403
|
+
await this.startInitialReplication(snapshotStatus);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Checks if the initial sync has already been completed and if updates from the last checkpoint are still available
|
|
408
|
+
* in the CDC instances.
|
|
409
|
+
*/
|
|
410
|
+
async checkSnapshotStatus() {
|
|
411
|
+
const status = await this.storage.getStatus();
|
|
412
|
+
if (status.snapshot_done && status.checkpoint_lsn) {
|
|
413
|
+
// Snapshot is done, but we still need to check that the last known checkpoint LSN is still
|
|
414
|
+
// within the threshold of the CDC tables
|
|
415
|
+
this.logger.info(`Initial replication already done`);
|
|
416
|
+
const lastCheckpointLSN = LSN.fromString(status.checkpoint_lsn);
|
|
417
|
+
// Check that the CDC tables still have valid data
|
|
418
|
+
const isAvailable = await isWithinRetentionThreshold({
|
|
419
|
+
checkpointLSN: lastCheckpointLSN,
|
|
420
|
+
tables: this.tableCache.getAll(),
|
|
421
|
+
connectionManager: this.connections
|
|
422
|
+
});
|
|
423
|
+
if (!isAvailable) {
|
|
424
|
+
this.logger.warn(`Updates from the last checkpoint are no longer available in the CDC instance, starting initial replication again.`);
|
|
425
|
+
}
|
|
426
|
+
return { status: isAvailable ? SnapshotStatus.DONE : SnapshotStatus.RESTART_REQUIRED, snapshotLSN: null };
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
return { status: SnapshotStatus.IN_PROGRESS, snapshotLSN: status.snapshot_lsn };
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
async streamChanges() {
|
|
433
|
+
await this.storage.startBatch({
|
|
434
|
+
logger: this.logger,
|
|
435
|
+
zeroLSN: LSN.ZERO,
|
|
436
|
+
defaultSchema: this.defaultSchema,
|
|
437
|
+
storeCurrentData: false,
|
|
438
|
+
skipExistingRows: false
|
|
439
|
+
}, async (batch) => {
|
|
440
|
+
if (batch.resumeFromLsn == null) {
|
|
441
|
+
throw new ReplicationAssertionError(`No LSN found to resume replication from.`);
|
|
442
|
+
}
|
|
443
|
+
const startLSN = LSN.fromString(batch.resumeFromLsn);
|
|
444
|
+
const sourceTables = this.tableCache.getAll();
|
|
445
|
+
const eventHandler = this.createEventHandler(batch);
|
|
446
|
+
const poller = new CDCPoller({
|
|
447
|
+
connectionManager: this.connections,
|
|
448
|
+
eventHandler,
|
|
449
|
+
sourceTables,
|
|
450
|
+
startLSN,
|
|
451
|
+
pollingOptions: this.options.pollingOptions,
|
|
452
|
+
logger: this.logger
|
|
453
|
+
});
|
|
454
|
+
this.abortSignal.addEventListener('abort', async () => {
|
|
455
|
+
await poller.stop();
|
|
456
|
+
}, { once: true });
|
|
457
|
+
await createCheckpoint(this.connections);
|
|
458
|
+
this.logger.info(`Streaming changes from: ${startLSN}`);
|
|
459
|
+
await poller.replicateUntilStopped();
|
|
460
|
+
});
|
|
461
|
+
}
|
|
462
|
+
createEventHandler(batch) {
|
|
463
|
+
return {
|
|
464
|
+
onInsert: async (row, table, columns) => {
|
|
465
|
+
const afterRow = this.toSqliteRow(row, columns);
|
|
466
|
+
await batch.save({
|
|
467
|
+
tag: storage.SaveOperationTag.INSERT,
|
|
468
|
+
sourceTable: table.sourceTable,
|
|
469
|
+
before: undefined,
|
|
470
|
+
beforeReplicaId: undefined,
|
|
471
|
+
after: afterRow,
|
|
472
|
+
afterReplicaId: getUuidReplicaIdentityBson(afterRow, table.sourceTable.replicaIdColumns)
|
|
473
|
+
});
|
|
474
|
+
this.metrics.getCounter(ReplicationMetric.ROWS_REPLICATED).add(1);
|
|
475
|
+
},
|
|
476
|
+
onUpdate: async (rowAfter, rowBefore, table, columns) => {
|
|
477
|
+
const beforeRow = this.toSqliteRow(rowBefore, columns);
|
|
478
|
+
const afterRow = this.toSqliteRow(rowAfter, columns);
|
|
479
|
+
await batch.save({
|
|
480
|
+
tag: storage.SaveOperationTag.UPDATE,
|
|
481
|
+
sourceTable: table.sourceTable,
|
|
482
|
+
before: beforeRow,
|
|
483
|
+
beforeReplicaId: getUuidReplicaIdentityBson(beforeRow, table.sourceTable.replicaIdColumns),
|
|
484
|
+
after: afterRow,
|
|
485
|
+
afterReplicaId: getUuidReplicaIdentityBson(afterRow, table.sourceTable.replicaIdColumns)
|
|
486
|
+
});
|
|
487
|
+
this.metrics.getCounter(ReplicationMetric.ROWS_REPLICATED).add(1);
|
|
488
|
+
},
|
|
489
|
+
onDelete: async (row, table, columns) => {
|
|
490
|
+
const beforeRow = this.toSqliteRow(row, columns);
|
|
491
|
+
await batch.save({
|
|
492
|
+
tag: storage.SaveOperationTag.DELETE,
|
|
493
|
+
sourceTable: table.sourceTable,
|
|
494
|
+
before: beforeRow,
|
|
495
|
+
beforeReplicaId: getUuidReplicaIdentityBson(beforeRow, table.sourceTable.replicaIdColumns),
|
|
496
|
+
after: undefined,
|
|
497
|
+
afterReplicaId: undefined
|
|
498
|
+
});
|
|
499
|
+
this.metrics.getCounter(ReplicationMetric.ROWS_REPLICATED).add(1);
|
|
500
|
+
},
|
|
501
|
+
onCommit: async (lsn, transactionCount) => {
|
|
502
|
+
await batch.commit(lsn);
|
|
503
|
+
this.metrics.getCounter(ReplicationMetric.TRANSACTIONS_REPLICATED).add(transactionCount);
|
|
504
|
+
this.isStartingReplication = false;
|
|
505
|
+
},
|
|
506
|
+
onSchemaChange: async () => {
|
|
507
|
+
// TODO: Handle schema changes
|
|
508
|
+
}
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Convert CDC row data to SqliteRow format.
|
|
513
|
+
* CDC rows include table columns plus CDC metadata columns (__$operation, __$start_lsn, etc.).
|
|
514
|
+
* We filter out the CDC metadata columns.
|
|
515
|
+
*/
|
|
516
|
+
toSqliteRow(row, columns) {
|
|
517
|
+
const inputRow = CDCToSqliteRow({ row, columns });
|
|
518
|
+
return this.syncRules.applyRowContext(inputRow);
|
|
519
|
+
}
|
|
520
|
+
async getReplicationLagMillis() {
|
|
521
|
+
if (this.oldestUncommittedChange == null) {
|
|
522
|
+
if (this.isStartingReplication) {
|
|
523
|
+
// We don't have anything to compute replication lag with yet.
|
|
524
|
+
return undefined;
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
// We don't have any uncommitted changes, so replication is up-to-date.
|
|
528
|
+
return 0;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return Date.now() - this.oldestUncommittedChange.getTime();
|
|
532
|
+
}
|
|
533
|
+
touch() {
|
|
534
|
+
container.probes.touch().catch((e) => {
|
|
535
|
+
this.logger.error(`Error touching probe`, e);
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
//# sourceMappingURL=CDCStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CDCStream.js","sourceRoot":"","sources":["../../src/replication/CDCStream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { BaseObserver } from '@powersync/lib-services-framework';
|
|
2
|
+
import sql from 'mssql';
|
|
3
|
+
import { NormalizedMSSQLConnectionConfig } from '../types/types.js';
|
|
4
|
+
import { MSSQLParameter } from '../types/mssql-data-types.js';
|
|
5
|
+
export declare const DEFAULT_SCHEMA = "dbo";
|
|
6
|
+
export interface MSSQLConnectionManagerListener {
|
|
7
|
+
onEnded(): void;
|
|
8
|
+
}
|
|
9
|
+
export declare class MSSQLConnectionManager extends BaseObserver<MSSQLConnectionManagerListener> {
|
|
10
|
+
options: NormalizedMSSQLConnectionConfig;
|
|
11
|
+
private readonly pool;
|
|
12
|
+
constructor(options: NormalizedMSSQLConnectionConfig, poolOptions: sql.PoolOpts<sql.Connection>);
|
|
13
|
+
get connectionTag(): string;
|
|
14
|
+
get connectionId(): string;
|
|
15
|
+
get databaseName(): string;
|
|
16
|
+
get schema(): string;
|
|
17
|
+
private ensureConnected;
|
|
18
|
+
createTransaction(): Promise<sql.Transaction>;
|
|
19
|
+
createRequest(): Promise<sql.Request>;
|
|
20
|
+
query(query: string, parameters?: MSSQLParameter[]): Promise<sql.IResult<any>>;
|
|
21
|
+
execute(procedure: string, parameters?: MSSQLParameter[]): Promise<sql.IProcedureResult<any>>;
|
|
22
|
+
end(): Promise<void>;
|
|
23
|
+
}
|