@rocicorp/zero 1.10.0-canary.0 → 1.10.0-canary.10
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/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/shared/src/promise-race.d.ts +14 -0
- package/out/shared/src/promise-race.d.ts.map +1 -1
- package/out/shared/src/promise-race.js +32 -1
- package/out/shared/src/promise-race.js.map +1 -1
- package/out/z2s/src/compiler.d.ts.map +1 -1
- package/out/z2s/src/compiler.js +1 -22
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/zero/package.js +3 -3
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +8 -1
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts +6 -0
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js +24 -2
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +65 -4
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +202 -35
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +1 -1
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/db/delete-lite-db.js +2 -1
- package/out/zero-cache/src/db/delete-lite-db.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +10 -5
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.d.ts.map +1 -1
- package/out/zero-cache/src/db/migration.js +4 -2
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/sqlite-corruption.d.ts +3 -2
- package/out/zero-cache/src/db/sqlite-corruption.d.ts.map +1 -1
- package/out/zero-cache/src/db/sqlite-corruption.js +13 -8
- package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts +5 -15
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +8 -72
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/observability/metrics.d.ts +6 -1
- package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
- package/out/zero-cache/src/observability/metrics.js +20 -2
- package/out/zero-cache/src/observability/metrics.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +105 -34
- 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 +8 -18
- 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 +48 -5
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +3 -2
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +1 -1
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.d.ts +0 -1
- package/out/zero-cache/src/server/worker-urls.d.ts.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js +1 -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 +81 -3
- 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 +14 -5
- 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.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +22 -11
- 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 +90 -31
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js +20 -11
- package/out/zero-cache/src/services/change-source/pg/decommission.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 +61 -76
- 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.d.ts +65 -2
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +101 -10
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +27 -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 +41 -8
- 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 +2 -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 +5 -13
- 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 +6 -3
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- 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-source/protocol/current/status.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +3 -7
- 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 +26 -10
- 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 +71 -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-compare-digest.d.ts +34 -0
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.js +67 -0
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.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 +5 -8
- 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 +20 -19
- 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 +90 -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 +456 -66
- 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 +50 -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 +42 -12
- 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} +68 -176
- 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/shard-sampling.d.ts +11 -0
- package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/shard-sampling.js +19 -0
- package/out/zero-cache/src/services/change-streamer/shard-sampling.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +24 -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 +119 -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 +99 -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 +344 -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-comparator.d.ts +83 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +417 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.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-read-router.d.ts +73 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js +157 -0
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.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 +164 -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 +85 -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 +286 -141
- 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/change-streamer/vfs-watermark-poller.d.ts +29 -0
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +154 -0
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +1 -0
- package/out/zero-cache/src/services/http-service.d.ts +1 -0
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +7 -3
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- 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 +4 -3
- 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 +115 -152
- 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/config.yml +3 -2
- package/out/zero-cache/src/services/litestream/metrics.d.ts +5 -4
- package/out/zero-cache/src/services/litestream/metrics.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/metrics.js +10 -10
- package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +5 -2
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- 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 +368 -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 +491 -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 +6 -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 +70 -25
- 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 +19 -6
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/notifier.d.ts +0 -22
- package/out/zero-cache/src/services/replicator/notifier.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/notifier.js +7 -1
- package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts +17 -2
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js +9 -3
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +27 -0
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.js +32 -0
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +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 +132 -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 +415 -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 +23 -12
- 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/client-handler.d.ts +3 -2
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +25 -17
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +14 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +53 -0
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js +68 -0
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -0
- 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/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +14 -4
- 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 +70 -8
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/downstream.d.ts +11 -0
- package/out/zero-cache/src/types/downstream.d.ts.map +1 -0
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +14 -4
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.d.ts +18 -0
- package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -0
- package/out/zero-cache/src/types/poke-chunk.js +57 -0
- package/out/zero-cache/src/types/poke-chunk.js.map +1 -0
- 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 -28
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts +16 -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/types/subscription.d.ts +2 -0
- package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
- package/out/zero-cache/src/types/subscription.js +6 -0
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/workers/connection.d.ts +23 -4
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js +130 -10
- 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-client/src/client/zero-poke-handler.d.ts +7 -2
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +52 -2
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +6 -7
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +194 -107
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +1 -1
- package/out/zero-protocol/src/poke.d.ts +89 -7
- package/out/zero-protocol/src/poke.d.ts.map +1 -1
- package/out/zero-protocol/src/poke.js +16 -8
- package/out/zero-protocol/src/poke.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.d.ts +12 -7
- package/out/zero-protocol/src/protocol-version.d.ts.map +1 -1
- package/out/zero-protocol/src/protocol-version.js.map +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-server/src/custom.js +10 -3
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/schema.d.ts +8 -0
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +63 -24
- package/out/zero-server/src/schema.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/ivm/memory-source.d.ts +10 -2
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +14 -6
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts +0 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js +1 -7
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +11 -2
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/mutate/crud.d.ts +10 -8
- package/out/zql/src/mutate/crud.d.ts.map +1 -1
- package/out/zql/src/mutate/crud.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +5 -1
- package/out/zql/src/query/query-delegate-base.js.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/db.js +2 -2
- 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 +33 -14
- package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +5 -5
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +4 -4
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +3 -3
- 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
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { must } from "../../../../shared/src/must.js";
|
|
2
|
+
import { readCookieRowCounts, readCookies } from "../replicator/change-log-cookies.js";
|
|
3
|
+
import { StatementRunner } from "../../db/statements.js";
|
|
4
|
+
import { isSQLiteCorruption, logSQLiteCorruptionDiagnostics } from "../../db/sqlite-corruption.js";
|
|
5
|
+
import { ChangeLogRebuildRequired, changeLogFileName, changeLogWipeReason, deleteChangeLogDB, openChangeLogDBForWriting, readChangeLogHead, rebuildChangeLogDBForWriting, reconcileChangeLog } from "../replicator/change-log-db.js";
|
|
6
|
+
import { ChangeLogStreamWriter } from "../replicator/change-log-stream-writer.js";
|
|
7
|
+
import { SQLiteChangeLogObserver, getSQLiteChangeLogInfo, logSQLiteChangeLogStartup, recordSQLiteChangeLogReconcile } from "../replicator/sqlite-change-log-observability.js";
|
|
8
|
+
import { SqliteError } from "@rocicorp/zero-sqlite3";
|
|
9
|
+
//#region ../zero-cache/src/services/change-streamer/sqlite-change-log-writer.ts
|
|
10
|
+
/**
|
|
11
|
+
* Appends the canonical change stream to the SQLite change log, from the
|
|
12
|
+
* change-streamer's own stream loop.
|
|
13
|
+
*
|
|
14
|
+
* ### Ordering
|
|
15
|
+
*
|
|
16
|
+
* The log's commit for a transaction precedes the forward of that transaction's
|
|
17
|
+
* `commit` message, and nothing `await`s in between. Everything that can
|
|
18
|
+
* advance the watermark the stream would resume from — the storer's Postgres
|
|
19
|
+
* commit, `lastWatermark`, the upstream ACK — runs strictly after it, so the
|
|
20
|
+
* log's head is always at or above the resume point. A *hole* is therefore
|
|
21
|
+
* unreachable at any crash timing, and a *phantom* is the normal state, which is
|
|
22
|
+
* what makes truncate-above the whole of reconciliation.
|
|
23
|
+
*
|
|
24
|
+
* ### Fail-soft
|
|
25
|
+
*
|
|
26
|
+
* The log is a catchup cache: nothing in it is not either already durable in the
|
|
27
|
+
* replica's litestream backup or re-derivable from the replication slot. A write
|
|
28
|
+
* failure must therefore not stop replication for the shard. Corruption is
|
|
29
|
+
* rebuilt once at open; any other write error — a full disk, an I/O error, a
|
|
30
|
+
* permissions problem — logs, disables the writer, deletes the file, closes the
|
|
31
|
+
* reader, and lets the stream continue. The cost is catchup reach, and reach is
|
|
32
|
+
* recoverable: `too-old` sends a subscriber to a restore.
|
|
33
|
+
*
|
|
34
|
+
* One carve-out keeps that from hiding the bug class this topology introduces. A
|
|
35
|
+
* missed truncate-above surfaces as `SQLITE_CONSTRAINT` on the writer's plain
|
|
36
|
+
* `INSERT`, which is "any write error other than corruption" and would be
|
|
37
|
+
* absorbed quietly. It is counted as an invariant failure and alerted on before
|
|
38
|
+
* failing soft.
|
|
39
|
+
*/
|
|
40
|
+
var SQLiteChangeLogWriter = class {
|
|
41
|
+
#lc;
|
|
42
|
+
#opts;
|
|
43
|
+
#now;
|
|
44
|
+
#db;
|
|
45
|
+
#writer;
|
|
46
|
+
#observer;
|
|
47
|
+
#disabled = false;
|
|
48
|
+
constructor(lc, opts) {
|
|
49
|
+
this.#lc = lc.withContext("component", "sqlite-change-log-writer");
|
|
50
|
+
this.#opts = opts;
|
|
51
|
+
this.#now = opts.now ?? Date.now;
|
|
52
|
+
}
|
|
53
|
+
/** False once the writer has failed soft, or after {@link close}. */
|
|
54
|
+
get enabled() {
|
|
55
|
+
return !this.#disabled;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The writer's own connection, which is the one purge runs on (§3.3): one
|
|
59
|
+
* process appends *and* deletes, on one handle, with no second writable
|
|
60
|
+
* connection and no cross-process barrier. `undefined` until the stream
|
|
61
|
+
* loop's first reconcile creates the log, and again once the writer has
|
|
62
|
+
* failed soft and deleted the file — both of which a purge cycle treats as
|
|
63
|
+
* "skip", not as an error.
|
|
64
|
+
*/
|
|
65
|
+
get connection() {
|
|
66
|
+
return this.#db;
|
|
67
|
+
}
|
|
68
|
+
/** Exposed for tests and for the integration assertions on the metrics. */
|
|
69
|
+
state() {
|
|
70
|
+
return this.#observer?.state();
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Opens the log if necessary and reconciles it with the Postgres resume
|
|
74
|
+
* point. Returns the resume point stored in the log.
|
|
75
|
+
*
|
|
76
|
+
* Returns `undefined` when the writer is disabled. The caller must then use
|
|
77
|
+
* another source.
|
|
78
|
+
*
|
|
79
|
+
* This runs for every connection because Postgres supplies a new resume point
|
|
80
|
+
* after each reconnect. The log can contain transactions above that point.
|
|
81
|
+
* Reconciliation removes them before Postgres sends them again.
|
|
82
|
+
*
|
|
83
|
+
* `resumeFrom` includes cookies because the cookies must match the resume
|
|
84
|
+
* watermark.
|
|
85
|
+
*/
|
|
86
|
+
reconcile(resumeFrom) {
|
|
87
|
+
return this.#reconcile(() => resumeFrom);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Reconciles the log without a Postgres resume point.
|
|
91
|
+
*
|
|
92
|
+
* A valid log uses its own head and cookies. A new or invalid log uses the
|
|
93
|
+
* replica values returned by `seed`.
|
|
94
|
+
*/
|
|
95
|
+
reconcileFromLog(seed) {
|
|
96
|
+
return this.#reconcile((db) => this.#resumeFromLog(db, seed));
|
|
97
|
+
}
|
|
98
|
+
#reconcile(resolve) {
|
|
99
|
+
if (this.#disabled) return;
|
|
100
|
+
const { replicaFile, identity } = this.#opts;
|
|
101
|
+
const nowMs = this.#now();
|
|
102
|
+
const anchor = (db) => ({
|
|
103
|
+
...resolve(db),
|
|
104
|
+
identity,
|
|
105
|
+
nowMs
|
|
106
|
+
});
|
|
107
|
+
try {
|
|
108
|
+
const db = this.#db;
|
|
109
|
+
if (db === void 0) {
|
|
110
|
+
const opened = openChangeLogDBForWriting(this.#lc, replicaFile, anchor);
|
|
111
|
+
this.#db = opened.db;
|
|
112
|
+
if (opened.replacedFile) this.#opts.onRebuilt?.();
|
|
113
|
+
recordSQLiteChangeLogReconcile(this.#lc, opened.result);
|
|
114
|
+
const info = getSQLiteChangeLogInfo(opened.db);
|
|
115
|
+
logSQLiteChangeLogStartup(this.#lc, changeLogFileName(replicaFile), info);
|
|
116
|
+
this.#observer = new SQLiteChangeLogObserver(this.#lc, info);
|
|
117
|
+
} else {
|
|
118
|
+
const resolved = anchor(db);
|
|
119
|
+
let result;
|
|
120
|
+
try {
|
|
121
|
+
result = reconcileChangeLog(this.#lc, db, resolved, { rebuildInsteadOfUnboundedWork: true });
|
|
122
|
+
} catch (e) {
|
|
123
|
+
if (!(e instanceof ChangeLogRebuildRequired)) throw e;
|
|
124
|
+
this.#writer = void 0;
|
|
125
|
+
this.#db = void 0;
|
|
126
|
+
db.close();
|
|
127
|
+
this.#opts.onRebuilt?.();
|
|
128
|
+
const rebuilt = rebuildChangeLogDBForWriting(this.#lc, replicaFile, resolved, e);
|
|
129
|
+
this.#db = rebuilt.db;
|
|
130
|
+
result = rebuilt.result;
|
|
131
|
+
}
|
|
132
|
+
recordSQLiteChangeLogReconcile(this.#lc, result);
|
|
133
|
+
if (result.action !== "none") this.#observer?.reconciled(getSQLiteChangeLogInfo(must(this.#db, "the SQLite change log is not open")));
|
|
134
|
+
}
|
|
135
|
+
const reconciledDB = must(this.#db, "the SQLite change log is not open");
|
|
136
|
+
this.#writer = new ChangeLogStreamWriter(new StatementRunner(reconciledDB));
|
|
137
|
+
return {
|
|
138
|
+
resumeWatermark: must(readChangeLogHead(reconciledDB), "the SQLite change log has no head after reconciliation"),
|
|
139
|
+
cookies: readCookies(reconciledDB)
|
|
140
|
+
};
|
|
141
|
+
} catch (e) {
|
|
142
|
+
this.#failSoft("reconciling the SQLite change log", e);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns the resume point supplied by the log.
|
|
148
|
+
*
|
|
149
|
+
* A valid log uses its own head and cookies. A log that must be recreated uses
|
|
150
|
+
* the replica values returned by `seed`.
|
|
151
|
+
*/
|
|
152
|
+
#resumeFromLog(db, seed) {
|
|
153
|
+
if (changeLogWipeReason(db, this.#opts.identity) !== void 0) return seed();
|
|
154
|
+
const head = readChangeLogHead(db);
|
|
155
|
+
return head === null ? seed() : {
|
|
156
|
+
resumeWatermark: head,
|
|
157
|
+
cookies: readCookies(db)
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Writes one stream message, committing at transaction boundaries. Never
|
|
162
|
+
* throws: a write failure disables the writer instead of failing the stream.
|
|
163
|
+
*/
|
|
164
|
+
write(change, json) {
|
|
165
|
+
const writer = this.#writer;
|
|
166
|
+
const db = this.#db;
|
|
167
|
+
if (this.#disabled || writer === void 0 || db === void 0) return;
|
|
168
|
+
const observer = this.#observer;
|
|
169
|
+
observer?.messageReceived(change, json);
|
|
170
|
+
const [type, msg] = change;
|
|
171
|
+
const startedAt = performance.now();
|
|
172
|
+
try {
|
|
173
|
+
let commit = null;
|
|
174
|
+
switch (type) {
|
|
175
|
+
case "begin":
|
|
176
|
+
writer.begin(change[2].commitWatermark, json);
|
|
177
|
+
break;
|
|
178
|
+
case "commit": {
|
|
179
|
+
const { watermark } = change[2];
|
|
180
|
+
const commitStart = performance.now();
|
|
181
|
+
commit = {
|
|
182
|
+
watermark,
|
|
183
|
+
stats: writer.commit(watermark, json, this.#now()),
|
|
184
|
+
logCommitMs: performance.now() - commitStart
|
|
185
|
+
};
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
case "rollback":
|
|
189
|
+
writer.rollback();
|
|
190
|
+
break;
|
|
191
|
+
default:
|
|
192
|
+
writer.append(json, msg);
|
|
193
|
+
break;
|
|
194
|
+
}
|
|
195
|
+
observer?.messageProcessed(change, commit, performance.now() - startedAt);
|
|
196
|
+
if (commit !== null && commit.stats.cookieMutations.length > 0) observer?.cookiesMutated(commit.stats.cookieMutations, readCookieRowCounts(db));
|
|
197
|
+
if (commit !== null) this.#opts.onCommit?.(commit.watermark);
|
|
198
|
+
} catch (e) {
|
|
199
|
+
observer?.messageFailed(change, e, performance.now() - startedAt);
|
|
200
|
+
if (isConstraintViolation(e)) observer?.invariantFailure("SQLite change-log insert violated a constraint, which means a transaction above the resume watermark was not truncated", {
|
|
201
|
+
tag: msg.tag,
|
|
202
|
+
error: String(e)
|
|
203
|
+
});
|
|
204
|
+
this.#failSoft("writing to the SQLite change log", e);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Discards the open transaction, if any. Called when the change stream is
|
|
209
|
+
* interrupted mid-transaction.
|
|
210
|
+
*/
|
|
211
|
+
abort() {
|
|
212
|
+
const writer = this.#writer;
|
|
213
|
+
if (this.#disabled || writer === void 0) return;
|
|
214
|
+
this.#observer?.abort();
|
|
215
|
+
try {
|
|
216
|
+
writer.rollback();
|
|
217
|
+
} catch (e) {
|
|
218
|
+
this.#failSoft("rolling back the SQLite change log", e);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
close() {
|
|
222
|
+
this.#disabled = true;
|
|
223
|
+
this.#writer = void 0;
|
|
224
|
+
this.#observer = void 0;
|
|
225
|
+
const db = this.#db;
|
|
226
|
+
this.#db = void 0;
|
|
227
|
+
try {
|
|
228
|
+
db?.close();
|
|
229
|
+
} catch (e) {
|
|
230
|
+
this.#lc.warn?.("error closing the SQLite change log", e);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Logs, disables the writer, deletes the file, and closes the reader, leaving
|
|
235
|
+
* replication running. Disabling is for the life of the process: a log that
|
|
236
|
+
* failed a write is not re-opened until the task restarts, so the behavior a
|
|
237
|
+
* subscriber sees is the same as `sqliteChangeLogMode=off`.
|
|
238
|
+
*/
|
|
239
|
+
#failSoft(what, e) {
|
|
240
|
+
const file = changeLogFileName(this.#opts.replicaFile);
|
|
241
|
+
if (isSQLiteCorruption(e)) logSQLiteCorruptionDiagnostics(this.#lc, "change-log", file, e);
|
|
242
|
+
this.#lc.error?.(`error ${what}: disabling the writer and deleting ${file}. Replication continues; catchup reach is lost until this task restarts.`, e);
|
|
243
|
+
this.close();
|
|
244
|
+
try {
|
|
245
|
+
deleteChangeLogDB(this.#opts.replicaFile);
|
|
246
|
+
} catch (deleteError) {
|
|
247
|
+
this.#lc.error?.(`unable to delete ${file}`, deleteError);
|
|
248
|
+
}
|
|
249
|
+
this.#opts.onDisabled?.();
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
function isConstraintViolation(e) {
|
|
253
|
+
return e instanceof SqliteError && e.code.startsWith("SQLITE_CONSTRAINT");
|
|
254
|
+
}
|
|
255
|
+
//#endregion
|
|
256
|
+
export { SQLiteChangeLogWriter };
|
|
257
|
+
|
|
258
|
+
//# sourceMappingURL=sqlite-change-log-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite-change-log-writer.js","names":["#lc","#opts","#now","#disabled","#db","#observer","#reconcile","#resumeFromLog","#writer","#failSoft"],"sources":["../../../../../../zero-cache/src/services/change-streamer/sqlite-change-log-writer.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {SqliteError} from '@rocicorp/zero-sqlite3';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {\n isSQLiteCorruption,\n logSQLiteCorruptionDiagnostics,\n} from '../../db/sqlite-corruption.ts';\nimport {StatementRunner} from '../../db/statements.ts';\nimport type {ChangeStreamData} from '../change-source/protocol/current/downstream.ts';\nimport {\n readCookieRowCounts,\n readCookies,\n} from '../replicator/change-log-cookies.ts';\nimport {\n ChangeLogRebuildRequired,\n changeLogFileName,\n changeLogWipeReason,\n deleteChangeLogDB,\n openChangeLogDBForWriting,\n readChangeLogHead,\n rebuildChangeLogDBForWriting,\n reconcileChangeLog,\n type ChangeLogAnchor,\n type ChangeLogIdentity,\n type ChangeLogResumePoint,\n type ReconcileResult,\n} from '../replicator/change-log-db.ts';\nimport {ChangeLogStreamWriter} from '../replicator/change-log-stream-writer.ts';\nimport {\n getSQLiteChangeLogInfo,\n logSQLiteChangeLogStartup,\n recordSQLiteChangeLogReconcile,\n SQLiteChangeLogObserver,\n type ChangeLogCommit,\n type SQLiteChangeLogObservabilityState,\n} from '../replicator/sqlite-change-log-observability.ts';\n\nexport type SQLiteChangeLogWriterOptions = {\n /** The replica file the log is named after, i.e. `${replicaFile}-change-log`. */\n replicaFile: string;\n /** The replica whose contents this log belongs to. */\n identity: ChangeLogIdentity;\n /**\n * Called after each transaction's log commit, with the log's new head. This\n * is what releases the catchup barrier: after the writer moved in-process,\n * the head advances here rather than at a subscriber's ACK.\n */\n onCommit?: ((watermark: string) => void) | undefined;\n /**\n * Called when the writer disables itself and deletes the file. The reader is\n * cached on the service, so a delete that leaves it open would leave an\n * in-process reader serving an unlinked inode while every new open sees\n * nothing.\n */\n onDisabled?: (() => void) | undefined;\n /** Called when reconciliation replaces the file, to close cached readers. */\n onRebuilt?: (() => void) | undefined;\n /** Overridable for tests. */\n now?: (() => number) | undefined;\n};\n\n/**\n * Appends the canonical change stream to the SQLite change log, from the\n * change-streamer's own stream loop.\n *\n * ### Ordering\n *\n * The log's commit for a transaction precedes the forward of that transaction's\n * `commit` message, and nothing `await`s in between. Everything that can\n * advance the watermark the stream would resume from — the storer's Postgres\n * commit, `lastWatermark`, the upstream ACK — runs strictly after it, so the\n * log's head is always at or above the resume point. A *hole* is therefore\n * unreachable at any crash timing, and a *phantom* is the normal state, which is\n * what makes truncate-above the whole of reconciliation.\n *\n * ### Fail-soft\n *\n * The log is a catchup cache: nothing in it is not either already durable in the\n * replica's litestream backup or re-derivable from the replication slot. A write\n * failure must therefore not stop replication for the shard. Corruption is\n * rebuilt once at open; any other write error — a full disk, an I/O error, a\n * permissions problem — logs, disables the writer, deletes the file, closes the\n * reader, and lets the stream continue. The cost is catchup reach, and reach is\n * recoverable: `too-old` sends a subscriber to a restore.\n *\n * One carve-out keeps that from hiding the bug class this topology introduces. A\n * missed truncate-above surfaces as `SQLITE_CONSTRAINT` on the writer's plain\n * `INSERT`, which is \"any write error other than corruption\" and would be\n * absorbed quietly. It is counted as an invariant failure and alerted on before\n * failing soft.\n */\nexport class SQLiteChangeLogWriter {\n readonly #lc: LogContext;\n readonly #opts: SQLiteChangeLogWriterOptions;\n readonly #now: () => number;\n\n #db: Database | undefined;\n #writer: ChangeLogStreamWriter | undefined;\n #observer: SQLiteChangeLogObserver | undefined;\n #disabled = false;\n\n constructor(lc: LogContext, opts: SQLiteChangeLogWriterOptions) {\n this.#lc = lc.withContext('component', 'sqlite-change-log-writer');\n this.#opts = opts;\n this.#now = opts.now ?? Date.now;\n }\n\n /** False once the writer has failed soft, or after {@link close}. */\n get enabled(): boolean {\n return !this.#disabled;\n }\n\n /**\n * The writer's own connection, which is the one purge runs on (§3.3): one\n * process appends *and* deletes, on one handle, with no second writable\n * connection and no cross-process barrier. `undefined` until the stream\n * loop's first reconcile creates the log, and again once the writer has\n * failed soft and deleted the file — both of which a purge cycle treats as\n * \"skip\", not as an error.\n */\n get connection(): Database | undefined {\n return this.#db;\n }\n\n /** Exposed for tests and for the integration assertions on the metrics. */\n state(): SQLiteChangeLogObservabilityState | undefined {\n return this.#observer?.state();\n }\n\n /**\n * Opens the log if necessary and reconciles it with the Postgres resume\n * point. Returns the resume point stored in the log.\n *\n * Returns `undefined` when the writer is disabled. The caller must then use\n * another source.\n *\n * This runs for every connection because Postgres supplies a new resume point\n * after each reconnect. The log can contain transactions above that point.\n * Reconciliation removes them before Postgres sends them again.\n *\n * `resumeFrom` includes cookies because the cookies must match the resume\n * watermark.\n */\n reconcile(\n resumeFrom: ChangeLogResumePoint,\n ): ChangeLogResumePoint | undefined {\n return this.#reconcile(() => resumeFrom);\n }\n\n /**\n * Reconciles the log without a Postgres resume point.\n *\n * A valid log uses its own head and cookies. A new or invalid log uses the\n * replica values returned by `seed`.\n */\n reconcileFromLog(\n seed: () => ChangeLogResumePoint,\n ): ChangeLogResumePoint | undefined {\n return this.#reconcile(db => this.#resumeFromLog(db, seed));\n }\n\n #reconcile(\n resolve: (db: Database) => ChangeLogResumePoint,\n ): ChangeLogResumePoint | undefined {\n if (this.#disabled) {\n return undefined;\n }\n const {replicaFile, identity} = this.#opts;\n const nowMs = this.#now();\n const anchor = (db: Database): ChangeLogAnchor => ({\n ...resolve(db),\n identity,\n nowMs,\n });\n try {\n const db = this.#db;\n if (db === undefined) {\n const opened = openChangeLogDBForWriting(this.#lc, replicaFile, anchor);\n this.#db = opened.db;\n if (opened.replacedFile) {\n this.#opts.onRebuilt?.();\n }\n recordSQLiteChangeLogReconcile(this.#lc, opened.result);\n const info = getSQLiteChangeLogInfo(opened.db);\n logSQLiteChangeLogStartup(\n this.#lc,\n changeLogFileName(replicaFile),\n info,\n );\n this.#observer = new SQLiteChangeLogObserver(this.#lc, info);\n } else {\n const resolved = anchor(db);\n let result: ReconcileResult;\n try {\n result = reconcileChangeLog(this.#lc, db, resolved, {\n rebuildInsteadOfUnboundedWork: true,\n });\n } catch (e) {\n if (!(e instanceof ChangeLogRebuildRequired)) {\n throw e;\n }\n // Close every handle to the old inode before unlinking it. The writer\n // is reconstructed below against the replacement connection.\n this.#writer = undefined;\n this.#db = undefined;\n db.close();\n this.#opts.onRebuilt?.();\n const rebuilt = rebuildChangeLogDBForWriting(\n this.#lc,\n replicaFile,\n resolved,\n e,\n );\n this.#db = rebuilt.db;\n result = rebuilt.result;\n }\n recordSQLiteChangeLogReconcile(this.#lc, result);\n if (result.action !== 'none') {\n this.#observer?.reconciled(\n getSQLiteChangeLogInfo(\n must(this.#db, 'the SQLite change log is not open'),\n ),\n );\n }\n }\n // A reseed drops and recreates the stream table, so the append statements\n // are prepared fresh against whatever the reconciliation left behind.\n const reconciledDB = must(this.#db, 'the SQLite change log is not open');\n this.#writer = new ChangeLogStreamWriter(\n new StatementRunner(reconciledDB),\n );\n // Read both values after reconciliation. A truncate or reseed updates the\n // head and cookies in the same transaction.\n return {\n resumeWatermark: must(\n readChangeLogHead(reconciledDB),\n 'the SQLite change log has no head after reconciliation',\n ),\n cookies: readCookies(reconciledDB),\n };\n } catch (e) {\n this.#failSoft('reconciling the SQLite change log', e);\n return undefined;\n }\n }\n\n /**\n * Returns the resume point supplied by the log.\n *\n * A valid log uses its own head and cookies. A log that must be recreated uses\n * the replica values returned by `seed`.\n */\n #resumeFromLog(\n db: Database,\n seed: () => ChangeLogResumePoint,\n ): ChangeLogResumePoint {\n if (changeLogWipeReason(db, this.#opts.identity) !== undefined) {\n return seed();\n }\n const head = readChangeLogHead(db);\n // An empty log has no resume point, so use the replica seed.\n return head === null\n ? seed()\n : {resumeWatermark: head, cookies: readCookies(db)};\n }\n\n /**\n * Writes one stream message, committing at transaction boundaries. Never\n * throws: a write failure disables the writer instead of failing the stream.\n */\n write(change: ChangeStreamData, json: string): void {\n const writer = this.#writer;\n const db = this.#db;\n if (this.#disabled || writer === undefined || db === undefined) {\n return;\n }\n const observer = this.#observer;\n observer?.messageReceived(change, json);\n const [type, msg] = change;\n const startedAt = performance.now();\n try {\n let commit: ChangeLogCommit | null = null;\n switch (type) {\n case 'begin':\n writer.begin(change[2].commitWatermark, json);\n break;\n case 'commit': {\n const {watermark} = change[2];\n const commitStart = performance.now();\n const stats = writer.commit(watermark, json, this.#now());\n commit = {\n watermark,\n stats,\n logCommitMs: performance.now() - commitStart,\n };\n break;\n }\n case 'rollback':\n writer.rollback();\n break;\n default:\n writer.append(json, msg);\n break;\n }\n observer?.messageProcessed(change, commit, performance.now() - startedAt);\n if (commit !== null && commit.stats.cookieMutations.length > 0) {\n // Only re-counted when a schema change actually moved the cookie jar,\n // which keeps the count off the forward path of every other\n // transaction. The counts are read after the commit, so they are what\n // a reader of the file would see.\n observer?.cookiesMutated(\n commit.stats.cookieMutations,\n readCookieRowCounts(db),\n );\n }\n if (commit !== null) {\n // The head advanced, and it is durable. Releasing the barrier here is\n // what makes its poll interval a backstop rather than the mechanism.\n this.#opts.onCommit?.(commit.watermark);\n }\n } catch (e) {\n observer?.messageFailed(change, e, performance.now() - startedAt);\n if (isConstraintViolation(e)) {\n // Reconciliation should have truncated whatever this collided with.\n // Report it as an invariant failure before failing soft, so that a\n // truncate-above bug cannot look like a lost cache.\n observer?.invariantFailure(\n 'SQLite change-log insert violated a constraint, which means a ' +\n 'transaction above the resume watermark was not truncated',\n {tag: msg.tag, error: String(e)},\n );\n }\n this.#failSoft('writing to the SQLite change log', e);\n }\n }\n\n /**\n * Discards the open transaction, if any. Called when the change stream is\n * interrupted mid-transaction.\n */\n abort(): void {\n const writer = this.#writer;\n if (this.#disabled || writer === undefined) {\n return;\n }\n this.#observer?.abort();\n try {\n writer.rollback();\n } catch (e) {\n this.#failSoft('rolling back the SQLite change log', e);\n }\n }\n\n close(): void {\n this.#disabled = true;\n this.#writer = undefined;\n this.#observer = undefined;\n const db = this.#db;\n this.#db = undefined;\n try {\n db?.close();\n } catch (e) {\n this.#lc.warn?.('error closing the SQLite change log', e);\n }\n }\n\n /**\n * Logs, disables the writer, deletes the file, and closes the reader, leaving\n * replication running. Disabling is for the life of the process: a log that\n * failed a write is not re-opened until the task restarts, so the behavior a\n * subscriber sees is the same as `sqliteChangeLogMode=off`.\n */\n #failSoft(what: string, e: unknown): void {\n const file = changeLogFileName(this.#opts.replicaFile);\n if (isSQLiteCorruption(e)) {\n // Open-time corruption is rebuilt by openChangeLogDBForWriting. Reaching\n // here means the file went bad under an open handle, which the same\n // delete-and-reseed answers -- on the next process start rather than now.\n logSQLiteCorruptionDiagnostics(this.#lc, 'change-log', file, e);\n }\n this.#lc.error?.(\n `error ${what}: disabling the writer and deleting ${file}. ` +\n `Replication continues; catchup reach is lost until this task restarts.`,\n e,\n );\n this.close();\n try {\n deleteChangeLogDB(this.#opts.replicaFile);\n } catch (deleteError) {\n this.#lc.error?.(`unable to delete ${file}`, deleteError);\n }\n this.#opts.onDisabled?.();\n }\n}\n\nfunction isConstraintViolation(e: unknown): boolean {\n return e instanceof SqliteError && e.code.startsWith('SQLITE_CONSTRAINT');\n}\n"],"mappings":"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"}
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import type { LogContext } from '@rocicorp/logger';
|
|
2
|
+
import { type JSONObject } from '../../../../shared/src/bigint-json.ts';
|
|
2
3
|
import { TransactionPool } from '../../db/transaction-pool.ts';
|
|
3
4
|
import { type PostgresDB } from '../../types/pg.ts';
|
|
4
5
|
import { type ShardID } from '../../types/shards.ts';
|
|
5
|
-
import { type BackfillRequest
|
|
6
|
+
import { type BackfillRequest } from '../change-source/protocol/current.ts';
|
|
6
7
|
import { type ChangeStreamData, type Commit } from '../change-source/protocol/current/downstream.ts';
|
|
7
|
-
import type {
|
|
8
|
+
import type { UpstreamStatusMessage } from '../change-source/protocol/current/status.ts';
|
|
9
|
+
import { type CookieSet } from '../replicator/change-log-cookies.ts';
|
|
8
10
|
import type { ReplicatorMode } from '../replicator/replicator.ts';
|
|
9
11
|
import type { Service } from '../service.ts';
|
|
12
|
+
import { type ChangeLogEntry } from './change-log-codec.ts';
|
|
10
13
|
import type { Subscriber } from './subscriber.ts';
|
|
11
14
|
export type TuningOptions = {
|
|
12
15
|
backPressureLimitHeapProportion: number;
|
|
13
16
|
statementTimeoutMs: number;
|
|
14
17
|
changeLogBatchSize: number;
|
|
18
|
+
drainTimeoutMs?: number | undefined;
|
|
15
19
|
};
|
|
16
20
|
/**
|
|
17
21
|
* Handles the storage of changes and the catchup of subscribers
|
|
@@ -46,20 +50,59 @@ export type TuningOptions = {
|
|
|
46
50
|
export declare class Storer implements Service {
|
|
47
51
|
#private;
|
|
48
52
|
readonly id = "storer";
|
|
49
|
-
constructor(lc: LogContext, shard: ShardID, taskID: string, discoveryAddress: string, discoveryProtocol: string, db: PostgresDB, replicaVersion: string,
|
|
53
|
+
constructor(lc: LogContext, shard: ShardID, taskID: string, discoveryAddress: string, discoveryProtocol: string, db: PostgresDB, replicaVersion: string, onCommitted: (c: Commit | UpstreamStatusMessage) => void, onFatal: (err: Error) => void, { backPressureLimitHeapProportion, statementTimeoutMs, changeLogBatchSize, drainTimeoutMs, }: TuningOptions);
|
|
50
54
|
assumeOwnership(purgeLock?: PurgeLock | null): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* The whole of what a stream connection starts from: where to resume, what to
|
|
57
|
+
* ask the change source to backfill, and the raw cookie set those requests
|
|
58
|
+
* were derived from.
|
|
59
|
+
*
|
|
60
|
+
* All four statements run in one REPEATABLE READ transaction, so they see one
|
|
61
|
+
* snapshot. That is invariant 15 — the resume watermark and the cookies must
|
|
62
|
+
* come from the same store, read at the same position — and it is why the
|
|
63
|
+
* cookies are read here rather than by a second call: a cookie set paired
|
|
64
|
+
* with a watermark it was not folded to loses every backfill that completed
|
|
65
|
+
* in the interval, and those rows are not replayable from the slot.
|
|
66
|
+
*
|
|
67
|
+
* `cookies` is not `backfillRequests` in another shape. The request list is
|
|
68
|
+
* driven off `backfilling`, so it drops the metadata of every table with no
|
|
69
|
+
* in-flight backfill — correct for starting a stream, lossy as the cookie
|
|
70
|
+
* snapshot that the SQLite change log continues folding onto.
|
|
71
|
+
*/
|
|
51
72
|
getStartStreamInitializationParameters(): Promise<{
|
|
52
73
|
lastWatermark: string;
|
|
53
74
|
backfillRequests: BackfillRequest[];
|
|
75
|
+
cookies: CookieSet;
|
|
54
76
|
}>;
|
|
55
77
|
getMinWatermarkForCatchup(): Promise<string | null>;
|
|
78
|
+
/**
|
|
79
|
+
* Returns the retained Postgres catchup bounds.
|
|
80
|
+
* `minWatermark` is the oldest transaction, or `null` for a new replica.
|
|
81
|
+
* `lastWatermark` is the durable head.
|
|
82
|
+
*/
|
|
83
|
+
getCatchupBounds(): Promise<{
|
|
84
|
+
minWatermark: string | null;
|
|
85
|
+
lastWatermark: string;
|
|
86
|
+
}>;
|
|
87
|
+
/**
|
|
88
|
+
* Lists at most `limit` committed transaction watermarks in
|
|
89
|
+
* `(afterWatermark, throughWatermark]`, in ascending order.
|
|
90
|
+
*/
|
|
91
|
+
listCommitWatermarks(afterWatermark: string, throughWatermark: string, limit: number): Promise<string[]>;
|
|
92
|
+
/**
|
|
93
|
+
* Reads `(afterWatermark, throughWatermark]` in stream order and bounded batches.
|
|
94
|
+
* This query matches the subscriber catchup query.
|
|
95
|
+
*
|
|
96
|
+
* Both queries fail when an escaped NUL reaches `change->'tag'`.
|
|
97
|
+
* Postgres cannot convert that value to text.
|
|
98
|
+
*/
|
|
99
|
+
readCatchupRange(afterWatermark: string, throughWatermark: string, batchRows?: number): AsyncIterable<ChangeLogEntry[]>;
|
|
56
100
|
purgeRecordsBefore(watermark: string): Promise<number>;
|
|
57
101
|
/**
|
|
58
102
|
* @returns The JSON stringified stream message to be sent downstream.
|
|
59
103
|
*/
|
|
60
104
|
store(watermark: string, data: ChangeStreamData): string;
|
|
61
105
|
abort(): void;
|
|
62
|
-
status(s: DownstreamStatusMessage): void;
|
|
63
106
|
catchup(subscriber: Subscriber, mode: ReplicatorMode): void;
|
|
64
107
|
readyForMore(): Promise<void> | undefined;
|
|
65
108
|
/**
|
|
@@ -72,16 +115,13 @@ export declare class Storer implements Service {
|
|
|
72
115
|
* This is only used in tests.
|
|
73
116
|
*/
|
|
74
117
|
allProcessed(): Promise<void>;
|
|
118
|
+
/**
|
|
119
|
+
* Stops the storer and waits up to a drain timeout for entries to drain,
|
|
120
|
+
* throwing an exception if it doesn't drain in time, in order to abort
|
|
121
|
+
* the server when PG (or the connection to it) appears to be wedged.
|
|
122
|
+
*/
|
|
75
123
|
stop(): Promise<void>;
|
|
76
124
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Extracts the stringified change message from the stringified
|
|
79
|
-
* stream message (e.g. the second tuple element). This optimization
|
|
80
|
-
* facilitates stringifying (and sharing the result of) the stream
|
|
81
|
-
* message exactly once, but storing only the change message substring
|
|
82
|
-
* in the changeLog for backwards compatibility.
|
|
83
|
-
*/
|
|
84
|
-
export declare function extractChangeSubstring(streamMessageJSON: string, tag: Change['tag'] | undefined): string;
|
|
85
125
|
export declare class PurgeLock {
|
|
86
126
|
#private;
|
|
87
127
|
readonly replicaVersion: string;
|
|
@@ -94,4 +134,37 @@ export declare class PurgeLocker {
|
|
|
94
134
|
constructor(lc: LogContext, shard: ShardID, db: PostgresDB);
|
|
95
135
|
acquire(): Promise<PurgeLock | null>;
|
|
96
136
|
}
|
|
137
|
+
type TaskKey = JSONObject;
|
|
138
|
+
type TaskDoneFn = () => void;
|
|
139
|
+
/**
|
|
140
|
+
* Periodic monitor for detecting the pathological condition in which a db
|
|
141
|
+
* query hangs forever because of a connection problem, such as a half-closed
|
|
142
|
+
* socket.
|
|
143
|
+
*
|
|
144
|
+
* Use this for db calls that recur or accumulate progress within a single
|
|
145
|
+
* logical operation on the main storer loop (e.g. the queue-processing loop,
|
|
146
|
+
* or a multi-batch catchup read), where "no progress for N ms" is the
|
|
147
|
+
* meaningful signal. For a one-off db call -- including ones made before
|
|
148
|
+
* {@link Storer.run} starts this monitor's polling -- use a plain timeout
|
|
149
|
+
* (see `Storer.#withTimeout`) instead.
|
|
150
|
+
*
|
|
151
|
+
* The failure handler should stop the server. The ProgressMonitor will
|
|
152
|
+
* assume this and stop itself after calling it.
|
|
153
|
+
*
|
|
154
|
+
* Internal to the Storer, but exported for testing.
|
|
155
|
+
*/
|
|
156
|
+
export declare class ProgressMonitor {
|
|
157
|
+
#private;
|
|
158
|
+
constructor(lc: LogContext, failureThresholdMs: number, onFailure: (err: Error) => void);
|
|
159
|
+
start(): void;
|
|
160
|
+
checkTaskProgress(now: Date): void;
|
|
161
|
+
/**
|
|
162
|
+
* Starts a task to be tracked.
|
|
163
|
+
*
|
|
164
|
+
* @return a callback to invoke when the task is done.
|
|
165
|
+
*/
|
|
166
|
+
trackTask(task: TaskKey, now?: Date): TaskDoneFn;
|
|
167
|
+
stop(): void;
|
|
168
|
+
}
|
|
169
|
+
export {};
|
|
97
170
|
//# sourceMappingURL=storer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/storer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"storer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/change-streamer/storer.ts"],"names":[],"mappings":"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"}
|