@powersync/service-core 0.8.4 → 0.8.6
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 +19 -0
- package/dist/db/mongo.d.ts +6 -0
- package/dist/db/mongo.js +6 -0
- package/dist/db/mongo.js.map +1 -1
- package/dist/replication/WalStream.js +8 -4
- package/dist/replication/WalStream.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +0 -1
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/ChecksumCache.d.ts +19 -1
- package/dist/storage/ChecksumCache.js +8 -1
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/MongoBucketStorage.js +19 -9
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +1 -1
- package/dist/storage/mongo/MongoSyncBucketStorage.js +40 -21
- package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/mongo/db.d.ts +9 -0
- package/dist/storage/mongo/db.js +11 -0
- package/dist/storage/mongo/db.js.map +1 -1
- package/dist/storage/mongo/util.d.ts +1 -1
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/util/protocol-types.d.ts +0 -65
- package/dist/util/protocol-types.js +0 -7
- package/dist/util/protocol-types.js.map +1 -1
- package/dist/util/utils.d.ts +2 -1
- package/dist/util/utils.js +10 -3
- package/dist/util/utils.js.map +1 -1
- package/package.json +4 -4
- package/src/db/mongo.ts +7 -0
- package/src/replication/WalStream.ts +11 -4
- package/src/storage/BucketStorage.ts +0 -2
- package/src/storage/ChecksumCache.ts +32 -2
- package/src/storage/MongoBucketStorage.ts +18 -9
- package/src/storage/mongo/MongoSyncBucketStorage.ts +44 -29
- package/src/storage/mongo/db.ts +12 -0
- package/src/storage/mongo/util.ts +3 -3
- package/src/util/protocol-types.ts +0 -89
- package/src/util/utils.ts +13 -6
- package/test/src/checksum_cache.test.ts +27 -20
- package/test/src/compacting.test.ts +78 -0
- package/test/src/data_storage.test.ts +22 -0
- package/test/src/sync.test.ts +0 -7
- package/test/src/util.ts +14 -3
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/storage/mongo/db.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAY3C,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAUrD,MAAM,UAAU,oBAAoB,CAAC,MAA6C;IAChF,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,OAAO,cAAc;IAczB,YAAY,MAAyB,EAAE,OAA+B;QACpE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE;YACtC,GAAG,wBAAwB;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QAEb,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,UAAU,CAAsB,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QAChD,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;QACpD,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../../src/storage/mongo/db.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAY3C,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAUrD,MAAM,UAAU,oBAAoB,CAAC,MAA6C;IAChF,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,OAAO,cAAc;IAczB,YAAY,MAAyB,EAAE,OAA+B;QACpE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QAErB,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE;YACtC,GAAG,wBAAwB;SAC5B,CAAC,CAAC;QACH,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QAEb,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC,UAAU,CAAsB,cAAc,CAAC,CAAC;QACvE,IAAI,CAAC,WAAW,GAAG,EAAE,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;QAChD,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,GAAG,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;QACpD,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACvC,MAAM,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACtC,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACzC,MAAM,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACrC,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACxC,MAAM,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QAC5C,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAClC,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAClC,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,IAAI;QACR,MAAM,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;IAC/B,CAAC;CACF"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { SqliteJsonValue } from '@powersync/service-sync-rules';
|
|
2
2
|
import * as bson from 'bson';
|
|
3
3
|
import * as mongo from 'mongodb';
|
|
4
|
-
import { BucketDataDocument } from './models.js';
|
|
5
4
|
import { OplogEntry } from '../../util/protocol-types.js';
|
|
5
|
+
import { BucketDataDocument } from './models.js';
|
|
6
6
|
/**
|
|
7
7
|
* Lookup serialization must be number-agnostic. I.e. normalize numbers, instead of preserving numbers.
|
|
8
8
|
* @param lookup
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/storage/mongo/util.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../../src/storage/mongo/util.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,46 +1,5 @@
|
|
|
1
1
|
import * as t from 'ts-codec';
|
|
2
2
|
import { SqliteJsonValue } from '@powersync/service-sync-rules';
|
|
3
|
-
/**
|
|
4
|
-
* For sync2.json
|
|
5
|
-
*/
|
|
6
|
-
export interface ContinueCheckpointRequest {
|
|
7
|
-
/**
|
|
8
|
-
* Existing bucket states. Only these buckets are synchronized.
|
|
9
|
-
*/
|
|
10
|
-
buckets: BucketRequest[];
|
|
11
|
-
checkpoint_token: string;
|
|
12
|
-
limit?: number;
|
|
13
|
-
}
|
|
14
|
-
export interface SyncNewCheckpointRequest {
|
|
15
|
-
/**
|
|
16
|
-
* Existing bucket states. Used if include_data is specified.
|
|
17
|
-
*/
|
|
18
|
-
buckets?: BucketRequest[];
|
|
19
|
-
request_checkpoint: {
|
|
20
|
-
/**
|
|
21
|
-
* Whether or not to include an initial data request.
|
|
22
|
-
*/
|
|
23
|
-
include_data: boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Whether or not to compute a checksum.
|
|
26
|
-
*/
|
|
27
|
-
include_checksum: boolean;
|
|
28
|
-
};
|
|
29
|
-
limit?: number;
|
|
30
|
-
}
|
|
31
|
-
export type SyncRequest = ContinueCheckpointRequest | SyncNewCheckpointRequest;
|
|
32
|
-
export interface SyncResponse {
|
|
33
|
-
/**
|
|
34
|
-
* Data for the buckets returned. May not have an an entry for each bucket in the request.
|
|
35
|
-
*/
|
|
36
|
-
data?: SyncBucketData[];
|
|
37
|
-
/**
|
|
38
|
-
* True if the response limit has been reached, and another request must be made.
|
|
39
|
-
*/
|
|
40
|
-
has_more: boolean;
|
|
41
|
-
checkpoint_token?: string;
|
|
42
|
-
checkpoint?: Checkpoint;
|
|
43
|
-
}
|
|
44
3
|
export declare const BucketRequest: t.ObjectCodec<{
|
|
45
4
|
name: t.IdentityCodec<t.CodecType.String>;
|
|
46
5
|
/**
|
|
@@ -160,27 +119,3 @@ export interface BucketChecksum {
|
|
|
160
119
|
*/
|
|
161
120
|
count: number;
|
|
162
121
|
}
|
|
163
|
-
export declare function isContinueCheckpointRequest(request: SyncRequest): request is ContinueCheckpointRequest;
|
|
164
|
-
export declare function isSyncNewCheckpointRequest(request: SyncRequest): request is SyncNewCheckpointRequest;
|
|
165
|
-
/**
|
|
166
|
-
* For crud.json
|
|
167
|
-
*/
|
|
168
|
-
export interface CrudRequest {
|
|
169
|
-
data: CrudEntry[];
|
|
170
|
-
}
|
|
171
|
-
export interface CrudEntry {
|
|
172
|
-
op: 'PUT' | 'PATCH' | 'DELETE';
|
|
173
|
-
type: string;
|
|
174
|
-
id: string;
|
|
175
|
-
data: string;
|
|
176
|
-
}
|
|
177
|
-
export interface CrudResponse {
|
|
178
|
-
/**
|
|
179
|
-
* A sync response with a checkpoint >= this checkpoint would contain all the changes in this request.
|
|
180
|
-
*
|
|
181
|
-
* Any earlier checkpoint may or may not contain these changes.
|
|
182
|
-
*
|
|
183
|
-
* May be empty when the request contains no ops.
|
|
184
|
-
*/
|
|
185
|
-
checkpoint?: OpId;
|
|
186
|
-
}
|
|
@@ -36,11 +36,4 @@ export const StreamingSyncRequest = t.object({
|
|
|
36
36
|
*/
|
|
37
37
|
client_id: t.string.optional()
|
|
38
38
|
});
|
|
39
|
-
export function isContinueCheckpointRequest(request) {
|
|
40
|
-
return (Array.isArray(request.buckets) &&
|
|
41
|
-
typeof request.checkpoint_token == 'string');
|
|
42
|
-
}
|
|
43
|
-
export function isSyncNewCheckpointRequest(request) {
|
|
44
|
-
return typeof request.request_checkpoint == 'object';
|
|
45
|
-
}
|
|
46
39
|
//# sourceMappingURL=protocol-types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"protocol-types.js","sourceRoot":"","sources":["../../src/util/protocol-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"protocol-types.js","sourceRoot":"","sources":["../../src/util/protocol-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAG9B,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC,CAAC,MAAM;IAEd;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC,MAAM;CAChB,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C;;OAEG;IACH,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;IAE1C;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;IAElC;;OAEG;IACH,gBAAgB,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;IAEtC;;OAEG;IACH,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;IAE9B;;OAEG;IACH,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE;IAEjC;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAEtC;;OAEG;IACH,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;CAC/B,CAAC,CAAC"}
|
package/dist/util/utils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as pgwire from '@powersync/service-jpgwire';
|
|
2
|
+
import { PartialChecksum } from '../storage/ChecksumCache.js';
|
|
2
3
|
import * as storage from '../storage/storage-index.js';
|
|
3
4
|
import { BucketChecksum, OpId } from './protocol-types.js';
|
|
4
5
|
export type ChecksumMap = Map<string, BucketChecksum>;
|
|
@@ -10,7 +11,7 @@ export declare function checksumsDiff(previous: ChecksumMap, current: ChecksumMa
|
|
|
10
11
|
removedBuckets: string[];
|
|
11
12
|
};
|
|
12
13
|
export declare function addChecksums(a: number, b: number): number;
|
|
13
|
-
export declare function addBucketChecksums(a: BucketChecksum, b:
|
|
14
|
+
export declare function addBucketChecksums(a: BucketChecksum, b: PartialChecksum | null): BucketChecksum;
|
|
14
15
|
export declare function getClientCheckpoint(db: pgwire.PgClient, bucketStorage: storage.BucketStorageFactory, options?: {
|
|
15
16
|
timeout?: number;
|
|
16
17
|
}): Promise<OpId>;
|
package/dist/util/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
2
3
|
import { pgwireRows } from '@powersync/service-jpgwire';
|
|
3
4
|
import { retriedQuery } from './pgwire_utils.js';
|
|
4
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
5
5
|
export function hashData(type, id, data) {
|
|
6
6
|
const hash = crypto.createHash('sha256');
|
|
7
7
|
hash.update(`put.${type}.${id}.${data}`);
|
|
@@ -55,11 +55,18 @@ export function addBucketChecksums(a, b) {
|
|
|
55
55
|
if (b == null) {
|
|
56
56
|
return a;
|
|
57
57
|
}
|
|
58
|
+
else if (b.isFullChecksum) {
|
|
59
|
+
return {
|
|
60
|
+
bucket: b.bucket,
|
|
61
|
+
count: b.partialCount,
|
|
62
|
+
checksum: b.partialChecksum
|
|
63
|
+
};
|
|
64
|
+
}
|
|
58
65
|
else {
|
|
59
66
|
return {
|
|
60
67
|
bucket: a.bucket,
|
|
61
|
-
count: a.count + b.
|
|
62
|
-
checksum: addChecksums(a.checksum, b.
|
|
68
|
+
count: a.count + b.partialCount,
|
|
69
|
+
checksum: addChecksums(a.checksum, b.partialChecksum)
|
|
63
70
|
};
|
|
64
71
|
}
|
|
65
72
|
}
|
package/dist/util/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/util/utils.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/util/utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|
|
8
|
-
"version": "0.8.
|
|
8
|
+
"version": "0.8.6",
|
|
9
9
|
"main": "dist/index.js",
|
|
10
10
|
"license": "FSL-1.1-Apache-2.0",
|
|
11
11
|
"type": "module",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"winston": "^3.13.0",
|
|
35
35
|
"yaml": "^2.3.2",
|
|
36
36
|
"@powersync/lib-services-framework": "0.1.1",
|
|
37
|
-
"@powersync/service-rsocket-router": "0.0.13",
|
|
38
|
-
"@powersync/service-jsonbig": "0.17.10",
|
|
39
37
|
"@powersync/service-jpgwire": "0.17.14",
|
|
40
|
-
"@powersync/service-
|
|
38
|
+
"@powersync/service-jsonbig": "0.17.10",
|
|
39
|
+
"@powersync/service-rsocket-router": "0.0.13",
|
|
40
|
+
"@powersync/service-sync-rules": "0.20.0",
|
|
41
41
|
"@powersync/service-types": "0.2.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
package/src/db/mongo.ts
CHANGED
|
@@ -22,6 +22,13 @@ export const MONGO_SOCKET_TIMEOUT_MS = 60_000;
|
|
|
22
22
|
*/
|
|
23
23
|
export const MONGO_OPERATION_TIMEOUT_MS = 30_000;
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Same as above, but specifically for clear operations.
|
|
27
|
+
*
|
|
28
|
+
* These are retried when reaching the timeout.
|
|
29
|
+
*/
|
|
30
|
+
export const MONGO_CLEAR_OPERATION_TIMEOUT_MS = 5_000;
|
|
31
|
+
|
|
25
32
|
export function createMongoClient(config: configFile.PowerSyncConfig['storage']) {
|
|
26
33
|
return new mongo.MongoClient(config.uri, {
|
|
27
34
|
auth: {
|
|
@@ -209,15 +209,22 @@ export class WalStream {
|
|
|
209
209
|
// We peek a large number of changes here, to make it more likely to pick up replication slot errors.
|
|
210
210
|
// For example, "publication does not exist" only occurs here if the peek actually includes changes related
|
|
211
211
|
// to the slot.
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
212
|
+
logger.info(`Checking ${slotName}`);
|
|
213
|
+
|
|
214
|
+
// The actual results can be quite large, so we don't actually return everything
|
|
215
|
+
// due to memory and processing overhead that would create.
|
|
216
|
+
const cursor = await this.connections.pool.stream({
|
|
217
|
+
statement: `SELECT 1 FROM pg_catalog.pg_logical_slot_peek_binary_changes($1, NULL, 1000, 'proto_version', '1', 'publication_names', $2)`,
|
|
216
218
|
params: [
|
|
217
219
|
{ type: 'varchar', value: slotName },
|
|
218
220
|
{ type: 'varchar', value: this.publication_name }
|
|
219
221
|
]
|
|
220
222
|
});
|
|
223
|
+
|
|
224
|
+
for await (let _chunk of cursor) {
|
|
225
|
+
// No-op, just exhaust the cursor
|
|
226
|
+
}
|
|
227
|
+
|
|
221
228
|
// Success
|
|
222
229
|
logger.info(`Slot ${slotName} appears healthy`);
|
|
223
230
|
return { needsInitialSync: false };
|
|
@@ -8,13 +8,34 @@ interface ChecksumFetchContext {
|
|
|
8
8
|
checkpoint: bigint;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
export interface PartialChecksum {
|
|
12
|
+
bucket: string;
|
|
13
|
+
/**
|
|
14
|
+
* 32-bit unsigned hash.
|
|
15
|
+
*/
|
|
16
|
+
partialChecksum: number;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Count of operations - informational only.
|
|
20
|
+
*/
|
|
21
|
+
partialCount: number;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* True if the queried operations contains (starts with) a CLEAR
|
|
25
|
+
* operation, indicating that the partial checksum is the full
|
|
26
|
+
* checksum, and must not be added to a previously-cached checksum.
|
|
27
|
+
*/
|
|
28
|
+
isFullChecksum: boolean;
|
|
29
|
+
}
|
|
11
30
|
export interface FetchPartialBucketChecksum {
|
|
12
31
|
bucket: string;
|
|
13
32
|
start?: OpId;
|
|
14
33
|
end: OpId;
|
|
15
34
|
}
|
|
16
35
|
|
|
17
|
-
export type
|
|
36
|
+
export type PartialChecksumMap = Map<string, PartialChecksum>;
|
|
37
|
+
|
|
38
|
+
export type FetchChecksums = (batch: FetchPartialBucketChecksum[]) => Promise<PartialChecksumMap>;
|
|
18
39
|
|
|
19
40
|
export interface ChecksumCacheOptions {
|
|
20
41
|
/**
|
|
@@ -33,6 +54,8 @@ export interface ChecksumCacheOptions {
|
|
|
33
54
|
// Approximately 5MB of memory, if we assume 50 bytes per entry
|
|
34
55
|
const DEFAULT_MAX_SIZE = 100_000;
|
|
35
56
|
|
|
57
|
+
const TTL_MS = 3_600_000;
|
|
58
|
+
|
|
36
59
|
/**
|
|
37
60
|
* Implement a LRU cache for checksum requests. Each (bucket, checkpoint) request is cached separately,
|
|
38
61
|
* while the lookups occur in batches.
|
|
@@ -93,7 +116,14 @@ export class ChecksumCache {
|
|
|
93
116
|
|
|
94
117
|
// When we have more fetches than the cache size, complete the fetches instead
|
|
95
118
|
// of failing with Error('evicted').
|
|
96
|
-
ignoreFetchAbort: true
|
|
119
|
+
ignoreFetchAbort: true,
|
|
120
|
+
|
|
121
|
+
// We use a TTL so that counts can eventually be refreshed
|
|
122
|
+
// after a compact. This only has effect if the bucket has
|
|
123
|
+
// not been checked in the meantime.
|
|
124
|
+
ttl: TTL_MS,
|
|
125
|
+
ttlResolution: 1_000,
|
|
126
|
+
allowStale: false
|
|
97
127
|
});
|
|
98
128
|
}
|
|
99
129
|
|
|
@@ -294,6 +294,15 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
async getStorageMetrics(): Promise<StorageMetrics> {
|
|
297
|
+
const ignoreNotExiting = (e: unknown) => {
|
|
298
|
+
if (e instanceof mongo.MongoServerError && e.codeName == 'NamespaceNotFound') {
|
|
299
|
+
// Collection doesn't exist - return 0
|
|
300
|
+
return [{ storageStats: { size: 0 } }];
|
|
301
|
+
} else {
|
|
302
|
+
return Promise.reject(e);
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
|
|
297
306
|
const active_sync_rules = await this.getActiveSyncRules();
|
|
298
307
|
if (active_sync_rules == null) {
|
|
299
308
|
return {
|
|
@@ -307,34 +316,34 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
307
316
|
.aggregate([
|
|
308
317
|
{
|
|
309
318
|
$collStats: {
|
|
310
|
-
storageStats: {}
|
|
311
|
-
count: {}
|
|
319
|
+
storageStats: {}
|
|
312
320
|
}
|
|
313
321
|
}
|
|
314
322
|
])
|
|
315
|
-
.toArray()
|
|
323
|
+
.toArray()
|
|
324
|
+
.catch(ignoreNotExiting);
|
|
316
325
|
|
|
317
326
|
const parameters_aggregate = await this.db.bucket_parameters
|
|
318
327
|
.aggregate([
|
|
319
328
|
{
|
|
320
329
|
$collStats: {
|
|
321
|
-
storageStats: {}
|
|
322
|
-
count: {}
|
|
330
|
+
storageStats: {}
|
|
323
331
|
}
|
|
324
332
|
}
|
|
325
333
|
])
|
|
326
|
-
.toArray()
|
|
334
|
+
.toArray()
|
|
335
|
+
.catch(ignoreNotExiting);
|
|
327
336
|
|
|
328
337
|
const replication_aggregate = await this.db.current_data
|
|
329
338
|
.aggregate([
|
|
330
339
|
{
|
|
331
340
|
$collStats: {
|
|
332
|
-
storageStats: {}
|
|
333
|
-
count: {}
|
|
341
|
+
storageStats: {}
|
|
334
342
|
}
|
|
335
343
|
}
|
|
336
344
|
])
|
|
337
|
-
.toArray()
|
|
345
|
+
.toArray()
|
|
346
|
+
.catch(ignoreNotExiting);
|
|
338
347
|
|
|
339
348
|
return {
|
|
340
349
|
operations_size_bytes: operations_aggregate[0].storageStats.size,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
SyncRulesBucketStorage,
|
|
19
19
|
SyncRuleStatus
|
|
20
20
|
} from '../BucketStorage.js';
|
|
21
|
-
import { ChecksumCache, FetchPartialBucketChecksum } from '../ChecksumCache.js';
|
|
21
|
+
import { ChecksumCache, FetchPartialBucketChecksum, PartialChecksum, PartialChecksumMap } from '../ChecksumCache.js';
|
|
22
22
|
import { MongoBucketStorage } from '../MongoBucketStorage.js';
|
|
23
23
|
import { SourceTable } from '../SourceTable.js';
|
|
24
24
|
import { PowerSyncMongo } from './db.js';
|
|
@@ -26,6 +26,8 @@ import { BucketDataDocument, BucketDataKey, SourceKey, SyncRuleState } from './m
|
|
|
26
26
|
import { MongoBucketBatch } from './MongoBucketBatch.js';
|
|
27
27
|
import { MongoCompactor } from './MongoCompactor.js';
|
|
28
28
|
import { BSON_DESERIALIZE_OPTIONS, idPrefixFilter, mapOpEntry, readSingleBatch, serializeLookup } from './util.js';
|
|
29
|
+
import { logger } from '@powersync/lib-services-framework';
|
|
30
|
+
import * as timers from 'timers/promises';
|
|
29
31
|
|
|
30
32
|
export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
31
33
|
private readonly db: PowerSyncMongo;
|
|
@@ -333,7 +335,7 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
333
335
|
return this.checksumCache.getChecksumMap(checkpoint, buckets);
|
|
334
336
|
}
|
|
335
337
|
|
|
336
|
-
private async getChecksumsInternal(batch: FetchPartialBucketChecksum[]): Promise<
|
|
338
|
+
private async getChecksumsInternal(batch: FetchPartialBucketChecksum[]): Promise<PartialChecksumMap> {
|
|
337
339
|
if (batch.length == 0) {
|
|
338
340
|
return new Map();
|
|
339
341
|
}
|
|
@@ -365,22 +367,32 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
365
367
|
}
|
|
366
368
|
},
|
|
367
369
|
{
|
|
368
|
-
$group: {
|
|
370
|
+
$group: {
|
|
371
|
+
_id: '$_id.b',
|
|
372
|
+
checksum_total: { $sum: '$checksum' },
|
|
373
|
+
count: { $sum: 1 },
|
|
374
|
+
has_clear_op: {
|
|
375
|
+
$max: {
|
|
376
|
+
$cond: [{ $eq: ['$op', 'CLEAR'] }, 1, 0]
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
369
380
|
}
|
|
370
381
|
],
|
|
371
|
-
{ session: undefined }
|
|
382
|
+
{ session: undefined, readConcern: 'snapshot' }
|
|
372
383
|
)
|
|
373
384
|
.toArray();
|
|
374
385
|
|
|
375
|
-
return new Map<string,
|
|
386
|
+
return new Map<string, PartialChecksum>(
|
|
376
387
|
aggregate.map((doc) => {
|
|
377
388
|
return [
|
|
378
389
|
doc._id,
|
|
379
390
|
{
|
|
380
391
|
bucket: doc._id,
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
392
|
+
partialCount: doc.count,
|
|
393
|
+
partialChecksum: Number(BigInt(doc.checksum_total) & 0xffffffffn) & 0xffffffff,
|
|
394
|
+
isFullChecksum: doc.has_clear_op == 1
|
|
395
|
+
} satisfies PartialChecksum
|
|
384
396
|
];
|
|
385
397
|
})
|
|
386
398
|
);
|
|
@@ -428,10 +440,28 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
428
440
|
}
|
|
429
441
|
|
|
430
442
|
async clear(): Promise<void> {
|
|
443
|
+
while (true) {
|
|
444
|
+
try {
|
|
445
|
+
await this.clearIteration();
|
|
446
|
+
return;
|
|
447
|
+
} catch (e: unknown) {
|
|
448
|
+
if (e instanceof mongo.MongoServerError && e.codeName == 'MaxTimeMSExpired') {
|
|
449
|
+
logger.info(
|
|
450
|
+
`Clearing took longer than ${db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS}ms, waiting and triggering another iteration.`
|
|
451
|
+
);
|
|
452
|
+
await timers.setTimeout(db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS / 5);
|
|
453
|
+
continue;
|
|
454
|
+
} else {
|
|
455
|
+
throw e;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private async clearIteration(): Promise<void> {
|
|
431
462
|
// Individual operations here may time out with the maxTimeMS option.
|
|
432
463
|
// It is expected to still make progress, and continue on the next try.
|
|
433
464
|
|
|
434
|
-
// TODO: Transactional?
|
|
435
465
|
await this.db.sync_rules.updateOne(
|
|
436
466
|
{
|
|
437
467
|
_id: this.group_id
|
|
@@ -445,48 +475,33 @@ export class MongoSyncBucketStorage implements SyncRulesBucketStorage {
|
|
|
445
475
|
no_checkpoint_before: null
|
|
446
476
|
}
|
|
447
477
|
},
|
|
448
|
-
{ maxTimeMS: db.mongo.
|
|
478
|
+
{ maxTimeMS: db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
449
479
|
);
|
|
450
480
|
await this.db.bucket_data.deleteMany(
|
|
451
481
|
{
|
|
452
482
|
_id: idPrefixFilter<BucketDataKey>({ g: this.group_id }, ['b', 'o'])
|
|
453
483
|
},
|
|
454
|
-
{ maxTimeMS: db.mongo.
|
|
484
|
+
{ maxTimeMS: db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
455
485
|
);
|
|
456
486
|
await this.db.bucket_parameters.deleteMany(
|
|
457
487
|
{
|
|
458
488
|
key: idPrefixFilter<SourceKey>({ g: this.group_id }, ['t', 'k'])
|
|
459
489
|
},
|
|
460
|
-
{ maxTimeMS: db.mongo.
|
|
490
|
+
{ maxTimeMS: db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
461
491
|
);
|
|
462
492
|
|
|
463
493
|
await this.db.current_data.deleteMany(
|
|
464
494
|
{
|
|
465
495
|
_id: idPrefixFilter<SourceKey>({ g: this.group_id }, ['t', 'k'])
|
|
466
496
|
},
|
|
467
|
-
{ maxTimeMS: db.mongo.
|
|
497
|
+
{ maxTimeMS: db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
468
498
|
);
|
|
469
499
|
|
|
470
500
|
await this.db.source_tables.deleteMany(
|
|
471
501
|
{
|
|
472
502
|
group_id: this.group_id
|
|
473
503
|
},
|
|
474
|
-
{ maxTimeMS: db.mongo.
|
|
475
|
-
);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
async setSnapshotDone(lsn: string): Promise<void> {
|
|
479
|
-
await this.db.sync_rules.updateOne(
|
|
480
|
-
{
|
|
481
|
-
_id: this.group_id
|
|
482
|
-
},
|
|
483
|
-
{
|
|
484
|
-
$set: {
|
|
485
|
-
snapshot_done: true,
|
|
486
|
-
persisted_lsn: lsn,
|
|
487
|
-
last_checkpoint_ts: new Date()
|
|
488
|
-
}
|
|
489
|
-
}
|
|
504
|
+
{ maxTimeMS: db.mongo.MONGO_CLEAR_OPERATION_TIMEOUT_MS }
|
|
490
505
|
);
|
|
491
506
|
}
|
|
492
507
|
|
package/src/storage/mongo/db.ts
CHANGED
|
@@ -59,6 +59,9 @@ export class PowerSyncMongo {
|
|
|
59
59
|
this.locks = this.db.collection('locks');
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Clear all collections.
|
|
64
|
+
*/
|
|
62
65
|
async clear() {
|
|
63
66
|
await this.current_data.deleteMany({});
|
|
64
67
|
await this.bucket_data.deleteMany({});
|
|
@@ -70,4 +73,13 @@ export class PowerSyncMongo {
|
|
|
70
73
|
await this.instance.deleteOne({});
|
|
71
74
|
await this.locks.deleteMany({});
|
|
72
75
|
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Drop the entire database.
|
|
79
|
+
*
|
|
80
|
+
* Primarily for tests.
|
|
81
|
+
*/
|
|
82
|
+
async drop() {
|
|
83
|
+
await this.db.dropDatabase();
|
|
84
|
+
}
|
|
73
85
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { SqliteJsonValue } from '@powersync/service-sync-rules';
|
|
2
2
|
import * as bson from 'bson';
|
|
3
|
-
import * as mongo from 'mongodb';
|
|
4
3
|
import * as crypto from 'crypto';
|
|
5
|
-
import
|
|
6
|
-
import { timestampToOpId } from '../../util/utils.js';
|
|
4
|
+
import * as mongo from 'mongodb';
|
|
7
5
|
import { OplogEntry } from '../../util/protocol-types.js';
|
|
6
|
+
import { timestampToOpId } from '../../util/utils.js';
|
|
7
|
+
import { BucketDataDocument } from './models.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Lookup serialization must be number-agnostic. I.e. normalize numbers, instead of preserving numbers.
|