@powersync/service-core 0.0.0-dev-20260602073133 → 0.0.0-dev-20260909133214
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 +152 -4
- package/dist/api/RouteAPI.d.ts +42 -14
- package/dist/api/diagnostics.d.ts +12 -1
- package/dist/api/diagnostics.js +36 -22
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/entry/commands/compact-action.js +30 -22
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/metrics/metrics-interfaces.d.ts +5 -1
- package/dist/metrics/metrics-interfaces.js.map +1 -1
- package/dist/metrics/open-telemetry/MetricAttributeFilteringExporter.d.ts +36 -0
- package/dist/metrics/open-telemetry/MetricAttributeFilteringExporter.js +70 -0
- package/dist/metrics/open-telemetry/MetricAttributeFilteringExporter.js.map +1 -0
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js +6 -1
- package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js.map +1 -1
- package/dist/metrics/open-telemetry/util.js +7 -3
- package/dist/metrics/open-telemetry/util.js.map +1 -1
- package/dist/modules/AbstractModule.d.ts +6 -2
- package/dist/modules/AbstractModule.js.map +1 -1
- package/dist/replication/AbstractReplicator.d.ts +31 -7
- package/dist/replication/AbstractReplicator.js +168 -74
- package/dist/replication/AbstractReplicator.js.map +1 -1
- package/dist/replication/ReplicationModule.d.ts +3 -3
- package/dist/replication/ReplicationModule.js.map +1 -1
- package/dist/routes/RouterEngine.d.ts +1 -0
- package/dist/routes/RouterEngine.js +6 -1
- package/dist/routes/RouterEngine.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +104 -56
- package/dist/routes/configure-fastify.js +15 -2
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/endpoints/admin.d.ts +42 -24
- package/dist/routes/endpoints/admin.js +49 -36
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.d.ts +62 -0
- package/dist/routes/endpoints/checkpointing.js +65 -7
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +3 -2
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.js +25 -14
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.js +1 -1
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/runner/teardown.js +8 -8
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorageBatch.d.ts +64 -17
- package/dist/storage/BucketStorageBatch.js.map +1 -1
- package/dist/storage/BucketStorageFactory.d.ts +50 -31
- package/dist/storage/BucketStorageFactory.js +10 -20
- package/dist/storage/BucketStorageFactory.js.map +1 -1
- package/dist/storage/CheckpointChecksumInvalidatedError.d.ts +12 -0
- package/dist/storage/CheckpointChecksumInvalidatedError.js +17 -0
- package/dist/storage/CheckpointChecksumInvalidatedError.js.map +1 -0
- package/dist/storage/ChecksumCache.d.ts +11 -6
- package/dist/storage/ChecksumCache.js +5 -4
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/ParsedSyncConfigSet.d.ts +23 -0
- package/dist/storage/ParsedSyncConfigSet.js +2 -0
- package/dist/storage/ParsedSyncConfigSet.js.map +1 -0
- package/dist/storage/PersistedReplicationStream.d.ts +32 -0
- package/dist/storage/PersistedReplicationStream.js +26 -0
- package/dist/storage/PersistedReplicationStream.js.map +1 -0
- package/dist/storage/PersistedSyncConfigContent.d.ts +65 -0
- package/dist/storage/PersistedSyncConfigContent.js +138 -0
- package/dist/storage/PersistedSyncConfigContent.js.map +1 -0
- package/dist/storage/PersistedSyncConfigStatus.d.ts +13 -0
- package/dist/storage/PersistedSyncConfigStatus.js +2 -0
- package/dist/storage/PersistedSyncConfigStatus.js.map +1 -0
- package/dist/storage/ReplicationEventPayload.d.ts +6 -1
- package/dist/storage/SourceEntity.d.ts +13 -2
- package/dist/storage/SourceTable.d.ts +53 -4
- package/dist/storage/SourceTable.js +62 -7
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/SourceTableReconciler.d.ts +83 -0
- package/dist/storage/SourceTableReconciler.js +95 -0
- package/dist/storage/SourceTableReconciler.js.map +1 -0
- package/dist/storage/StorageVersionConfig.d.ts +4 -0
- package/dist/storage/StorageVersionConfig.js +10 -1
- package/dist/storage/StorageVersionConfig.js.map +1 -1
- package/dist/storage/SyncRulesBucketStorage.d.ts +162 -26
- package/dist/storage/SyncRulesBucketStorage.js +3 -0
- package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
- package/dist/storage/WriteCheckpointAPI.d.ts +85 -6
- package/dist/storage/WriteCheckpointAPI.js +33 -0
- package/dist/storage/WriteCheckpointAPI.js.map +1 -1
- package/dist/storage/implementation/BucketDefinitionMapping.d.ts +133 -0
- package/dist/storage/implementation/BucketDefinitionMapping.js +351 -0
- package/dist/storage/implementation/BucketDefinitionMapping.js.map +1 -0
- package/dist/storage/implementation/IncrementalReprocessingCompatibility.d.ts +6 -0
- package/dist/storage/implementation/IncrementalReprocessingCompatibility.js +31 -0
- package/dist/storage/implementation/IncrementalReprocessingCompatibility.js.map +1 -0
- package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.d.ts +17 -0
- package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.js +70 -0
- package/dist/storage/implementation/IncrementalReprocessingSyncConfigLog.js.map +1 -0
- package/dist/storage/implementation/ReplicationStreamStorageIds.d.ts +15 -0
- package/dist/storage/implementation/ReplicationStreamStorageIds.js +20 -0
- package/dist/storage/implementation/ReplicationStreamStorageIds.js.map +1 -0
- package/dist/storage/storage-index.d.ts +10 -1
- package/dist/storage/storage-index.js +10 -1
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/storage/storage-metrics.js +120 -4
- package/dist/storage/storage-metrics.js.map +1 -1
- package/dist/sync/BucketChecksumState.d.ts +12 -2
- package/dist/sync/BucketChecksumState.js +69 -21
- package/dist/sync/BucketChecksumState.js.map +1 -1
- package/dist/sync/RequestTracker.d.ts +7 -0
- package/dist/sync/RequestTracker.js +12 -0
- package/dist/sync/RequestTracker.js.map +1 -1
- package/dist/sync/sync.js +184 -43
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.d.ts +5 -0
- package/dist/sync/util.js +19 -1
- package/dist/sync/util.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +2 -0
- package/dist/system/ServiceContext.js +2 -0
- package/dist/system/ServiceContext.js.map +1 -1
- package/dist/tracing/PerformanceTracer.d.ts +23 -1
- package/dist/tracing/PerformanceTracer.js +11 -0
- package/dist/tracing/PerformanceTracer.js.map +1 -1
- package/dist/util/checkpointing.d.ts +4 -8
- package/dist/util/checkpointing.js +1 -16
- package/dist/util/checkpointing.js.map +1 -1
- package/dist/util/config/compound-config-collector.js +23 -2
- package/dist/util/config/compound-config-collector.js.map +1 -1
- package/dist/util/config/defaults.d.ts +2 -0
- package/dist/util/config/defaults.js +2 -0
- package/dist/util/config/defaults.js.map +1 -1
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js +1 -0
- package/dist/util/config/sync-rules/impl/base64-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js +1 -0
- package/dist/util/config/sync-rules/impl/filesystem-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/sync-rules-provider.d.ts +2 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js +3 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -1
- package/dist/util/config/types.d.ts +4 -1
- package/dist/util/lsn.d.ts +4 -0
- package/dist/util/lsn.js +10 -0
- package/dist/util/lsn.js.map +1 -1
- package/dist/util/protocol-types.d.ts +4 -4
- package/dist/util/protocol-types.js +3 -2
- package/dist/util/protocol-types.js.map +1 -1
- package/dist/util/util-index.d.ts +1 -0
- package/dist/util/util-index.js +1 -0
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +3 -2
- package/dist/util/utils.js +17 -2
- package/dist/util/utils.js.map +1 -1
- package/dist/util/write-checkpoint-batcher.d.ts +19 -0
- package/dist/util/write-checkpoint-batcher.js +100 -0
- package/dist/util/write-checkpoint-batcher.js.map +1 -0
- package/package.json +7 -7
- package/src/api/RouteAPI.ts +43 -14
- package/src/api/diagnostics.ts +45 -26
- package/src/entry/commands/compact-action.ts +37 -23
- package/src/metrics/metrics-interfaces.ts +6 -1
- package/src/metrics/open-telemetry/MetricAttributeFilteringExporter.ts +85 -0
- package/src/metrics/open-telemetry/OpenTelemetryMetricsFactory.ts +7 -2
- package/src/metrics/open-telemetry/util.ts +7 -3
- package/src/modules/AbstractModule.ts +6 -2
- package/src/replication/AbstractReplicator.ts +212 -78
- package/src/replication/ReplicationModule.ts +2 -3
- package/src/routes/RouterEngine.ts +7 -1
- package/src/routes/configure-fastify.ts +25 -2
- package/src/routes/endpoints/admin.ts +75 -51
- package/src/routes/endpoints/checkpointing.ts +79 -8
- package/src/routes/endpoints/socket-route.ts +3 -2
- package/src/routes/endpoints/sync-rules.ts +26 -14
- package/src/routes/endpoints/sync-stream.ts +1 -1
- package/src/runner/teardown.ts +8 -8
- package/src/storage/BucketStorageBatch.ts +65 -18
- package/src/storage/BucketStorageFactory.ts +73 -46
- package/src/storage/CheckpointChecksumInvalidatedError.ts +17 -0
- package/src/storage/ChecksumCache.ts +27 -14
- package/src/storage/ParsedSyncConfigSet.ts +25 -0
- package/src/storage/PersistedReplicationStream.ts +55 -0
- package/src/storage/PersistedSyncConfigContent.ts +207 -0
- package/src/storage/PersistedSyncConfigStatus.ts +14 -0
- package/src/storage/ReplicationEventPayload.ts +6 -1
- package/src/storage/SourceEntity.ts +12 -2
- package/src/storage/SourceTable.ts +96 -8
- package/src/storage/SourceTableReconciler.ts +188 -0
- package/src/storage/StorageVersionConfig.ts +11 -1
- package/src/storage/SyncRulesBucketStorage.ts +189 -27
- package/src/storage/WriteCheckpointAPI.ts +140 -6
- package/src/storage/implementation/BucketDefinitionMapping.ts +539 -0
- package/src/storage/implementation/IncrementalReprocessingCompatibility.ts +41 -0
- package/src/storage/implementation/IncrementalReprocessingSyncConfigLog.ts +126 -0
- package/src/storage/implementation/ReplicationStreamStorageIds.ts +21 -0
- package/src/storage/storage-index.ts +11 -1
- package/src/storage/storage-metrics.ts +154 -8
- package/src/sync/BucketChecksumState.ts +105 -21
- package/src/sync/RequestTracker.ts +20 -0
- package/src/sync/sync.ts +214 -50
- package/src/sync/util.ts +33 -8
- package/src/system/ServiceContext.ts +7 -0
- package/src/tracing/PerformanceTracer.ts +41 -1
- package/src/util/checkpointing.ts +4 -22
- package/src/util/config/compound-config-collector.ts +31 -1
- package/src/util/config/defaults.ts +2 -0
- package/src/util/config/sync-rules/impl/base64-sync-rules-collector.ts +1 -0
- package/src/util/config/sync-rules/impl/filesystem-sync-rules-collector.ts +1 -0
- package/src/util/config/sync-rules/sync-rules-provider.ts +5 -0
- package/src/util/config/types.ts +4 -1
- package/src/util/lsn.ts +9 -0
- package/src/util/protocol-types.ts +3 -2
- package/src/util/util-index.ts +1 -0
- package/src/util/utils.ts +16 -2
- package/src/util/write-checkpoint-batcher.ts +142 -0
- package/test/src/AbstractReplicator.test.ts +177 -0
- package/test/src/MetricAttributeFilteringExporter.test.ts +96 -0
- package/test/src/PersistedSyncConfigContent.test.ts +152 -0
- package/test/src/checksum_cache.test.ts +22 -0
- package/test/src/config.test.ts +142 -0
- package/test/src/diagnostics.test.ts +87 -34
- package/test/src/module-loader.test.ts +33 -1
- package/test/src/routes/admin.test.ts +188 -18
- package/test/src/routes/checkpointing.test.ts +54 -0
- package/test/src/routes/mocks.ts +6 -2
- package/test/src/routes/stream.test.ts +123 -2
- package/test/src/source-table-reconciler.test.ts +244 -0
- package/test/src/storage/SourceTable.test.ts +92 -0
- package/test/src/storage-metrics.test.ts +148 -0
- package/test/src/sync/BucketChecksumState.test.ts +98 -12
- package/test/src/sync/util.test.ts +28 -1
- package/test/src/util/checkpointing.test.ts +249 -0
- package/test/src/util/utils.test.ts +23 -0
- package/tsconfig.json +1 -4
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/storage/PersistedSyncRulesContent.d.ts +0 -59
- package/dist/storage/PersistedSyncRulesContent.js +0 -100
- package/dist/storage/PersistedSyncRulesContent.js.map +0 -1
- package/src/storage/PersistedSyncRulesContent.ts +0 -174
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BucketDefinitionId, ParameterIndexId } from '@powersync/service-sync-rules';
|
|
2
|
+
import { SingleSyncConfigBucketDefinitionMapping } from './BucketDefinitionMapping.js';
|
|
3
|
+
/**
|
|
4
|
+
* Persisted storage ids for a replication stream, derived from the rule_mapping documents
|
|
5
|
+
* of all its sync configs.
|
|
6
|
+
*
|
|
7
|
+
* This requires no parsed sync configs, and deliberately does not resolve individual
|
|
8
|
+
* sources - use the parsed-set-bound {@link BucketDefinitionMapping} for that.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ReplicationStreamStorageIds {
|
|
11
|
+
private readonly mappings;
|
|
12
|
+
constructor(mappings: SingleSyncConfigBucketDefinitionMapping[]);
|
|
13
|
+
get bucketDefinitionIds(): BucketDefinitionId[];
|
|
14
|
+
get parameterIndexIds(): ParameterIndexId[];
|
|
15
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persisted storage ids for a replication stream, derived from the rule_mapping documents
|
|
3
|
+
* of all its sync configs.
|
|
4
|
+
*
|
|
5
|
+
* This requires no parsed sync configs, and deliberately does not resolve individual
|
|
6
|
+
* sources - use the parsed-set-bound {@link BucketDefinitionMapping} for that.
|
|
7
|
+
*/
|
|
8
|
+
export class ReplicationStreamStorageIds {
|
|
9
|
+
mappings;
|
|
10
|
+
constructor(mappings) {
|
|
11
|
+
this.mappings = mappings;
|
|
12
|
+
}
|
|
13
|
+
get bucketDefinitionIds() {
|
|
14
|
+
return [...new Set(this.mappings.flatMap((mapping) => mapping.allBucketDefinitionIds()))];
|
|
15
|
+
}
|
|
16
|
+
get parameterIndexIds() {
|
|
17
|
+
return [...new Set(this.mappings.flatMap((mapping) => mapping.allParameterIndexIds()))];
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ReplicationStreamStorageIds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReplicationStreamStorageIds.js","sourceRoot":"","sources":["../../../src/storage/implementation/ReplicationStreamStorageIds.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,MAAM,OAAO,2BAA2B;IACT;IAA7B,YAA6B,QAAmD;QAAnD,aAAQ,GAAR,QAAQ,CAA2C;IAAG,CAAC;IAEpF,IAAI,mBAAmB;QACrB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5F,CAAC;IAED,IAAI,iBAAiB;QACnB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1F,CAAC;CACF"}
|
|
@@ -2,16 +2,25 @@ export * from './bson.js';
|
|
|
2
2
|
export * from './BucketStorage.js';
|
|
3
3
|
export * from './BucketStorageBatch.js';
|
|
4
4
|
export * from './BucketStorageFactory.js';
|
|
5
|
+
export * from './CheckpointChecksumInvalidatedError.js';
|
|
5
6
|
export * from './ChecksumCache.js';
|
|
6
|
-
export * from './
|
|
7
|
+
export * from './ParsedSyncConfigSet.js';
|
|
8
|
+
export * from './PersistedReplicationStream.js';
|
|
9
|
+
export * from './PersistedSyncConfigContent.js';
|
|
10
|
+
export * from './PersistedSyncConfigStatus.js';
|
|
7
11
|
export * from './ReplicationEventPayload.js';
|
|
8
12
|
export * from './ReplicationLock.js';
|
|
9
13
|
export * from './ReportStorage.js';
|
|
10
14
|
export * from './SourceEntity.js';
|
|
11
15
|
export * from './SourceTable.js';
|
|
16
|
+
export * from './SourceTableReconciler.js';
|
|
12
17
|
export * from './storage-metrics.js';
|
|
13
18
|
export * from './StorageEngine.js';
|
|
14
19
|
export * from './StorageProvider.js';
|
|
15
20
|
export * from './StorageVersionConfig.js';
|
|
16
21
|
export * from './SyncRulesBucketStorage.js';
|
|
17
22
|
export * from './WriteCheckpointAPI.js';
|
|
23
|
+
export * from './implementation/BucketDefinitionMapping.js';
|
|
24
|
+
export * from './implementation/IncrementalReprocessingCompatibility.js';
|
|
25
|
+
export * from './implementation/IncrementalReprocessingSyncConfigLog.js';
|
|
26
|
+
export * from './implementation/ReplicationStreamStorageIds.js';
|
|
@@ -2,17 +2,26 @@ export * from './bson.js';
|
|
|
2
2
|
export * from './BucketStorage.js';
|
|
3
3
|
export * from './BucketStorageBatch.js';
|
|
4
4
|
export * from './BucketStorageFactory.js';
|
|
5
|
+
export * from './CheckpointChecksumInvalidatedError.js';
|
|
5
6
|
export * from './ChecksumCache.js';
|
|
6
|
-
export * from './
|
|
7
|
+
export * from './ParsedSyncConfigSet.js';
|
|
8
|
+
export * from './PersistedReplicationStream.js';
|
|
9
|
+
export * from './PersistedSyncConfigContent.js';
|
|
10
|
+
export * from './PersistedSyncConfigStatus.js';
|
|
7
11
|
export * from './ReplicationEventPayload.js';
|
|
8
12
|
export * from './ReplicationLock.js';
|
|
9
13
|
export * from './ReportStorage.js';
|
|
10
14
|
export * from './SourceEntity.js';
|
|
11
15
|
export * from './SourceTable.js';
|
|
16
|
+
export * from './SourceTableReconciler.js';
|
|
12
17
|
export * from './storage-metrics.js';
|
|
13
18
|
export * from './StorageEngine.js';
|
|
14
19
|
export * from './StorageProvider.js';
|
|
15
20
|
export * from './StorageVersionConfig.js';
|
|
16
21
|
export * from './SyncRulesBucketStorage.js';
|
|
17
22
|
export * from './WriteCheckpointAPI.js';
|
|
23
|
+
export * from './implementation/BucketDefinitionMapping.js';
|
|
24
|
+
export * from './implementation/IncrementalReprocessingCompatibility.js';
|
|
25
|
+
export * from './implementation/IncrementalReprocessingSyncConfigLog.js';
|
|
26
|
+
export * from './implementation/ReplicationStreamStorageIds.js';
|
|
18
27
|
//# sourceMappingURL=storage-index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-index.js","sourceRoot":"","sources":["../../src/storage/storage-index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC"}
|
|
1
|
+
{"version":3,"file":"storage-index.js","sourceRoot":"","sources":["../../src/storage/storage-index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,yCAAyC,CAAC;AACxD,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,iCAAiC,CAAC;AAChD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,yBAAyB,CAAC;AAExC,cAAc,6CAA6C,CAAC;AAC5D,cAAc,0DAA0D,CAAC;AACzE,cAAc,0DAA0D,CAAC;AACzE,cAAc,iDAAiD,CAAC"}
|
|
@@ -6,50 +6,166 @@ export function createCoreStorageMetrics(engine) {
|
|
|
6
6
|
description: 'Size of current data stored in PowerSync',
|
|
7
7
|
unit: 'bytes'
|
|
8
8
|
});
|
|
9
|
+
engine.createObservableGauge({
|
|
10
|
+
name: StorageMetric.ATTRIBUTED_SOURCE_RECORDS_BYTES,
|
|
11
|
+
description: 'Size of current data stored in PowerSync by sync config',
|
|
12
|
+
unit: 'bytes'
|
|
13
|
+
});
|
|
9
14
|
engine.createObservableGauge({
|
|
10
15
|
name: StorageMetric.OPERATION_SIZE_BYTES,
|
|
11
16
|
description: 'Size of operations stored in PowerSync',
|
|
12
17
|
unit: 'bytes'
|
|
13
18
|
});
|
|
19
|
+
engine.createObservableGauge({
|
|
20
|
+
name: StorageMetric.ATTRIBUTED_BUCKET_DATA_BYTES,
|
|
21
|
+
description: 'Size of operations stored in PowerSync by sync config',
|
|
22
|
+
unit: 'bytes'
|
|
23
|
+
});
|
|
14
24
|
engine.createObservableGauge({
|
|
15
25
|
name: StorageMetric.PARAMETER_SIZE_BYTES,
|
|
16
26
|
description: 'Size of parameter data stored in PowerSync',
|
|
17
27
|
unit: 'bytes'
|
|
18
28
|
});
|
|
29
|
+
engine.createObservableGauge({
|
|
30
|
+
name: StorageMetric.ATTRIBUTED_PARAMETER_INDEXES_BYTES,
|
|
31
|
+
description: 'Size of parameter data stored in PowerSync by sync config',
|
|
32
|
+
unit: 'bytes'
|
|
33
|
+
});
|
|
34
|
+
engine.createObservableGauge({
|
|
35
|
+
name: StorageMetric.OBJECT_STORAGE_SIZE_BYTES,
|
|
36
|
+
description: 'Size of active object-storage references stored in PowerSync',
|
|
37
|
+
unit: 'bytes'
|
|
38
|
+
});
|
|
39
|
+
engine.createObservableGauge({
|
|
40
|
+
name: StorageMetric.ATTRIBUTED_OBJECT_STORAGE_BYTES,
|
|
41
|
+
description: 'Size of active object-storage references by sync config',
|
|
42
|
+
unit: 'bytes'
|
|
43
|
+
});
|
|
19
44
|
}
|
|
20
45
|
export function initializeCoreStorageMetrics(engine, storage) {
|
|
21
46
|
const replication_storage_size_bytes = engine.getObservableGauge(StorageMetric.REPLICATION_SIZE_BYTES);
|
|
47
|
+
const attributed_source_records_bytes = engine.getObservableGauge(StorageMetric.ATTRIBUTED_SOURCE_RECORDS_BYTES);
|
|
22
48
|
const operation_storage_size_bytes = engine.getObservableGauge(StorageMetric.OPERATION_SIZE_BYTES);
|
|
49
|
+
const attributed_bucket_data_bytes = engine.getObservableGauge(StorageMetric.ATTRIBUTED_BUCKET_DATA_BYTES);
|
|
23
50
|
const parameter_storage_size_bytes = engine.getObservableGauge(StorageMetric.PARAMETER_SIZE_BYTES);
|
|
51
|
+
const attributed_parameter_indexes_bytes = engine.getObservableGauge(StorageMetric.ATTRIBUTED_PARAMETER_INDEXES_BYTES);
|
|
52
|
+
const object_storage_size_bytes = engine.getObservableGauge(StorageMetric.OBJECT_STORAGE_SIZE_BYTES);
|
|
53
|
+
const attributed_object_storage_bytes = engine.getObservableGauge(StorageMetric.ATTRIBUTED_OBJECT_STORAGE_BYTES);
|
|
24
54
|
const MINIMUM_INTERVAL = 60_000;
|
|
55
|
+
/**
|
|
56
|
+
* How long a sync config that is no longer present keeps being reported as zero.
|
|
57
|
+
*
|
|
58
|
+
* This must comfortably exceed the longest metric export interval, so that every configured
|
|
59
|
+
* reader observes the zero at least once. The OTLP reader exports every 5 minutes.
|
|
60
|
+
*/
|
|
61
|
+
const RETIRED_SYNC_CONFIG_INTERVAL = 15 * 60_000;
|
|
62
|
+
/**
|
|
63
|
+
* Attribute sets reported at least once, along with the last time each was present in the
|
|
64
|
+
* storage metrics.
|
|
65
|
+
*
|
|
66
|
+
* These gauges are exported with cumulative temporality, which means the metrics SDK keeps
|
|
67
|
+
* re-exporting the last reported value for every attribute set it has seen, also after we stop
|
|
68
|
+
* reporting that set. Without this, a sync config that has since been pruned would keep
|
|
69
|
+
* reporting its last non-zero size indefinitely, so sums over these gauges would drift upwards
|
|
70
|
+
* permanently. Reporting zero for a while instead leaves the SDK carrying a zero forward.
|
|
71
|
+
*/
|
|
72
|
+
const reportedSyncConfigs = new Map();
|
|
73
|
+
const syncConfigKey = (attributes) => JSON.stringify([attributes.sync_config_id, attributes.sync_config_state, attributes.version_label]);
|
|
74
|
+
const syncConfigAttributes = (syncConfig) => ({
|
|
75
|
+
sync_config_id: syncConfig.sync_config_id,
|
|
76
|
+
sync_config_state: syncConfig.sync_config_state,
|
|
77
|
+
...(syncConfig.version_label == null ? {} : { version_label: syncConfig.version_label })
|
|
78
|
+
});
|
|
79
|
+
const trackSyncConfigs = (metrics) => {
|
|
80
|
+
if (metrics == null) {
|
|
81
|
+
// Failed to read the metrics - this says nothing about which sync configs still exist.
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
for (const syncConfig of metrics.sync_config_metrics ?? []) {
|
|
86
|
+
const attributes = syncConfigAttributes(syncConfig);
|
|
87
|
+
reportedSyncConfigs.set(syncConfigKey(attributes), { attributes, lastSeen: now });
|
|
88
|
+
}
|
|
89
|
+
for (const [key, entry] of reportedSyncConfigs) {
|
|
90
|
+
if (now - entry.lastSeen > RETIRED_SYNC_CONFIG_INTERVAL) {
|
|
91
|
+
reportedSyncConfigs.delete(key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
};
|
|
25
95
|
let cachedRequest = undefined;
|
|
26
96
|
let cacheTimestamp = 0;
|
|
27
97
|
const getMetrics = () => {
|
|
28
98
|
if (!cachedRequest || Date.now() - cacheTimestamp > MINIMUM_INTERVAL) {
|
|
29
|
-
cachedRequest = storage
|
|
99
|
+
cachedRequest = storage
|
|
100
|
+
.getStorageMetrics()
|
|
101
|
+
.catch((e) => {
|
|
30
102
|
logger.error(`Failed to get storage metrics`, e);
|
|
31
103
|
return null;
|
|
104
|
+
})
|
|
105
|
+
.then((metrics) => {
|
|
106
|
+
trackSyncConfigs(metrics);
|
|
107
|
+
return metrics;
|
|
32
108
|
});
|
|
33
109
|
cacheTimestamp = Date.now();
|
|
34
110
|
}
|
|
35
111
|
return cachedRequest;
|
|
36
112
|
};
|
|
113
|
+
function nonNegative(value) {
|
|
114
|
+
return value == null ? value : Math.max(0, value);
|
|
115
|
+
}
|
|
116
|
+
const observationsForSyncConfigs = (metrics, key) => {
|
|
117
|
+
const observations = [];
|
|
118
|
+
const present = new Set();
|
|
119
|
+
for (const syncConfig of metrics.sync_config_metrics ?? []) {
|
|
120
|
+
const attributes = syncConfigAttributes(syncConfig);
|
|
121
|
+
present.add(syncConfigKey(attributes));
|
|
122
|
+
observations.push({ value: nonNegative(syncConfig[key]), attributes });
|
|
123
|
+
}
|
|
124
|
+
for (const entry of reportedSyncConfigs.values()) {
|
|
125
|
+
if (!present.has(syncConfigKey(entry.attributes))) {
|
|
126
|
+
observations.push({ value: 0, attributes: entry.attributes });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return observations;
|
|
130
|
+
};
|
|
37
131
|
replication_storage_size_bytes.setValueProvider(async () => {
|
|
132
|
+
const metrics = await getMetrics();
|
|
133
|
+
return nonNegative(metrics?.replication_size_bytes);
|
|
134
|
+
});
|
|
135
|
+
attributed_source_records_bytes.setValueProvider(async () => {
|
|
38
136
|
const metrics = await getMetrics();
|
|
39
137
|
if (metrics) {
|
|
40
|
-
return metrics
|
|
138
|
+
return observationsForSyncConfigs(metrics, 'attributed_source_records_bytes');
|
|
41
139
|
}
|
|
42
140
|
});
|
|
43
141
|
operation_storage_size_bytes.setValueProvider(async () => {
|
|
142
|
+
const metrics = await getMetrics();
|
|
143
|
+
return nonNegative(metrics?.operations_size_bytes);
|
|
144
|
+
});
|
|
145
|
+
attributed_bucket_data_bytes.setValueProvider(async () => {
|
|
44
146
|
const metrics = await getMetrics();
|
|
45
147
|
if (metrics) {
|
|
46
|
-
return metrics
|
|
148
|
+
return observationsForSyncConfigs(metrics, 'attributed_bucket_data_bytes');
|
|
47
149
|
}
|
|
48
150
|
});
|
|
49
151
|
parameter_storage_size_bytes.setValueProvider(async () => {
|
|
152
|
+
const metrics = await getMetrics();
|
|
153
|
+
return nonNegative(metrics?.parameters_size_bytes);
|
|
154
|
+
});
|
|
155
|
+
attributed_parameter_indexes_bytes.setValueProvider(async () => {
|
|
156
|
+
const metrics = await getMetrics();
|
|
157
|
+
if (metrics) {
|
|
158
|
+
return observationsForSyncConfigs(metrics, 'attributed_parameter_indexes_bytes');
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
object_storage_size_bytes.setValueProvider(async () => {
|
|
162
|
+
const metrics = await getMetrics();
|
|
163
|
+
return nonNegative(metrics?.object_storage_size_bytes);
|
|
164
|
+
});
|
|
165
|
+
attributed_object_storage_bytes.setValueProvider(async () => {
|
|
50
166
|
const metrics = await getMetrics();
|
|
51
167
|
if (metrics) {
|
|
52
|
-
return metrics
|
|
168
|
+
return observationsForSyncConfigs(metrics, 'attributed_object_storage_bytes');
|
|
53
169
|
}
|
|
54
170
|
});
|
|
55
171
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-metrics.js","sourceRoot":"","sources":["../../src/storage/storage-metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAIzD,MAAM,UAAU,wBAAwB,CAAC,MAAqB;IAC5D,MAAM,CAAC,qBAAqB,CAAC;QAC3B,IAAI,EAAE,aAAa,CAAC,sBAAsB;QAC1C,WAAW,EAAE,0CAA0C;QACvD,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,qBAAqB,CAAC;QAC3B,IAAI,EAAE,aAAa,CAAC,oBAAoB;QACxC,WAAW,EAAE,wCAAwC;QACrD,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;IAEH,MAAM,CAAC,qBAAqB,CAAC;QAC3B,IAAI,EAAE,aAAa,CAAC,oBAAoB;QACxC,WAAW,EAAE,4CAA4C;QACzD,IAAI,EAAE,OAAO;KACd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,MAAqB,EAAE,OAA6B;IAC/F,MAAM,8BAA8B,GAAG,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,sBAAsB,CAAC,CAAC;IACvG,MAAM,4BAA4B,GAAG,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;IACnG,MAAM,4BAA4B,GAAG,MAAM,CAAC,kBAAkB,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"storage-metrics.js","sourceRoot":"","sources":["../../src/storage/storage-metrics.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,9 @@ import * as storage from '../storage/storage-index.js';
|
|
|
3
3
|
import * as util from '../util/util-index.js';
|
|
4
4
|
import { Logger } from '@powersync/lib-services-framework';
|
|
5
5
|
import { JwtPayload } from '../auth/JwtPayload.js';
|
|
6
|
+
import { PerformanceTracer } from '../tracing/PerformanceTracer.js';
|
|
6
7
|
import { SyncContext } from './SyncContext.js';
|
|
8
|
+
export type SyncCheckpointTraceCategory = 'checkpoint' | 'parameters' | 'checksum' | 'acquiring_lock' | 'bucket_data' | 'sending' | 's3';
|
|
7
9
|
export interface BucketChecksumStateOptions {
|
|
8
10
|
syncContext: SyncContext;
|
|
9
11
|
bucketStorage: BucketChecksumStateStorage;
|
|
@@ -35,6 +37,12 @@ export declare class BucketChecksumState {
|
|
|
35
37
|
*/
|
|
36
38
|
private lastChecksums;
|
|
37
39
|
private lastWriteCheckpoint;
|
|
40
|
+
/**
|
|
41
|
+
* The next storage checkpoint diff may be relative to a checksum-invalidated
|
|
42
|
+
* checkpoint that was never sent to the client. Re-check every bucket once
|
|
43
|
+
* instead of applying that diff to the last client-visible checksums.
|
|
44
|
+
*/
|
|
45
|
+
private forceFullChecksumForNextCheckpoint;
|
|
38
46
|
/**
|
|
39
47
|
* Once we've sent the first full checkpoint line including all {@link util.Checkpoint.streams} that the user is
|
|
40
48
|
* subscribed to, we keep an index of the stream names to their index in that array.
|
|
@@ -54,6 +62,7 @@ export declare class BucketChecksumState {
|
|
|
54
62
|
private pendingBucketDownloads;
|
|
55
63
|
private readonly logger;
|
|
56
64
|
constructor(options: BucketChecksumStateOptions);
|
|
65
|
+
invalidateChecksumBaseline(): void;
|
|
57
66
|
/**
|
|
58
67
|
* Build a new checkpoint line for an underlying storage checkpoint update if any buckets have changed.
|
|
59
68
|
*
|
|
@@ -65,7 +74,7 @@ export declare class BucketChecksumState {
|
|
|
65
74
|
* @param next The updated checkpoint
|
|
66
75
|
* @returns A {@link CheckpointLine} if any of the buckets watched by this connected was updated, or otherwise `null`.
|
|
67
76
|
*/
|
|
68
|
-
buildNextCheckpointLine(next: storage.StorageCheckpointUpdate): Promise<CheckpointLine | null>;
|
|
77
|
+
buildNextCheckpointLine(next: storage.StorageCheckpointUpdate, tracer?: PerformanceTracer<SyncCheckpointTraceCategory>): Promise<CheckpointLine | null>;
|
|
69
78
|
}
|
|
70
79
|
declare const INVALIDATE_ALL_BUCKETS: unique symbol;
|
|
71
80
|
export interface CheckpointUpdate {
|
|
@@ -111,7 +120,7 @@ export declare class BucketParameterState {
|
|
|
111
120
|
*/
|
|
112
121
|
translateResolvedBucket(description: ResolvedBucket, lookupIndex: Map<string, number>): util.ClientBucketDescription;
|
|
113
122
|
isSubscribedToStream(desc: BucketSource): boolean;
|
|
114
|
-
getCheckpointUpdate(checkpoint: storage.StorageCheckpointUpdate): Promise<CheckpointUpdate>;
|
|
123
|
+
getCheckpointUpdate(checkpoint: storage.StorageCheckpointUpdate, tracer: PerformanceTracer<SyncCheckpointTraceCategory>): Promise<CheckpointUpdate>;
|
|
115
124
|
/**
|
|
116
125
|
* For static buckets, we can keep track of which buckets have been updated.
|
|
117
126
|
*/
|
|
@@ -124,6 +133,7 @@ export declare class BucketParameterState {
|
|
|
124
133
|
export interface CheckpointLine {
|
|
125
134
|
checkpointLine: util.StreamingSyncCheckpointDiff | util.StreamingSyncCheckpoint;
|
|
126
135
|
bucketsToFetch: ResolvedBucket[];
|
|
136
|
+
bucketDataRequestHint: storage.BucketRequestHint;
|
|
127
137
|
/**
|
|
128
138
|
* Call when a checkpoint line is being sent to a client, to update the internal state.
|
|
129
139
|
*/
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { mergeBuckets, RequestParameters } from '@powersync/service-sync-rules';
|
|
1
|
+
import { BucketSourceType, mergeBuckets, RequestParameters } from '@powersync/service-sync-rules';
|
|
2
2
|
import * as util from '../util/util-index.js';
|
|
3
3
|
import { logger as defaultLogger, ErrorCode, ServiceAssertionError, ServiceError } from '@powersync/lib-services-framework';
|
|
4
4
|
import { ParameterSetLimitExceededError } from '../storage/storage-index.js';
|
|
5
|
+
import { PerformanceTracer } from '../tracing/PerformanceTracer.js';
|
|
5
6
|
import { getIntersection, hasIntersection } from './util.js';
|
|
6
7
|
/**
|
|
7
8
|
* Represents the state of the checksums and data for a specific connection.
|
|
@@ -23,6 +24,12 @@ export class BucketChecksumState {
|
|
|
23
24
|
*/
|
|
24
25
|
lastChecksums = null;
|
|
25
26
|
lastWriteCheckpoint = null;
|
|
27
|
+
/**
|
|
28
|
+
* The next storage checkpoint diff may be relative to a checksum-invalidated
|
|
29
|
+
* checkpoint that was never sent to the client. Re-check every bucket once
|
|
30
|
+
* instead of applying that diff to the last client-visible checksums.
|
|
31
|
+
*/
|
|
32
|
+
forceFullChecksumForNextCheckpoint = false;
|
|
26
33
|
/**
|
|
27
34
|
* Once we've sent the first full checkpoint line including all {@link util.Checkpoint.streams} that the user is
|
|
28
35
|
* subscribed to, we keep an index of the stream names to their index in that array.
|
|
@@ -51,6 +58,9 @@ export class BucketChecksumState {
|
|
|
51
58
|
this.bucketDataPositions.set(name, { start_op_id: BigInt(start) });
|
|
52
59
|
}
|
|
53
60
|
}
|
|
61
|
+
invalidateChecksumBaseline() {
|
|
62
|
+
this.forceFullChecksumForNextCheckpoint = true;
|
|
63
|
+
}
|
|
54
64
|
/**
|
|
55
65
|
* Build a new checkpoint line for an underlying storage checkpoint update if any buckets have changed.
|
|
56
66
|
*
|
|
@@ -62,12 +72,14 @@ export class BucketChecksumState {
|
|
|
62
72
|
* @param next The updated checkpoint
|
|
63
73
|
* @returns A {@link CheckpointLine} if any of the buckets watched by this connected was updated, or otherwise `null`.
|
|
64
74
|
*/
|
|
65
|
-
async buildNextCheckpointLine(next) {
|
|
75
|
+
async buildNextCheckpointLine(next, tracer) {
|
|
76
|
+
tracer ??= new PerformanceTracer(`sync checkpoint ${next.base.checkpoint}`);
|
|
66
77
|
const { writeCheckpoint, base } = next;
|
|
67
78
|
const userIdForLogs = this.parameterState.syncParams.userId;
|
|
68
79
|
const storage = this.bucketStorage;
|
|
69
|
-
const update = await this.parameterState.getCheckpointUpdate(next);
|
|
80
|
+
const update = await this.parameterState.getCheckpointUpdate(next, tracer);
|
|
70
81
|
const { buckets: allBuckets, updatedBuckets, usedParameterResults } = update;
|
|
82
|
+
const forceFullChecksum = this.forceFullChecksumForNextCheckpoint;
|
|
71
83
|
/** Set of all buckets in this checkpoint. */
|
|
72
84
|
const bucketDescriptionMap = new Map(allBuckets.map((b) => [b.bucket, b]));
|
|
73
85
|
if (bucketDescriptionMap.size > this.context.maxBuckets) {
|
|
@@ -85,19 +97,22 @@ export class BucketChecksumState {
|
|
|
85
97
|
const count = bucketsByDefinition.get(definition) ?? 0;
|
|
86
98
|
bucketsByDefinition.set(definition, count + 1);
|
|
87
99
|
}
|
|
88
|
-
|
|
100
|
+
// Only 1 type is allowed per sync config
|
|
101
|
+
const bucketSourceType = this.parameterState.syncRules.bucketSourceDefinitions[0].type;
|
|
102
|
+
const breakdown = formatBucketDefinitionBreakdown(bucketsByDefinition, bucketSourceType);
|
|
89
103
|
errorMessage += breakdown.message;
|
|
90
104
|
logData.buckets_by_definition = breakdown.countsByDefinition;
|
|
91
105
|
this.logger.error(errorMessage, logData);
|
|
92
106
|
throw error;
|
|
93
107
|
}
|
|
94
108
|
let checksumMap;
|
|
95
|
-
if (updatedBuckets != INVALIDATE_ALL_BUCKETS) {
|
|
109
|
+
if (!forceFullChecksum && updatedBuckets != INVALIDATE_ALL_BUCKETS) {
|
|
96
110
|
if (this.lastChecksums == null) {
|
|
97
111
|
throw new ServiceAssertionError(`Bucket diff received without existing checksums`);
|
|
98
112
|
}
|
|
99
113
|
// Re-check updated buckets only
|
|
100
114
|
let checksumLookups = [];
|
|
115
|
+
let hasNewBucket = false;
|
|
101
116
|
let newChecksums = new Map();
|
|
102
117
|
for (let desc of bucketDescriptionMap.values()) {
|
|
103
118
|
if (!updatedBuckets.has(desc.bucket)) {
|
|
@@ -111,10 +126,14 @@ export class BucketChecksumState {
|
|
|
111
126
|
}
|
|
112
127
|
else {
|
|
113
128
|
checksumLookups.push({ bucket: desc.bucket, source: desc.source });
|
|
129
|
+
hasNewBucket ||= !this.lastChecksums.has(desc.bucket);
|
|
114
130
|
}
|
|
115
131
|
}
|
|
116
132
|
if (checksumLookups.length > 0) {
|
|
117
|
-
|
|
133
|
+
const requestHint = hasNewBucket ? 'bulk' : 'incremental';
|
|
134
|
+
let updatedChecksums;
|
|
135
|
+
using _ = tracer.span('checksum');
|
|
136
|
+
updatedChecksums = await storage.getChecksums(base, checksumLookups, { requestHint });
|
|
118
137
|
for (let [bucket, value] of updatedChecksums.entries()) {
|
|
119
138
|
newChecksums.set(bucket, value);
|
|
120
139
|
}
|
|
@@ -123,11 +142,20 @@ export class BucketChecksumState {
|
|
|
123
142
|
}
|
|
124
143
|
else {
|
|
125
144
|
// Re-check all buckets
|
|
126
|
-
const
|
|
127
|
-
|
|
145
|
+
const hasNewBucket = this.lastChecksums == null ||
|
|
146
|
+
[...bucketDescriptionMap.values()].some((b) => !this.lastChecksums.has(b.bucket));
|
|
147
|
+
const requestHint = hasNewBucket ? 'bulk' : 'incremental';
|
|
148
|
+
const bucketList = [...bucketDescriptionMap.values()].map((b) => ({
|
|
149
|
+
bucket: b.bucket,
|
|
150
|
+
source: b.source
|
|
151
|
+
}));
|
|
152
|
+
using _ = tracer.span('checksum');
|
|
153
|
+
checksumMap = await storage.getChecksums(base, bucketList, { requestHint });
|
|
128
154
|
}
|
|
129
155
|
// Subset of buckets for which there may be new data in this batch.
|
|
130
156
|
let bucketsToFetch;
|
|
157
|
+
let bucketDataRequestHint;
|
|
158
|
+
const newBucketDownloads = new Set();
|
|
131
159
|
let checkpointLine;
|
|
132
160
|
// Log function that is deferred until the checkpoint line is sent to the client.
|
|
133
161
|
let deferredLog;
|
|
@@ -140,6 +168,9 @@ export class BucketChecksumState {
|
|
|
140
168
|
diff.removedBuckets.length == 0 &&
|
|
141
169
|
diff.updatedBuckets.length == 0) {
|
|
142
170
|
// No changes - don't send anything to the client
|
|
171
|
+
if (forceFullChecksum) {
|
|
172
|
+
this.forceFullChecksumForNextCheckpoint = false;
|
|
173
|
+
}
|
|
143
174
|
return null;
|
|
144
175
|
}
|
|
145
176
|
let generateBucketsToFetch = new Set();
|
|
@@ -160,6 +191,12 @@ export class BucketChecksumState {
|
|
|
160
191
|
bucketsToFetch = [...generateBucketsToFetch].map((b) => {
|
|
161
192
|
return bucketDescriptionMap.get(b);
|
|
162
193
|
});
|
|
194
|
+
for (const bucket of diff.updatedBuckets) {
|
|
195
|
+
if (!this.lastChecksums.has(bucket.bucket)) {
|
|
196
|
+
newBucketDownloads.add(bucket.bucket);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
bucketDataRequestHint = newBucketDownloads.size > 0 ? 'bulk' : 'incremental';
|
|
163
200
|
deferredLog = () => {
|
|
164
201
|
let message = `Updated checkpoint: ${base.checkpoint} | `;
|
|
165
202
|
message += `write: ${writeCheckpoint} | `;
|
|
@@ -197,6 +234,10 @@ export class BucketChecksumState {
|
|
|
197
234
|
}, usedParameterResults);
|
|
198
235
|
};
|
|
199
236
|
bucketsToFetch = allBuckets;
|
|
237
|
+
for (const bucket of bucketsToFetch) {
|
|
238
|
+
newBucketDownloads.add(bucket.bucket);
|
|
239
|
+
}
|
|
240
|
+
bucketDataRequestHint = 'bulk';
|
|
200
241
|
const subscriptions = [];
|
|
201
242
|
const streamNameToIndex = new Map();
|
|
202
243
|
this.streamNameToIndex = streamNameToIndex;
|
|
@@ -230,6 +271,7 @@ export class BucketChecksumState {
|
|
|
230
271
|
return {
|
|
231
272
|
checkpointLine,
|
|
232
273
|
bucketsToFetch,
|
|
274
|
+
bucketDataRequestHint,
|
|
233
275
|
advance: () => {
|
|
234
276
|
hasAdvanced = true;
|
|
235
277
|
// bucketDataPositions must be updated in-place - it represents the current state of
|
|
@@ -261,6 +303,9 @@ export class BucketChecksumState {
|
|
|
261
303
|
this.lastChecksums = checksumMap;
|
|
262
304
|
this.lastWriteCheckpoint = writeCheckpoint;
|
|
263
305
|
this.pendingBucketDownloads = pendingBucketDownloads;
|
|
306
|
+
if (forceFullChecksum) {
|
|
307
|
+
this.forceFullChecksumForNextCheckpoint = false;
|
|
308
|
+
}
|
|
264
309
|
deferredLog();
|
|
265
310
|
},
|
|
266
311
|
getFilteredBucketPositions: (buckets) => {
|
|
@@ -383,12 +428,12 @@ export class BucketParameterState {
|
|
|
383
428
|
isSubscribedToStream(desc) {
|
|
384
429
|
return (desc.subscribedToByDefault && this.includeDefaultStreams) || this.subscribedStreamNames.has(desc.name);
|
|
385
430
|
}
|
|
386
|
-
async getCheckpointUpdate(checkpoint) {
|
|
431
|
+
async getCheckpointUpdate(checkpoint, tracer) {
|
|
387
432
|
const querier = this.querier;
|
|
388
433
|
let update;
|
|
389
434
|
if (querier.hasDynamicBuckets) {
|
|
390
435
|
try {
|
|
391
|
-
update = await this.getCheckpointUpdateDynamic(checkpoint);
|
|
436
|
+
update = await this.getCheckpointUpdateDynamic(checkpoint, tracer);
|
|
392
437
|
}
|
|
393
438
|
catch (e) {
|
|
394
439
|
if (e instanceof ParameterSetLimitExceededError) {
|
|
@@ -441,7 +486,7 @@ export class BucketParameterState {
|
|
|
441
486
|
/**
|
|
442
487
|
* For dynamic buckets, we need to re-query the list of buckets every time.
|
|
443
488
|
*/
|
|
444
|
-
async getCheckpointUpdateDynamic(checkpoint) {
|
|
489
|
+
async getCheckpointUpdateDynamic(checkpoint, tracer) {
|
|
445
490
|
const querier = this.querier;
|
|
446
491
|
const staticBuckets = this.staticBuckets.values();
|
|
447
492
|
const update = checkpoint.update;
|
|
@@ -490,6 +535,7 @@ export class BucketParameterState {
|
|
|
490
535
|
recordedLookups.add(lookup.serializedRepresentation);
|
|
491
536
|
}
|
|
492
537
|
try {
|
|
538
|
+
using _ = tracer.span('parameters', definition);
|
|
493
539
|
const results = await checkpoint.base.getParameterSets(lookups, remainingBudget);
|
|
494
540
|
const numRows = results.reduce((a, b) => a + b.rows.length, 0);
|
|
495
541
|
lookupLog.push({ definition, resultsOrLimit: numRows, didExceedLimit: false });
|
|
@@ -555,25 +601,27 @@ function logCheckpoint(logger, message, logData, totalParamResults) {
|
|
|
555
601
|
logger.info(message, logData);
|
|
556
602
|
}
|
|
557
603
|
/**
|
|
558
|
-
* Format a breakdown of dynamic
|
|
604
|
+
* Format a breakdown of dynamic buckets by sync stream or legacy bucket definition.
|
|
559
605
|
*
|
|
560
|
-
* Sorts definitions by count (descending), includes the top
|
|
606
|
+
* Sorts definitions by count (descending), includes the top 100, and returns both the
|
|
561
607
|
* formatted message string and the counts record suitable for structured log data.
|
|
562
608
|
*/
|
|
563
|
-
function formatBucketDefinitionBreakdown(bucketsByDefinition) {
|
|
564
|
-
|
|
609
|
+
function formatBucketDefinitionBreakdown(bucketsByDefinition, bucketSourceType) {
|
|
610
|
+
const maxLoggedDefinitions = 100;
|
|
611
|
+
// Sort definitions by count (descending) and take the largest entries.
|
|
565
612
|
const allSorted = Array.from(bucketsByDefinition.entries()).sort((a, b) => b[1] - a[1]);
|
|
566
|
-
const sortedDefinitions = allSorted.slice(0,
|
|
567
|
-
|
|
613
|
+
const sortedDefinitions = allSorted.slice(0, maxLoggedDefinitions);
|
|
614
|
+
const sourceLabel = bucketSourceType == BucketSourceType.SYNC_STREAM ? 'sync stream' : 'bucket definition';
|
|
615
|
+
let message = `\nBuckets by ${sourceLabel}:`;
|
|
568
616
|
const countsByDefinition = {};
|
|
569
617
|
for (const [definition, count] of sortedDefinitions) {
|
|
570
618
|
message += `\n ${definition}: ${count}`;
|
|
571
619
|
countsByDefinition[definition] = count;
|
|
572
620
|
}
|
|
573
|
-
if (allSorted.length >
|
|
574
|
-
const remainingResults = allSorted.slice(
|
|
575
|
-
const remainingDefinitions = allSorted.length -
|
|
576
|
-
message += `\n ... and ${remainingResults} more
|
|
621
|
+
if (allSorted.length > maxLoggedDefinitions) {
|
|
622
|
+
const remainingResults = allSorted.slice(maxLoggedDefinitions).reduce((sum, [, count]) => sum + count, 0);
|
|
623
|
+
const remainingDefinitions = allSorted.length - maxLoggedDefinitions;
|
|
624
|
+
message += `\n ... and ${remainingResults} more buckets from ${remainingDefinitions} ${sourceLabel}s`;
|
|
577
625
|
}
|
|
578
626
|
return { message, countsByDefinition };
|
|
579
627
|
}
|