@rocicorp/zero 1.9.1-canary.1 → 1.10.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/analyze-query/src/analyze-cli.js +2 -2
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/replicache/src/db/commit.js +1 -4
- package/out/replicache/src/db/commit.js.map +1 -1
- package/out/replicache/src/db/read.d.ts +1 -0
- package/out/replicache/src/db/read.d.ts.map +1 -1
- package/out/replicache/src/db/read.js +1 -4
- package/out/replicache/src/db/read.js.map +1 -1
- package/out/replicache/src/db/write.d.ts +2 -1
- package/out/replicache/src/db/write.d.ts.map +1 -1
- package/out/replicache/src/db/write.js +4 -51
- package/out/replicache/src/db/write.js.map +1 -1
- package/out/replicache/src/persist/clients.d.ts +1 -0
- package/out/replicache/src/persist/clients.d.ts.map +1 -1
- package/out/replicache/src/persist/clients.js +4 -31
- package/out/replicache/src/persist/clients.js.map +1 -1
- package/out/replicache/src/process-env.d.ts +28 -0
- package/out/replicache/src/process-env.d.ts.map +1 -0
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/scan-iterator.js +2 -14
- package/out/replicache/src/scan-iterator.js.map +1 -1
- package/out/replicache/src/subscriptions.d.ts +1 -0
- package/out/replicache/src/subscriptions.d.ts.map +1 -1
- package/out/replicache/src/subscriptions.js +2 -10
- package/out/replicache/src/subscriptions.js.map +1 -1
- package/out/replicache/src/transactions.d.ts +1 -0
- package/out/replicache/src/transactions.d.ts.map +1 -1
- package/out/replicache/src/transactions.js +2 -4
- package/out/replicache/src/transactions.js.map +1 -1
- package/out/zero/package.js +2 -2
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts +1 -0
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js +10 -1
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +43 -1
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +139 -20
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/db/migration.js +1 -1
- package/out/zero-cache/src/observability/metrics.d.ts +5 -0
- package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
- package/out/zero-cache/src/observability/metrics.js +15 -1
- package/out/zero-cache/src/observability/metrics.js.map +1 -1
- package/out/zero-cache/src/server/backup-watermark-poller.js +31 -0
- package/out/zero-cache/src/server/backup-watermark-poller.js.map +1 -0
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +90 -30
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/main.js +5 -15
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/server/replicator.js +46 -3
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +2 -1
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.d.ts +1 -1
- package/out/zero-cache/src/server/worker-urls.js +2 -2
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/change-source/change-source.d.ts +4 -2
- package/out/zero-cache/src/services/change-source/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +35 -0
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/common/replica-restore.js +34 -0
- package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -0
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +2 -0
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +73 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +2 -6
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +16 -7
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -7
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +7 -7
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +75 -23
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +9 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +34 -4
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +4 -2
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js +7 -4
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -5
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +29 -41
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +35 -16
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +77 -7
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js +1 -12
- package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +3 -3
- package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.d.ts +6 -0
- package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.js +21 -0
- package/out/zero-cache/src/services/change-source/protocol/current/schema-change-tags.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +5 -6
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +32 -9
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +15 -5
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js +66 -0
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +68 -78
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +84 -92
- package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -0
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js +50 -0
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +141 -0
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +270 -0
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +19 -0
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js +39 -0
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +3 -4
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +15 -20
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +69 -24
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +330 -63
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +55 -13
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +8 -0
- package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +14 -3
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.js +41 -11
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/{litestream3-backup-monitor.d.ts → litestream3-prometheus-poller.d.ts} +19 -45
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/{litestream3-backup-monitor.js → litestream3-prometheus-poller.js} +57 -171
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +15 -0
- package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/replica-poller.js +55 -0
- package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +5 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +2 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +14 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +86 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +4 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.js +39 -14
- package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +75 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +261 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +121 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js +391 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +62 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +159 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +109 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +258 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +22 -12
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +93 -117
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +61 -10
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +101 -8
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +34 -0
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js +86 -0
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -0
- package/out/zero-cache/src/services/life-cycle.d.ts +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +3 -2
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +12 -11
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +50 -140
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config-v5.yml +42 -0
- package/out/zero-cache/src/services/litestream/metrics.d.ts +4 -4
- package/out/zero-cache/src/services/litestream/metrics.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/metrics.js +7 -10
- package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-poller.d.ts +57 -0
- package/out/zero-cache/src/services/litestream/vfs-watermark-poller.d.ts.map +1 -0
- package/out/zero-cache/src/services/litestream/vfs-watermark-poller.js +137 -0
- package/out/zero-cache/src/services/litestream/vfs-watermark-poller.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-cookies.d.ts +169 -0
- package/out/zero-cache/src/services/replicator/change-log-cookies.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-cookies.js +434 -0
- package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-db.d.ts +358 -0
- package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-db.js +477 -0
- package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +55 -0
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +150 -0
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +44 -17
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +11 -4
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js +2 -2
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +119 -0
- package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/schema/backfilling.js +214 -0
- package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -0
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +3 -3
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +9 -5
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +131 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +413 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +120 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +1 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +283 -0
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -0
- package/out/zero-cache/src/services/replicator/write-worker.js +9 -6
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +2 -1
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/running-state.d.ts +1 -1
- package/out/zero-cache/src/services/running-state.d.ts.map +1 -1
- package/out/zero-cache/src/services/running-state.js +1 -0
- package/out/zero-cache/src/services/running-state.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +9 -0
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js +9 -0
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +18 -3
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +48 -7
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/processes.d.ts +1 -2
- package/out/zero-cache/src/types/processes.d.ts.map +1 -1
- package/out/zero-cache/src/types/processes.js +1 -25
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts +10 -0
- package/out/zero-cache/src/types/streams.d.ts.map +1 -1
- package/out/zero-cache/src/types/streams.js +25 -4
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/workers/connection.d.ts +1 -0
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js +25 -3
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/replicator.d.ts +25 -0
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +33 -1
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts +12 -0
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +75 -0
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-schema/src/builder/table-builder.d.ts +23 -0
- package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/table-builder.js +18 -0
- package/out/zero-schema/src/builder/table-builder.js.map +1 -1
- package/out/zero-types/src/schema.d.ts +11 -0
- package/out/zero-types/src/schema.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +2 -2
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query.d.ts +83 -14
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/static-query.d.ts +1 -1
- package/out/zql/src/query/static-query.d.ts.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts +15 -0
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.js +20 -13
- package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
- package/package.json +2 -2
- package/out/replicache/src/db/index.js +0 -91
- package/out/replicache/src/db/index.js.map +0 -1
- package/out/replicache/src/lazy.d.ts +0 -2
- package/out/replicache/src/lazy.d.ts.map +0 -1
- package/out/replicache/src/lazy.js +0 -12
- package/out/replicache/src/lazy.js.map +0 -1
- package/out/zero-cache/src/server/backup-watermark-reader.js +0 -35
- package/out/zero-cache/src/server/backup-watermark-reader.js.map +0 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-backup-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-backup-monitor.js.map +0 -1
- package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts +0 -16
- package/out/zero-cache/src/services/change-streamer/replica-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/replica-monitor.js +0 -54
- package/out/zero-cache/src/services/change-streamer/replica-monitor.js.map +0 -1
- package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.d.ts +0 -25
- package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.js +0 -159
- package/out/zero-cache/src/services/change-streamer/vfs-backup-monitor.js.map +0 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-reader.d.ts +0 -44
- package/out/zero-cache/src/services/litestream/vfs-watermark-reader.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-reader.js +0 -65
- package/out/zero-cache/src/services/litestream/vfs-watermark-reader.js.map +0 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.d.ts +0 -11
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.js +0 -74
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker-source.js.map +0 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker.d.ts +0 -42
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker.js +0 -117
- package/out/zero-cache/src/services/litestream/vfs-watermark-worker.js.map +0 -1
|
@@ -2,36 +2,81 @@ import type { LogContext } from '@rocicorp/logger';
|
|
|
2
2
|
import type { PostgresDB } from '../../types/pg.ts';
|
|
3
3
|
import type { ShardID } from '../../types/shards.ts';
|
|
4
4
|
import type { ChangeSource } from '../change-source/change-source.ts';
|
|
5
|
-
import {
|
|
5
|
+
import type { LitestreamVersion } from '../litestream/metrics.ts';
|
|
6
6
|
import { type ReplicationStatusPublisher } from '../replicator/replication-status.ts';
|
|
7
7
|
import type { SubscriptionState } from '../replicator/schema/replication-state.ts';
|
|
8
|
-
import { type ChangeStreamerService } from './change-streamer.ts';
|
|
8
|
+
import { type ChangeStreamerService, type SubscriberContext } from './change-streamer.ts';
|
|
9
|
+
import { type SQLiteChangeLogCleanupGuard } from './sqlite-change-log-catchup.ts';
|
|
10
|
+
import { type SQLiteChangeLogPurgeSchedulerOptions } from './sqlite-change-log-purge-scheduler.ts';
|
|
11
|
+
import { type SQLiteChangeLogWriterOptions } from './sqlite-change-log-writer.ts';
|
|
9
12
|
import { type PurgeLock, type TuningOptions as StorerOptions } from './storer.ts';
|
|
13
|
+
export type BackupConfig = {
|
|
14
|
+
backupURL: string;
|
|
15
|
+
litestreamVersion: LitestreamVersion;
|
|
16
|
+
};
|
|
17
|
+
export type SQLiteCatchupOptions = {
|
|
18
|
+
/** The change-log database, i.e. `changeLogFileName(replicaFile)`. */
|
|
19
|
+
changeLogFile: string;
|
|
20
|
+
readBatchRows: number;
|
|
21
|
+
barrierTimeoutMs: number;
|
|
22
|
+
/**
|
|
23
|
+
* Backstop for the change-log writer's ACK, which is what normally releases
|
|
24
|
+
* the barrier. Defaults to the catchup coordinator's interval.
|
|
25
|
+
*/
|
|
26
|
+
barrierPollIntervalMs?: number | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* Slice 11 supplies the production canary selector.
|
|
29
|
+
*
|
|
30
|
+
* It does not need to exclude backup subscribers or the change-log writer:
|
|
31
|
+
* eligibility checks reject both before invoking this selector. Serving a
|
|
32
|
+
* writer from SQLite would make it wait on its own ACK.
|
|
33
|
+
*/
|
|
34
|
+
shouldUse?: ((ctx: SubscriberContext) => boolean) | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* Overrides the purge scheduler's guard, for tests. When absent, the
|
|
37
|
+
* service supplies the scheduler's real writer-serialized guard, or the
|
|
38
|
+
* catchup's no-op default when purging is not configured.
|
|
39
|
+
*/
|
|
40
|
+
cleanupGuard?: SQLiteChangeLogCleanupGuard | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* How long the change log may be unavailable before declining to serve from
|
|
43
|
+
* it is reported as a warning rather than a debug line. Defaults to
|
|
44
|
+
* {@link DEFAULT_CHANGE_LOG_UNAVAILABLE_WARN_THRESHOLD_MS}.
|
|
45
|
+
*/
|
|
46
|
+
notReadyWarnThresholdMs?: number | undefined;
|
|
47
|
+
};
|
|
10
48
|
export type TuningOptions = StorerOptions & {
|
|
11
|
-
|
|
49
|
+
flowControlConsensusTimeoutProportion: number;
|
|
50
|
+
flowControlSlowSubscriberGracePeriodMs?: number | undefined;
|
|
51
|
+
sqliteCatchup?: SQLiteCatchupOptions | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Supplied when `sqliteChangeLogMode != off`, i.e. this is the gate on the
|
|
54
|
+
* change-log writer. Absent, nothing writes the log.
|
|
55
|
+
*/
|
|
56
|
+
sqliteChangeLogWriter?: Omit<SQLiteChangeLogWriterOptions, 'onCommit' | 'onDisabled' | 'onRebuilt'> | undefined;
|
|
57
|
+
/**
|
|
58
|
+
* Also supplied when `sqliteChangeLogMode != off`, and deliberately not
|
|
59
|
+
* gated on the read path: in `write` mode no reader ever opens, and this is
|
|
60
|
+
* the configuration the purge scheduler actually ships in. The scheduler
|
|
61
|
+
* runs on the writer's own connection, so with the writer absent (mode
|
|
62
|
+
* `off`) it is never constructed, and a leftover file on disk is left to
|
|
63
|
+
* the replicator's cleanup.
|
|
64
|
+
*/
|
|
65
|
+
sqliteChangeLogPurge?: SQLiteChangeLogPurgeSchedulerOptions | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Supplied at `sqliteChangeLogMode >= compare`, and the gate on deriving the
|
|
68
|
+
* stream's initialization parameters from the replica as well as from
|
|
69
|
+
* Postgres. Postgres stays authoritative; the two are compared and the
|
|
70
|
+
* result is reported. Not a new configuration option -- the mode ladder
|
|
71
|
+
* carries it, because a state in which the log's buffer and its cookies were
|
|
72
|
+
* at different rollout stages is what invariant 15 exists to forbid.
|
|
73
|
+
*/
|
|
74
|
+
sqliteChangeLogCompare?: {
|
|
75
|
+
replicaFile: string;
|
|
76
|
+
} | undefined;
|
|
12
77
|
};
|
|
13
78
|
/**
|
|
14
79
|
* Performs initialization and schema migrations to initialize a ChangeStreamerImpl.
|
|
15
80
|
*/
|
|
16
|
-
export declare function initializeStreamer(lc: LogContext, shard: ShardID, taskID: string, discoveryAddress: string, discoveryProtocol: string, changeDB: PostgresDB, changeSource: ChangeSource, replicationStatusPublisher: ReplicationStatusPublisher, subscriptionState: SubscriptionState, purgeLock: PurgeLock | null, autoReset: boolean, opts: TuningOptions, setTimeoutFn?: typeof setTimeout): Promise<ChangeStreamerService>;
|
|
17
|
-
export type ChangeTag = ChangeStreamData[1]['tag'];
|
|
18
|
-
/**
|
|
19
|
-
* Internally all Downstream messages (not just commits) are given a watermark.
|
|
20
|
-
* These are used for internal ordering for:
|
|
21
|
-
* 1. Replaying new changes in the Storer
|
|
22
|
-
* 2. Filtering old changes in the Subscriber
|
|
23
|
-
*
|
|
24
|
-
* However, only the watermark for `Commit` messages are exposed to
|
|
25
|
-
* subscribers, as that is the only semantically correct watermark to
|
|
26
|
-
* use for tracking a position in a replication stream.
|
|
27
|
-
*
|
|
28
|
-
* Additionally, the ChangeStreamData is eagerly stringified once, after which
|
|
29
|
-
* the string is passed to the changeLog and all subscribers, eliminating
|
|
30
|
-
* redundant stringification and reducing GC churn.
|
|
31
|
-
*/
|
|
32
|
-
export type WatermarkedChange = [
|
|
33
|
-
watermark: string,
|
|
34
|
-
tag: ChangeTag,
|
|
35
|
-
json: string
|
|
36
|
-
];
|
|
81
|
+
export declare function initializeStreamer(lc: LogContext, shard: ShardID, taskID: string, discoveryAddress: string, discoveryProtocol: string, changeDB: PostgresDB, changeSource: ChangeSource, replicationStatusPublisher: ReplicationStatusPublisher, subscriptionState: SubscriptionState, backupConfig: BackupConfig | null, purgeLock: PurgeLock | null, autoReset: boolean, opts: TuningOptions, setTimeoutFn?: typeof setTimeout): Promise<ChangeStreamerService>;
|
|
37
82
|
//# sourceMappingURL=change-streamer-service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-streamer-service.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/change-streamer-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAWjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAGnD,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"change-streamer-service.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/change-streamer-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAWjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AAGnD,OAAO,KAAK,EACV,YAAY,EAEb,MAAM,mCAAmC,CAAC;AAM3C,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAGL,KAAK,0BAA0B,EAChC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,2CAA2C,CAAC;AAUjF,OAAO,EACL,KAAK,qBAAqB,EAE1B,KAAK,iBAAiB,EAEvB,MAAM,sBAAsB,CAAC;AAU9B,OAAO,EAEL,KAAK,2BAA2B,EACjC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAGL,KAAK,oCAAoC,EAC1C,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAEL,KAAK,4BAA4B,EAClC,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAEL,KAAK,SAAS,EACd,KAAK,aAAa,IAAI,aAAa,EACpC,MAAM,aAAa,CAAC;AAIrB,MAAM,MAAM,YAAY,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,iBAAiB,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,sEAAsE;IACtE,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,iBAAiB,KAAK,OAAO,CAAC,GAAG,SAAS,CAAC;IAC9D;;;;OAIG;IACH,YAAY,CAAC,EAAE,2BAA2B,GAAG,SAAS,CAAC;IACvD;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG;IAC1C,qCAAqC,EAAE,MAAM,CAAC;IAC9C,sCAAsC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5D,aAAa,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACjD;;;OAGG;IACH,qBAAqB,CAAC,EAClB,IAAI,CACF,4BAA4B,EAC5B,UAAU,GAAG,YAAY,GAAG,WAAW,CACxC,GACD,SAAS,CAAC;IACd;;;;;;;OAOG;IACH,oBAAoB,CAAC,EAAE,oCAAoC,GAAG,SAAS,CAAC;IACxE;;;;;;;OAOG;IACH,sBAAsB,CAAC,EAAE;QAAC,WAAW,EAAE,MAAM,CAAA;KAAC,GAAG,SAAS,CAAC;CAC5D,CAAC;AAEF;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,EACxB,iBAAiB,EAAE,MAAM,EACzB,QAAQ,EAAE,UAAU,EACpB,YAAY,EAAE,YAAY,EAC1B,0BAA0B,EAAE,0BAA0B,EACtD,iBAAiB,EAAE,iBAAiB,EACpC,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,SAAS,EAAE,SAAS,GAAG,IAAI,EAC3B,SAAS,EAAE,OAAO,EAClB,IAAI,EAAE,aAAa,EACnB,YAAY,oBAAa,GACxB,OAAO,CAAC,qBAAqB,CAAC,CA4BhC"}
|
|
@@ -1,31 +1,38 @@
|
|
|
1
|
-
import { unreachable } from "../../../../shared/src/asserts.js";
|
|
1
|
+
import { assert, unreachable } from "../../../../shared/src/asserts.js";
|
|
2
2
|
import { promiseVoid } from "../../../../shared/src/resolved-promises.js";
|
|
3
|
+
import { must } from "../../../../shared/src/must.js";
|
|
3
4
|
import "../change-source/protocol/current/downstream.js";
|
|
4
|
-
import { getOrCreateCounter } from "../../observability/metrics.js";
|
|
5
|
+
import { getOrCreateCounter, getOrCreateLatencyHistogram } from "../../observability/metrics.js";
|
|
5
6
|
import { DEFAULT_MAX_RETRY_DELAY_MS, RunningState, UnrecoverableError } from "../running-state.js";
|
|
6
7
|
import { min } from "../../types/lexi-version.js";
|
|
7
8
|
import { publishCriticalEvent } from "../../observability/events.js";
|
|
8
|
-
import { AutoResetSignal, ensureReplicationConfig, markResetRequired } from "./schema/tables.js";
|
|
9
9
|
import { Subscription } from "../../types/subscription.js";
|
|
10
|
+
import { AutoResetSignal, ensureReplicationConfig, markResetRequired } from "./schema/tables.js";
|
|
10
11
|
import { publishReplicationError, replicationStatusError } from "../replicator/replication-status.js";
|
|
11
12
|
import "./change-streamer.js";
|
|
13
|
+
import { SQLiteChangeLogReader } from "./sqlite-change-log-reader.js";
|
|
14
|
+
import { ChangeLogInitializer, replicaInitializationSource } from "./change-log-initializer.js";
|
|
12
15
|
import { Forwarder } from "./forwarder.js";
|
|
13
|
-
import {
|
|
16
|
+
import { SnapshotReservations } from "./snapshot-reservations.js";
|
|
17
|
+
import { SQLiteChangeLogCatchup } from "./sqlite-change-log-catchup.js";
|
|
18
|
+
import { SQLiteChangeLogPurgeScheduler } from "./sqlite-change-log-purge-scheduler.js";
|
|
19
|
+
import { SQLiteChangeLogWriter } from "./sqlite-change-log-writer.js";
|
|
14
20
|
import { Storer } from "./storer.js";
|
|
15
21
|
import { Subscriber } from "./subscriber.js";
|
|
22
|
+
import { UpstreamAcker } from "./upstream-acker.js";
|
|
16
23
|
import { resolver } from "@rocicorp/resolver";
|
|
17
24
|
import { getDefaultHighWaterMark } from "node:stream";
|
|
18
25
|
//#region ../zero-cache/src/services/change-streamer/change-streamer-service.ts
|
|
19
26
|
/**
|
|
20
27
|
* Performs initialization and schema migrations to initialize a ChangeStreamerImpl.
|
|
21
28
|
*/
|
|
22
|
-
async function initializeStreamer(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, changeSource, replicationStatusPublisher, subscriptionState, purgeLock, autoReset, opts, setTimeoutFn = setTimeout) {
|
|
23
|
-
await
|
|
24
|
-
await ensureReplicationConfig(lc, changeDB, subscriptionState, shard, autoReset, setTimeoutFn);
|
|
29
|
+
async function initializeStreamer(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, changeSource, replicationStatusPublisher, subscriptionState, backupConfig, purgeLock, autoReset, opts, setTimeoutFn = setTimeout) {
|
|
30
|
+
await ensureReplicationConfig(lc, changeDB, subscriptionState, shard, autoReset, purgeLock ?? void 0, setTimeoutFn);
|
|
25
31
|
const { replicaVersion } = subscriptionState;
|
|
26
|
-
return new ChangeStreamerImpl(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, changeSource, replicationStatusPublisher, purgeLock, autoReset, opts, setTimeoutFn);
|
|
32
|
+
return new ChangeStreamerImpl(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, changeSource, replicationStatusPublisher, backupConfig, purgeLock, autoReset, opts, setTimeoutFn);
|
|
27
33
|
}
|
|
28
34
|
var REPLICATION_STATUS_ERROR_DELAY_THRESHOLD_MS = 5e3;
|
|
35
|
+
var DEFAULT_CHANGE_LOG_UNAVAILABLE_WARN_THRESHOLD_MS = 6e4;
|
|
29
36
|
/**
|
|
30
37
|
* Upstream-agnostic dispatch of messages in a {@link ChangeStreamMessage} to a
|
|
31
38
|
* {@link Forwarder} and {@link Storer} to execute the forward-store-ack
|
|
@@ -173,30 +180,84 @@ var ChangeStreamerImpl = class {
|
|
|
173
180
|
#source;
|
|
174
181
|
#storer;
|
|
175
182
|
#forwarder;
|
|
183
|
+
#reservations;
|
|
176
184
|
#replicationStatusPublisher;
|
|
185
|
+
#sqliteCatchupOptions;
|
|
186
|
+
#changeLogWriter;
|
|
187
|
+
#purgeScheduler;
|
|
188
|
+
#acker;
|
|
189
|
+
#initializer;
|
|
177
190
|
#autoReset;
|
|
178
191
|
#state;
|
|
179
|
-
#initialWatermarks = /* @__PURE__ */ new Set();
|
|
180
192
|
#serving = resolver();
|
|
181
193
|
#txCounter = getOrCreateCounter("replication", "transactions", "Count of replicated transactions");
|
|
182
194
|
#changeCounter = getOrCreateCounter("replication", "changes", "Count of replicated changes (DML or DDL statements)");
|
|
195
|
+
#transactionForwardDuration = getOrCreateLatencyHistogram("replication", "transaction_forward_duration", "Time from receiving a transaction's `begin` to forwarding its `commit`, i.e. the change-streamer half of forward-to-subscriber latency.");
|
|
183
196
|
#latestStatus;
|
|
197
|
+
#latestLagReportCommitTimeMs = 0;
|
|
198
|
+
#backupWatermark;
|
|
199
|
+
#pgPurgedWatermark = "";
|
|
200
|
+
/**
|
|
201
|
+
* The floor last logged as held back by a laggard. The level-triggered
|
|
202
|
+
* retry re-evaluates every {@link CLEANUP_DELAY_MS}; logging only when the
|
|
203
|
+
* blocking floor moves keeps a stuck subscriber from emitting the same
|
|
204
|
+
* line indefinitely.
|
|
205
|
+
*/
|
|
206
|
+
#loggedBehindWatermark;
|
|
207
|
+
#sqlitePurgeContinuation;
|
|
184
208
|
#purgeLock;
|
|
209
|
+
#pgPurgeScheduled = false;
|
|
210
|
+
#pgPurgeRunning = false;
|
|
211
|
+
#sqlitePurgeScheduled = false;
|
|
212
|
+
#sqlitePurgeRunning = false;
|
|
185
213
|
#stream;
|
|
186
|
-
|
|
214
|
+
#sqliteCatchup;
|
|
215
|
+
#changeLogUnavailableSince;
|
|
216
|
+
#lastForwardedCommitWatermark;
|
|
217
|
+
#transactionForwardStartedAt;
|
|
218
|
+
#currentTransactionCompletion;
|
|
219
|
+
constructor(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, source, replicationStatusPublisher, backupConfig, initialPurgeLock, autoReset, opts, setTimeoutFn = setTimeout) {
|
|
187
220
|
this.id = `change-streamer`;
|
|
188
221
|
this.#lc = lc.withContext("component", "change-streamer");
|
|
189
222
|
this.#shard = shard;
|
|
190
223
|
this.#changeDB = changeDB;
|
|
191
224
|
this.#replicaVersion = replicaVersion;
|
|
192
225
|
this.#source = source;
|
|
193
|
-
this.#storer = new Storer(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, (consumed) => this.#
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
this.#
|
|
226
|
+
this.#storer = new Storer(lc, shard, taskID, discoveryAddress, discoveryProtocol, changeDB, replicaVersion, (consumed) => this.#acker.trackPgChangeLog(consumed[2].watermark), (err) => this.stop(err), opts);
|
|
227
|
+
this.#forwarder = new Forwarder(lc, {
|
|
228
|
+
flowControlConsensusTimeoutProportion: opts.flowControlConsensusTimeoutProportion,
|
|
229
|
+
flowControlSlowSubscriberGracePeriodMs: opts.flowControlSlowSubscriberGracePeriodMs
|
|
230
|
+
});
|
|
231
|
+
this.#reservations = backupConfig ? new SnapshotReservations(lc, backupConfig, (taskID) => this.#purgeScheduler?.resume(taskID)) : void 0;
|
|
199
232
|
this.#replicationStatusPublisher = replicationStatusPublisher;
|
|
233
|
+
this.#changeLogWriter = opts.sqliteChangeLogWriter ? new SQLiteChangeLogWriter(lc, {
|
|
234
|
+
...opts.sqliteChangeLogWriter,
|
|
235
|
+
onCommit: (watermark) => {
|
|
236
|
+
this.#sqliteCatchup?.onChangeLogCommit(watermark);
|
|
237
|
+
this.#purgeScheduler?.onWriterIdle();
|
|
238
|
+
},
|
|
239
|
+
onDisabled: () => this.#closeSQLiteCatchup(),
|
|
240
|
+
onRebuilt: () => this.#closeSQLiteCatchup()
|
|
241
|
+
}) : void 0;
|
|
242
|
+
this.#purgeScheduler = opts.sqliteChangeLogPurge && this.#changeLogWriter ? new SQLiteChangeLogPurgeScheduler(lc, () => this.#changeLogWriter?.connection, () => this.#forwarder.getAcks(), opts.sqliteChangeLogPurge) : void 0;
|
|
243
|
+
this.#acker = new UpstreamAcker({
|
|
244
|
+
trackPgChangeLog: true,
|
|
245
|
+
trackBackup: backupConfig?.litestreamVersion === "v5"
|
|
246
|
+
});
|
|
247
|
+
const replicaSource = opts.sqliteChangeLogCompare ? replicaInitializationSource(lc, opts.sqliteChangeLogCompare.replicaFile) : void 0;
|
|
248
|
+
this.#initializer = new ChangeLogInitializer(lc, {
|
|
249
|
+
initFromPgChangeLog: true,
|
|
250
|
+
initFromReplica: replicaSource !== void 0
|
|
251
|
+
}, {
|
|
252
|
+
pgChangeLog: () => this.#storer.getStartStreamInitializationParameters(),
|
|
253
|
+
replica: () => must(replicaSource)(),
|
|
254
|
+
reconcileChangeLog: (resumeFrom, seed) => resumeFrom ? this.#changeLogWriter?.reconcile(resumeFrom) : this.#changeLogWriter?.reconcileFromLog(seed),
|
|
255
|
+
changeLog: () => this.#changeLogWriter?.connection
|
|
256
|
+
});
|
|
257
|
+
this.#sqliteCatchupOptions = opts.sqliteCatchup ? {
|
|
258
|
+
...opts.sqliteCatchup,
|
|
259
|
+
cleanupGuard: opts.sqliteCatchup.cleanupGuard ?? this.#purgeScheduler?.cleanupGuard
|
|
260
|
+
} : void 0;
|
|
200
261
|
this.#purgeLock = initialPurgeLock;
|
|
201
262
|
this.#autoReset = autoReset;
|
|
202
263
|
this.#state = new RunningState(this.id, void 0, setTimeoutFn);
|
|
@@ -205,8 +266,11 @@ var ChangeStreamerImpl = class {
|
|
|
205
266
|
async run() {
|
|
206
267
|
this.#lc.info?.("starting change stream");
|
|
207
268
|
this.#forwarder.startProgressMonitor();
|
|
208
|
-
const
|
|
209
|
-
if (
|
|
269
|
+
const lagReportInit = await this.#source.startLagReporter();
|
|
270
|
+
if (lagReportInit) {
|
|
271
|
+
this.#latestStatus.lagReport = { nextSendTimeMs: lagReportInit.nextSendTimeMs };
|
|
272
|
+
this.#latestLagReportCommitTimeMs = lagReportInit.firstCommitTimeMs;
|
|
273
|
+
}
|
|
210
274
|
await this.#storer.assumeOwnership(this.#purgeLock);
|
|
211
275
|
this.#purgeLock = null;
|
|
212
276
|
const flushBytesThreshold = getDefaultHighWaterMark(false);
|
|
@@ -215,19 +279,22 @@ var ChangeStreamerImpl = class {
|
|
|
215
279
|
let watermark = null;
|
|
216
280
|
let unflushedBytes = 0;
|
|
217
281
|
try {
|
|
218
|
-
const { lastWatermark, backfillRequests } = await this.#
|
|
282
|
+
const { lastWatermark, backfillRequests } = await this.#initializer.initialize();
|
|
283
|
+
this.#lastForwardedCommitWatermark = lastWatermark;
|
|
219
284
|
const stream = await this.#source.startStream(lastWatermark, backfillRequests);
|
|
220
285
|
this.#storer.run().catch((e) => stream.changes.cancel(e));
|
|
221
286
|
this.#stream = stream;
|
|
222
287
|
if (this.#state.resetBackoff() > REPLICATION_STATUS_ERROR_DELAY_THRESHOLD_MS) this.#replicationStatusPublisher.publish(this.#lc, "Replicating", `Replicating from ${lastWatermark}`);
|
|
223
288
|
watermark = null;
|
|
289
|
+
this.#acker.reset(stream.acks);
|
|
224
290
|
for await (const change of stream.changes) {
|
|
291
|
+
this.#acker.trackDownstream(change);
|
|
225
292
|
const [type, msg] = change;
|
|
226
293
|
switch (type) {
|
|
227
294
|
case "status":
|
|
228
|
-
if (msg.
|
|
229
|
-
if (msg.lagReport) {
|
|
295
|
+
if (msg.lagReport && msg.lagReport.lastTimings.commitTimeMs >= this.#latestLagReportCommitTimeMs) {
|
|
230
296
|
this.#latestStatus.lagReport = msg.lagReport;
|
|
297
|
+
this.#latestLagReportCommitTimeMs = msg.lagReport.lastTimings.commitTimeMs;
|
|
231
298
|
this.#forwarder.sendStatus(this.#latestStatus);
|
|
232
299
|
}
|
|
233
300
|
continue;
|
|
@@ -247,15 +314,19 @@ var ChangeStreamerImpl = class {
|
|
|
247
314
|
break;
|
|
248
315
|
}
|
|
249
316
|
const json = this.#storer.store(watermark, change);
|
|
317
|
+
this.#changeLogWriter?.write(change, json);
|
|
250
318
|
const entry = [
|
|
251
319
|
watermark,
|
|
252
320
|
change[1].tag,
|
|
253
321
|
json
|
|
254
322
|
];
|
|
255
323
|
unflushedBytes += json.length;
|
|
256
|
-
if (unflushedBytes < flushBytesThreshold)
|
|
257
|
-
|
|
324
|
+
if (unflushedBytes < flushBytesThreshold) {
|
|
325
|
+
this.#forwarder.forward(entry);
|
|
326
|
+
this.#recordForwardedTransactionBoundary(type, entry[0]);
|
|
327
|
+
} else {
|
|
258
328
|
const forwarded = this.#forwarder.forwardWithFlowControl(entry);
|
|
329
|
+
this.#recordForwardedTransactionBoundary(type, entry[0]);
|
|
259
330
|
await stream.changes.doneOr(forwarded);
|
|
260
331
|
unflushedBytes = 0;
|
|
261
332
|
}
|
|
@@ -272,11 +343,14 @@ var ChangeStreamerImpl = class {
|
|
|
272
343
|
if (watermark) {
|
|
273
344
|
this.#lc.warn?.(`aborting interrupted transaction ${watermark}`);
|
|
274
345
|
this.#storer.abort();
|
|
346
|
+
this.#changeLogWriter?.abort();
|
|
347
|
+
this.#purgeScheduler?.onWriterIdle();
|
|
275
348
|
this.#forwarder.forward([
|
|
276
349
|
watermark,
|
|
277
350
|
"rollback",
|
|
278
351
|
ROLLBACK_JSON
|
|
279
352
|
]);
|
|
353
|
+
this.#recordForwardedTransactionBoundary("rollback", watermark);
|
|
280
354
|
}
|
|
281
355
|
await Promise.all([
|
|
282
356
|
this.#storer.stop(),
|
|
@@ -302,27 +376,88 @@ var ChangeStreamerImpl = class {
|
|
|
302
376
|
default: unreachable(tag);
|
|
303
377
|
}
|
|
304
378
|
}
|
|
305
|
-
subscribe(ctx) {
|
|
379
|
+
async subscribe(ctx) {
|
|
306
380
|
const { protocolVersion, id, mode, replicaVersion, watermark } = ctx;
|
|
307
381
|
if (mode === "serving") this.#serving.resolve();
|
|
308
|
-
|
|
309
|
-
const
|
|
382
|
+
let cleanupSubscriber = () => {};
|
|
383
|
+
const downstream = Subscription.create({ cleanup: () => cleanupSubscriber() });
|
|
384
|
+
const subscriber = new Subscriber(protocolVersion, id, watermark, downstream, () => this.#latestStatus, {});
|
|
385
|
+
const lc = this.#lc.withContext("subscriber", subscriber.id);
|
|
386
|
+
cleanupSubscriber = () => {
|
|
387
|
+
lc.info?.(`removing subscriber ${subscriber.id}`);
|
|
388
|
+
this.#forwarder.remove(subscriber);
|
|
389
|
+
};
|
|
310
390
|
if (replicaVersion !== this.#replicaVersion) {
|
|
311
|
-
|
|
391
|
+
lc.warn?.(`rejecting subscriber at replica version ${replicaVersion}`);
|
|
312
392
|
subscriber.close(1, `current replica version is ${this.#replicaVersion} (requested ${replicaVersion})`);
|
|
313
393
|
} else {
|
|
314
|
-
|
|
315
|
-
this.#
|
|
316
|
-
|
|
394
|
+
lc.info?.(`adding subscriber ${subscriber.id}`);
|
|
395
|
+
const sqliteCatchup = this.#selectSQLiteCatchup(ctx);
|
|
396
|
+
if (sqliteCatchup) {
|
|
397
|
+
cleanupSubscriber = () => sqliteCatchup.remove(subscriber);
|
|
398
|
+
await sqliteCatchup.catchup(subscriber, () => this.#captureRequiredHead());
|
|
399
|
+
} else {
|
|
400
|
+
this.#forwarder.add(subscriber);
|
|
401
|
+
this.#storer.catchup(subscriber, mode);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
this.#reservations?.close(ctx.taskID);
|
|
405
|
+
return downstream;
|
|
406
|
+
}
|
|
407
|
+
async startSnapshotReservation(taskID) {
|
|
408
|
+
if (!this.#reservations) throw new Error("backups are not configured");
|
|
409
|
+
const downstream = this.#reservations.open(taskID);
|
|
410
|
+
try {
|
|
411
|
+
await (this.#purgeScheduler?.pause(taskID) ?? promiseVoid);
|
|
412
|
+
await this.#confirmReservations();
|
|
413
|
+
return downstream;
|
|
414
|
+
} catch (e) {
|
|
415
|
+
downstream.cancel();
|
|
416
|
+
throw e;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
trackBackupWatermark(watermark) {
|
|
420
|
+
this.#backupWatermark = watermark;
|
|
421
|
+
this.#acker.trackBackup(watermark);
|
|
422
|
+
this.#requestSQLitePurge("deferred");
|
|
423
|
+
this.#maybeSchedulePGPurge();
|
|
424
|
+
this.#maybeScheduleSQLitePurge();
|
|
425
|
+
this.#confirmReservations().catch((e) => this.#lc.warn?.(`error confirming snapshot reservation`, e));
|
|
426
|
+
}
|
|
427
|
+
async #confirmReservations() {
|
|
428
|
+
if (this.#backupWatermark && this.#reservations?.confirmationsRequired()) {
|
|
429
|
+
const { replicaVersion, minWatermark } = await this.#getChangeLogState();
|
|
430
|
+
if (minWatermark <= this.#backupWatermark) this.#reservations?.confirm(replicaVersion, this.#backupWatermark);
|
|
431
|
+
else this.#lc.error?.(`change-log minWatermark ${minWatermark} is later than backupWatermark ${this.#backupWatermark}. Delaying confirmation of snapshot reservation until next backup.`);
|
|
317
432
|
}
|
|
318
|
-
return Promise.resolve(downstream);
|
|
319
433
|
}
|
|
320
|
-
|
|
321
|
-
const
|
|
322
|
-
this.#
|
|
323
|
-
|
|
434
|
+
#maybeSchedulePGPurge() {
|
|
435
|
+
const backupWatermark = this.#backupWatermark;
|
|
436
|
+
if (this.#pgPurgeScheduled || this.#pgPurgeRunning || backupWatermark === void 0 || this.#pgPurgedWatermark >= backupWatermark) return;
|
|
437
|
+
this.#pgPurgeScheduled = true;
|
|
438
|
+
this.#state.setTimeout(() => {
|
|
439
|
+
this.#pgPurgeScheduled = false;
|
|
440
|
+
this.#pgPurgeRunning = true;
|
|
441
|
+
return this.#purgePGChangeLog().finally(() => {
|
|
442
|
+
this.#pgPurgeRunning = false;
|
|
443
|
+
this.#maybeSchedulePGPurge();
|
|
444
|
+
});
|
|
445
|
+
}, CLEANUP_DELAY_MS);
|
|
324
446
|
}
|
|
325
|
-
|
|
447
|
+
#maybeScheduleSQLitePurge() {
|
|
448
|
+
if (this.#sqlitePurgeScheduled || this.#sqlitePurgeRunning || this.#backupWatermark === void 0 || this.#sqlitePurgeContinuation === void 0) return;
|
|
449
|
+
const delay = this.#sqlitePurgeContinuation === "immediate" ? 0 : CLEANUP_DELAY_MS;
|
|
450
|
+
this.#sqlitePurgeScheduled = true;
|
|
451
|
+
this.#state.setTimeout(() => {
|
|
452
|
+
this.#sqlitePurgeScheduled = false;
|
|
453
|
+
this.#sqlitePurgeRunning = true;
|
|
454
|
+
return this.#purgeSQLiteChangeLog().finally(() => {
|
|
455
|
+
this.#sqlitePurgeRunning = false;
|
|
456
|
+
this.#maybeScheduleSQLitePurge();
|
|
457
|
+
});
|
|
458
|
+
}, delay);
|
|
459
|
+
}
|
|
460
|
+
async #getChangeLogState() {
|
|
326
461
|
const minWatermark = await this.#storer.getMinWatermarkForCatchup();
|
|
327
462
|
if (!minWatermark) this.#lc.warn?.(`Unexpected empty changeLog. Resync if "Local replica watermark" errors arise`);
|
|
328
463
|
return {
|
|
@@ -330,44 +465,176 @@ var ChangeStreamerImpl = class {
|
|
|
330
465
|
minWatermark: minWatermark ?? this.#replicaVersion
|
|
331
466
|
};
|
|
332
467
|
}
|
|
468
|
+
#getCleanupFloor() {
|
|
469
|
+
const backupWatermark = this.#backupWatermark;
|
|
470
|
+
assert(backupWatermark !== void 0, "cleanup cannot run without a backup watermark");
|
|
471
|
+
const current = [...this.#forwarder.getAcks(), ...this.#reservations?.getReservedWatermarks() ?? []];
|
|
472
|
+
return {
|
|
473
|
+
backupWatermark,
|
|
474
|
+
purgeWatermark: min(backupWatermark, ...current),
|
|
475
|
+
current
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
async #purgePGChangeLog() {
|
|
479
|
+
try {
|
|
480
|
+
const { backupWatermark, purgeWatermark, current } = this.#getCleanupFloor();
|
|
481
|
+
if (purgeWatermark < backupWatermark) {
|
|
482
|
+
if (this.#loggedBehindWatermark !== purgeWatermark) {
|
|
483
|
+
this.#loggedBehindWatermark = purgeWatermark;
|
|
484
|
+
this.#lc.info?.(`At least one client is behind backup ${backupWatermark}`, { watermarks: current });
|
|
485
|
+
}
|
|
486
|
+
} else this.#loggedBehindWatermark = void 0;
|
|
487
|
+
if (purgeWatermark <= this.#pgPurgedWatermark) return;
|
|
488
|
+
this.#lc.info?.(`Purging PG changes before ${purgeWatermark} ...`);
|
|
489
|
+
const start = performance.now();
|
|
490
|
+
const deleted = await this.#storer.purgeRecordsBefore(purgeWatermark);
|
|
491
|
+
const elapsed = (performance.now() - start).toFixed(2);
|
|
492
|
+
this.#lc.info?.(`Purged ${deleted} PG changes before ${purgeWatermark} (${elapsed} ms)`);
|
|
493
|
+
this.#pgPurgedWatermark = purgeWatermark;
|
|
494
|
+
} catch (e) {
|
|
495
|
+
this.#lc.warn?.(`error purging the PG change log`, e);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
async #purgeSQLiteChangeLog() {
|
|
499
|
+
const scheduler = this.#purgeScheduler;
|
|
500
|
+
if (!scheduler) return;
|
|
501
|
+
try {
|
|
502
|
+
const { backupWatermark, purgeWatermark } = this.#getCleanupFloor();
|
|
503
|
+
this.#sqlitePurgeContinuation = void 0;
|
|
504
|
+
if (purgeWatermark < backupWatermark) this.#requestSQLitePurge("deferred");
|
|
505
|
+
const result = await scheduler.purge(purgeWatermark);
|
|
506
|
+
this.#requestSQLitePurge(result.continuation);
|
|
507
|
+
} catch (e) {
|
|
508
|
+
this.#requestSQLitePurge("deferred");
|
|
509
|
+
this.#lc.warn?.(`error purging the SQLite change log`, e);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
#requestSQLitePurge(continuation) {
|
|
513
|
+
if (!this.#purgeScheduler || continuation === void 0) return;
|
|
514
|
+
if (continuation === "immediate" || this.#sqlitePurgeContinuation === void 0) this.#sqlitePurgeContinuation = continuation;
|
|
515
|
+
}
|
|
516
|
+
async stop(err) {
|
|
517
|
+
this.#state.stop(this.#lc, err);
|
|
518
|
+
this.#stream?.changes.cancel();
|
|
519
|
+
this.#purgeScheduler?.stop();
|
|
520
|
+
this.#sqliteCatchup?.close();
|
|
521
|
+
this.#changeLogWriter?.close();
|
|
522
|
+
await Promise.allSettled([this.#storer.stop(), this.#source.stop()]);
|
|
523
|
+
}
|
|
524
|
+
#recordForwardedTransactionBoundary(type, watermark) {
|
|
525
|
+
switch (type) {
|
|
526
|
+
case "begin":
|
|
527
|
+
assert(this.#currentTransactionCompletion === void 0, "forwarded begin while a transaction is already in progress");
|
|
528
|
+
this.#currentTransactionCompletion = resolver();
|
|
529
|
+
this.#transactionForwardStartedAt = performance.now();
|
|
530
|
+
break;
|
|
531
|
+
case "commit": {
|
|
532
|
+
const completion = this.#currentTransactionCompletion;
|
|
533
|
+
assert(completion, "forwarded commit without a pending transaction");
|
|
534
|
+
this.#recordTransactionForwardDuration();
|
|
535
|
+
this.#lastForwardedCommitWatermark = watermark;
|
|
536
|
+
this.#currentTransactionCompletion = void 0;
|
|
537
|
+
completion.resolve({
|
|
538
|
+
kind: "committed",
|
|
539
|
+
watermark
|
|
540
|
+
});
|
|
541
|
+
break;
|
|
542
|
+
}
|
|
543
|
+
case "rollback": {
|
|
544
|
+
const completion = this.#currentTransactionCompletion;
|
|
545
|
+
assert(completion, "forwarded rollback without a pending transaction");
|
|
546
|
+
const committed = this.#lastForwardedCommitWatermark;
|
|
547
|
+
assert(committed, "last forwarded commit watermark is not initialized");
|
|
548
|
+
this.#transactionForwardStartedAt = void 0;
|
|
549
|
+
this.#currentTransactionCompletion = void 0;
|
|
550
|
+
completion.resolve({
|
|
551
|
+
kind: "rolled-back",
|
|
552
|
+
watermark: committed
|
|
553
|
+
});
|
|
554
|
+
break;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
#recordTransactionForwardDuration() {
|
|
559
|
+
const startedAt = this.#transactionForwardStartedAt;
|
|
560
|
+
this.#transactionForwardStartedAt = void 0;
|
|
561
|
+
if (startedAt !== void 0) this.#transactionForwardDuration.recordMs(performance.now() - startedAt, { sqlite_change_log: this.#changeLogWriter?.enabled ? "on" : "off" });
|
|
562
|
+
}
|
|
333
563
|
/**
|
|
334
|
-
*
|
|
335
|
-
*
|
|
336
|
-
*
|
|
564
|
+
* Closes and forgets the cached catchup coordinator, so that a later
|
|
565
|
+
* subscription re-opens the log from scratch rather than reading a handle
|
|
566
|
+
* whose file is gone.
|
|
337
567
|
*/
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
568
|
+
#closeSQLiteCatchup() {
|
|
569
|
+
this.#sqliteCatchup?.close();
|
|
570
|
+
this.#sqliteCatchup = void 0;
|
|
571
|
+
}
|
|
572
|
+
#captureRequiredHead() {
|
|
573
|
+
const committed = this.#lastForwardedCommitWatermark;
|
|
574
|
+
assert(committed, "last forwarded commit watermark is not initialized");
|
|
575
|
+
return this.#currentTransactionCompletion?.promise.then((completion) => completion.watermark) ?? committed;
|
|
576
|
+
}
|
|
577
|
+
#selectSQLiteCatchup(ctx) {
|
|
578
|
+
const opts = this.#sqliteCatchupOptions;
|
|
579
|
+
if (this.#lastForwardedCommitWatermark === void 0 || !opts) return;
|
|
580
|
+
if (ctx.mode !== "serving") {
|
|
581
|
+
this.#lc.info?.(`not serving backup subscriber ${ctx.id} from SQLite catchup`);
|
|
342
582
|
return;
|
|
343
583
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
this.#lc.warn?.("No subscribers to confirm cleanup");
|
|
584
|
+
if (ctx.logsChangeStream) {
|
|
585
|
+
this.#lc.warn?.(`not serving legacy change-log writer ${ctx.id} from SQLite catchup`);
|
|
347
586
|
return;
|
|
348
587
|
}
|
|
588
|
+
if (!opts.shouldUse?.(ctx)) return;
|
|
589
|
+
return this.#sqliteCatchup ?? this.#openSQLiteCatchup(opts, ctx);
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Opens the change log and, if it can serve, wraps it in the coordinator that
|
|
593
|
+
* subsequent subscriptions reuse.
|
|
594
|
+
*
|
|
595
|
+
* The log may not exist yet -- the writer creates it at the stream loop's
|
|
596
|
+
* first reconcile, and deletes it when it fails soft -- or may exist without
|
|
597
|
+
* content, or may be unreadable. None of those can be allowed to fail a
|
|
598
|
+
* subscription:
|
|
599
|
+
* this is the last point at which PG catchup is still available -- past
|
|
600
|
+
* `Forwarder.add()` the subscriber is committed to SQLite -- so each declines
|
|
601
|
+
* here instead. Neither the failure nor the reader is retained, so a later
|
|
602
|
+
* subscription retries from scratch.
|
|
603
|
+
*/
|
|
604
|
+
#openSQLiteCatchup(opts, ctx) {
|
|
605
|
+
let reader;
|
|
349
606
|
try {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const start = performance.now();
|
|
356
|
-
const deleted = await this.#storer.purgeRecordsBefore(earliestInitial);
|
|
357
|
-
const elapsed = (performance.now() - start).toFixed(2);
|
|
358
|
-
this.#lc.info?.(`Purged ${deleted} changes before ${earliestInitial} (${elapsed} ms)`);
|
|
359
|
-
this.#initialWatermarks.delete(earliestInitial);
|
|
607
|
+
reader = new SQLiteChangeLogReader(this.#lc, opts.changeLogFile);
|
|
608
|
+
if (reader.plan(ctx.watermark).kind === "not-ready") {
|
|
609
|
+
reader.close();
|
|
610
|
+
this.#declineSQLiteCatchup(ctx, opts, `${opts.changeLogFile} has no changes to serve yet`);
|
|
611
|
+
return;
|
|
360
612
|
}
|
|
361
613
|
} catch (e) {
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
614
|
+
reader?.close();
|
|
615
|
+
this.#declineSQLiteCatchup(ctx, opts, `cannot read ${opts.changeLogFile}`, e);
|
|
616
|
+
return;
|
|
365
617
|
}
|
|
618
|
+
this.#changeLogUnavailableSince = void 0;
|
|
619
|
+
this.#sqliteCatchup = new SQLiteChangeLogCatchup(this.#lc, this.#forwarder, reader, {
|
|
620
|
+
batchSize: opts.readBatchRows,
|
|
621
|
+
barrierTimeoutMs: opts.barrierTimeoutMs,
|
|
622
|
+
barrierPollIntervalMs: opts.barrierPollIntervalMs,
|
|
623
|
+
cleanupGuard: opts.cleanupGuard
|
|
624
|
+
});
|
|
625
|
+
return this.#sqliteCatchup;
|
|
366
626
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
627
|
+
/**
|
|
628
|
+
* Reports falling back to PG catchup, tracking how long the log has been
|
|
629
|
+
* unavailable so that a subscription that merely arrived before the writer's
|
|
630
|
+
* first reconcile does not look like an incident.
|
|
631
|
+
*/
|
|
632
|
+
#declineSQLiteCatchup(ctx, opts, reason, error) {
|
|
633
|
+
const now = Date.now();
|
|
634
|
+
this.#changeLogUnavailableSince ??= now;
|
|
635
|
+
const unavailableMs = now - this.#changeLogUnavailableSince;
|
|
636
|
+
const threshold = opts.notReadyWarnThresholdMs ?? DEFAULT_CHANGE_LOG_UNAVAILABLE_WARN_THRESHOLD_MS;
|
|
637
|
+
this.#lc[unavailableMs >= threshold ? "warn" : "debug"]?.(`serving ${ctx.id} from PG catchup: ${reason} (unavailable for ${unavailableMs} ms)`, ...error === void 0 ? [] : [error]);
|
|
371
638
|
}
|
|
372
639
|
};
|
|
373
640
|
var CLEANUP_DELAY_MS = DEFAULT_MAX_RETRY_DELAY_MS * 3;
|