@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.
Files changed (64) hide show
  1. package/CHANGELOG.md +67 -0
  2. package/dist/api/MongoRouteAPIAdapter.js +12 -21
  3. package/dist/api/MongoRouteAPIAdapter.js.map +1 -1
  4. package/dist/replication/ChangeStream.d.ts +23 -42
  5. package/dist/replication/ChangeStream.js +363 -600
  6. package/dist/replication/ChangeStream.js.map +1 -1
  7. package/dist/replication/ChangeStreamReplicationJob.js +2 -2
  8. package/dist/replication/ChangeStreamReplicationJob.js.map +1 -1
  9. package/dist/replication/JsonBufferWriter.d.ts +80 -0
  10. package/dist/replication/JsonBufferWriter.js +342 -0
  11. package/dist/replication/JsonBufferWriter.js.map +1 -0
  12. package/dist/replication/MongoRelation.d.ts +1 -1
  13. package/dist/replication/MongoRelation.js +45 -21
  14. package/dist/replication/MongoRelation.js.map +1 -1
  15. package/dist/replication/MongoSnapshotQuery.d.ts +1 -1
  16. package/dist/replication/MongoSnapshotQuery.js +6 -3
  17. package/dist/replication/MongoSnapshotQuery.js.map +1 -1
  18. package/dist/replication/MongoSnapshotter.d.ts +81 -0
  19. package/dist/replication/MongoSnapshotter.js +594 -0
  20. package/dist/replication/MongoSnapshotter.js.map +1 -0
  21. package/dist/replication/RawChangeStream.d.ts +55 -0
  22. package/dist/replication/RawChangeStream.js +322 -0
  23. package/dist/replication/RawChangeStream.js.map +1 -0
  24. package/dist/replication/SourceRowConverter.d.ts +46 -0
  25. package/dist/replication/SourceRowConverter.js +42 -0
  26. package/dist/replication/SourceRowConverter.js.map +1 -0
  27. package/dist/replication/bufferToSqlite.d.ts +43 -0
  28. package/dist/replication/bufferToSqlite.js +740 -0
  29. package/dist/replication/bufferToSqlite.js.map +1 -0
  30. package/dist/replication/internal-mongodb-utils.d.ts +0 -12
  31. package/dist/replication/internal-mongodb-utils.js +0 -54
  32. package/dist/replication/internal-mongodb-utils.js.map +1 -1
  33. package/dist/replication/replication-index.d.ts +2 -0
  34. package/dist/replication/replication-index.js +2 -0
  35. package/dist/replication/replication-index.js.map +1 -1
  36. package/package.json +11 -11
  37. package/scripts/benchmark-change-document-json.mts +358 -0
  38. package/scripts/benchmark-change-document.mts +370 -0
  39. package/src/api/MongoRouteAPIAdapter.ts +13 -21
  40. package/src/replication/ChangeStream.ts +421 -720
  41. package/src/replication/ChangeStreamReplicationJob.ts +2 -2
  42. package/src/replication/JsonBufferWriter.ts +390 -0
  43. package/src/replication/MongoRelation.ts +54 -25
  44. package/src/replication/MongoSnapshotQuery.ts +8 -5
  45. package/src/replication/MongoSnapshotter.ts +729 -0
  46. package/src/replication/RawChangeStream.ts +460 -0
  47. package/src/replication/SourceRowConverter.ts +65 -0
  48. package/src/replication/bufferToSqlite.ts +944 -0
  49. package/src/replication/internal-mongodb-utils.ts +0 -65
  50. package/src/replication/replication-index.ts +2 -0
  51. package/test/src/buffer_to_sqlite.test.ts +1146 -0
  52. package/test/src/change_stream.test.ts +259 -19
  53. package/test/src/change_stream_utils.ts +28 -27
  54. package/test/src/checkpoint_retry.test.ts +131 -0
  55. package/test/src/mongo_test.test.ts +66 -64
  56. package/test/src/parse_document_id.test.ts +54 -0
  57. package/test/src/raw_change_stream.test.ts +547 -0
  58. package/test/src/resume.test.ts +12 -2
  59. package/test/src/resuming_snapshots.test.ts +10 -6
  60. package/test/src/util.ts +56 -3
  61. package/test/tsconfig.json +0 -1
  62. package/tsconfig.scripts.json +13 -0
  63. package/tsconfig.tsbuildinfo +1 -1
  64. 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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"}