@powersync/service-module-mongodb 0.15.4 → 0.17.0
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 +67 -0
- package/dist/api/MongoRouteAPIAdapter.js +12 -21
- package/dist/api/MongoRouteAPIAdapter.js.map +1 -1
- package/dist/replication/ChangeStream.d.ts +23 -42
- package/dist/replication/ChangeStream.js +363 -600
- package/dist/replication/ChangeStream.js.map +1 -1
- package/dist/replication/ChangeStreamReplicationJob.js +2 -2
- package/dist/replication/ChangeStreamReplicationJob.js.map +1 -1
- package/dist/replication/JsonBufferWriter.d.ts +80 -0
- package/dist/replication/JsonBufferWriter.js +342 -0
- package/dist/replication/JsonBufferWriter.js.map +1 -0
- package/dist/replication/MongoRelation.d.ts +1 -1
- package/dist/replication/MongoRelation.js +45 -21
- package/dist/replication/MongoRelation.js.map +1 -1
- package/dist/replication/MongoSnapshotQuery.d.ts +1 -1
- package/dist/replication/MongoSnapshotQuery.js +6 -3
- package/dist/replication/MongoSnapshotQuery.js.map +1 -1
- package/dist/replication/MongoSnapshotter.d.ts +81 -0
- package/dist/replication/MongoSnapshotter.js +594 -0
- package/dist/replication/MongoSnapshotter.js.map +1 -0
- package/dist/replication/RawChangeStream.d.ts +55 -0
- package/dist/replication/RawChangeStream.js +322 -0
- package/dist/replication/RawChangeStream.js.map +1 -0
- package/dist/replication/SourceRowConverter.d.ts +46 -0
- package/dist/replication/SourceRowConverter.js +42 -0
- package/dist/replication/SourceRowConverter.js.map +1 -0
- package/dist/replication/bufferToSqlite.d.ts +43 -0
- package/dist/replication/bufferToSqlite.js +740 -0
- package/dist/replication/bufferToSqlite.js.map +1 -0
- package/dist/replication/internal-mongodb-utils.d.ts +0 -12
- package/dist/replication/internal-mongodb-utils.js +0 -54
- package/dist/replication/internal-mongodb-utils.js.map +1 -1
- package/dist/replication/replication-index.d.ts +2 -0
- package/dist/replication/replication-index.js +2 -0
- package/dist/replication/replication-index.js.map +1 -1
- package/package.json +11 -11
- package/scripts/benchmark-change-document-json.mts +358 -0
- package/scripts/benchmark-change-document.mts +370 -0
- package/src/api/MongoRouteAPIAdapter.ts +13 -21
- package/src/replication/ChangeStream.ts +421 -720
- package/src/replication/ChangeStreamReplicationJob.ts +2 -2
- package/src/replication/JsonBufferWriter.ts +390 -0
- package/src/replication/MongoRelation.ts +54 -25
- package/src/replication/MongoSnapshotQuery.ts +8 -5
- package/src/replication/MongoSnapshotter.ts +729 -0
- package/src/replication/RawChangeStream.ts +460 -0
- package/src/replication/SourceRowConverter.ts +65 -0
- package/src/replication/bufferToSqlite.ts +944 -0
- package/src/replication/internal-mongodb-utils.ts +0 -65
- package/src/replication/replication-index.ts +2 -0
- package/test/src/buffer_to_sqlite.test.ts +1146 -0
- package/test/src/change_stream.test.ts +259 -19
- package/test/src/change_stream_utils.ts +28 -27
- package/test/src/checkpoint_retry.test.ts +131 -0
- package/test/src/mongo_test.test.ts +66 -64
- package/test/src/parse_document_id.test.ts +54 -0
- package/test/src/raw_change_stream.test.ts +547 -0
- package/test/src/resume.test.ts +12 -2
- package/test/src/resuming_snapshots.test.ts +10 -6
- package/test/src/util.ts +56 -3
- package/test/tsconfig.json +0 -1
- package/tsconfig.scripts.json +13 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/test/src/internal_mongodb_utils.test.ts +0 -103
|
@@ -0,0 +1,594 @@
|
|
|
1
|
+
import { container, ErrorCode, ReplicationAbortedError, ServiceError } from '@powersync/lib-services-framework';
|
|
2
|
+
import { PerformanceTracer, SaveOperationTag } from '@powersync/service-core';
|
|
3
|
+
import { ReplicationMetric } from '@powersync/service-types';
|
|
4
|
+
import { performance } from 'node:perf_hooks';
|
|
5
|
+
import { MongoLSN } from '../common/MongoLSN.js';
|
|
6
|
+
import { PostImagesOption } from '../types/types.js';
|
|
7
|
+
import { escapeRegExp } from '../utils.js';
|
|
8
|
+
import { createCheckpoint, getMongoRelation, STANDALONE_CHECKPOINT_ID } from './MongoRelation.js';
|
|
9
|
+
import { ChunkedSnapshotQuery } from './MongoSnapshotQuery.js';
|
|
10
|
+
import { parseChangeDocument, rawChangeStream } from './RawChangeStream.js';
|
|
11
|
+
import { CHECKPOINTS_COLLECTION } from './replication-utils.js';
|
|
12
|
+
import { DirectSourceRowConverter } from './SourceRowConverter.js';
|
|
13
|
+
export class MongoSnapshotter {
|
|
14
|
+
storage;
|
|
15
|
+
metrics;
|
|
16
|
+
connections;
|
|
17
|
+
client;
|
|
18
|
+
defaultDb;
|
|
19
|
+
syncRules;
|
|
20
|
+
sourceRowConverter;
|
|
21
|
+
maxAwaitTimeMS;
|
|
22
|
+
snapshotChunkLength;
|
|
23
|
+
abortSignal;
|
|
24
|
+
logger;
|
|
25
|
+
checkpointStreamId;
|
|
26
|
+
storageHooks;
|
|
27
|
+
snapshotHooks;
|
|
28
|
+
changeStreamTimeout;
|
|
29
|
+
connectionId = 1;
|
|
30
|
+
queue = new Set();
|
|
31
|
+
initialSnapshotDone = Promise.withResolvers();
|
|
32
|
+
nextItemQueued = null;
|
|
33
|
+
lastSnapshotOpId = null;
|
|
34
|
+
lastTouchedAt = performance.now();
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.storage = options.storage;
|
|
37
|
+
this.metrics = options.metrics;
|
|
38
|
+
this.connections = options.connections;
|
|
39
|
+
this.client = options.connections.client;
|
|
40
|
+
this.defaultDb = options.connections.db;
|
|
41
|
+
this.maxAwaitTimeMS = options.maxAwaitTimeMS ?? 10_000;
|
|
42
|
+
this.snapshotChunkLength = options.snapshotChunkLength ?? 6_000;
|
|
43
|
+
this.abortSignal = options.abortSignal;
|
|
44
|
+
this.logger = options.logger ?? options.storage.logger;
|
|
45
|
+
this.checkpointStreamId = options.checkpointStreamId;
|
|
46
|
+
this.storageHooks = options.storageHooks;
|
|
47
|
+
this.snapshotHooks = options.snapshotHooks;
|
|
48
|
+
this.changeStreamTimeout = Math.ceil(this.client.options.socketTimeoutMS * 0.9);
|
|
49
|
+
this.syncRules = options.storage.getParsedSyncRules({
|
|
50
|
+
defaultSchema: this.defaultDb.databaseName
|
|
51
|
+
});
|
|
52
|
+
this.sourceRowConverter = new DirectSourceRowConverter(this.syncRules.compatibility);
|
|
53
|
+
this.abortSignal.addEventListener('abort', () => {
|
|
54
|
+
this.nextItemQueued?.resolve();
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
get usePostImages() {
|
|
58
|
+
return this.connections.options.postImages != PostImagesOption.OFF;
|
|
59
|
+
}
|
|
60
|
+
get configurePostImages() {
|
|
61
|
+
return this.connections.options.postImages == PostImagesOption.AUTO_CONFIGURE;
|
|
62
|
+
}
|
|
63
|
+
get supportsConcurrentSnapshots() {
|
|
64
|
+
return this.storage.storageConfig.softDeleteCurrentData;
|
|
65
|
+
}
|
|
66
|
+
async checkSlot() {
|
|
67
|
+
const status = await this.storage.getStatus();
|
|
68
|
+
if (status.snapshot_done && status.checkpoint_lsn) {
|
|
69
|
+
this.logger.info(`Initial replication already done`);
|
|
70
|
+
return { needsInitialSync: false, snapshotLsn: null };
|
|
71
|
+
}
|
|
72
|
+
return { needsInitialSync: true, snapshotLsn: status.snapshot_lsn };
|
|
73
|
+
}
|
|
74
|
+
async setupCheckpointsCollection() {
|
|
75
|
+
const collection = await this.getCollectionInfo(this.defaultDb.databaseName, CHECKPOINTS_COLLECTION);
|
|
76
|
+
if (collection == null) {
|
|
77
|
+
await this.defaultDb.createCollection(CHECKPOINTS_COLLECTION, {
|
|
78
|
+
changeStreamPreAndPostImages: { enabled: true }
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
else if (this.usePostImages && collection.options?.changeStreamPreAndPostImages?.enabled != true) {
|
|
82
|
+
// Drop + create requires less permissions than collMod,
|
|
83
|
+
// and we don't care about the data in this collection.
|
|
84
|
+
await this.defaultDb.dropCollection(CHECKPOINTS_COLLECTION);
|
|
85
|
+
await this.defaultDb.createCollection(CHECKPOINTS_COLLECTION, {
|
|
86
|
+
changeStreamPreAndPostImages: { enabled: true }
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
// Clear the collection on startup, to keep it clean
|
|
91
|
+
// We never query this collection directly, and don't want to keep the data around.
|
|
92
|
+
// We only use this to get data into the oplog/changestream.
|
|
93
|
+
await this.defaultDb.collection(CHECKPOINTS_COLLECTION).deleteMany({});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async queueSnapshotTables(snapshotLsn) {
|
|
97
|
+
await this.client.connect();
|
|
98
|
+
await using writer = await this.storage.createWriter({
|
|
99
|
+
zeroLSN: MongoLSN.ZERO.comparable,
|
|
100
|
+
defaultSchema: this.defaultDb.databaseName,
|
|
101
|
+
storeCurrentData: false,
|
|
102
|
+
skipExistingRows: true,
|
|
103
|
+
tracer: new PerformanceTracer('MongoDB initial snapshot setup')
|
|
104
|
+
});
|
|
105
|
+
if (snapshotLsn == null) {
|
|
106
|
+
// First replication attempt - get a snapshot and store the timestamp
|
|
107
|
+
snapshotLsn = await this.getSnapshotLsn();
|
|
108
|
+
await writer.setResumeLsn(snapshotLsn);
|
|
109
|
+
this.logger.info(`Marking snapshot at ${snapshotLsn}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
this.logger.info(`Resuming snapshot at ${snapshotLsn}`);
|
|
113
|
+
// Check that the snapshot is still valid.
|
|
114
|
+
await this.validateSnapshotLsn(snapshotLsn);
|
|
115
|
+
}
|
|
116
|
+
// Start by resolving all tables.
|
|
117
|
+
// This checks postImage configuration, and that should fail as
|
|
118
|
+
// early as possible.
|
|
119
|
+
const allSourceTables = [];
|
|
120
|
+
for (const tablePattern of this.syncRules.getSourceTables()) {
|
|
121
|
+
allSourceTables.push(...(await this.resolveQualifiedTableNames(writer, tablePattern)));
|
|
122
|
+
}
|
|
123
|
+
for (const table of allSourceTables) {
|
|
124
|
+
if (table.snapshotComplete) {
|
|
125
|
+
this.logger.info(`Skipping ${table.qualifiedName} - snapshot already done`);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const count = await this.estimatedCountNumber(table);
|
|
129
|
+
const updated = await writer.updateTableProgress(table, {
|
|
130
|
+
totalEstimatedCount: count
|
|
131
|
+
});
|
|
132
|
+
this.queueTable(updated);
|
|
133
|
+
this.logger.info(`To replicate: ${updated.qualifiedName}: ${updated.snapshotStatus?.replicatedCount}/~${updated.snapshotStatus?.totalEstimatedCount}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
async waitForInitialSnapshot() {
|
|
137
|
+
await this.initialSnapshotDone.promise;
|
|
138
|
+
}
|
|
139
|
+
async replicationLoop() {
|
|
140
|
+
try {
|
|
141
|
+
if (this.queue.size == 0) {
|
|
142
|
+
// Special case where we start with no tables to snapshot
|
|
143
|
+
await this.markSnapshotDone();
|
|
144
|
+
}
|
|
145
|
+
while (!this.abortSignal.aborted) {
|
|
146
|
+
const item = this.queue.values().next().value;
|
|
147
|
+
if (item == null) {
|
|
148
|
+
this.initialSnapshotDone.resolve();
|
|
149
|
+
this.nextItemQueued = Promise.withResolvers();
|
|
150
|
+
await this.nextItemQueued.promise;
|
|
151
|
+
this.nextItemQueued = null;
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
await item.ready;
|
|
155
|
+
if (!item.cancelled) {
|
|
156
|
+
await this.replicateTable(item.table);
|
|
157
|
+
}
|
|
158
|
+
this.queue.delete(item);
|
|
159
|
+
if (this.queue.size == 0) {
|
|
160
|
+
await this.markSnapshotDone();
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
throw new ReplicationAbortedError(`Replication snapshotter aborted`, this.abortSignal.reason);
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
// If initial snapshot already completed, this has no effect
|
|
167
|
+
this.initialSnapshotDone.reject(e);
|
|
168
|
+
throw e;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async queueSnapshot(batch, table) {
|
|
172
|
+
const ready = Promise.withResolvers();
|
|
173
|
+
const item = this.queueTable(table, ready.promise);
|
|
174
|
+
try {
|
|
175
|
+
await batch.markTableSnapshotRequired(table);
|
|
176
|
+
ready.resolve();
|
|
177
|
+
}
|
|
178
|
+
catch (e) {
|
|
179
|
+
item.cancelled = true;
|
|
180
|
+
ready.resolve();
|
|
181
|
+
throw e;
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
this.nextItemQueued?.resolve();
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Snapshot tables.
|
|
189
|
+
*
|
|
190
|
+
* If concurrency is supported, the snapshots are queued and processed in the background.
|
|
191
|
+
* Otherwise, snapshots are processed inline.
|
|
192
|
+
*/
|
|
193
|
+
async snapshotTables(batch, tables) {
|
|
194
|
+
if (this.supportsConcurrentSnapshots) {
|
|
195
|
+
// Queue concurrent snapshots
|
|
196
|
+
for (const tableToSnapshot of tables) {
|
|
197
|
+
await this.queueSnapshot(batch, tableToSnapshot);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
// No concurrency supported - snapshot inline
|
|
202
|
+
// Truncate in case a previous inline snapshot was interrupted after flushing rows, but before
|
|
203
|
+
// recording snapshot progress. Without this, resuming can replay already-flushed rows on v1/v2 storage.
|
|
204
|
+
await batch.truncate(tables);
|
|
205
|
+
for (const table of tables) {
|
|
206
|
+
await this.snapshotTable(batch, table);
|
|
207
|
+
}
|
|
208
|
+
const noCheckpointBefore = await createCheckpoint(this.client, this.defaultDb, STANDALONE_CHECKPOINT_ID);
|
|
209
|
+
await batch.markTableSnapshotDone(tables, noCheckpointBefore);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
queueTable(table, ready = Promise.resolve()) {
|
|
213
|
+
const item = { table, ready, cancelled: false };
|
|
214
|
+
this.queue.add(item);
|
|
215
|
+
this.nextItemQueued?.resolve();
|
|
216
|
+
return item;
|
|
217
|
+
}
|
|
218
|
+
async markSnapshotDone() {
|
|
219
|
+
if (this.queue.size != 0) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
const status = await this.storage.getStatus();
|
|
223
|
+
if (status.snapshot_done) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const lastOp = this.lastSnapshotOpId ?? status.keepalive_op;
|
|
227
|
+
if (lastOp != null) {
|
|
228
|
+
// Populate the cache _after_ initial replication, but _before_ we switch to this replication stream.
|
|
229
|
+
// Keeping snapshot_done false until this completes makes this resumable after interruption.
|
|
230
|
+
await this.storage.populatePersistentChecksumCache({
|
|
231
|
+
// No checkpoint yet, but we do have the opId.
|
|
232
|
+
maxOpId: lastOp,
|
|
233
|
+
signal: this.abortSignal
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (this.queue.size != 0) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
await using writer = await this.storage.createWriter({
|
|
240
|
+
logger: this.logger,
|
|
241
|
+
zeroLSN: MongoLSN.ZERO.comparable,
|
|
242
|
+
defaultSchema: this.defaultDb.databaseName,
|
|
243
|
+
storeCurrentData: false,
|
|
244
|
+
skipExistingRows: true
|
|
245
|
+
});
|
|
246
|
+
// The checkpoint here is a marker - we need to replicate up to at least this
|
|
247
|
+
// point before the data can be considered consistent.
|
|
248
|
+
const checkpoint = await createCheckpoint(this.client, this.defaultDb, STANDALONE_CHECKPOINT_ID);
|
|
249
|
+
if (this.queue.size != 0) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
await writer.markSnapshotDone(checkpoint, {
|
|
253
|
+
// If there is a conflict, we'll try again after the next snapshot
|
|
254
|
+
throwOnConflict: false
|
|
255
|
+
});
|
|
256
|
+
// KLUDGE: We need to create an extra checkpoint _after_ marking the snapshot done, to fix
|
|
257
|
+
// issues with order of processing commits(). This is picked up by tests on postgres storage,
|
|
258
|
+
// the issue may be specific to that storage engine.
|
|
259
|
+
await createCheckpoint(this.client, this.defaultDb, STANDALONE_CHECKPOINT_ID);
|
|
260
|
+
}
|
|
261
|
+
async replicateTable(tableRequest) {
|
|
262
|
+
await this.snapshotHooks?.beforeSnapshotStarted?.(tableRequest);
|
|
263
|
+
await using writer = await this.storage.createWriter({
|
|
264
|
+
logger: this.logger,
|
|
265
|
+
zeroLSN: MongoLSN.ZERO.comparable,
|
|
266
|
+
defaultSchema: this.defaultDb.databaseName,
|
|
267
|
+
storeCurrentData: false,
|
|
268
|
+
skipExistingRows: true,
|
|
269
|
+
hooks: this.storageHooks,
|
|
270
|
+
tracer: new PerformanceTracer('MongoDB snapshot table')
|
|
271
|
+
});
|
|
272
|
+
// Get fresh table info, in case it was updated while queuing.
|
|
273
|
+
// This deliberately does not resolve by namespace, since that could recreate a replacement source table
|
|
274
|
+
// for a dropped/recreated collection and leave the original queued snapshot with no owner.
|
|
275
|
+
const table = await writer.getSourceTableStatus(tableRequest);
|
|
276
|
+
if (table == null || table.snapshotComplete) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
await this.snapshotTable(writer, table);
|
|
280
|
+
const noCheckpointBefore = await createCheckpoint(this.client, this.defaultDb, STANDALONE_CHECKPOINT_ID);
|
|
281
|
+
await writer.markTableSnapshotDone([table], noCheckpointBefore);
|
|
282
|
+
// This commit ensures we set keepalive_op.
|
|
283
|
+
const resumeLsn = writer.resumeFromLsn ?? MongoLSN.ZERO.comparable;
|
|
284
|
+
await writer.commit(resumeLsn);
|
|
285
|
+
if (writer.last_flushed_op != null) {
|
|
286
|
+
this.lastSnapshotOpId = writer.last_flushed_op;
|
|
287
|
+
}
|
|
288
|
+
this.logger.info(`Flushed snapshot at ${writer.last_flushed_op}`);
|
|
289
|
+
}
|
|
290
|
+
async resolveQualifiedTableNames(batch, tablePattern) {
|
|
291
|
+
const schema = tablePattern.schema;
|
|
292
|
+
if (tablePattern.connectionTag != this.connections.connectionTag) {
|
|
293
|
+
return [];
|
|
294
|
+
}
|
|
295
|
+
const nameFilter = tablePattern.isWildcard
|
|
296
|
+
? new RegExp('^' + escapeRegExp(tablePattern.tablePrefix))
|
|
297
|
+
: tablePattern.name;
|
|
298
|
+
// Check if the collection exists
|
|
299
|
+
const collections = await this.client
|
|
300
|
+
.db(schema)
|
|
301
|
+
.listCollections({ name: nameFilter }, { nameOnly: false })
|
|
302
|
+
.toArray();
|
|
303
|
+
if (!tablePattern.isWildcard && collections.length == 0) {
|
|
304
|
+
this.logger.warn(`Collection ${schema}.${tablePattern.name} not found`);
|
|
305
|
+
}
|
|
306
|
+
const result = [];
|
|
307
|
+
for (const collection of collections) {
|
|
308
|
+
result.push(...(await this.handleRelation(batch, getMongoRelation({ db: schema, coll: collection.name }, this.connections.connectionTag), {
|
|
309
|
+
collectionInfo: collection
|
|
310
|
+
})));
|
|
311
|
+
}
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
async snapshotTable(batch, table) {
|
|
315
|
+
const rowsReplicatedMetric = this.metrics.getCounter(ReplicationMetric.ROWS_REPLICATED);
|
|
316
|
+
const bytesReplicatedMetric = this.metrics.getCounter(ReplicationMetric.DATA_REPLICATED_BYTES);
|
|
317
|
+
const chunksReplicatedMetric = this.metrics.getCounter(ReplicationMetric.CHUNKS_REPLICATED);
|
|
318
|
+
const totalEstimatedCount = await this.estimatedCountNumber(table);
|
|
319
|
+
let at = table.snapshotStatus?.replicatedCount ?? 0;
|
|
320
|
+
const collection = this.client.db(table.schema).collection(table.name);
|
|
321
|
+
await using query = new ChunkedSnapshotQuery({
|
|
322
|
+
collection,
|
|
323
|
+
key: table.snapshotStatus?.lastKey,
|
|
324
|
+
batchSize: this.snapshotChunkLength
|
|
325
|
+
});
|
|
326
|
+
if (query.lastKey != null) {
|
|
327
|
+
this.logger.info(`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()} - resuming at _id > ${query.lastKey}`);
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
this.logger.info(`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()}`);
|
|
331
|
+
}
|
|
332
|
+
let lastBatch = performance.now();
|
|
333
|
+
let nextChunkPromise = query.nextChunk();
|
|
334
|
+
while (true) {
|
|
335
|
+
const { docs: docBatch, lastKey, bytes: chunkBytes } = await nextChunkPromise;
|
|
336
|
+
if (docBatch.length == 0) {
|
|
337
|
+
// No more data - stop iterating
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
bytesReplicatedMetric.add(chunkBytes);
|
|
341
|
+
chunksReplicatedMetric.add(1);
|
|
342
|
+
if (this.abortSignal.aborted) {
|
|
343
|
+
throw new ReplicationAbortedError(`Aborted initial replication`, this.abortSignal.reason);
|
|
344
|
+
}
|
|
345
|
+
// Pre-fetch next batch, so that we can read and write concurrently
|
|
346
|
+
nextChunkPromise = query.nextChunk();
|
|
347
|
+
for (const buffer of docBatch) {
|
|
348
|
+
const { row, replicaId } = this.sourceRowConverter.rawToSqliteRow(buffer);
|
|
349
|
+
// This auto-flushes when the batch reaches its size limit
|
|
350
|
+
await batch.save({
|
|
351
|
+
tag: SaveOperationTag.INSERT,
|
|
352
|
+
sourceTable: table,
|
|
353
|
+
before: undefined,
|
|
354
|
+
beforeReplicaId: undefined,
|
|
355
|
+
after: row,
|
|
356
|
+
afterReplicaId: replicaId
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
// Important: flush before marking progress
|
|
360
|
+
const result = await batch.flush();
|
|
361
|
+
if (result?.flushed_op != null) {
|
|
362
|
+
this.lastSnapshotOpId = result.flushed_op;
|
|
363
|
+
}
|
|
364
|
+
at += docBatch.length;
|
|
365
|
+
rowsReplicatedMetric.add(docBatch.length);
|
|
366
|
+
table = await batch.updateTableProgress(table, {
|
|
367
|
+
lastKey,
|
|
368
|
+
replicatedCount: at,
|
|
369
|
+
totalEstimatedCount
|
|
370
|
+
});
|
|
371
|
+
const duration = performance.now() - lastBatch;
|
|
372
|
+
lastBatch = performance.now();
|
|
373
|
+
this.logger.info(`Replicating ${table.qualifiedName} ${table.formatSnapshotProgress()} in ${duration.toFixed(0)}ms`);
|
|
374
|
+
this.touch();
|
|
375
|
+
}
|
|
376
|
+
// In case the loop was interrupted, make sure we await the last promise.
|
|
377
|
+
await nextChunkPromise;
|
|
378
|
+
}
|
|
379
|
+
async handleRelation(batch, descriptor, options) {
|
|
380
|
+
if (options.collectionInfo != null) {
|
|
381
|
+
await this.checkPostImages(descriptor.schema, options.collectionInfo);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
// If collectionInfo is null, the collection may have been dropped.
|
|
385
|
+
// Ignore the postImages check in this case.
|
|
386
|
+
}
|
|
387
|
+
const result = await batch.resolveTables({
|
|
388
|
+
connection_id: this.connectionId,
|
|
389
|
+
source: descriptor,
|
|
390
|
+
syncRules: this.syncRules
|
|
391
|
+
});
|
|
392
|
+
// Drop conflicting collections.
|
|
393
|
+
// This is generally not expected for MongoDB source dbs, so we log an error.
|
|
394
|
+
if (result.dropTables.length > 0) {
|
|
395
|
+
this.logger.error(`Conflicting collections found for ${JSON.stringify(descriptor)}. Dropping: ${result.dropTables.map((t) => t.id).join(', ')}`);
|
|
396
|
+
await batch.drop(result.dropTables);
|
|
397
|
+
}
|
|
398
|
+
return result.tables;
|
|
399
|
+
}
|
|
400
|
+
async estimatedCountNumber(table) {
|
|
401
|
+
return await this.client.db(table.schema).collection(table.name).estimatedDocumentCount();
|
|
402
|
+
}
|
|
403
|
+
async getCollectionInfo(db, name) {
|
|
404
|
+
return (await this.client.db(db).listCollections({ name }, { nameOnly: false }).toArray())[0];
|
|
405
|
+
}
|
|
406
|
+
async checkPostImages(db, collectionInfo) {
|
|
407
|
+
if (!this.usePostImages) {
|
|
408
|
+
// Nothing to check
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
const enabled = collectionInfo.options?.changeStreamPreAndPostImages?.enabled == true;
|
|
412
|
+
if (!enabled && this.configurePostImages) {
|
|
413
|
+
await this.client.db(db).command({
|
|
414
|
+
collMod: collectionInfo.name,
|
|
415
|
+
changeStreamPreAndPostImages: { enabled: true }
|
|
416
|
+
});
|
|
417
|
+
this.logger.info(`Enabled postImages on ${db}.${collectionInfo.name}`);
|
|
418
|
+
}
|
|
419
|
+
else if (!enabled) {
|
|
420
|
+
throw new ServiceError(ErrorCode.PSYNC_S1343, `postImages not enabled on ${db}.${collectionInfo.name}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
async getSnapshotLsn() {
|
|
424
|
+
const hello = await this.defaultDb.command({ hello: 1 });
|
|
425
|
+
// Basic sanity check
|
|
426
|
+
if (hello.msg == 'isdbgrid') {
|
|
427
|
+
throw new ServiceError(ErrorCode.PSYNC_S1341, 'Sharded MongoDB Clusters are not supported yet (including MongoDB Serverless instances).');
|
|
428
|
+
}
|
|
429
|
+
else if (hello.setName == null) {
|
|
430
|
+
throw new ServiceError(ErrorCode.PSYNC_S1342, 'Standalone MongoDB instances are not supported - use a replicaset.');
|
|
431
|
+
}
|
|
432
|
+
// Open a change stream just to get a resume token for later use.
|
|
433
|
+
// We could use clusterTime from the hello command, but that won't tell us if the
|
|
434
|
+
// snapshot isn't valid anymore.
|
|
435
|
+
// If we just use the first resumeToken from the stream, we get two potential issues:
|
|
436
|
+
// 1. The resumeToken may just be a wrapped clusterTime, which does not detect changes
|
|
437
|
+
// in source db or other stream issues.
|
|
438
|
+
// 2. The first actual change we get may have the same clusterTime, causing us to incorrect
|
|
439
|
+
// skip that event.
|
|
440
|
+
// Instead, we create a new checkpoint document, and wait until we get that document back in the stream.
|
|
441
|
+
// To avoid potential race conditions with the checkpoint creation, we create a new checkpoint document
|
|
442
|
+
// periodically until the timeout is reached.
|
|
443
|
+
const LSN_TIMEOUT_SECONDS = 60;
|
|
444
|
+
const LSN_CREATE_INTERVAL_SECONDS = 1;
|
|
445
|
+
const firstCheckpointLsn = await createCheckpoint(this.client, this.defaultDb, this.checkpointStreamId);
|
|
446
|
+
const filters = this.getSourceNamespaceFilters();
|
|
447
|
+
const iter = this.rawChangeStreamBatches({
|
|
448
|
+
lsn: firstCheckpointLsn,
|
|
449
|
+
maxAwaitTimeMS: 0,
|
|
450
|
+
signal: this.abortSignal,
|
|
451
|
+
filters
|
|
452
|
+
});
|
|
453
|
+
const startTime = performance.now();
|
|
454
|
+
let lastCheckpointCreated = performance.now();
|
|
455
|
+
let eventsSeen = 0;
|
|
456
|
+
let batchesSeen = 0;
|
|
457
|
+
for await (const { events } of iter) {
|
|
458
|
+
if (performance.now() - startTime >= LSN_TIMEOUT_SECONDS * 1000) {
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
if (performance.now() - lastCheckpointCreated >= LSN_CREATE_INTERVAL_SECONDS * 1000) {
|
|
462
|
+
await createCheckpoint(this.client, this.defaultDb, this.checkpointStreamId);
|
|
463
|
+
lastCheckpointCreated = performance.now();
|
|
464
|
+
}
|
|
465
|
+
batchesSeen += 1;
|
|
466
|
+
for (const rawChangeDocument of events) {
|
|
467
|
+
const changeDocument = parseChangeDocument(rawChangeDocument);
|
|
468
|
+
const ns = 'ns' in changeDocument && 'coll' in changeDocument.ns ? changeDocument.ns : undefined;
|
|
469
|
+
if (ns?.coll == CHECKPOINTS_COLLECTION && 'documentKey' in changeDocument) {
|
|
470
|
+
const checkpointId = changeDocument.documentKey._id;
|
|
471
|
+
if (!this.checkpointStreamId.equals(checkpointId)) {
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
return new MongoLSN({
|
|
475
|
+
timestamp: changeDocument.clusterTime,
|
|
476
|
+
resume_token: changeDocument._id
|
|
477
|
+
}).comparable;
|
|
478
|
+
}
|
|
479
|
+
eventsSeen += 1;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
// Could happen if there is a very large replication lag?
|
|
483
|
+
throw new ServiceError(ErrorCode.PSYNC_S1301, `Timeout after while waiting for checkpoint document for ${LSN_TIMEOUT_SECONDS}s. Streamed events = ${eventsSeen}, batches = ${batchesSeen}`);
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Given a snapshot LSN, validate that we can read from it, by opening a change stream.
|
|
487
|
+
*/
|
|
488
|
+
async validateSnapshotLsn(lsn) {
|
|
489
|
+
const stream = this.rawChangeStreamBatches({
|
|
490
|
+
lsn,
|
|
491
|
+
maxAwaitTimeMS: 0,
|
|
492
|
+
filters: this.getSourceNamespaceFilters()
|
|
493
|
+
});
|
|
494
|
+
for await (const _batch of stream) {
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
getSourceNamespaceFilters() {
|
|
499
|
+
const sourceTables = this.syncRules.getSourceTables();
|
|
500
|
+
const inFilters = [
|
|
501
|
+
{ db: this.defaultDb.databaseName, coll: CHECKPOINTS_COLLECTION }
|
|
502
|
+
];
|
|
503
|
+
const regexFilters = [];
|
|
504
|
+
let multipleDatabases = false;
|
|
505
|
+
for (const tablePattern of sourceTables) {
|
|
506
|
+
if (tablePattern.connectionTag != this.connections.connectionTag) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (tablePattern.schema != this.defaultDb.databaseName) {
|
|
510
|
+
multipleDatabases = true;
|
|
511
|
+
}
|
|
512
|
+
if (tablePattern.isWildcard) {
|
|
513
|
+
regexFilters.push({
|
|
514
|
+
'ns.db': tablePattern.schema,
|
|
515
|
+
'ns.coll': new RegExp('^' + escapeRegExp(tablePattern.tablePrefix))
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
inFilters.push({
|
|
520
|
+
db: tablePattern.schema,
|
|
521
|
+
coll: tablePattern.name
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
const nsFilter = multipleDatabases
|
|
526
|
+
? { ns: { $in: inFilters } }
|
|
527
|
+
: { 'ns.coll': { $in: inFilters.map((ns) => ns.coll) } };
|
|
528
|
+
if (regexFilters.length > 0) {
|
|
529
|
+
return { $match: { $or: [nsFilter, ...regexFilters] }, multipleDatabases };
|
|
530
|
+
}
|
|
531
|
+
return { $match: nsFilter, multipleDatabases };
|
|
532
|
+
}
|
|
533
|
+
rawChangeStreamBatches(options) {
|
|
534
|
+
const lastLsn = options.lsn ? MongoLSN.fromSerialized(options.lsn) : null;
|
|
535
|
+
const startAfter = lastLsn?.timestamp;
|
|
536
|
+
const resumeAfter = lastLsn?.resumeToken;
|
|
537
|
+
let fullDocument;
|
|
538
|
+
if (this.usePostImages) {
|
|
539
|
+
// 'read_only' or 'auto_configure'
|
|
540
|
+
// Configuration happens during snapshot, or when we see new
|
|
541
|
+
// collections.
|
|
542
|
+
fullDocument = 'required';
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
fullDocument = 'updateLookup';
|
|
546
|
+
}
|
|
547
|
+
const streamOptions = {
|
|
548
|
+
showExpandedEvents: true,
|
|
549
|
+
fullDocument
|
|
550
|
+
};
|
|
551
|
+
const pipeline = [
|
|
552
|
+
{ $changeStream: streamOptions },
|
|
553
|
+
{ $match: options.filters.$match },
|
|
554
|
+
{ $changeStreamSplitLargeEvent: {} }
|
|
555
|
+
];
|
|
556
|
+
// Only one of these options can be supplied at a time.
|
|
557
|
+
if (resumeAfter) {
|
|
558
|
+
streamOptions.resumeAfter = resumeAfter;
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
// Legacy: We don't persist lsns without resumeTokens anymore, but we do still handle the
|
|
562
|
+
// case if we have an old one.
|
|
563
|
+
streamOptions.startAtOperationTime = startAfter;
|
|
564
|
+
}
|
|
565
|
+
let watchDb;
|
|
566
|
+
if (options.filters.multipleDatabases) {
|
|
567
|
+
// Requires readAnyDatabase@admin on Atlas
|
|
568
|
+
watchDb = this.client.db('admin');
|
|
569
|
+
streamOptions.allChangesForCluster = true;
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
// Same general result, but requires less permissions than the above
|
|
573
|
+
watchDb = this.defaultDb;
|
|
574
|
+
}
|
|
575
|
+
return rawChangeStream(watchDb, pipeline, {
|
|
576
|
+
batchSize: options.batchSize ?? this.snapshotChunkLength,
|
|
577
|
+
maxAwaitTimeMS: options.maxAwaitTimeMS ?? this.maxAwaitTimeMS,
|
|
578
|
+
maxTimeMS: this.changeStreamTimeout,
|
|
579
|
+
signal: options.signal,
|
|
580
|
+
logger: this.logger,
|
|
581
|
+
tracer: options.tracer
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
touch() {
|
|
585
|
+
if (performance.now() - this.lastTouchedAt > 1_000) {
|
|
586
|
+
this.lastTouchedAt = performance.now();
|
|
587
|
+
// Update the probes, but don't wait for it
|
|
588
|
+
container.probes.touch().catch((e) => {
|
|
589
|
+
this.logger.error(`Failed to touch the container probe: ${e.message}`, e);
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
//# sourceMappingURL=MongoSnapshotter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MongoSnapshotter.js","sourceRoot":"","sources":["../../src/replication/MongoSnapshotter.ts"],"names":[],"mappings":"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"}
|