@powersync/service-module-mongodb 0.15.3 → 0.16.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 +52 -0
- package/dist/api/MongoRouteAPIAdapter.js +2 -2
- package/dist/api/MongoRouteAPIAdapter.js.map +1 -1
- package/dist/replication/ChangeStream.d.ts +6 -6
- package/dist/replication/ChangeStream.js +300 -322
- 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/ChangeStreamReplicator.d.ts +1 -1
- package/dist/replication/ChangeStreamReplicator.js +1 -1
- package/dist/replication/ChangeStreamReplicator.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/MongoManager.d.ts +1 -1
- package/dist/replication/MongoManager.js +1 -1
- package/dist/replication/MongoManager.js.map +1 -1
- package/dist/replication/MongoRelation.js +4 -0
- 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/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 +4 -2
- package/dist/replication/replication-index.js +4 -2
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/replication/replication-utils.d.ts +1 -1
- package/dist/types/types.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 +2 -2
- package/src/replication/ChangeStream.ts +348 -371
- package/src/replication/ChangeStreamReplicationJob.ts +2 -2
- package/src/replication/ChangeStreamReplicator.ts +2 -5
- package/src/replication/JsonBufferWriter.ts +390 -0
- package/src/replication/MongoManager.ts +2 -2
- package/src/replication/MongoRelation.ts +5 -2
- package/src/replication/MongoSnapshotQuery.ts +8 -5
- 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 -66
- package/src/replication/replication-index.ts +4 -2
- package/src/replication/replication-utils.ts +2 -2
- package/src/types/types.ts +1 -1
- package/test/src/buffer_to_sqlite.test.ts +1146 -0
- package/test/src/change_stream.test.ts +49 -3
- package/test/src/change_stream_utils.ts +4 -10
- 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/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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
-
import { NormalizedMongoConnectionConfig } from '../types/types.js';
|
|
3
2
|
import { BaseObserver } from '@powersync/lib-services-framework';
|
|
3
|
+
import { NormalizedMongoConnectionConfig } from '../types/types.js';
|
|
4
4
|
export interface MongoManagerListener {
|
|
5
5
|
onEnded(): void;
|
|
6
6
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
-
import { BSON_DESERIALIZE_DATA_OPTIONS, POWERSYNC_VERSION } from '@powersync/service-core';
|
|
3
2
|
import { BaseObserver } from '@powersync/lib-services-framework';
|
|
3
|
+
import { BSON_DESERIALIZE_DATA_OPTIONS, POWERSYNC_VERSION } from '@powersync/service-core';
|
|
4
4
|
/**
|
|
5
5
|
* Manage a MongoDB source database connection.
|
|
6
6
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoManager.js","sourceRoot":"","sources":["../../src/replication/MongoManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"MongoManager.js","sourceRoot":"","sources":["../../src/replication/MongoManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,6BAA6B,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAO3F;;GAEG;AACH,MAAM,OAAO,YAAa,SAAQ,YAAkC;IAKzD;IAJO,MAAM,CAAoB;IAC1B,EAAE,CAAW;IAE7B,YACS,OAAwC,EAC/C,SAAoC;QAEpC,KAAK,EAAE,CAAC;QAHD,YAAO,GAAP,OAAO,CAAiC;QAI/C,MAAM,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;QAExC,2EAA2E;QAC3E,IAAI,CAAC,MAAM,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE;YAC/C,IAAI,EAAE;gBACJ,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC3B;YAED,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,+DAA+D;YAC/D,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,KAAK;YAClD,wEAAwE;YACxE,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,MAAM;YACjD,2EAA2E;YAC3E,wBAAwB,EAAE,MAAM,CAAC,wBAAwB,IAAI,MAAM;YAEnE,sBAAsB;YACtB,OAAO,EAAE,aAAa,iBAAiB,EAAE;YACzC,sFAAsF;YACtF,UAAU,EAAE;gBACV,4CAA4C;gBAC5C,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,iBAAiB;aAC3B;YAED,8BAA8B;YAC9B,2CAA2C;YAC3C,yFAAyF;YACzF,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,CAAC;YAEpC,aAAa,EAAE,CAAC;YAChB,aAAa,EAAE,MAAM,CAAC,aAAa,IAAI,MAAM;YAE7C,GAAG,6BAA6B;YAEhC,GAAG,SAAS;SACb,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,IAAW,aAAa;QACtB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,GAAG;QACP,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE,EAAE;YACjC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -121,6 +121,10 @@ function filterJsonData(data, context, depth = 0) {
|
|
|
121
121
|
if (autoBigNum && Number.isInteger(data)) {
|
|
122
122
|
return BigInt(data);
|
|
123
123
|
}
|
|
124
|
+
else if (!Number.isFinite(data)) {
|
|
125
|
+
// Only finite numbers can be represented in JSON.
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
124
128
|
else {
|
|
125
129
|
return data;
|
|
126
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoRelation.js","sourceRoot":"","sources":["../../src/replication/MongoRelation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAEL,WAAW,EACX,YAAY,EACZ,iBAAiB,
|
|
1
|
+
{"version":3,"file":"MongoRelation.js","sourceRoot":"","sources":["../../src/replication/MongoRelation.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReplicationAssertionError } from '@powersync/lib-services-framework';
|
|
2
2
|
import { bson } from '@powersync/service-core';
|
|
3
|
+
import { parseDocumentId } from './bufferToSqlite.js';
|
|
3
4
|
import { getCursorBatchBytes } from './internal-mongodb-utils.js';
|
|
4
5
|
/**
|
|
5
6
|
* Performs a collection snapshot query, chunking by ranges of _id.
|
|
@@ -39,7 +40,8 @@ export class ChunkedSnapshotQuery {
|
|
|
39
40
|
// batchSize is 1 more than limit to auto-close the cursor.
|
|
40
41
|
// See https://github.com/mongodb/node-mongodb-native/pull/4580
|
|
41
42
|
batchSize: this.batchSize + 1,
|
|
42
|
-
sort: { _id: 1 }
|
|
43
|
+
sort: { _id: 1 },
|
|
44
|
+
raw: true
|
|
43
45
|
});
|
|
44
46
|
newCursor = true;
|
|
45
47
|
}
|
|
@@ -61,9 +63,10 @@ export class ChunkedSnapshotQuery {
|
|
|
61
63
|
if (docBatch.length == 0) {
|
|
62
64
|
throw new ReplicationAssertionError(`MongoDB snapshot query returned an empty batch, but hasNext() was true.`);
|
|
63
65
|
}
|
|
64
|
-
const
|
|
66
|
+
const lastDoc = docBatch[docBatch.length - 1];
|
|
67
|
+
const { id: lastKey, idBuffer } = parseDocumentId(lastDoc);
|
|
65
68
|
this.lastKey = lastKey;
|
|
66
|
-
return { docs: docBatch, lastKey:
|
|
69
|
+
return { docs: docBatch, lastKey: idBuffer, bytes };
|
|
67
70
|
}
|
|
68
71
|
async [Symbol.asyncDispose]() {
|
|
69
72
|
await this.lastCursor?.close();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoSnapshotQuery.js","sourceRoot":"","sources":["../../src/replication/MongoSnapshotQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAElE;;;;;GAKG;AACH,MAAM,OAAO,oBAAoB;IAC/B,OAAO,GAAQ,IAAI,CAAC;IACZ,UAAU,GAA4B,IAAI,CAAC;IAC3C,UAAU,CAAmB;IAC7B,SAAS,CAAS;IAE1B,YAAmB,OAAqF;QACtG,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7F,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;QACrC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACrC,CAAC;IAED,KAAK,CAAC,SAAS;QAGb,IAAI,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC;QAC7B,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACpC,sFAAsF;YACtF,wGAAwG;YACxG,yGAAyG;YACzG,sCAAsC;YACtC,oBAAoB;YACpB,kGAAkG;YAClG,0GAA0G;YAC1G,8BAA8B;YAC9B,sEAAsE;YACtE,0FAA0F;YAC1F,MAAM,MAAM,GACV,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC;YACvF,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE;gBACpC,WAAW,EAAE,UAAU;gBACvB,KAAK,EAAE,IAAI,CAAC,SAAS;gBACrB,2DAA2D;gBAC3D,+DAA+D;gBAC/D,SAAS,EAAE,IAAI,CAAC,SAAS,GAAG,CAAC;gBAC7B,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE;
|
|
1
|
+
{"version":3,"file":"MongoSnapshotQuery.js","sourceRoot":"","sources":["../../src/replication/MongoSnapshotQuery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
+
import { Logger } from '@powersync/lib-services-framework';
|
|
3
|
+
import { PerformanceTracer } from '@powersync/service-core';
|
|
4
|
+
export interface RawChangeStreamOptions {
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
/**
|
|
7
|
+
* How long to wait for new data per batch (max time for long-polling).
|
|
8
|
+
*
|
|
9
|
+
* This is used for maxTimeMS for the getMore command.
|
|
10
|
+
*/
|
|
11
|
+
maxAwaitTimeMS: number;
|
|
12
|
+
/**
|
|
13
|
+
* Timeout for the initial aggregate command.
|
|
14
|
+
*/
|
|
15
|
+
maxTimeMS: number;
|
|
16
|
+
/**
|
|
17
|
+
* batchSize for the getMore commands.
|
|
18
|
+
*
|
|
19
|
+
* The aggregate command always uses a batchSize of 1.
|
|
20
|
+
*
|
|
21
|
+
* After a timeout error, the batchSize will be reduced and ramped up again.
|
|
22
|
+
*/
|
|
23
|
+
batchSize: number;
|
|
24
|
+
/**
|
|
25
|
+
* Mostly for testing.
|
|
26
|
+
*/
|
|
27
|
+
collection?: string;
|
|
28
|
+
logger?: Logger;
|
|
29
|
+
tracer?: PerformanceTracer<'changestream'>;
|
|
30
|
+
}
|
|
31
|
+
export interface ChangeStreamBatch {
|
|
32
|
+
resumeToken: mongo.ResumeToken;
|
|
33
|
+
events: Buffer[];
|
|
34
|
+
/**
|
|
35
|
+
* Size in bytes of this event.
|
|
36
|
+
*/
|
|
37
|
+
byteSize: number;
|
|
38
|
+
}
|
|
39
|
+
export declare function rawChangeStream(db: mongo.Db, pipeline: mongo.Document[], options: RawChangeStreamOptions): AsyncGenerator<ChangeStreamBatch, void, unknown>;
|
|
40
|
+
export type ProjectedChangeStreamDocument = Omit<mongo.ChangeStreamDropDocument, 'wallTime' | 'collectionUUID'> | Omit<mongo.ChangeStreamRenameDocument, 'wallTime'> | Omit<mongo.ChangeStreamDeleteDocument<Buffer>, 'wallTime'> | Omit<mongo.ChangeStreamInsertDocument<Buffer>, 'wallTime'> | Omit<mongo.ChangeStreamUpdateDocument<Buffer>, 'wallTime' | 'updateDescription'> | Omit<mongo.ChangeStreamReplaceDocument<Buffer>, 'wallTime'>;
|
|
41
|
+
/**
|
|
42
|
+
* Parse a change stream document, while keeping `fullDocument` as a Buffer.
|
|
43
|
+
*
|
|
44
|
+
* @param Buffer the raw change stream document
|
|
45
|
+
*/
|
|
46
|
+
export declare function parseChangeDocument(buffer: Buffer): ProjectedChangeStreamDocument;
|
|
47
|
+
export declare function mapChangeStreamError(e: unknown): void;
|
|
48
|
+
/**
|
|
49
|
+
* Get the "collection" from a ns.
|
|
50
|
+
*
|
|
51
|
+
* This drops everything before the first . character.
|
|
52
|
+
*
|
|
53
|
+
* "my_db_name.$cmd.aggregate" -> "$cmd.aggregate"
|
|
54
|
+
*/
|
|
55
|
+
export declare function namespaceCollection(ns: string): string;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { isMongoNetworkTimeoutError, isMongoServerError, mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
+
import { DatabaseConnectionError, ErrorCode, ReplicationAssertionError } from '@powersync/lib-services-framework';
|
|
3
|
+
import { ChangeStreamInvalidatedError } from './ChangeStream.js';
|
|
4
|
+
const deserialize = mongo.BSON.deserialize;
|
|
5
|
+
const DESERIALIZE_DEFAULT = { useBigInt64: true };
|
|
6
|
+
const DESERIALIZE_RAW = {
|
|
7
|
+
...DESERIALIZE_DEFAULT,
|
|
8
|
+
raw: true,
|
|
9
|
+
// No need to validate utf8 for the core change stream fields
|
|
10
|
+
validation: { utf8: false }
|
|
11
|
+
};
|
|
12
|
+
const DESERIALIZE_CHANGE_STREAM = {
|
|
13
|
+
...DESERIALIZE_DEFAULT,
|
|
14
|
+
// These are embedded _arrays_ that we want to preserve as buffers
|
|
15
|
+
fieldsAsRaw: { firstBatch: true, nextBatch: true },
|
|
16
|
+
// No need to validate utf8 for the core change stream response
|
|
17
|
+
validation: { utf8: false }
|
|
18
|
+
};
|
|
19
|
+
export async function* rawChangeStream(db, pipeline, options) {
|
|
20
|
+
// We generally attempt to follow the spec at: https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md
|
|
21
|
+
// Intentional differences:
|
|
22
|
+
// 1. We don't attempt to follow the client API.
|
|
23
|
+
// 2. We require that `postBatchResumeToken` is present.
|
|
24
|
+
// 3. We don't attempt to handle resumeToken from individual documents - the consumer can handle that.
|
|
25
|
+
if (!('$changeStream' in pipeline[0])) {
|
|
26
|
+
throw new ReplicationAssertionError(`First pipeline stage must be $changeStream`);
|
|
27
|
+
}
|
|
28
|
+
let lastResumeToken = null;
|
|
29
|
+
const batchSizer = new AdaptiveBatchSize(options.batchSize);
|
|
30
|
+
// > If the server supports sessions, the resume attempt MUST use the same session as the previous attempt's command.
|
|
31
|
+
const session = db.client.startSession();
|
|
32
|
+
await using _ = { [Symbol.asyncDispose]: () => session.endSession() };
|
|
33
|
+
while (true) {
|
|
34
|
+
options.signal?.throwIfAborted();
|
|
35
|
+
try {
|
|
36
|
+
let innerPipeline = pipeline;
|
|
37
|
+
if (lastResumeToken != null) {
|
|
38
|
+
const [first, ...rest] = pipeline;
|
|
39
|
+
const changeStreamStage = { ...first.$changeStream };
|
|
40
|
+
delete changeStreamStage.startAtOperationTime;
|
|
41
|
+
delete changeStreamStage.startAfter;
|
|
42
|
+
changeStreamStage.resumeAfter = lastResumeToken;
|
|
43
|
+
innerPipeline = [{ $changeStream: changeStreamStage }, ...rest];
|
|
44
|
+
}
|
|
45
|
+
const inner = rawChangeStreamInner(session, db, innerPipeline, {
|
|
46
|
+
...options
|
|
47
|
+
}, batchSizer);
|
|
48
|
+
for await (let batch of inner) {
|
|
49
|
+
yield batch;
|
|
50
|
+
lastResumeToken = batch.resumeToken;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (e) {
|
|
54
|
+
if (e instanceof ResumableChangeStreamError) {
|
|
55
|
+
// This is only triggered on the getMore command.
|
|
56
|
+
// If there is a persistent error, we expect it to occur on the aggregate command as well,
|
|
57
|
+
// which will trigger a hard error on the next attempt.
|
|
58
|
+
// This matches the change stream spec of:
|
|
59
|
+
// > A change stream MUST attempt to resume a single time if it encounters any resumable error per Resumable Error. A change stream MUST NOT attempt to resume on any other type of error.
|
|
60
|
+
// > An error on an aggregate command is not a resumable error. Only errors on a getMore command may be considered resumable errors.
|
|
61
|
+
// https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md#resume-process
|
|
62
|
+
// Technically we don't _need_ this resume functionality - we can let the replication job handle the failure
|
|
63
|
+
// and restart. However, this provides a faster restart path in common cases.
|
|
64
|
+
options.logger?.warn(`Resumable change stream error, retrying: ${e.message}`, e.cause);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
throw e;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function* rawChangeStreamInner(session, db, pipeline, options, batchSizer) {
|
|
74
|
+
// See specs:
|
|
75
|
+
// https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md
|
|
76
|
+
let cursorId = null;
|
|
77
|
+
/**
|
|
78
|
+
* Typically '$cmd.aggregate', but we need to use the ns from the cursor.
|
|
79
|
+
*/
|
|
80
|
+
let nsCollection = null;
|
|
81
|
+
const collection = options.collection ?? 1;
|
|
82
|
+
let abortPromise = null;
|
|
83
|
+
const onAbort = () => {
|
|
84
|
+
if (cursorId != null && cursorId !== 0n && nsCollection != null) {
|
|
85
|
+
// This would result in a CursorKilled error.
|
|
86
|
+
abortPromise = db
|
|
87
|
+
.command({
|
|
88
|
+
killCursors: nsCollection,
|
|
89
|
+
cursors: [cursorId]
|
|
90
|
+
})
|
|
91
|
+
.catch(() => { });
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
options.signal?.addEventListener('abort', onAbort);
|
|
95
|
+
try {
|
|
96
|
+
{
|
|
97
|
+
using aggregateSpan = options.tracer?.span('changestream', 'aggregate');
|
|
98
|
+
// Step 1: Send the aggregate command to start the change stream
|
|
99
|
+
const aggregateResult = await db
|
|
100
|
+
.command({
|
|
101
|
+
aggregate: collection,
|
|
102
|
+
pipeline,
|
|
103
|
+
cursor: {
|
|
104
|
+
// Always use batchSize of 1 for the initial aggregate command,
|
|
105
|
+
// to maximize the chance of success in case of timeouts.
|
|
106
|
+
batchSize: 1
|
|
107
|
+
},
|
|
108
|
+
maxTimeMS: options.maxTimeMS
|
|
109
|
+
}, { session, raw: true })
|
|
110
|
+
.catch((e) => {
|
|
111
|
+
throw mapChangeStreamError(e);
|
|
112
|
+
});
|
|
113
|
+
aggregateSpan?.end();
|
|
114
|
+
const cursor = deserialize(aggregateResult.cursor, DESERIALIZE_CHANGE_STREAM);
|
|
115
|
+
cursorId = BigInt(cursor.id);
|
|
116
|
+
nsCollection = namespaceCollection(cursor.ns);
|
|
117
|
+
let batch = cursor.firstBatch;
|
|
118
|
+
if (cursor.postBatchResumeToken == null) {
|
|
119
|
+
// Deviation from spec: We require that the server always returns a postBatchResumeToken.
|
|
120
|
+
// postBatchResumeToken is returned in MongoDB 4.0.7 and later, and we support 6.0+
|
|
121
|
+
throw new ReplicationAssertionError(`postBatchResumeToken from aggregate response`);
|
|
122
|
+
}
|
|
123
|
+
yield {
|
|
124
|
+
events: batch,
|
|
125
|
+
resumeToken: cursor.postBatchResumeToken,
|
|
126
|
+
byteSize: aggregateResult.cursor.byteLength
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
// Step 2: Poll using getMore until the cursor is closed
|
|
130
|
+
while (cursorId && cursorId !== 0n) {
|
|
131
|
+
options.signal?.throwIfAborted();
|
|
132
|
+
using commandSpan = options.tracer?.span('changestream', 'getmore');
|
|
133
|
+
const getMoreResult = await db
|
|
134
|
+
.command({
|
|
135
|
+
getMore: cursorId,
|
|
136
|
+
collection: nsCollection,
|
|
137
|
+
batchSize: batchSizer.next(),
|
|
138
|
+
maxTimeMS: options.maxAwaitTimeMS
|
|
139
|
+
}, { session, raw: true })
|
|
140
|
+
.catch((e) => {
|
|
141
|
+
if (isMongoServerError(e) && e.codeName == 'CursorKilled') {
|
|
142
|
+
// This may be due to the killCursors command issued when aborting.
|
|
143
|
+
// In that case, use the abort error instead.
|
|
144
|
+
options.signal?.throwIfAborted();
|
|
145
|
+
}
|
|
146
|
+
if (isResumableChangeStreamError(e)) {
|
|
147
|
+
if (isTimeoutError(e)) {
|
|
148
|
+
batchSizer.reduceAfterError();
|
|
149
|
+
}
|
|
150
|
+
throw new ResumableChangeStreamError(e.message, { cause: e });
|
|
151
|
+
}
|
|
152
|
+
throw mapChangeStreamError(e);
|
|
153
|
+
});
|
|
154
|
+
commandSpan?.end();
|
|
155
|
+
const cursor = deserialize(getMoreResult.cursor, DESERIALIZE_CHANGE_STREAM);
|
|
156
|
+
cursorId = BigInt(cursor.id);
|
|
157
|
+
const nextBatch = cursor.nextBatch;
|
|
158
|
+
if (cursor.postBatchResumeToken == null) {
|
|
159
|
+
// Deviation from spec: We require that the server always returns a postBatchResumeToken.
|
|
160
|
+
// postBatchResumeToken is returned in MongoDB 4.0.7 and later, and we support 6.0+
|
|
161
|
+
throw new ReplicationAssertionError(`postBatchResumeToken from aggregate response`);
|
|
162
|
+
}
|
|
163
|
+
yield {
|
|
164
|
+
events: nextBatch,
|
|
165
|
+
resumeToken: cursor.postBatchResumeToken,
|
|
166
|
+
byteSize: getMoreResult.cursor.byteLength
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
options.signal?.throwIfAborted();
|
|
170
|
+
throw new ReplicationAssertionError(`Change stream ended unexpectedly`);
|
|
171
|
+
}
|
|
172
|
+
finally {
|
|
173
|
+
options.signal?.removeEventListener('abort', onAbort);
|
|
174
|
+
if (abortPromise != null) {
|
|
175
|
+
// killCursors is already sent - we wait for the response in abortPromise.
|
|
176
|
+
await abortPromise;
|
|
177
|
+
}
|
|
178
|
+
else if (cursorId != null && cursorId !== 0n && nsCollection != null) {
|
|
179
|
+
await db
|
|
180
|
+
.command({
|
|
181
|
+
killCursors: nsCollection,
|
|
182
|
+
cursors: [cursorId]
|
|
183
|
+
})
|
|
184
|
+
.catch(() => { });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
class ResumableChangeStreamError extends Error {
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* After a timeout error, we reduce the batch size to this number, then multiply by this for each batch.
|
|
192
|
+
*
|
|
193
|
+
* Must be an integer >= 2 with the current implementation.
|
|
194
|
+
*/
|
|
195
|
+
const BATCH_SIZE_MULTIPLIER = 2;
|
|
196
|
+
/**
|
|
197
|
+
* Manage batch sizes after timeout errors.
|
|
198
|
+
*
|
|
199
|
+
* This starts with the initial batch size.
|
|
200
|
+
*
|
|
201
|
+
* After a timeout error, we reduce the batch size for aggregate command to 1,
|
|
202
|
+
* then multiply by BATCH_SIZE_MULTIPLIER for each subsequent batch, until we reach the initial batch size again.
|
|
203
|
+
*
|
|
204
|
+
* We use this to protect against timeout errors:
|
|
205
|
+
* [PSYNC_S1345] Timeout while reading MongoDB ChangeStream
|
|
206
|
+
*
|
|
207
|
+
* When we run into that, the stream is restarted automatically. starting with an aggregate command
|
|
208
|
+
* with batchSize: 1.
|
|
209
|
+
*
|
|
210
|
+
* We then ramp up the batchSize for getMore commands.
|
|
211
|
+
*/
|
|
212
|
+
class AdaptiveBatchSize {
|
|
213
|
+
maxBatchSize;
|
|
214
|
+
nextBatchSize;
|
|
215
|
+
constructor(maxBatchSize) {
|
|
216
|
+
this.maxBatchSize = maxBatchSize;
|
|
217
|
+
this.nextBatchSize = maxBatchSize;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Get the next batchSize for a getMore command.
|
|
221
|
+
*/
|
|
222
|
+
next() {
|
|
223
|
+
const current = this.nextBatchSize;
|
|
224
|
+
this.nextBatchSize = Math.min(this.maxBatchSize, this.nextBatchSize * BATCH_SIZE_MULTIPLIER);
|
|
225
|
+
return current;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* After a timeout error, the next aggregate command will start with a batchSize of 1.
|
|
229
|
+
*
|
|
230
|
+
* The next getMore will then have a batchSize of BATCH_SIZE_MULTIPLIER.
|
|
231
|
+
*/
|
|
232
|
+
reduceAfterError() {
|
|
233
|
+
this.nextBatchSize = BATCH_SIZE_MULTIPLIER;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Parse a change stream document, while keeping `fullDocument` as a Buffer.
|
|
238
|
+
*
|
|
239
|
+
* @param Buffer the raw change stream document
|
|
240
|
+
*/
|
|
241
|
+
export function parseChangeDocument(buffer) {
|
|
242
|
+
const doc = deserialize(buffer, DESERIALIZE_RAW);
|
|
243
|
+
// We update the document in-place
|
|
244
|
+
doc._id = deserialize(doc._id, DESERIALIZE_DEFAULT);
|
|
245
|
+
if (doc.lsid != null) {
|
|
246
|
+
doc.lsid = deserialize(doc.lsid, DESERIALIZE_DEFAULT);
|
|
247
|
+
}
|
|
248
|
+
if (doc.splitEvent != null) {
|
|
249
|
+
doc.splitEvent = deserialize(doc.splitEvent, DESERIALIZE_DEFAULT);
|
|
250
|
+
}
|
|
251
|
+
if ('ns' in doc) {
|
|
252
|
+
doc.ns = deserialize(doc.ns, DESERIALIZE_DEFAULT);
|
|
253
|
+
}
|
|
254
|
+
if ('to' in doc) {
|
|
255
|
+
doc.to = deserialize(doc.to, DESERIALIZE_DEFAULT);
|
|
256
|
+
}
|
|
257
|
+
if ('documentKey' in doc) {
|
|
258
|
+
doc.documentKey = deserialize(doc.documentKey, DESERIALIZE_DEFAULT);
|
|
259
|
+
}
|
|
260
|
+
return doc;
|
|
261
|
+
}
|
|
262
|
+
function isTimeoutError(e) {
|
|
263
|
+
return isMongoNetworkTimeoutError(e) || (isMongoServerError(e) && e.codeName == 'MaxTimeMSExpired');
|
|
264
|
+
}
|
|
265
|
+
function isResumableChangeStreamError(e) {
|
|
266
|
+
// See: https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md#resumable-error
|
|
267
|
+
if (!isMongoServerError(e)) {
|
|
268
|
+
// Any error encountered which is not a server error (e.g. a socket timeout error or network error)
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
else if (e.codeName == 'CursorNotFound') {
|
|
272
|
+
// A server error with code 43 (CursorNotFound)
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
else if (e.hasErrorLabel('ResumableChangeStreamError')) {
|
|
276
|
+
// For servers with wire version 9 or higher (server version 4.4 or higher), any server error with the ResumableChangeStreamError error label.
|
|
277
|
+
return true;
|
|
278
|
+
}
|
|
279
|
+
else if (e.codeName == 'MaxTimeMSExpired') {
|
|
280
|
+
// Our own exception for MaxTimeMSExpired.
|
|
281
|
+
// This can help us retry faster, with a smaller batch size (if initialBatchSize is set to 1), which should hopefully avoid the timeout.
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
// Other errors are not retried.
|
|
286
|
+
// We ignore the spec for servers with wire version less than 9, since we only support MongoDB 6.0+.
|
|
287
|
+
return false;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
export function mapChangeStreamError(e) {
|
|
291
|
+
if (isTimeoutError(e)) {
|
|
292
|
+
// For isMongoNetworkTimeoutError():
|
|
293
|
+
// This typically has an unhelpful message like "connection 2 to 159.41.94.47:27017 timed out".
|
|
294
|
+
// We wrap the error to make it more useful.
|
|
295
|
+
// Example for MaxTimeMSExpired:
|
|
296
|
+
// MongoServerError: Executor error during aggregate command on namespace: powersync_test_data.$cmd.aggregate :: caused by :: operation exceeded time limit
|
|
297
|
+
throw new DatabaseConnectionError(ErrorCode.PSYNC_S1345, `Timeout while reading MongoDB ChangeStream`, e);
|
|
298
|
+
}
|
|
299
|
+
else if (isMongoServerError(e) &&
|
|
300
|
+
e.codeName == 'NoMatchingDocument' &&
|
|
301
|
+
e.errmsg?.includes('post-image was not found')) {
|
|
302
|
+
throw new ChangeStreamInvalidatedError(e.errmsg, e);
|
|
303
|
+
}
|
|
304
|
+
else if (isMongoServerError(e) && e.hasErrorLabel('NonResumableChangeStreamError')) {
|
|
305
|
+
throw new ChangeStreamInvalidatedError(e.message, e);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
throw new DatabaseConnectionError(ErrorCode.PSYNC_S1346, `Error reading MongoDB ChangeStream`, e);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get the "collection" from a ns.
|
|
313
|
+
*
|
|
314
|
+
* This drops everything before the first . character.
|
|
315
|
+
*
|
|
316
|
+
* "my_db_name.$cmd.aggregate" -> "$cmd.aggregate"
|
|
317
|
+
*/
|
|
318
|
+
export function namespaceCollection(ns) {
|
|
319
|
+
const dot = ns.indexOf('.');
|
|
320
|
+
return ns.substring(dot + 1);
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=RawChangeStream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RawChangeStream.js","sourceRoot":"","sources":["../../src/replication/RawChangeStream.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
+
import { CompatibilityContext, SqliteRow } from '@powersync/service-sync-rules';
|
|
3
|
+
export interface SourceRowConverter {
|
|
4
|
+
/**
|
|
5
|
+
* Convert a Buffer, containing BSON document bytes, to a SqliteRow for use
|
|
6
|
+
* in sync config.
|
|
7
|
+
*
|
|
8
|
+
* The returned replicaId is the plain parsed bson _id value, to preserve the source id as-is.
|
|
9
|
+
*/
|
|
10
|
+
rawToSqliteRow(source: Buffer): {
|
|
11
|
+
row: SqliteRow;
|
|
12
|
+
replicaId: any;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Convert a document, as received from MongoDB query or change stream, to
|
|
16
|
+
* a SqliteRow for use in sync config.
|
|
17
|
+
*
|
|
18
|
+
* The document must be parsed using { useBigInt64: true }.
|
|
19
|
+
*
|
|
20
|
+
* @deprecated This is remaining as a helper for tests only.
|
|
21
|
+
*/
|
|
22
|
+
documentToSqliteRow(source: mongo.Document): SqliteRow;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Older converter using bson.deserialize -> constructAfterRecord -> applyRowContext.
|
|
26
|
+
*
|
|
27
|
+
* @deprecated Only used for parity testing
|
|
28
|
+
*/
|
|
29
|
+
export declare class LegacySourceRowConverter implements SourceRowConverter {
|
|
30
|
+
private readonly compatibilityContext;
|
|
31
|
+
constructor(compatibilityContext: CompatibilityContext);
|
|
32
|
+
rawToSqliteRow(source: Buffer): {
|
|
33
|
+
row: SqliteRow;
|
|
34
|
+
replicaId: any;
|
|
35
|
+
};
|
|
36
|
+
documentToSqliteRow(document: mongo.Document): SqliteRow;
|
|
37
|
+
}
|
|
38
|
+
export declare class DirectSourceRowConverter implements SourceRowConverter {
|
|
39
|
+
private readonly dateRenderMode;
|
|
40
|
+
constructor(compatibilityContext: CompatibilityContext);
|
|
41
|
+
rawToSqliteRow(source: Buffer): {
|
|
42
|
+
row: SqliteRow;
|
|
43
|
+
replicaId: any;
|
|
44
|
+
};
|
|
45
|
+
documentToSqliteRow(document: mongo.Document): SqliteRow;
|
|
46
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { mongo } from '@powersync/lib-service-mongodb';
|
|
2
|
+
import { applyRowContext } from '@powersync/service-sync-rules';
|
|
3
|
+
import { bufferToSqlite, getDateRenderMode, parseDocumentId } from './bufferToSqlite.js';
|
|
4
|
+
import { constructAfterRecord } from './MongoRelation.js';
|
|
5
|
+
/**
|
|
6
|
+
* Older converter using bson.deserialize -> constructAfterRecord -> applyRowContext.
|
|
7
|
+
*
|
|
8
|
+
* @deprecated Only used for parity testing
|
|
9
|
+
*/
|
|
10
|
+
export class LegacySourceRowConverter {
|
|
11
|
+
compatibilityContext;
|
|
12
|
+
constructor(compatibilityContext) {
|
|
13
|
+
this.compatibilityContext = compatibilityContext;
|
|
14
|
+
}
|
|
15
|
+
rawToSqliteRow(source) {
|
|
16
|
+
const parsed = mongo.BSON.deserialize(source, { useBigInt64: true });
|
|
17
|
+
const row = this.documentToSqliteRow(parsed);
|
|
18
|
+
const replicaId = parsed._id;
|
|
19
|
+
return { row, replicaId };
|
|
20
|
+
}
|
|
21
|
+
documentToSqliteRow(document) {
|
|
22
|
+
const input = constructAfterRecord(document);
|
|
23
|
+
return applyRowContext(input, this.compatibilityContext);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export class DirectSourceRowConverter {
|
|
27
|
+
dateRenderMode;
|
|
28
|
+
constructor(compatibilityContext) {
|
|
29
|
+
this.dateRenderMode = getDateRenderMode(compatibilityContext);
|
|
30
|
+
}
|
|
31
|
+
rawToSqliteRow(source) {
|
|
32
|
+
const row = bufferToSqlite(source, this.dateRenderMode);
|
|
33
|
+
const replicaId = parseDocumentId(source).id;
|
|
34
|
+
return { row, replicaId };
|
|
35
|
+
}
|
|
36
|
+
documentToSqliteRow(document) {
|
|
37
|
+
// This is slow, but should not be used other than in tests
|
|
38
|
+
const buffer = mongo.BSON.serialize(document);
|
|
39
|
+
return this.rawToSqliteRow(buffer).row;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=SourceRowConverter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SourceRowConverter.js","sourceRoot":"","sources":["../../src/replication/SourceRowConverter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gCAAgC,CAAC;AACvD,OAAO,EAAE,eAAe,EAAmC,MAAM,+BAA+B,CAAC;AACjG,OAAO,EAAE,cAAc,EAAkB,iBAAiB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACzG,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAsB1D;;;;GAIG;AACH,MAAM,OAAO,wBAAwB;IACN;IAA7B,YAA6B,oBAA0C;QAA1C,yBAAoB,GAApB,oBAAoB,CAAsB;IAAG,CAAC;IAE3E,cAAc,CAAC,MAAc;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC;QAC7B,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;IAC5B,CAAC;IAED,mBAAmB,CAAC,QAAwB;QAC1C,MAAM,KAAK,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,eAAe,CAAQ,KAAK,EAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAClE,CAAC;CACF;AAED,MAAM,OAAO,wBAAwB;IAClB,cAAc,CAAiB;IAEhD,YAAY,oBAA0C;QACpD,IAAI,CAAC,cAAc,GAAG,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;IAChE,CAAC;IAED,cAAc,CAAC,MAAc;QAC3B,MAAM,GAAG,GAAG,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAC7C,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;IAC5B,CAAC;IAED,mBAAmB,CAAC,QAAwB;QAC1C,2DAA2D;QAC3D,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAW,CAAC;QACxD,OAAO,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC;IACzC,CAAC;CACF"}
|