@powersync/service-core 0.8.8 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/api/RouteAPI.d.ts +67 -0
- package/dist/api/RouteAPI.js +2 -0
- package/dist/api/RouteAPI.js.map +1 -0
- package/dist/api/api-index.d.ts +1 -0
- package/dist/api/api-index.js +1 -0
- package/dist/api/api-index.js.map +1 -1
- package/dist/api/diagnostics.d.ts +4 -4
- package/dist/api/diagnostics.js +170 -158
- package/dist/api/diagnostics.js.map +1 -1
- package/dist/api/schema.d.ts +3 -5
- package/dist/api/schema.js +14 -80
- package/dist/api/schema.js.map +1 -1
- package/dist/auth/CachedKeyCollector.js.map +1 -1
- package/dist/auth/KeySpec.js.map +1 -1
- package/dist/auth/KeyStore.d.ts +7 -4
- package/dist/auth/KeyStore.js +1 -1
- package/dist/auth/KeyStore.js.map +1 -1
- package/dist/auth/LeakyBucket.js.map +1 -1
- package/dist/auth/RemoteJWKSCollector.d.ts +0 -2
- package/dist/auth/RemoteJWKSCollector.js.map +1 -1
- package/dist/auth/auth-index.d.ts +0 -1
- package/dist/auth/auth-index.js +0 -1
- package/dist/auth/auth-index.js.map +1 -1
- package/dist/db/mongo.js +5 -3
- package/dist/db/mongo.js.map +1 -1
- package/dist/entry/cli-entry.js +3 -2
- package/dist/entry/cli-entry.js.map +1 -1
- package/dist/entry/commands/compact-action.js +90 -14
- package/dist/entry/commands/compact-action.js.map +1 -1
- package/dist/entry/commands/migrate-action.js +4 -5
- package/dist/entry/commands/migrate-action.js.map +1 -1
- package/dist/entry/commands/teardown-action.js +2 -2
- package/dist/entry/commands/teardown-action.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/locks/MongoLocks.js.map +1 -1
- package/dist/metrics/Metrics.d.ts +2 -2
- package/dist/metrics/Metrics.js +5 -13
- package/dist/metrics/Metrics.js.map +1 -1
- package/dist/migrations/db/migrations/1684951997326-init.d.ts +2 -2
- package/dist/migrations/db/migrations/1684951997326-init.js +4 -2
- package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -1
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +2 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +4 -2
- package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -1
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +2 -2
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +4 -2
- package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -1
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +31 -0
- package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
- package/dist/migrations/executor.js.map +1 -1
- package/dist/migrations/migrations.d.ts +8 -0
- package/dist/migrations/migrations.js +19 -7
- package/dist/migrations/migrations.js.map +1 -1
- package/dist/migrations/store/migration-store.js.map +1 -1
- package/dist/modules/AbstractModule.d.ts +26 -0
- package/dist/modules/AbstractModule.js +11 -0
- package/dist/modules/AbstractModule.js.map +1 -0
- package/dist/modules/ModuleManager.d.ts +11 -0
- package/dist/modules/ModuleManager.js +32 -0
- package/dist/modules/ModuleManager.js.map +1 -0
- package/dist/modules/modules-index.d.ts +2 -0
- package/dist/modules/modules-index.js +3 -0
- package/dist/modules/modules-index.js.map +1 -0
- package/dist/replication/AbstractReplicationJob.d.ts +37 -0
- package/dist/replication/AbstractReplicationJob.js +51 -0
- package/dist/replication/AbstractReplicationJob.js.map +1 -0
- package/dist/replication/AbstractReplicator.d.ts +53 -0
- package/dist/replication/AbstractReplicator.js +250 -0
- package/dist/replication/AbstractReplicator.js.map +1 -0
- package/dist/replication/ErrorRateLimiter.d.ts +0 -10
- package/dist/replication/ErrorRateLimiter.js +1 -42
- package/dist/replication/ErrorRateLimiter.js.map +1 -1
- package/dist/replication/ReplicationEngine.d.ts +18 -0
- package/dist/replication/ReplicationEngine.js +41 -0
- package/dist/replication/ReplicationEngine.js.map +1 -0
- package/dist/replication/ReplicationModule.d.ts +51 -0
- package/dist/replication/ReplicationModule.js +68 -0
- package/dist/replication/ReplicationModule.js.map +1 -0
- package/dist/replication/replication-index.d.ts +4 -6
- package/dist/replication/replication-index.js +4 -6
- package/dist/replication/replication-index.js.map +1 -1
- package/dist/routes/RouterEngine.d.ts +42 -0
- package/dist/routes/RouterEngine.js +80 -0
- package/dist/routes/RouterEngine.js.map +1 -0
- package/dist/routes/auth.d.ts +2 -2
- package/dist/routes/auth.js +11 -11
- package/dist/routes/auth.js.map +1 -1
- package/dist/routes/configure-fastify.d.ts +37 -23
- package/dist/routes/configure-fastify.js +18 -18
- package/dist/routes/configure-fastify.js.map +1 -1
- package/dist/routes/configure-rsocket.d.ts +3 -4
- package/dist/routes/configure-rsocket.js +7 -4
- package/dist/routes/configure-rsocket.js.map +1 -1
- package/dist/routes/endpoints/admin.d.ts +30 -0
- package/dist/routes/endpoints/admin.js +46 -67
- package/dist/routes/endpoints/admin.js.map +1 -1
- package/dist/routes/endpoints/checkpointing.js +103 -15
- package/dist/routes/endpoints/checkpointing.js.map +1 -1
- package/dist/routes/endpoints/socket-route.js +8 -6
- package/dist/routes/endpoints/socket-route.js.map +1 -1
- package/dist/routes/endpoints/sync-rules.d.ts +1 -1
- package/dist/routes/endpoints/sync-rules.js +32 -23
- package/dist/routes/endpoints/sync-rules.js.map +1 -1
- package/dist/routes/endpoints/sync-stream.d.ts +0 -1
- package/dist/routes/endpoints/sync-stream.js +8 -8
- package/dist/routes/endpoints/sync-stream.js.map +1 -1
- package/dist/routes/hooks.js.map +1 -1
- package/dist/routes/route-register.js.map +1 -1
- package/dist/routes/router.d.ts +9 -2
- package/dist/routes/router.js.map +1 -1
- package/dist/routes/routes-index.d.ts +1 -0
- package/dist/routes/routes-index.js +1 -0
- package/dist/routes/routes-index.js.map +1 -1
- package/dist/runner/teardown.js +109 -76
- package/dist/runner/teardown.js.map +1 -1
- package/dist/storage/BucketStorage.d.ts +86 -36
- package/dist/storage/BucketStorage.js +6 -10
- package/dist/storage/BucketStorage.js.map +1 -1
- package/dist/storage/ChecksumCache.js.map +1 -1
- package/dist/storage/MongoBucketStorage.d.ts +7 -11
- package/dist/storage/MongoBucketStorage.js +48 -41
- package/dist/storage/MongoBucketStorage.js.map +1 -1
- package/dist/storage/ReplicationEventPayload.d.ts +14 -0
- package/dist/storage/ReplicationEventPayload.js +2 -0
- package/dist/storage/ReplicationEventPayload.js.map +1 -0
- package/dist/storage/SourceEntity.d.ts +20 -0
- package/dist/storage/SourceEntity.js +2 -0
- package/dist/storage/SourceEntity.js.map +1 -0
- package/dist/storage/SourceTable.d.ts +12 -5
- package/dist/storage/SourceTable.js +12 -5
- package/dist/storage/SourceTable.js.map +1 -1
- package/dist/storage/StorageEngine.d.ts +28 -0
- package/dist/storage/StorageEngine.js +45 -0
- package/dist/storage/StorageEngine.js.map +1 -0
- package/dist/storage/StorageProvider.d.ts +21 -0
- package/dist/storage/StorageProvider.js +2 -0
- package/dist/storage/StorageProvider.js.map +1 -0
- package/dist/storage/WriteCheckpointAPI.d.ts +74 -0
- package/dist/storage/WriteCheckpointAPI.js +16 -0
- package/dist/storage/WriteCheckpointAPI.js.map +1 -0
- package/dist/storage/mongo/MongoBucketBatch.d.ts +24 -5
- package/dist/storage/mongo/MongoBucketBatch.js +119 -62
- package/dist/storage/mongo/MongoBucketBatch.js.map +1 -1
- package/dist/storage/mongo/MongoCompactor.js +20 -3
- package/dist/storage/mongo/MongoCompactor.js.map +1 -1
- package/dist/storage/mongo/MongoIdSequence.js.map +1 -1
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.d.ts +2 -2
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js +2 -2
- package/dist/storage/mongo/MongoPersistedSyncRulesContent.js.map +1 -1
- package/dist/storage/mongo/MongoStorageProvider.d.ts +5 -0
- package/dist/storage/mongo/MongoStorageProvider.js +26 -0
- package/dist/storage/mongo/MongoStorageProvider.js.map +1 -0
- package/dist/storage/mongo/MongoSyncBucketStorage.d.ts +18 -10
- package/dist/storage/mongo/MongoSyncBucketStorage.js +140 -25
- package/dist/storage/mongo/MongoSyncBucketStorage.js.map +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js +1 -1
- package/dist/storage/mongo/MongoSyncRulesLock.js.map +1 -1
- package/dist/storage/mongo/MongoWriteCheckpointAPI.d.ts +20 -0
- package/dist/storage/mongo/MongoWriteCheckpointAPI.js +103 -0
- package/dist/storage/mongo/MongoWriteCheckpointAPI.js.map +1 -0
- package/dist/storage/mongo/OperationBatch.d.ts +13 -4
- package/dist/storage/mongo/OperationBatch.js +25 -7
- package/dist/storage/mongo/OperationBatch.js.map +1 -1
- package/dist/storage/mongo/PersistedBatch.d.ts +3 -3
- package/dist/storage/mongo/PersistedBatch.js +2 -2
- package/dist/storage/mongo/PersistedBatch.js.map +1 -1
- package/dist/storage/mongo/config.d.ts +19 -0
- package/dist/storage/mongo/config.js +26 -0
- package/dist/storage/mongo/config.js.map +1 -0
- package/dist/storage/mongo/db.d.ts +3 -2
- package/dist/storage/mongo/db.js +1 -0
- package/dist/storage/mongo/db.js.map +1 -1
- package/dist/storage/mongo/models.d.ts +20 -5
- package/dist/storage/mongo/models.js.map +1 -1
- package/dist/storage/mongo/util.d.ts +12 -1
- package/dist/storage/mongo/util.js +50 -2
- package/dist/storage/mongo/util.js.map +1 -1
- package/dist/storage/storage-index.d.ts +8 -2
- package/dist/storage/storage-index.js +8 -2
- package/dist/storage/storage-index.js.map +1 -1
- package/dist/sync/BroadcastIterable.d.ts +0 -1
- package/dist/sync/BroadcastIterable.js.map +1 -1
- package/dist/sync/LastValueSink.d.ts +0 -1
- package/dist/sync/LastValueSink.js.map +1 -1
- package/dist/sync/merge.d.ts +0 -1
- package/dist/sync/merge.js.map +1 -1
- package/dist/sync/safeRace.js.map +1 -1
- package/dist/sync/sync.d.ts +1 -1
- package/dist/sync/sync.js +5 -5
- package/dist/sync/sync.js.map +1 -1
- package/dist/sync/util.d.ts +0 -2
- package/dist/sync/util.js.map +1 -1
- package/dist/system/ServiceContext.d.ts +37 -0
- package/dist/system/ServiceContext.js +48 -0
- package/dist/system/ServiceContext.js.map +1 -0
- package/dist/system/system-index.d.ts +1 -1
- package/dist/system/system-index.js +1 -1
- package/dist/system/system-index.js.map +1 -1
- package/dist/util/Mutex.js.map +1 -1
- package/dist/util/config/collectors/config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/base64-config-collector.js.map +1 -1
- package/dist/util/config/collectors/impl/filesystem-config-collector.js.map +1 -1
- package/dist/util/config/compound-config-collector.d.ts +9 -2
- package/dist/util/config/compound-config-collector.js +16 -24
- package/dist/util/config/compound-config-collector.js.map +1 -1
- 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.map +1 -1
- package/dist/util/config/sync-rules/impl/inline-sync-rules-collector.js.map +1 -1
- package/dist/util/config/sync-rules/sync-rules-provider.d.ts +9 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js +15 -0
- package/dist/util/config/sync-rules/sync-rules-provider.js.map +1 -0
- package/dist/util/config/types.d.ts +7 -4
- package/dist/util/config/types.js.map +1 -1
- package/dist/util/config.d.ts +3 -4
- package/dist/util/config.js +5 -20
- package/dist/util/config.js.map +1 -1
- package/dist/util/memory-tracking.js.map +1 -1
- package/dist/util/secs.js.map +1 -1
- package/dist/util/util-index.d.ts +3 -6
- package/dist/util/util-index.js +3 -6
- package/dist/util/util-index.js.map +1 -1
- package/dist/util/utils.d.ts +10 -7
- package/dist/util/utils.js +36 -25
- package/dist/util/utils.js.map +1 -1
- package/package.json +8 -12
- package/src/api/RouteAPI.ts +78 -0
- package/src/api/api-index.ts +1 -0
- package/src/api/diagnostics.ts +18 -70
- package/src/api/schema.ts +18 -90
- package/src/auth/KeyStore.ts +9 -6
- package/src/auth/RemoteJWKSCollector.ts +4 -1
- package/src/auth/auth-index.ts +0 -1
- package/src/db/mongo.ts +5 -3
- package/src/entry/cli-entry.ts +3 -2
- package/src/entry/commands/compact-action.ts +24 -12
- package/src/entry/commands/migrate-action.ts +5 -8
- package/src/entry/commands/teardown-action.ts +2 -2
- package/src/index.ts +5 -2
- package/src/metrics/Metrics.ts +6 -16
- package/src/migrations/db/migrations/1684951997326-init.ts +9 -4
- package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +7 -4
- package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +6 -4
- package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +37 -0
- package/src/migrations/migrations.ts +24 -8
- package/src/modules/AbstractModule.ts +37 -0
- package/src/modules/ModuleManager.ts +34 -0
- package/src/modules/modules-index.ts +2 -0
- package/src/replication/AbstractReplicationJob.ts +79 -0
- package/src/replication/AbstractReplicator.ts +228 -0
- package/src/replication/ErrorRateLimiter.ts +0 -44
- package/src/replication/ReplicationEngine.ts +43 -0
- package/src/replication/ReplicationModule.ts +122 -0
- package/src/replication/replication-index.ts +4 -6
- package/src/routes/RouterEngine.ts +120 -0
- package/src/routes/auth.ts +21 -12
- package/src/routes/configure-fastify.ts +26 -27
- package/src/routes/configure-rsocket.ts +13 -8
- package/src/routes/endpoints/admin.ts +72 -76
- package/src/routes/endpoints/checkpointing.ts +51 -11
- package/src/routes/endpoints/socket-route.ts +10 -6
- package/src/routes/endpoints/sync-rules.ts +41 -25
- package/src/routes/endpoints/sync-stream.ts +8 -8
- package/src/routes/router.ts +8 -3
- package/src/routes/routes-index.ts +1 -0
- package/src/runner/teardown.ts +50 -88
- package/src/storage/BucketStorage.ts +103 -41
- package/src/storage/MongoBucketStorage.ts +65 -53
- package/src/storage/ReplicationEventPayload.ts +16 -0
- package/src/storage/SourceEntity.ts +22 -0
- package/src/storage/SourceTable.ts +14 -7
- package/src/storage/StorageEngine.ts +62 -0
- package/src/storage/StorageProvider.ts +27 -0
- package/src/storage/WriteCheckpointAPI.ts +85 -0
- package/src/storage/mongo/MongoBucketBatch.ts +164 -84
- package/src/storage/mongo/MongoCompactor.ts +25 -4
- package/src/storage/mongo/MongoPersistedSyncRulesContent.ts +7 -4
- package/src/storage/mongo/MongoStorageProvider.ts +31 -0
- package/src/storage/mongo/MongoSyncBucketStorage.ts +118 -41
- package/src/storage/mongo/MongoSyncRulesLock.ts +7 -3
- package/src/storage/mongo/MongoWriteCheckpointAPI.ts +151 -0
- package/src/storage/mongo/OperationBatch.ts +28 -12
- package/src/storage/mongo/PersistedBatch.ts +10 -6
- package/src/storage/mongo/config.ts +40 -0
- package/src/storage/mongo/db.ts +4 -1
- package/src/storage/mongo/models.ts +21 -5
- package/src/storage/mongo/util.ts +48 -3
- package/src/storage/storage-index.ts +8 -2
- package/src/sync/sync.ts +7 -4
- package/src/sync/util.ts +0 -1
- package/src/system/ServiceContext.ts +68 -0
- package/src/system/system-index.ts +1 -1
- package/src/util/config/compound-config-collector.ts +31 -31
- package/src/util/config/sync-rules/sync-rules-provider.ts +18 -0
- package/src/util/config/types.ts +7 -5
- package/src/util/config.ts +6 -23
- package/src/util/util-index.ts +3 -6
- package/src/util/utils.ts +48 -41
- package/test/src/__snapshots__/sync.test.ts.snap +14 -14
- package/test/src/auth.test.ts +7 -7
- package/test/src/broadcast_iterable.test.ts +1 -1
- package/test/src/compacting.test.ts +50 -40
- package/test/src/data_storage.test.ts +382 -202
- package/test/src/env.ts +1 -3
- package/test/src/merge_iterable.test.ts +1 -6
- package/test/src/routes/probes.integration.test.ts +34 -30
- package/test/src/setup.ts +1 -1
- package/test/src/stream_utils.ts +42 -0
- package/test/src/sync.test.ts +115 -39
- package/test/src/util.ts +48 -51
- package/test/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.ts +7 -1
- package/dist/auth/SupabaseKeyCollector.d.ts +0 -22
- package/dist/auth/SupabaseKeyCollector.js +0 -61
- package/dist/auth/SupabaseKeyCollector.js.map +0 -1
- package/dist/replication/PgRelation.d.ts +0 -16
- package/dist/replication/PgRelation.js +0 -26
- package/dist/replication/PgRelation.js.map +0 -1
- package/dist/replication/WalConnection.d.ts +0 -34
- package/dist/replication/WalConnection.js +0 -190
- package/dist/replication/WalConnection.js.map +0 -1
- package/dist/replication/WalStream.d.ts +0 -57
- package/dist/replication/WalStream.js +0 -519
- package/dist/replication/WalStream.js.map +0 -1
- package/dist/replication/WalStreamManager.d.ts +0 -30
- package/dist/replication/WalStreamManager.js +0 -198
- package/dist/replication/WalStreamManager.js.map +0 -1
- package/dist/replication/WalStreamRunner.d.ts +0 -38
- package/dist/replication/WalStreamRunner.js +0 -155
- package/dist/replication/WalStreamRunner.js.map +0 -1
- package/dist/replication/util.d.ts +0 -9
- package/dist/replication/util.js +0 -62
- package/dist/replication/util.js.map +0 -1
- package/dist/system/CorePowerSyncSystem.d.ts +0 -23
- package/dist/system/CorePowerSyncSystem.js +0 -52
- package/dist/system/CorePowerSyncSystem.js.map +0 -1
- package/dist/util/PgManager.d.ts +0 -24
- package/dist/util/PgManager.js +0 -55
- package/dist/util/PgManager.js.map +0 -1
- package/dist/util/migration_lib.d.ts +0 -11
- package/dist/util/migration_lib.js +0 -64
- package/dist/util/migration_lib.js.map +0 -1
- package/dist/util/pgwire_utils.d.ts +0 -24
- package/dist/util/pgwire_utils.js +0 -117
- package/dist/util/pgwire_utils.js.map +0 -1
- package/dist/util/populate_test_data.d.ts +0 -8
- package/dist/util/populate_test_data.js +0 -65
- package/dist/util/populate_test_data.js.map +0 -1
- package/src/auth/SupabaseKeyCollector.ts +0 -67
- package/src/replication/PgRelation.ts +0 -42
- package/src/replication/WalConnection.ts +0 -227
- package/src/replication/WalStream.ts +0 -631
- package/src/replication/WalStreamManager.ts +0 -213
- package/src/replication/WalStreamRunner.ts +0 -180
- package/src/replication/util.ts +0 -76
- package/src/system/CorePowerSyncSystem.ts +0 -64
- package/src/util/PgManager.ts +0 -64
- package/src/util/migration_lib.ts +0 -79
- package/src/util/pgwire_utils.ts +0 -139
- package/src/util/populate_test_data.ts +0 -78
- package/test/src/__snapshots__/pg_test.test.ts.snap +0 -256
- package/test/src/large_batch.test.ts +0 -194
- package/test/src/pg_test.test.ts +0 -450
- package/test/src/schema_changes.test.ts +0 -545
- package/test/src/slow_tests.test.ts +0 -338
- package/test/src/validation.test.ts +0 -63
- package/test/src/wal_stream.test.ts +0 -319
- package/test/src/wal_stream_utils.ts +0 -156
package/src/runner/teardown.ts
CHANGED
|
@@ -1,108 +1,70 @@
|
|
|
1
1
|
// Script to tear down the data when deleting an instance.
|
|
2
|
-
// This
|
|
3
|
-
// 1.
|
|
4
|
-
// 2.
|
|
2
|
+
// This should:
|
|
3
|
+
// 1. Attempt to clean up any remote configuration of data sources that was set up.
|
|
4
|
+
// 2. Delete the storage
|
|
5
5
|
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import * as
|
|
6
|
+
import { container, logger } from '@powersync/lib-services-framework';
|
|
7
|
+
import timers from 'timers/promises';
|
|
8
|
+
import * as modules from '../modules/modules-index.js';
|
|
9
9
|
import * as storage from '../storage/storage-index.js';
|
|
10
|
+
import * as system from '../system/system-index.js';
|
|
10
11
|
import * as utils from '../util/util-index.js';
|
|
11
|
-
import * as replication from '../replication/replication-index.js';
|
|
12
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
* Attempt to terminate a single sync rules instance.
|
|
16
|
-
*
|
|
17
|
-
* This may fail with a lock error.
|
|
18
|
-
*/
|
|
19
|
-
async function terminateReplicator(
|
|
20
|
-
storageFactory: storage.BucketStorageFactory,
|
|
21
|
-
connection: utils.ResolvedConnection,
|
|
22
|
-
syncRules: storage.PersistedSyncRulesContent
|
|
23
|
-
) {
|
|
24
|
-
// The lock may still be active if the current replication instance
|
|
25
|
-
// hasn't stopped yet.
|
|
26
|
-
const lock = await syncRules.lock();
|
|
13
|
+
export async function teardown(runnerConfig: utils.RunnerConfig) {
|
|
27
14
|
try {
|
|
28
|
-
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
});
|
|
15
|
+
logger.info(`Tearing down PowerSync instance...`);
|
|
16
|
+
const config = await utils.loadConfig(runnerConfig);
|
|
17
|
+
const serviceContext = new system.ServiceContextContainer(config);
|
|
18
|
+
const moduleManager = container.getImplementation(modules.ModuleManager);
|
|
19
|
+
await moduleManager.initialize(serviceContext);
|
|
20
|
+
// This is mostly done to ensure that the storage is ready
|
|
21
|
+
await serviceContext.lifeCycleEngine.start();
|
|
36
22
|
|
|
37
|
-
|
|
38
|
-
await
|
|
39
|
-
logger.info(`
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
await terminateSyncRules(serviceContext.storageEngine.activeBucketStorage, moduleManager);
|
|
24
|
+
await serviceContext.storageEngine.activeStorage.tearDown();
|
|
25
|
+
logger.info(`Teardown complete.`);
|
|
26
|
+
process.exit(0);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
logger.error(`Teardown failure`, e);
|
|
29
|
+
process.exit(1);
|
|
42
30
|
}
|
|
43
31
|
}
|
|
44
32
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
*
|
|
48
|
-
* Retries lock and other errors for up to two minutes.
|
|
49
|
-
*
|
|
50
|
-
* This is a best-effot attempt. In some cases it may not be possible to delete the replication
|
|
51
|
-
* slot, such as when the postgres instance is unreachable.
|
|
52
|
-
*/
|
|
53
|
-
async function terminateReplicators(
|
|
54
|
-
storageFactory: storage.BucketStorageFactory,
|
|
55
|
-
connection: utils.ResolvedConnection
|
|
56
|
-
) {
|
|
33
|
+
async function terminateSyncRules(storageFactory: storage.BucketStorageFactory, moduleManager: modules.ModuleManager) {
|
|
34
|
+
logger.info(`Terminating sync rules...`);
|
|
57
35
|
const start = Date.now();
|
|
58
|
-
|
|
36
|
+
const locks: storage.ReplicationLock[] = [];
|
|
37
|
+
while (Date.now() - start < 120_000) {
|
|
59
38
|
let retry = false;
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
39
|
+
const replicatingSyncRules = await storageFactory.getReplicatingSyncRules();
|
|
40
|
+
// Lock all the replicating sync rules
|
|
41
|
+
for (const replicatingSyncRule of replicatingSyncRules) {
|
|
42
|
+
const lock = await replicatingSyncRule.lock();
|
|
43
|
+
locks.push(lock);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stoppedSyncRules = await storageFactory.getStoppedSyncRules();
|
|
47
|
+
const combinedSyncRules = [...replicatingSyncRules, ...stoppedSyncRules];
|
|
48
|
+
try {
|
|
49
|
+
// Clean up any module specific configuration for the sync rules
|
|
50
|
+
await moduleManager.tearDown({ syncRules: combinedSyncRules });
|
|
51
|
+
|
|
52
|
+
// Mark the sync rules as terminated
|
|
53
|
+
for (let syncRules of combinedSyncRules) {
|
|
54
|
+
using syncRulesStorage = storageFactory.getInstance(syncRules);
|
|
55
|
+
// The storage will be dropped at the end of the teardown, so we don't need to clear it here
|
|
56
|
+
await syncRulesStorage.terminate({ clearStorage: false });
|
|
57
|
+
}
|
|
58
|
+
} catch (e) {
|
|
59
|
+
retry = true;
|
|
60
|
+
for (const lock of locks) {
|
|
61
|
+
await lock.release();
|
|
68
62
|
}
|
|
69
63
|
}
|
|
64
|
+
|
|
70
65
|
if (!retry) {
|
|
71
66
|
break;
|
|
72
67
|
}
|
|
73
68
|
await timers.setTimeout(5_000);
|
|
74
69
|
}
|
|
75
70
|
}
|
|
76
|
-
|
|
77
|
-
export async function teardown(runnerConfig: utils.RunnerConfig) {
|
|
78
|
-
const config = await utils.loadConfig(runnerConfig);
|
|
79
|
-
const mongoDB = storage.createPowerSyncMongo(config.storage);
|
|
80
|
-
try {
|
|
81
|
-
logger.info(`Waiting for auth`);
|
|
82
|
-
await db.mongo.waitForAuth(mongoDB.db);
|
|
83
|
-
|
|
84
|
-
const bucketStorage = new storage.MongoBucketStorage(mongoDB, { slot_name_prefix: config.slot_name_prefix });
|
|
85
|
-
const connection = config.connection;
|
|
86
|
-
|
|
87
|
-
logger.info(`Terminating replication slots`);
|
|
88
|
-
|
|
89
|
-
if (connection) {
|
|
90
|
-
await terminateReplicators(bucketStorage, connection);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const database = mongoDB.db;
|
|
94
|
-
logger.info(`Dropping database ${database.namespace}`);
|
|
95
|
-
await database.dropDatabase();
|
|
96
|
-
logger.info(`Done`);
|
|
97
|
-
await mongoDB.client.close();
|
|
98
|
-
|
|
99
|
-
// If there was an error connecting to postgress, the process may stay open indefinitely.
|
|
100
|
-
// This forces an exit.
|
|
101
|
-
// We do not consider those errors a teardown failure.
|
|
102
|
-
process.exit(0);
|
|
103
|
-
} catch (e) {
|
|
104
|
-
logger.error(`Teardown failure`, e);
|
|
105
|
-
await mongoDB.client.close();
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DisposableListener, DisposableObserverClient } from '@powersync/lib-services-framework';
|
|
1
2
|
import {
|
|
2
3
|
EvaluatedParameters,
|
|
3
4
|
EvaluatedRow,
|
|
@@ -7,12 +8,19 @@ import {
|
|
|
7
8
|
SqliteRow,
|
|
8
9
|
ToastableSqliteRow
|
|
9
10
|
} from '@powersync/service-sync-rules';
|
|
10
|
-
|
|
11
|
-
import * as replication from '../replication/replication-index.js';
|
|
12
11
|
import * as util from '../util/util-index.js';
|
|
12
|
+
import { ReplicationEventPayload } from './ReplicationEventPayload.js';
|
|
13
|
+
import { SourceEntityDescriptor } from './SourceEntity.js';
|
|
13
14
|
import { SourceTable } from './SourceTable.js';
|
|
15
|
+
import { BatchedCustomWriteCheckpointOptions, ReplicaId } from './storage-index.js';
|
|
16
|
+
import { SyncStorageWriteCheckpointAPI } from './WriteCheckpointAPI.js';
|
|
17
|
+
|
|
18
|
+
export interface BucketStorageFactoryListener extends DisposableListener {
|
|
19
|
+
syncStorageCreated: (storage: SyncRulesBucketStorage) => void;
|
|
20
|
+
replicationEvent: (event: ReplicationEventPayload) => void;
|
|
21
|
+
}
|
|
14
22
|
|
|
15
|
-
export interface BucketStorageFactory {
|
|
23
|
+
export interface BucketStorageFactory extends DisposableObserverClient<BucketStorageFactoryListener> {
|
|
16
24
|
/**
|
|
17
25
|
* Update sync rules from configuration, if changed.
|
|
18
26
|
*/
|
|
@@ -24,7 +32,7 @@ export interface BucketStorageFactory {
|
|
|
24
32
|
/**
|
|
25
33
|
* Get a storage instance to query sync data for specific sync rules.
|
|
26
34
|
*/
|
|
27
|
-
getInstance(options:
|
|
35
|
+
getInstance(options: PersistedSyncRulesContent): SyncRulesBucketStorage;
|
|
28
36
|
|
|
29
37
|
/**
|
|
30
38
|
* Deploy new sync rules.
|
|
@@ -48,7 +56,7 @@ export interface BucketStorageFactory {
|
|
|
48
56
|
/**
|
|
49
57
|
* Get the sync rules used for querying.
|
|
50
58
|
*/
|
|
51
|
-
getActiveSyncRules(): Promise<PersistedSyncRules | null>;
|
|
59
|
+
getActiveSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null>;
|
|
52
60
|
|
|
53
61
|
/**
|
|
54
62
|
* Get the sync rules used for querying.
|
|
@@ -58,7 +66,7 @@ export interface BucketStorageFactory {
|
|
|
58
66
|
/**
|
|
59
67
|
* Get the sync rules that will be active next once done with initial replicatino.
|
|
60
68
|
*/
|
|
61
|
-
getNextSyncRules(): Promise<PersistedSyncRules | null>;
|
|
69
|
+
getNextSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null>;
|
|
62
70
|
|
|
63
71
|
/**
|
|
64
72
|
* Get the sync rules that will be active next once done with initial replicatino.
|
|
@@ -81,10 +89,9 @@ export interface BucketStorageFactory {
|
|
|
81
89
|
*/
|
|
82
90
|
getActiveCheckpoint(): Promise<ActiveCheckpoint>;
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
92
|
+
/**
|
|
93
|
+
* Yields the latest user write checkpoint whenever the sync checkpoint updates.
|
|
94
|
+
*/
|
|
88
95
|
watchWriteCheckpoint(user_id: string, signal: AbortSignal): AsyncIterable<WriteCheckpoint>;
|
|
89
96
|
|
|
90
97
|
/**
|
|
@@ -98,20 +105,22 @@ export interface BucketStorageFactory {
|
|
|
98
105
|
getPowerSyncInstanceId(): Promise<string>;
|
|
99
106
|
}
|
|
100
107
|
|
|
101
|
-
export interface
|
|
102
|
-
base: ActiveCheckpoint;
|
|
103
|
-
writeCheckpoint: bigint | null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export interface ActiveCheckpoint {
|
|
108
|
+
export interface ReplicationCheckpoint {
|
|
107
109
|
readonly checkpoint: util.OpId;
|
|
108
|
-
readonly lsn: string;
|
|
110
|
+
readonly lsn: string | null;
|
|
111
|
+
}
|
|
109
112
|
|
|
113
|
+
export interface ActiveCheckpoint extends ReplicationCheckpoint {
|
|
110
114
|
hasSyncRules(): boolean;
|
|
111
115
|
|
|
112
116
|
getBucketStorage(): Promise<SyncRulesBucketStorage | null>;
|
|
113
117
|
}
|
|
114
118
|
|
|
119
|
+
export interface WriteCheckpoint {
|
|
120
|
+
base: ActiveCheckpoint;
|
|
121
|
+
writeCheckpoint: bigint | null;
|
|
122
|
+
}
|
|
123
|
+
|
|
115
124
|
export interface StorageMetrics {
|
|
116
125
|
/**
|
|
117
126
|
* Size of operations (bucket_data)
|
|
@@ -131,6 +140,10 @@ export interface StorageMetrics {
|
|
|
131
140
|
replication_size_bytes: number;
|
|
132
141
|
}
|
|
133
142
|
|
|
143
|
+
export interface ParseSyncRulesOptions {
|
|
144
|
+
defaultSchema: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
134
147
|
export interface PersistedSyncRulesContent {
|
|
135
148
|
readonly id: number;
|
|
136
149
|
readonly sync_rules_content: string;
|
|
@@ -140,7 +153,7 @@ export interface PersistedSyncRulesContent {
|
|
|
140
153
|
readonly last_keepalive_ts?: Date | null;
|
|
141
154
|
readonly last_checkpoint_ts?: Date | null;
|
|
142
155
|
|
|
143
|
-
parsed(): PersistedSyncRules;
|
|
156
|
+
parsed(options: ParseSyncRulesOptions): PersistedSyncRules;
|
|
144
157
|
|
|
145
158
|
lock(): Promise<ReplicationLock>;
|
|
146
159
|
}
|
|
@@ -157,18 +170,6 @@ export interface PersistedSyncRules {
|
|
|
157
170
|
readonly slot_name: string;
|
|
158
171
|
}
|
|
159
172
|
|
|
160
|
-
export class DefaultPersistedSyncRules implements PersistedSyncRules {
|
|
161
|
-
public readonly checkpoint_lsn: string | null;
|
|
162
|
-
|
|
163
|
-
constructor(public readonly id: number, public readonly sync_rules: SqlSyncRules, checkpoint_lsn: string | null) {
|
|
164
|
-
this.checkpoint_lsn = checkpoint_lsn;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
get slot_name(): string {
|
|
168
|
-
return `powersync_${this.id}`;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
173
|
export interface UpdateSyncRulesOptions {
|
|
173
174
|
content: string;
|
|
174
175
|
lock?: boolean;
|
|
@@ -198,8 +199,27 @@ export interface BucketDataBatchOptions {
|
|
|
198
199
|
chunkLimitBytes?: number;
|
|
199
200
|
}
|
|
200
201
|
|
|
201
|
-
export interface
|
|
202
|
-
|
|
202
|
+
export interface StartBatchOptions extends ParseSyncRulesOptions {
|
|
203
|
+
zeroLSN: string;
|
|
204
|
+
/**
|
|
205
|
+
* Whether or not to store a copy of the current data.
|
|
206
|
+
*
|
|
207
|
+
* This is needed if we need to apply partial updates, for example
|
|
208
|
+
* when we get TOAST values from Postgres.
|
|
209
|
+
*
|
|
210
|
+
* This is not needed when we get the full document from the source
|
|
211
|
+
* database, for example from MongoDB.
|
|
212
|
+
*/
|
|
213
|
+
storeCurrentData: boolean;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface SyncRulesBucketStorageListener extends DisposableListener {
|
|
217
|
+
batchStarted: (batch: BucketStorageBatch) => void;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface SyncRulesBucketStorage
|
|
221
|
+
extends DisposableObserverClient<SyncRulesBucketStorageListener>,
|
|
222
|
+
SyncStorageWriteCheckpointAPI {
|
|
203
223
|
readonly group_id: number;
|
|
204
224
|
readonly slot_name: string;
|
|
205
225
|
|
|
@@ -207,9 +227,14 @@ export interface SyncRulesBucketStorage {
|
|
|
207
227
|
|
|
208
228
|
resolveTable(options: ResolveTableOptions): Promise<ResolveTableResult>;
|
|
209
229
|
|
|
210
|
-
startBatch(
|
|
230
|
+
startBatch(
|
|
231
|
+
options: StartBatchOptions,
|
|
232
|
+
callback: (batch: BucketStorageBatch) => Promise<void>
|
|
233
|
+
): Promise<FlushedResult | null>;
|
|
234
|
+
|
|
235
|
+
getCheckpoint(): Promise<ReplicationCheckpoint>;
|
|
211
236
|
|
|
212
|
-
|
|
237
|
+
getParsedSyncRules(options: ParseSyncRulesOptions): SqlSyncRules;
|
|
213
238
|
|
|
214
239
|
getParameterSets(checkpoint: util.OpId, lookups: SqliteJsonValue[][]): Promise<SqliteJsonRow[]>;
|
|
215
240
|
|
|
@@ -244,7 +269,7 @@ export interface SyncRulesBucketStorage {
|
|
|
244
269
|
*
|
|
245
270
|
* Must only be called on stopped sync rules.
|
|
246
271
|
*/
|
|
247
|
-
terminate(): Promise<void>;
|
|
272
|
+
terminate(options?: TerminateOptions): Promise<void>;
|
|
248
273
|
|
|
249
274
|
getStatus(): Promise<SyncRuleStatus>;
|
|
250
275
|
|
|
@@ -277,7 +302,7 @@ export interface ResolveTableOptions {
|
|
|
277
302
|
group_id: number;
|
|
278
303
|
connection_id: number;
|
|
279
304
|
connection_tag: string;
|
|
280
|
-
|
|
305
|
+
entity_descriptor: SourceEntityDescriptor;
|
|
281
306
|
|
|
282
307
|
sync_rules: SqlSyncRules;
|
|
283
308
|
}
|
|
@@ -291,7 +316,11 @@ export interface FlushedResult {
|
|
|
291
316
|
flushed_op: string;
|
|
292
317
|
}
|
|
293
318
|
|
|
294
|
-
export interface
|
|
319
|
+
export interface BucketBatchStorageListener extends DisposableListener {
|
|
320
|
+
replicationEvent: (payload: ReplicationEventPayload) => void;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export interface BucketStorageBatch extends DisposableObserverClient<BucketBatchStorageListener> {
|
|
295
324
|
/**
|
|
296
325
|
* Save an op, and potentially flush.
|
|
297
326
|
*
|
|
@@ -337,7 +366,17 @@ export interface BucketStorageBatch {
|
|
|
337
366
|
*/
|
|
338
367
|
keepalive(lsn: string): Promise<boolean>;
|
|
339
368
|
|
|
369
|
+
/**
|
|
370
|
+
* Get the last checkpoint LSN, from either commit or keepalive.
|
|
371
|
+
*/
|
|
372
|
+
lastCheckpointLsn: string | null;
|
|
373
|
+
|
|
340
374
|
markSnapshotDone(tables: SourceTable[], no_checkpoint_before_lsn: string): Promise<SourceTable[]>;
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Queues the creation of a custom Write Checkpoint. This will be persisted after operations are flushed.
|
|
378
|
+
*/
|
|
379
|
+
addCustomWriteCheckpoint(checkpoint: BatchedCustomWriteCheckpointOptions): void;
|
|
341
380
|
}
|
|
342
381
|
|
|
343
382
|
export interface SaveParameterData {
|
|
@@ -355,23 +394,34 @@ export interface SaveBucketData {
|
|
|
355
394
|
evaluated: EvaluatedRow[];
|
|
356
395
|
}
|
|
357
396
|
|
|
397
|
+
export type SaveOp = 'insert' | 'update' | 'delete';
|
|
398
|
+
|
|
358
399
|
export type SaveOptions = SaveInsert | SaveUpdate | SaveDelete;
|
|
359
400
|
|
|
401
|
+
export enum SaveOperationTag {
|
|
402
|
+
INSERT = 'insert',
|
|
403
|
+
UPDATE = 'update',
|
|
404
|
+
DELETE = 'delete'
|
|
405
|
+
}
|
|
406
|
+
|
|
360
407
|
export interface SaveInsert {
|
|
361
|
-
tag:
|
|
408
|
+
tag: SaveOperationTag.INSERT;
|
|
362
409
|
sourceTable: SourceTable;
|
|
363
410
|
before?: undefined;
|
|
411
|
+
beforeReplicaId?: undefined;
|
|
364
412
|
after: SqliteRow;
|
|
413
|
+
afterReplicaId: ReplicaId;
|
|
365
414
|
}
|
|
366
415
|
|
|
367
416
|
export interface SaveUpdate {
|
|
368
|
-
tag:
|
|
417
|
+
tag: SaveOperationTag.UPDATE;
|
|
369
418
|
sourceTable: SourceTable;
|
|
370
419
|
|
|
371
420
|
/**
|
|
372
421
|
* This is only present when the id has changed, and will only contain replica identity columns.
|
|
373
422
|
*/
|
|
374
423
|
before?: SqliteRow;
|
|
424
|
+
beforeReplicaId?: ReplicaId;
|
|
375
425
|
|
|
376
426
|
/**
|
|
377
427
|
* A null value means null column.
|
|
@@ -379,13 +429,16 @@ export interface SaveUpdate {
|
|
|
379
429
|
* An undefined value means it's a TOAST value - must be copied from another record.
|
|
380
430
|
*/
|
|
381
431
|
after: ToastableSqliteRow;
|
|
432
|
+
afterReplicaId: ReplicaId;
|
|
382
433
|
}
|
|
383
434
|
|
|
384
435
|
export interface SaveDelete {
|
|
385
|
-
tag:
|
|
436
|
+
tag: SaveOperationTag.DELETE;
|
|
386
437
|
sourceTable: SourceTable;
|
|
387
|
-
before
|
|
438
|
+
before?: SqliteRow;
|
|
439
|
+
beforeReplicaId: ReplicaId;
|
|
388
440
|
after?: undefined;
|
|
441
|
+
afterReplicaId?: undefined;
|
|
389
442
|
}
|
|
390
443
|
|
|
391
444
|
export interface SyncBucketDataBatch {
|
|
@@ -429,6 +482,15 @@ export interface CompactOptions {
|
|
|
429
482
|
* If specified, compact only the specific buckets.
|
|
430
483
|
*
|
|
431
484
|
* If not specified, compacts all buckets.
|
|
485
|
+
*
|
|
486
|
+
* These can be individual bucket names, or bucket definition names.
|
|
432
487
|
*/
|
|
433
488
|
compactBuckets?: string[];
|
|
434
489
|
}
|
|
490
|
+
|
|
491
|
+
export interface TerminateOptions {
|
|
492
|
+
/**
|
|
493
|
+
* If true, also clear the storage before terminating.
|
|
494
|
+
*/
|
|
495
|
+
clearStorage: boolean;
|
|
496
|
+
}
|
|
@@ -1,36 +1,39 @@
|
|
|
1
|
-
import * as mongo from 'mongodb';
|
|
2
|
-
import * as timers from 'timers/promises';
|
|
3
|
-
import { LRUCache } from 'lru-cache/min';
|
|
4
1
|
import { SqlSyncRules } from '@powersync/service-sync-rules';
|
|
5
2
|
import { wrapWithAbort } from 'ix/asynciterable/operators/withabort.js';
|
|
3
|
+
import { LRUCache } from 'lru-cache/min';
|
|
4
|
+
import * as mongo from 'mongodb';
|
|
5
|
+
import * as timers from 'timers/promises';
|
|
6
6
|
|
|
7
|
-
import * as
|
|
7
|
+
import * as locks from '../locks/locks-index.js';
|
|
8
8
|
import * as sync from '../sync/sync-index.js';
|
|
9
9
|
import * as util from '../util/util-index.js';
|
|
10
|
-
import * as locks from '../locks/locks-index.js';
|
|
11
10
|
|
|
11
|
+
import { DisposableObserver, logger } from '@powersync/lib-services-framework';
|
|
12
|
+
import { v4 as uuid } from 'uuid';
|
|
12
13
|
import {
|
|
13
14
|
ActiveCheckpoint,
|
|
14
15
|
BucketStorageFactory,
|
|
16
|
+
BucketStorageFactoryListener,
|
|
17
|
+
ParseSyncRulesOptions,
|
|
15
18
|
PersistedSyncRules,
|
|
16
19
|
PersistedSyncRulesContent,
|
|
17
20
|
StorageMetrics,
|
|
18
21
|
UpdateSyncRulesOptions,
|
|
19
22
|
WriteCheckpoint
|
|
20
23
|
} from './BucketStorage.js';
|
|
24
|
+
import { PowerSyncMongo } from './mongo/db.js';
|
|
25
|
+
import { SyncRuleDocument, SyncRuleState } from './mongo/models.js';
|
|
21
26
|
import { MongoPersistedSyncRulesContent } from './mongo/MongoPersistedSyncRulesContent.js';
|
|
22
27
|
import { MongoSyncBucketStorage } from './mongo/MongoSyncBucketStorage.js';
|
|
23
|
-
import { PowerSyncMongo, PowerSyncMongoOptions } from './mongo/db.js';
|
|
24
|
-
import { SyncRuleDocument, SyncRuleState } from './mongo/models.js';
|
|
25
28
|
import { generateSlotName } from './mongo/util.js';
|
|
26
|
-
import { v4 as uuid } from 'uuid';
|
|
27
|
-
import { logger } from '@powersync/lib-services-framework';
|
|
28
|
-
|
|
29
|
-
export interface MongoBucketStorageOptions extends PowerSyncMongoOptions {}
|
|
30
29
|
|
|
31
|
-
export class MongoBucketStorage
|
|
30
|
+
export class MongoBucketStorage
|
|
31
|
+
extends DisposableObserver<BucketStorageFactoryListener>
|
|
32
|
+
implements BucketStorageFactory
|
|
33
|
+
{
|
|
32
34
|
private readonly client: mongo.MongoClient;
|
|
33
35
|
private readonly session: mongo.ClientSession;
|
|
36
|
+
// TODO: This is still Postgres specific and needs to be reworked
|
|
34
37
|
public readonly slot_name_prefix: string;
|
|
35
38
|
|
|
36
39
|
private readonly storageCache = new LRUCache<number, MongoSyncBucketStorage>({
|
|
@@ -47,26 +50,44 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
47
50
|
return undefined;
|
|
48
51
|
}
|
|
49
52
|
const rules = new MongoPersistedSyncRulesContent(this.db, doc2);
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
return this.getInstance(rules);
|
|
54
|
+
},
|
|
55
|
+
dispose: (storage) => {
|
|
56
|
+
storage[Symbol.dispose]();
|
|
52
57
|
}
|
|
53
58
|
});
|
|
54
59
|
|
|
55
60
|
public readonly db: PowerSyncMongo;
|
|
56
61
|
|
|
57
|
-
constructor(
|
|
62
|
+
constructor(
|
|
63
|
+
db: PowerSyncMongo,
|
|
64
|
+
options: {
|
|
65
|
+
slot_name_prefix: string;
|
|
66
|
+
}
|
|
67
|
+
) {
|
|
68
|
+
super();
|
|
58
69
|
this.client = db.client;
|
|
59
70
|
this.db = db;
|
|
60
71
|
this.session = this.client.startSession();
|
|
61
72
|
this.slot_name_prefix = options.slot_name_prefix;
|
|
62
73
|
}
|
|
63
74
|
|
|
64
|
-
getInstance(options:
|
|
65
|
-
let { id,
|
|
75
|
+
getInstance(options: PersistedSyncRulesContent): MongoSyncBucketStorage {
|
|
76
|
+
let { id, slot_name } = options;
|
|
66
77
|
if ((typeof id as any) == 'bigint') {
|
|
67
78
|
id = Number(id);
|
|
68
79
|
}
|
|
69
|
-
|
|
80
|
+
const storage = new MongoSyncBucketStorage(this, id, options, slot_name);
|
|
81
|
+
this.iterateListeners((cb) => cb.syncStorageCreated?.(storage));
|
|
82
|
+
storage.registerListener({
|
|
83
|
+
batchStarted: (batch) => {
|
|
84
|
+
// This nested listener will be automatically disposed when the storage is disposed
|
|
85
|
+
batch.registerManagedListener(storage, {
|
|
86
|
+
replicationEvent: (payload) => this.iterateListeners((cb) => cb.replicationEvent?.(payload))
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return storage;
|
|
70
91
|
}
|
|
71
92
|
|
|
72
93
|
async configureSyncRules(sync_rules: string, options?: { lock?: boolean }) {
|
|
@@ -136,7 +157,12 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
136
157
|
|
|
137
158
|
async updateSyncRules(options: UpdateSyncRulesOptions): Promise<MongoPersistedSyncRulesContent> {
|
|
138
159
|
// Parse and validate before applying any changes
|
|
139
|
-
const parsed = SqlSyncRules.fromYaml(options.content
|
|
160
|
+
const parsed = SqlSyncRules.fromYaml(options.content, {
|
|
161
|
+
// No schema-based validation at this point
|
|
162
|
+
schema: undefined,
|
|
163
|
+
defaultSchema: 'not_applicable', // Not needed for validation
|
|
164
|
+
throwOnError: true
|
|
165
|
+
});
|
|
140
166
|
|
|
141
167
|
let rules: MongoPersistedSyncRulesContent | undefined = undefined;
|
|
142
168
|
|
|
@@ -204,9 +230,9 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
204
230
|
return new MongoPersistedSyncRulesContent(this.db, doc);
|
|
205
231
|
}
|
|
206
232
|
|
|
207
|
-
async getActiveSyncRules(): Promise<PersistedSyncRules | null> {
|
|
233
|
+
async getActiveSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null> {
|
|
208
234
|
const content = await this.getActiveSyncRulesContent();
|
|
209
|
-
return content?.parsed() ?? null;
|
|
235
|
+
return content?.parsed(options) ?? null;
|
|
210
236
|
}
|
|
211
237
|
|
|
212
238
|
async getNextSyncRulesContent(): Promise<MongoPersistedSyncRulesContent | null> {
|
|
@@ -223,9 +249,9 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
223
249
|
return new MongoPersistedSyncRulesContent(this.db, doc);
|
|
224
250
|
}
|
|
225
251
|
|
|
226
|
-
async getNextSyncRules(): Promise<PersistedSyncRules | null> {
|
|
252
|
+
async getNextSyncRules(options: ParseSyncRulesOptions): Promise<PersistedSyncRules | null> {
|
|
227
253
|
const content = await this.getNextSyncRulesContent();
|
|
228
|
-
return content?.parsed() ?? null;
|
|
254
|
+
return content?.parsed(options) ?? null;
|
|
229
255
|
}
|
|
230
256
|
|
|
231
257
|
async getReplicatingSyncRules(): Promise<PersistedSyncRulesContent[]> {
|
|
@@ -252,32 +278,6 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
252
278
|
});
|
|
253
279
|
}
|
|
254
280
|
|
|
255
|
-
async createWriteCheckpoint(user_id: string, lsns: Record<string, string>): Promise<bigint> {
|
|
256
|
-
const doc = await this.db.write_checkpoints.findOneAndUpdate(
|
|
257
|
-
{
|
|
258
|
-
user_id: user_id
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
$set: {
|
|
262
|
-
lsns: lsns
|
|
263
|
-
},
|
|
264
|
-
$inc: {
|
|
265
|
-
client_id: 1n
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
|
-
{ upsert: true, returnDocument: 'after' }
|
|
269
|
-
);
|
|
270
|
-
return doc!.client_id;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
async lastWriteCheckpoint(user_id: string, lsn: string): Promise<bigint | null> {
|
|
274
|
-
const lastWriteCheckpoint = await this.db.write_checkpoints.findOne({
|
|
275
|
-
user_id: user_id,
|
|
276
|
-
'lsns.1': { $lte: lsn }
|
|
277
|
-
});
|
|
278
|
-
return lastWriteCheckpoint?.client_id ?? null;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
281
|
async getActiveCheckpoint(): Promise<ActiveCheckpoint> {
|
|
282
282
|
const doc = await this.db.sync_rules.findOne(
|
|
283
283
|
{
|
|
@@ -303,7 +303,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
303
303
|
}
|
|
304
304
|
};
|
|
305
305
|
|
|
306
|
-
const active_sync_rules = await this.getActiveSyncRules();
|
|
306
|
+
const active_sync_rules = await this.getActiveSyncRules({ defaultSchema: 'public' });
|
|
307
307
|
if (active_sync_rules == null) {
|
|
308
308
|
return {
|
|
309
309
|
operations_size_bytes: 0,
|
|
@@ -379,7 +379,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
379
379
|
private makeActiveCheckpoint(doc: SyncRuleDocument | null) {
|
|
380
380
|
return {
|
|
381
381
|
checkpoint: util.timestampToOpId(doc?.last_checkpoint ?? 0n),
|
|
382
|
-
lsn: doc?.last_checkpoint_lsn ??
|
|
382
|
+
lsn: doc?.last_checkpoint_lsn ?? null,
|
|
383
383
|
hasSyncRules() {
|
|
384
384
|
return doc != null;
|
|
385
385
|
},
|
|
@@ -389,7 +389,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
389
389
|
}
|
|
390
390
|
return (await this.storageCache.fetch(doc._id)) ?? null;
|
|
391
391
|
}
|
|
392
|
-
};
|
|
392
|
+
} satisfies ActiveCheckpoint;
|
|
393
393
|
}
|
|
394
394
|
|
|
395
395
|
/**
|
|
@@ -479,6 +479,7 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
479
479
|
if (doc == null) {
|
|
480
480
|
continue;
|
|
481
481
|
}
|
|
482
|
+
|
|
482
483
|
const op = this.makeActiveCheckpoint(doc);
|
|
483
484
|
// Check for LSN / checkpoint changes - ignore other metadata changes
|
|
484
485
|
if (lastOp == null || op.lsn != lastOp.lsn || op.checkpoint != lastOp.checkpoint) {
|
|
@@ -508,8 +509,19 @@ export class MongoBucketStorage implements BucketStorageFactory {
|
|
|
508
509
|
// What is important is:
|
|
509
510
|
// 1. checkpoint (op_id) changes.
|
|
510
511
|
// 2. write checkpoint changes for the specific user
|
|
512
|
+
const bucketStorage = await cp.getBucketStorage();
|
|
513
|
+
if (!bucketStorage) {
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
const lsnFilters: Record<string, string> = lsn ? { 1: lsn } : {};
|
|
511
518
|
|
|
512
|
-
const currentWriteCheckpoint = await
|
|
519
|
+
const currentWriteCheckpoint = await bucketStorage.lastWriteCheckpoint({
|
|
520
|
+
user_id,
|
|
521
|
+
heads: {
|
|
522
|
+
...lsnFilters
|
|
523
|
+
}
|
|
524
|
+
});
|
|
513
525
|
|
|
514
526
|
if (currentWriteCheckpoint == lastWriteCheckpoint && checkpoint == lastCheckpoint) {
|
|
515
527
|
// No change - wait for next one
|