@powersync/service-module-mongodb-storage 0.23.2 → 0.24.1
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 +45 -0
- package/LICENSE +201 -67
- package/dist/storage/MongoBucketStorage.d.ts +1 -0
- package/dist/storage/MongoBucketStorage.js +45 -83
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoBucketBatch.d.ts +60 -39
- package/dist/storage/implementation/MongoBucketBatch.js +123 -296
- package/dist/storage/implementation/MongoBucketBatch.js.map +1 -1
- package/dist/storage/implementation/MongoOpIdAllocator.d.ts +6 -1
- package/dist/storage/implementation/MongoOpIdAllocator.js +12 -5
- package/dist/storage/implementation/MongoOpIdAllocator.js.map +1 -1
- package/dist/storage/implementation/MongoParsedSyncConfigSet.d.ts +7 -0
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js +28 -2
- package/dist/storage/implementation/MongoParsedSyncConfigSet.js.map +1 -1
- package/dist/storage/implementation/MongoReplicationOptions.d.ts +27 -0
- package/dist/storage/implementation/MongoReplicationOptions.js +26 -0
- package/dist/storage/implementation/MongoReplicationOptions.js.map +1 -0
- package/dist/storage/implementation/MongoSyncBucketStorage.js +2 -3
- package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/implementation/MongoSyncRulesLock.d.ts +15 -2
- package/dist/storage/implementation/MongoSyncRulesLock.js +36 -14
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/implementation/common/BatchOperationBuffer.d.ts +79 -0
- package/dist/storage/implementation/common/BatchOperationBuffer.js +286 -0
- package/dist/storage/implementation/common/BatchOperationBuffer.js.map +1 -0
- package/dist/storage/implementation/common/PersistedBatch.d.ts +10 -103
- package/dist/storage/implementation/common/PersistedBatch.js +1 -291
- package/dist/storage/implementation/common/PersistedBatch.js.map +1 -1
- package/dist/storage/implementation/common/PreparedPublication.d.ts +43 -0
- package/dist/storage/implementation/common/PreparedPublication.js +2 -0
- package/dist/storage/implementation/common/PreparedPublication.js.map +1 -0
- package/dist/storage/implementation/common/SourceRecordStore.d.ts +0 -2
- package/dist/storage/implementation/v1/MongoBucketBatchV1.d.ts +17 -13
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js +259 -18
- package/dist/storage/implementation/v1/MongoBucketBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/PersistedBatchV1.d.ts +21 -15
- package/dist/storage/implementation/v1/PersistedBatchV1.js +58 -24
- package/dist/storage/implementation/v1/PersistedBatchV1.js.map +1 -1
- package/dist/storage/implementation/v1/SourceRecordStoreV1.d.ts +0 -2
- package/dist/storage/implementation/v1/SourceRecordStoreV1.js +0 -3
- package/dist/storage/implementation/v1/SourceRecordStoreV1.js.map +1 -1
- package/dist/storage/implementation/v3/MongoBucketBatchV3.d.ts +25 -14
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js +350 -23
- package/dist/storage/implementation/v3/MongoBucketBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoCompactorV3.d.ts +1 -0
- package/dist/storage/implementation/v3/MongoCompactorV3.js +10 -4
- package/dist/storage/implementation/v3/MongoCompactorV3.js.map +1 -1
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js +39 -28
- package/dist/storage/implementation/v3/MongoSyncBucketStorageV3.js.map +1 -1
- package/dist/storage/implementation/v3/PersistedBatchV3.d.ts +46 -24
- package/dist/storage/implementation/v3/PersistedBatchV3.js +159 -83
- package/dist/storage/implementation/v3/PersistedBatchV3.js.map +1 -1
- package/dist/storage/implementation/v3/SourceRecordStoreV3.d.ts +12 -0
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js +41 -13
- package/dist/storage/implementation/v3/SourceRecordStoreV3.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.d.ts +4 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js +4 -0
- package/dist/storage/implementation/v3/object-storage/BucketDataObjectStorage.js.map +1 -1
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.d.ts +27 -2
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js +61 -5
- package/dist/storage/implementation/v3/object-storage/ObjectStorageLifecycle.js.map +1 -1
- package/package.json +9 -10
- package/src/storage/MongoBucketStorage.ts +55 -122
- package/src/storage/implementation/MongoBucketBatch.ts +185 -392
- package/src/storage/implementation/MongoOpIdAllocator.ts +12 -5
- package/src/storage/implementation/MongoParsedSyncConfigSet.ts +40 -1
- package/src/storage/implementation/MongoReplicationOptions.ts +28 -0
- package/src/storage/implementation/MongoSyncBucketStorage.ts +2 -3
- package/src/storage/implementation/MongoSyncRulesLock.ts +39 -17
- package/src/storage/implementation/common/BatchOperationBuffer.ts +353 -0
- package/src/storage/implementation/common/PersistedBatch.ts +12 -390
- package/src/storage/implementation/common/PreparedPublication.ts +49 -0
- package/src/storage/implementation/common/SourceRecordStore.ts +0 -2
- package/src/storage/implementation/v1/MongoBucketBatchV1.ts +339 -27
- package/src/storage/implementation/v1/PersistedBatchV1.ts +74 -32
- package/src/storage/implementation/v1/SourceRecordStoreV1.ts +0 -5
- package/src/storage/implementation/v3/MongoBucketBatchV3.ts +430 -32
- package/src/storage/implementation/v3/MongoCompactorV3.ts +13 -4
- package/src/storage/implementation/v3/MongoSyncBucketStorageV3.ts +43 -29
- package/src/storage/implementation/v3/PersistedBatchV3.ts +209 -108
- package/src/storage/implementation/v3/SourceRecordStoreV3.ts +45 -15
- package/src/storage/implementation/v3/object-storage/BucketDataObjectStorage.ts +9 -0
- package/src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts +79 -5
- package/test/src/checkpoint_cleanup.test.ts +75 -0
- package/test/src/concurrent_writers.test.ts +127 -53
- package/test/src/helpers/PublicationCommandMonitor.ts +119 -0
- package/test/src/helpers/concurrentWriter.mjs +2 -2
- package/test/src/invalid_sync_config.test.ts +9 -0
- package/test/src/object_storage_lifecycle.test.ts +72 -2
- package/test/src/prepared_publication.test.ts +388 -0
- package/test/src/replication_preparation.test.ts +829 -0
- package/test/src/replication_publication_baseline.test.ts +203 -0
- package/test/src/replication_publication_batching.test.ts +212 -0
- package/test/src/replication_uploads.test.ts +393 -0
- package/test/src/source_table_config.test.ts +4 -4
- package/test/src/storage_object_storage_inline_threshold.test.ts +1 -1
- package/test/src/storage_s3_compaction_lifecycle.test.ts +93 -1
- package/test/src/storage_sync.test.ts +101 -2
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { mongo } from '@powersync/lib-service-mongodb';
|
|
1
2
|
import { Logger } from '@powersync/lib-services-framework';
|
|
2
3
|
import * as bson from 'bson';
|
|
3
4
|
import { MongoWriteBatch } from '../../MongoWriteBatch.js';
|
|
@@ -5,6 +6,12 @@ import { VersionedPowerSyncMongoV3 } from '../VersionedPowerSyncMongoV3.js';
|
|
|
5
6
|
import { BucketDataObjectStorage } from './BucketDataObjectStorage.js';
|
|
6
7
|
import { ObjectStorage, ObjectStorageOperationOptions } from './ObjectStorage.js';
|
|
7
8
|
export declare const OBJECT_STORAGE_UPLOAD_LEASE_MS: number;
|
|
9
|
+
/**
|
|
10
|
+
* Leave time for the bounded publication transaction and clock skew before
|
|
11
|
+
* cleanup can select a marker. Publication must finish within this margin after
|
|
12
|
+
* its eligibility check; checked marker deletion alone cannot protect an object
|
|
13
|
+
* from a cleanup worker that already selected an expired marker.
|
|
14
|
+
*/
|
|
8
15
|
export declare const OBJECT_STORAGE_PUBLICATION_SAFETY_MARGIN_MS: number;
|
|
9
16
|
export declare const OBJECT_STORAGE_REFERENCE_GRACE_MS: number;
|
|
10
17
|
export interface PreparedObjectStorageUpload {
|
|
@@ -12,6 +19,10 @@ export interface PreparedObjectStorageUpload {
|
|
|
12
19
|
path: string;
|
|
13
20
|
deleteAfter: Date;
|
|
14
21
|
}
|
|
22
|
+
export interface ObjectStorageUploadPayload {
|
|
23
|
+
upload: PreparedObjectStorageUpload;
|
|
24
|
+
payload: Uint8Array;
|
|
25
|
+
}
|
|
15
26
|
/**
|
|
16
27
|
* Coordinates the MongoDB outbox used to make object-storage changes recoverable.
|
|
17
28
|
*
|
|
@@ -35,10 +46,24 @@ export declare class ObjectStorageLifecycle {
|
|
|
35
46
|
* Indicate that files will be uploaded to S3.
|
|
36
47
|
*
|
|
37
48
|
* These markers are expected to be removed using publishUploads(). If that does not happen within
|
|
38
|
-
* the grace period, the files will be deleted.
|
|
49
|
+
* the grace period, the files will be deleted. Registration must be majority
|
|
50
|
+
* acknowledged before any PUT starts: losing a marker on failover would lose
|
|
51
|
+
* the only cleanup obligation for an unpublished object. A failed/ambiguous
|
|
52
|
+
* insert must therefore prevent uploads, even if some markers were inserted.
|
|
39
53
|
*/
|
|
40
|
-
prepareUploads(paths: string[], now?: Date): Promise<PreparedObjectStorageUpload[]>;
|
|
54
|
+
prepareUploads(paths: string[], now?: Date, session?: mongo.ClientSession): Promise<PreparedObjectStorageUpload[]>;
|
|
41
55
|
canPublish(upload: PreparedObjectStorageUpload, now?: Date): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Upload a durably registered generation, joining every started PUT on failure.
|
|
58
|
+
* The shared adapter limits concurrency; its queue must observe the same signal
|
|
59
|
+
* as an active request so no queued PUT can start after the protection deadline.
|
|
60
|
+
*
|
|
61
|
+
* Failed/ambiguous PUTs retain their original markers. S3's bounded request
|
|
62
|
+
* timeouts are far shorter than the one-hour orphan grace, including when a
|
|
63
|
+
* response is lost or the process dies. Cancellation does not prove an object
|
|
64
|
+
* is absent, so never delete an object or its marker on upload failure.
|
|
65
|
+
*/
|
|
66
|
+
storeUploads(uploads: ObjectStorageUploadPayload[], options?: ObjectStorageOperationOptions): Promise<void>;
|
|
42
67
|
/**
|
|
43
68
|
* Remove markers for files that have finished uploading, and are now referenced from other documents.
|
|
44
69
|
*
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import * as bson from 'bson';
|
|
2
2
|
import { createHash, randomUUID } from 'node:crypto';
|
|
3
|
+
import { REPLICATION_WRITE_OPTIONS } from '../../MongoReplicationOptions.js';
|
|
3
4
|
import { BucketDataObjectStorage } from './BucketDataObjectStorage.js';
|
|
4
5
|
export const OBJECT_STORAGE_UPLOAD_LEASE_MS = 60 * 60 * 1000;
|
|
6
|
+
/**
|
|
7
|
+
* Leave time for the bounded publication transaction and clock skew before
|
|
8
|
+
* cleanup can select a marker. Publication must finish within this margin after
|
|
9
|
+
* its eligibility check; checked marker deletion alone cannot protect an object
|
|
10
|
+
* from a cleanup worker that already selected an expired marker.
|
|
11
|
+
*/
|
|
5
12
|
export const OBJECT_STORAGE_PUBLICATION_SAFETY_MARGIN_MS = 2 * 60 * 1000;
|
|
6
13
|
export const OBJECT_STORAGE_REFERENCE_GRACE_MS = 15 * 60 * 1000;
|
|
7
14
|
/**
|
|
@@ -50,23 +57,71 @@ export class ObjectStorageLifecycle {
|
|
|
50
57
|
* Indicate that files will be uploaded to S3.
|
|
51
58
|
*
|
|
52
59
|
* These markers are expected to be removed using publishUploads(). If that does not happen within
|
|
53
|
-
* the grace period, the files will be deleted.
|
|
60
|
+
* the grace period, the files will be deleted. Registration must be majority
|
|
61
|
+
* acknowledged before any PUT starts: losing a marker on failover would lose
|
|
62
|
+
* the only cleanup obligation for an unpublished object. A failed/ambiguous
|
|
63
|
+
* insert must therefore prevent uploads, even if some markers were inserted.
|
|
54
64
|
*/
|
|
55
|
-
async prepareUploads(paths, now = new Date()) {
|
|
65
|
+
async prepareUploads(paths, now = new Date(), session) {
|
|
56
66
|
const deleteAfter = new Date(now.getTime() + OBJECT_STORAGE_UPLOAD_LEASE_MS);
|
|
57
67
|
const uploads = paths.map((path) => ({ markerId: new bson.ObjectId(), path, deleteAfter }));
|
|
58
|
-
if (uploads.length) {
|
|
68
|
+
if (uploads.length > 0) {
|
|
59
69
|
await this.db.pendingObjectStorageDeletes(this.replicationStreamId).insertMany(uploads.map((upload) => ({
|
|
60
70
|
_id: upload.markerId,
|
|
61
71
|
path: upload.path,
|
|
62
72
|
delete_after: upload.deleteAfter
|
|
63
|
-
})));
|
|
73
|
+
})), { ...REPLICATION_WRITE_OPTIONS, session });
|
|
64
74
|
}
|
|
65
75
|
return uploads;
|
|
66
76
|
}
|
|
67
77
|
canPublish(upload, now = new Date()) {
|
|
68
78
|
return now.getTime() < upload.deleteAfter.getTime() - OBJECT_STORAGE_PUBLICATION_SAFETY_MARGIN_MS;
|
|
69
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Upload a durably registered generation, joining every started PUT on failure.
|
|
82
|
+
* The shared adapter limits concurrency; its queue must observe the same signal
|
|
83
|
+
* as an active request so no queued PUT can start after the protection deadline.
|
|
84
|
+
*
|
|
85
|
+
* Failed/ambiguous PUTs retain their original markers. S3's bounded request
|
|
86
|
+
* timeouts are far shorter than the one-hour orphan grace, including when a
|
|
87
|
+
* response is lost or the process dies. Cancellation does not prove an object
|
|
88
|
+
* is absent, so never delete an object or its marker on upload failure.
|
|
89
|
+
*/
|
|
90
|
+
async storeUploads(uploads, options) {
|
|
91
|
+
if (uploads.length === 0) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const deadline = Math.min(...uploads.map(({ upload }) => upload.deleteAfter.getTime())) -
|
|
95
|
+
OBJECT_STORAGE_PUBLICATION_SAFETY_MARGIN_MS;
|
|
96
|
+
const remaining = deadline - Date.now();
|
|
97
|
+
if (remaining <= 0) {
|
|
98
|
+
throw new Error('Object storage upload lease expired before PUT');
|
|
99
|
+
}
|
|
100
|
+
const expiration = new AbortController();
|
|
101
|
+
const timer = setTimeout(() => expiration.abort(new Error('Object storage upload lease expired during PUT')), remaining);
|
|
102
|
+
timer.unref();
|
|
103
|
+
const signal = options?.signal ? AbortSignal.any([options.signal, expiration.signal]) : expiration.signal;
|
|
104
|
+
let results;
|
|
105
|
+
try {
|
|
106
|
+
results = await Promise.allSettled(uploads.map(async ({ upload, payload }) => {
|
|
107
|
+
signal.throwIfAborted();
|
|
108
|
+
// The timer handles time in the adapter's queue; this check also catches
|
|
109
|
+
// wall-clock changes before dispatch. Publication checks again later.
|
|
110
|
+
if (!this.canPublish(upload)) {
|
|
111
|
+
throw new Error(`Object storage upload lease expired for ${upload.path}`);
|
|
112
|
+
}
|
|
113
|
+
await this.bucketData.storeSerialized(upload.path, payload, { signal });
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
clearTimeout(timer);
|
|
118
|
+
}
|
|
119
|
+
const failure = results.find((result) => result.status === 'rejected');
|
|
120
|
+
if (failure?.status === 'rejected') {
|
|
121
|
+
throw failure.reason;
|
|
122
|
+
}
|
|
123
|
+
signal.throwIfAborted();
|
|
124
|
+
}
|
|
70
125
|
/**
|
|
71
126
|
* Remove markers for files that have finished uploading, and are now referenced from other documents.
|
|
72
127
|
*
|
|
@@ -82,8 +137,9 @@ export class ObjectStorageLifecycle {
|
|
|
82
137
|
return;
|
|
83
138
|
}
|
|
84
139
|
writes.deleteMany(this.db.pendingObjectStorageDeletes(this.replicationStreamId), { _id: { $in: uploads.map((upload) => upload.markerId) } }, (deletedCount) => {
|
|
85
|
-
if (deletedCount !== uploads.length)
|
|
140
|
+
if (deletedCount !== uploads.length) {
|
|
86
141
|
throw new Error('Missing object storage publication markers');
|
|
142
|
+
}
|
|
87
143
|
});
|
|
88
144
|
}
|
|
89
145
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ObjectStorageLifecycle.js","sourceRoot":"","sources":["../../../../../src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ObjectStorageLifecycle.js","sourceRoot":"","sources":["../../../../../src/storage/implementation/v3/object-storage/ObjectStorageLifecycle.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powersync/service-module-mongodb-storage",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
|
-
"version": "0.
|
|
5
|
-
"license": "
|
|
4
|
+
"version": "0.24.1",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
@@ -17,19 +17,18 @@
|
|
|
17
17
|
"@smithy/node-http-handler": "^4.11.3",
|
|
18
18
|
"async-mutex": "^0.5.0",
|
|
19
19
|
"bson": "^6.10.4",
|
|
20
|
-
"ix": "^5.0.0",
|
|
21
20
|
"lru-cache": "^10.2.2",
|
|
22
21
|
"ts-codec": "^1.3.0",
|
|
23
22
|
"uuid": "^14.0.0",
|
|
24
|
-
"@powersync/lib-service-mongodb": "0.6.
|
|
25
|
-
"@powersync/lib-services-framework": "0.10.
|
|
26
|
-
"@powersync/service-core": "1.
|
|
27
|
-
"@powersync/service-jsonbig": "0.17.
|
|
28
|
-
"@powersync/service-sync-rules": "0.
|
|
29
|
-
"@powersync/service-types": "0.
|
|
23
|
+
"@powersync/lib-service-mongodb": "0.6.36",
|
|
24
|
+
"@powersync/lib-services-framework": "0.10.5",
|
|
25
|
+
"@powersync/service-core": "1.28.1",
|
|
26
|
+
"@powersync/service-jsonbig": "0.17.14",
|
|
27
|
+
"@powersync/service-sync-rules": "0.45.0",
|
|
28
|
+
"@powersync/service-types": "0.21.0"
|
|
30
29
|
},
|
|
31
30
|
"devDependencies": {
|
|
32
|
-
"@powersync/service-core-tests": "0.18.
|
|
31
|
+
"@powersync/service-core-tests": "0.18.5"
|
|
33
32
|
},
|
|
34
33
|
"scripts": {
|
|
35
34
|
"build": "tsc -b",
|
|
@@ -652,6 +652,10 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
652
652
|
*
|
|
653
653
|
* Use in the same transaction that the replacement stream is created.
|
|
654
654
|
*/
|
|
655
|
+
async stopProcessingSyncConfigs(): Promise<void> {
|
|
656
|
+
await this.withTransaction((session) => this.stopExistingProcessingWork(session));
|
|
657
|
+
}
|
|
658
|
+
|
|
655
659
|
private async stopExistingProcessingWork(session: mongo.ClientSession) {
|
|
656
660
|
await this.db.sync_rules.updateMany(
|
|
657
661
|
{
|
|
@@ -824,89 +828,45 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
824
828
|
}
|
|
825
829
|
|
|
826
830
|
async getStorageMetrics(): Promise<storage.StorageMetrics> {
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
};
|
|
835
|
-
|
|
836
|
-
const aggregateStaticCollection = async <T extends mongo.Document>(collection: mongo.Collection<T>) => {
|
|
837
|
-
// We check whether the collection exists before getting the statistics. This avoids repeated
|
|
838
|
-
// errors in the MongoDB logs if the collection hasn't been created yet.
|
|
839
|
-
const exists =
|
|
840
|
-
(await this.db.db.listCollections({ name: collection.collectionName }, { nameOnly: true }).toArray()).length >
|
|
841
|
-
0;
|
|
842
|
-
if (!exists) {
|
|
843
|
-
return [{ storageStats: { size: 0 } }];
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
return collection
|
|
847
|
-
.aggregate([
|
|
848
|
-
{
|
|
849
|
-
$collStats: {
|
|
850
|
-
storageStats: {}
|
|
851
|
-
}
|
|
831
|
+
// We check which collections exist before getting statistics to avoid repeated errors in
|
|
832
|
+
// MongoDB logs for collections that have not been created yet.
|
|
833
|
+
const collections = await this.db.db
|
|
834
|
+
.listCollections(
|
|
835
|
+
{
|
|
836
|
+
name: {
|
|
837
|
+
$regex: '^(bucket_data|bucket_parameters|current_data)$|^(bucket_data_|parameter_index_|source_records_)'
|
|
852
838
|
}
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
.catch(ignoreNotExisting);
|
|
856
|
-
};
|
|
857
|
-
|
|
858
|
-
const operations_aggregate = await aggregateStaticCollection(this.db.bucket_data);
|
|
859
|
-
const v3OperationCollections = await this.db.listBucketDataCollectionsV3();
|
|
860
|
-
const v3_operation_aggregates = await Promise.all(
|
|
861
|
-
v3OperationCollections.map((collection) =>
|
|
862
|
-
collection
|
|
863
|
-
.aggregate([
|
|
864
|
-
{
|
|
865
|
-
$collStats: {
|
|
866
|
-
storageStats: {}
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
])
|
|
870
|
-
.toArray()
|
|
871
|
-
.catch(ignoreNotExisting)
|
|
872
|
-
)
|
|
873
|
-
);
|
|
874
|
-
|
|
875
|
-
const parameters_aggregate = await aggregateStaticCollection(this.db.bucket_parameters);
|
|
876
|
-
|
|
877
|
-
const v3ParameterCollections = await this.db.listAllParameterIndexCollectionsV3();
|
|
878
|
-
const v3_parameter_aggregates = await Promise.all(
|
|
879
|
-
v3ParameterCollections.map((collection) =>
|
|
880
|
-
collection
|
|
881
|
-
.aggregate([
|
|
882
|
-
{
|
|
883
|
-
$collStats: {
|
|
884
|
-
storageStats: {}
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
])
|
|
888
|
-
.toArray()
|
|
889
|
-
.catch(ignoreNotExisting)
|
|
890
|
-
)
|
|
891
|
-
);
|
|
892
|
-
|
|
893
|
-
const v1_source_record_aggregate = await aggregateStaticCollection(this.db.current_data);
|
|
894
|
-
|
|
895
|
-
const v3SourceRecordCollections = await this.db.listAllSourceRecordCollectionsV3();
|
|
896
|
-
const source_record_aggregates = await Promise.all(
|
|
897
|
-
v3SourceRecordCollections.map((collection) =>
|
|
898
|
-
collection
|
|
899
|
-
.aggregate([
|
|
900
|
-
{
|
|
901
|
-
$collStats: {
|
|
902
|
-
storageStats: {}
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
])
|
|
906
|
-
.toArray()
|
|
907
|
-
.catch(ignoreNotExisting)
|
|
839
|
+
},
|
|
840
|
+
{ nameOnly: true }
|
|
908
841
|
)
|
|
909
|
-
|
|
842
|
+
.toArray();
|
|
843
|
+
const sizesByCollection = new Map<string, number>();
|
|
844
|
+
const statsPipeline: mongo.Document[] = [
|
|
845
|
+
{ $collStats: { storageStats: {} } },
|
|
846
|
+
{ $project: { ns: 1, size: '$storageStats.size' } }
|
|
847
|
+
];
|
|
848
|
+
// MongoDB has a limit of 1000 stages per aggregation pipeline. Additionally, we want
|
|
849
|
+
// to avoid too much work per aggregation, so we limit the number of collections per batch.
|
|
850
|
+
const COLLECTIONS_PER_BATCH = 100;
|
|
851
|
+
// Query batches sequentially so metrics collection does not fill the connection pool on standby pods.
|
|
852
|
+
// If a collection disappears during aggregation, let the next metrics collection retry.
|
|
853
|
+
for (let offset = 0; offset < collections.length; offset += COLLECTIONS_PER_BATCH) {
|
|
854
|
+
const batch = collections.slice(offset, offset + COLLECTIONS_PER_BATCH);
|
|
855
|
+
const pipeline = [
|
|
856
|
+
...statsPipeline,
|
|
857
|
+
...batch.slice(1).map((collection) => ({
|
|
858
|
+
$unionWith: { coll: collection.name, pipeline: statsPipeline }
|
|
859
|
+
}))
|
|
860
|
+
];
|
|
861
|
+
const stats = await this.db.db
|
|
862
|
+
.collection(batch[0].name)
|
|
863
|
+
.aggregate<{ ns: string; size: number | bigint }>(pipeline)
|
|
864
|
+
.toArray();
|
|
865
|
+
for (const stat of stats) {
|
|
866
|
+
const name = stat.ns.slice(this.db.db.databaseName.length + 1);
|
|
867
|
+
sizesByCollection.set(name, (sizesByCollection.get(name) ?? 0) + Number(stat.size));
|
|
868
|
+
}
|
|
869
|
+
}
|
|
910
870
|
|
|
911
871
|
const v3StorageConfig = getMongoStorageConfig(storage.STORAGE_VERSION_3) as StorageConfig & {
|
|
912
872
|
incrementalReprocessing: true;
|
|
@@ -918,29 +878,8 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
918
878
|
.find({ storage_version: { $gte: storage.STORAGE_VERSION_3 } }, { projection: { _id: 1, sync_configs: 1 } })
|
|
919
879
|
.toArray()) as unknown as Pick<ReplicationStreamDocumentV3, '_id' | 'sync_configs'>[];
|
|
920
880
|
|
|
921
|
-
const
|
|
922
|
-
|
|
923
|
-
collection: { collectionName: string },
|
|
924
|
-
aggregate: { storageStats?: { size?: number | bigint } }[],
|
|
925
|
-
prefix: string,
|
|
926
|
-
sizes: Map<string, number>
|
|
927
|
-
) => {
|
|
928
|
-
const match = collection.collectionName.match(new RegExp(`^${prefix}(\\d+)_(.+)$`));
|
|
929
|
-
if (match == null) {
|
|
930
|
-
return;
|
|
931
|
-
}
|
|
932
|
-
sizes.set(`${prefix}${match[1]}:${match[2]}`, Number(aggregate[0]?.storageStats?.size ?? 0));
|
|
933
|
-
};
|
|
934
|
-
|
|
935
|
-
v3OperationCollections.forEach((collection, index) =>
|
|
936
|
-
addCollectionSize(collection, v3_operation_aggregates[index], 'bucket_data_', collectionSizes)
|
|
937
|
-
);
|
|
938
|
-
v3ParameterCollections.forEach((collection, index) =>
|
|
939
|
-
addCollectionSize(collection, v3_parameter_aggregates[index], 'parameter_index_', collectionSizes)
|
|
940
|
-
);
|
|
941
|
-
v3SourceRecordCollections.forEach((collection, index) =>
|
|
942
|
-
addCollectionSize(collection, source_record_aggregates[index], 'source_records_', collectionSizes)
|
|
943
|
-
);
|
|
881
|
+
const sumCollectionSizesByPrefix = (prefix: string) =>
|
|
882
|
+
[...sizesByCollection].reduce((total, [name, size]) => total + (name.startsWith(prefix) ? size : 0), 0);
|
|
944
883
|
|
|
945
884
|
const syncConfigIds = v3StreamDocs.flatMap((stream) => (stream.sync_configs ?? []).map((config) => config._id));
|
|
946
885
|
const syncConfigDefinitions =
|
|
@@ -957,15 +896,13 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
957
896
|
number,
|
|
958
897
|
{ _id: ObjectId; bucket_data_source_ids: string[]; parameter_lookup_source_ids: string[] }[]
|
|
959
898
|
>();
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
})
|
|
968
|
-
);
|
|
899
|
+
for (const stream of v3StreamDocs) {
|
|
900
|
+
const sourceTables = await v3Db
|
|
901
|
+
.sourceTables(stream._id)
|
|
902
|
+
.find({}, { projection: { _id: 1, bucket_data_source_ids: 1, parameter_lookup_source_ids: 1 } })
|
|
903
|
+
.toArray();
|
|
904
|
+
sourceTablesByStream.set(stream._id, sourceTables);
|
|
905
|
+
}
|
|
969
906
|
|
|
970
907
|
const objectStorageSizeByDefinition = new Map<string, number>();
|
|
971
908
|
for (const usage of objectStorageDefinitionUsage) {
|
|
@@ -976,7 +913,7 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
976
913
|
}
|
|
977
914
|
|
|
978
915
|
const sumCollectionSizes = (prefix: string, streamId: number, ids: ReadonlySet<string>) =>
|
|
979
|
-
[...ids].reduce((total, id) => total + (
|
|
916
|
+
[...ids].reduce((total, id) => total + (sizesByCollection.get(`${prefix}${streamId}_${id}`) ?? 0), 0);
|
|
980
917
|
|
|
981
918
|
const syncConfigMetrics: storage.StorageSyncConfigMetrics[] = [];
|
|
982
919
|
for (const stream of v3StreamDocs) {
|
|
@@ -999,7 +936,7 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
999
936
|
) {
|
|
1000
937
|
return total;
|
|
1001
938
|
}
|
|
1002
|
-
return total + (
|
|
939
|
+
return total + (sizesByCollection.get(`source_records_${stream._id}_${sourceTable._id.toHexString()}`) ?? 0);
|
|
1003
940
|
}, 0);
|
|
1004
941
|
|
|
1005
942
|
syncConfigMetrics.push({
|
|
@@ -1022,15 +959,11 @@ export class MongoBucketStorage extends storage.BucketStorageFactory {
|
|
|
1022
959
|
0n
|
|
1023
960
|
);
|
|
1024
961
|
return {
|
|
1025
|
-
operations_size_bytes:
|
|
1026
|
-
Number(operations_aggregate[0].storageStats.size) +
|
|
1027
|
-
v3_operation_aggregates.reduce((total, aggregate) => total + Number(aggregate[0].storageStats.size), 0),
|
|
962
|
+
operations_size_bytes: (sizesByCollection.get('bucket_data') ?? 0) + sumCollectionSizesByPrefix('bucket_data_'),
|
|
1028
963
|
parameters_size_bytes:
|
|
1029
|
-
|
|
1030
|
-
v3_parameter_aggregates.reduce((total, aggregate) => total + Number(aggregate[0].storageStats.size), 0),
|
|
964
|
+
(sizesByCollection.get('bucket_parameters') ?? 0) + sumCollectionSizesByPrefix('parameter_index_'),
|
|
1031
965
|
replication_size_bytes:
|
|
1032
|
-
|
|
1033
|
-
source_record_aggregates.reduce((total, aggregate) => total + Number(aggregate[0]?.storageStats?.size ?? 0), 0),
|
|
966
|
+
(sizesByCollection.get('current_data') ?? 0) + sumCollectionSizesByPrefix('source_records_'),
|
|
1034
967
|
object_storage_size_bytes: Number(totalObjectStorageSize),
|
|
1035
968
|
sync_config_metrics: syncConfigMetrics
|
|
1036
969
|
};
|