@rocicorp/zero 1.11.0-canary.0 → 1.11.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/analyze-query/src/bin-analyze.js +1 -1
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/replicache/src/btree/read.d.ts +12 -1
- package/out/replicache/src/btree/read.d.ts.map +1 -1
- package/out/replicache/src/btree/read.js +24 -12
- package/out/replicache/src/btree/read.js.map +1 -1
- package/out/replicache/src/dag/gc.d.ts.map +1 -1
- package/out/replicache/src/dag/gc.js +2 -1
- package/out/replicache/src/dag/gc.js.map +1 -1
- package/out/replicache/src/dag/invalid-ref-count-error.d.ts +12 -0
- package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +1 -0
- package/out/replicache/src/dag/invalid-ref-count-error.js +19 -0
- package/out/replicache/src/dag/invalid-ref-count-error.js.map +1 -0
- package/out/replicache/src/dag/store-impl.d.ts +12 -2
- package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
- package/out/replicache/src/dag/store-impl.js +22 -8
- package/out/replicache/src/dag/store-impl.js.map +1 -1
- package/out/replicache/src/db/rebase.d.ts +14 -2
- package/out/replicache/src/db/rebase.d.ts.map +1 -1
- package/out/replicache/src/db/rebase.js +27 -5
- package/out/replicache/src/db/rebase.js.map +1 -1
- package/out/replicache/src/db/write.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js +28 -5
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +15 -5
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +1 -1
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js +25 -25
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +1 -1
- package/out/replicache/src/kv/idb-store.d.ts +9 -0
- package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
- package/out/replicache/src/kv/idb-store.js +14 -2
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-store.d.ts +1 -0
- package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
- package/out/replicache/src/kv/mem-store.js +3 -0
- package/out/replicache/src/kv/mem-store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts +13 -1
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +49 -4
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/store.d.ts +6 -0
- package/out/replicache/src/kv/store.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +10 -5
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +16 -9
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/persist.d.ts.map +1 -1
- package/out/replicache/src/persist/persist.js +12 -5
- package/out/replicache/src/persist/persist.js.map +1 -1
- package/out/replicache/src/persist/refresh.js +6 -2
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +14 -3
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +118 -11
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/replicache-options.d.ts +9 -0
- package/out/replicache/src/replicache-options.d.ts.map +1 -1
- package/out/replicache/src/transactions.d.ts.map +1 -1
- package/out/replicache/src/transactions.js +1 -1
- package/out/replicache/src/transactions.js.map +1 -1
- package/out/shared/src/error.d.ts +11 -0
- package/out/shared/src/error.d.ts.map +1 -1
- package/out/shared/src/error.js +35 -1
- package/out/shared/src/error.js.map +1 -1
- package/out/shared/src/iterables.d.ts +2 -0
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +18 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/map.d.ts +7 -2
- package/out/shared/src/map.d.ts.map +1 -1
- package/out/shared/src/map.js.map +1 -1
- package/out/shared/src/ring-buffer.d.ts +8 -0
- package/out/shared/src/ring-buffer.d.ts.map +1 -1
- package/out/shared/src/ring-buffer.js +22 -1
- package/out/shared/src/ring-buffer.js.map +1 -1
- package/out/zero/package.js +3 -4
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js +25 -1
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +48 -2
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +171 -29
- package/out/zero-cache/src/config/zero-config.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 +25 -9
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +18 -2
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +20 -7
- package/out/zero-cache/src/server/inspector-delegate.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 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/mutator.js +2 -0
- package/out/zero-cache/src/server/mutator.js.map +1 -1
- package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -0
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/server/replicator.js +8 -2
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.js +3 -0
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +2 -0
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
- package/out/zero-cache/src/services/analyze.js +3 -2
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +14 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +15 -3
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- 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 +2 -39
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.d.ts +156 -0
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.js +15 -0
- package/out/zero-cache/src/services/change-source/pg/backfill-resume.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +25 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +202 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +14 -16
- 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 +64 -143
- 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 +28 -2
- 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 +44 -21
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +16 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +113 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +21 -15
- 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 +86 -23
- 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/index-predicate.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +68 -8
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
- 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 +32 -1
- 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/replica-stage-enum.d.ts +10 -0
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js +6 -0
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +50 -27
- 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 +100 -34
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- 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 +58 -7
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +8 -2
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +24 -4
- 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 -4
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js +28 -8
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +5 -2
- 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 +21 -14
- 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 +6 -0
- 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 +97 -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 +12 -8
- 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/forwarder.d.ts +3 -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 +36 -5
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -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 +4 -4
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +3 -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 +54 -20
- package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +6 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +27 -9
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +2 -2
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +8 -5
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +4 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +42 -0
- 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 +17 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js +19 -3
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +1 -0
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +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 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +8 -3
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config-v5.yml +15 -1
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +131 -0
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -0
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +70 -0
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +1 -0
- package/out/zero-cache/src/services/litestream/litestream-controller.js +101 -0
- package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +5 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +7 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +2 -1
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/profz.d.ts +7 -0
- package/out/zero-cache/src/services/profz.d.ts.map +1 -0
- package/out/zero-cache/src/services/profz.js +105 -0
- package/out/zero-cache/src/services/profz.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-db.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +5 -4
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +20 -22
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +1 -0
- 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 +58 -17
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts +35 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +96 -6
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +6 -6
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +19 -14
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +31 -6
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js +5 -4
- package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker.js +30 -5
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.d.ts +12 -0
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +26 -14
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/runner.d.ts.map +1 -1
- package/out/zero-cache/src/services/runner.js +1 -1
- package/out/zero-cache/src/services/runner.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +1 -1
- 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 +36 -31
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +45 -0
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +133 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +14 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +30 -4
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +33 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js +62 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +51 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +78 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +2 -2
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +2 -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 +33 -18
- 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 +4 -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 +9 -3
- 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 +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 +507 -93
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/processes.d.ts +32 -0
- package/out/zero-cache/src/types/processes.d.ts.map +1 -1
- package/out/zero-cache/src/types/processes.js +43 -4
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/profiler.d.ts +12 -0
- package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
- package/out/zero-cache/src/types/profiler.js +46 -1
- package/out/zero-cache/src/types/profiler.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts +25 -9
- package/out/zero-cache/src/types/streams.d.ts.map +1 -1
- package/out/zero-cache/src/types/streams.js +118 -34
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/types/subscription.d.ts +4 -0
- package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
- package/out/zero-cache/src/types/subscription.js +71 -0
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/types/ws.d.ts.map +1 -1
- package/out/zero-cache/src/types/ws.js +23 -8
- package/out/zero-cache/src/types/ws.js.map +1 -1
- package/out/zero-cache/src/workers/connection.js +2 -2
- package/out/zero-cache/src/workers/replicator.d.ts +1 -0
- package/out/zero-cache/src/workers/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/workers/replicator.js +4 -2
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +21 -16
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +10 -1
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +20 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +77 -13
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
- package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-status-enum.js +3 -1
- package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts +6 -0
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +2 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.d.ts +27 -2
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +112 -1
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/custom.js +2 -2
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/error.js +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js +2 -2
- package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +20 -3
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +2 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +3 -0
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +42 -6
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts +1 -0
- package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-rep.js +9 -6
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +18 -3
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +122 -34
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/types/query-result.d.ts +2 -0
- package/out/zero-client/src/types/query-result.d.ts.map +1 -1
- package/out/zero-events/src/status.d.ts +26 -0
- package/out/zero-events/src/status.d.ts.map +1 -1
- package/out/zero-protocol/src/analyze-query-result.d.ts +5 -5
- package/out/zero-protocol/src/analyze-query-result.d.ts.map +1 -1
- package/out/zero-protocol/src/analyze-query-result.js +1 -1
- package/out/zero-protocol/src/analyze-query-result.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +4 -4
- package/out/zero-protocol/src/inspect-down.d.ts +6 -6
- package/out/zero-protocol/src/protocol-version.d.ts +1 -1
- 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-react/src/use-query.d.ts +5 -4
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +86 -9
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-server/src/adapters/drizzle.d.ts +2 -1
- package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js +12 -7
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/kysely.d.ts +2 -1
- package/out/zero-server/src/adapters/kysely.d.ts.map +1 -1
- package/out/zero-server/src/adapters/kysely.js +8 -2
- package/out/zero-server/src/adapters/kysely.js.map +1 -1
- package/out/zero-server/src/adapters/pg.d.ts +1 -0
- package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
- package/out/zero-server/src/adapters/pg.js +8 -2
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.d.ts +1 -0
- package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js +7 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.d.ts +3 -2
- package/out/zero-server/src/adapters/prisma.d.ts.map +1 -1
- package/out/zero-server/src/adapters/prisma.js +8 -2
- package/out/zero-server/src/adapters/prisma.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +5 -1
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +6 -3
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +1 -1
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/pg-query-executor.d.ts +2 -2
- package/out/zero-server/src/pg-query-executor.d.ts.map +1 -1
- package/out/zero-server/src/pg-query-executor.js +2 -2
- package/out/zero-server/src/pg-query-executor.js.map +1 -1
- package/out/zero-server/src/schema.d.ts +2 -2
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +2 -2
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts +21 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +33 -2
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/solid-view.d.ts +17 -0
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +39 -1
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.js +5 -3
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +16 -10
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/debug-delegate.d.ts +6 -1
- package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
- package/out/zql/src/builder/debug-delegate.js +14 -2
- package/out/zql/src/builder/debug-delegate.js.map +1 -1
- package/out/zql/src/ivm/array-view.d.ts +29 -0
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +63 -12
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.d.ts.map +1 -1
- package/out/zql/src/ivm/cap.js +5 -3
- package/out/zql/src/ivm/cap.js.map +1 -1
- package/out/zql/src/ivm/data.d.ts.map +1 -1
- package/out/zql/src/ivm/data.js +8 -3
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.d.ts +44 -0
- package/out/zql/src/ivm/deferred-input.d.ts.map +1 -0
- package/out/zql/src/ivm/deferred-input.js +89 -0
- package/out/zql/src/ivm/deferred-input.js.map +1 -0
- package/out/zql/src/ivm/exists.d.ts +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +2 -2
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js +6 -5
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +2 -2
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +7 -6
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +29 -12
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +2 -2
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js +7 -4
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +2 -2
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +6 -4
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +15 -3
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +57 -23
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +40 -0
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +3 -4
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +9 -7
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +9 -4
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/ivm/view.d.ts +15 -0
- package/out/zql/src/ivm/view.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.d.ts +24 -1
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js +2 -2
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
- package/out/zql/src/planner/planner-builder.js +14 -4
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-connection.d.ts +13 -0
- package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
- package/out/zql/src/planner/planner-connection.js +42 -7
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +1 -1
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/planner/planner-fan-out.d.ts +1 -0
- package/out/zql/src/planner/planner-fan-out.d.ts.map +1 -1
- package/out/zql/src/planner/planner-fan-out.js +3 -0
- package/out/zql/src/planner/planner-fan-out.js.map +1 -1
- package/out/zql/src/planner/planner-filter.d.ts +59 -0
- package/out/zql/src/planner/planner-filter.d.ts.map +1 -0
- package/out/zql/src/planner/planner-filter.js +116 -0
- package/out/zql/src/planner/planner-filter.js.map +1 -0
- package/out/zql/src/planner/planner-graph.d.ts +2 -0
- package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
- package/out/zql/src/planner/planner-graph.js +2 -0
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/planner/planner-join.d.ts +2 -0
- package/out/zql/src/planner/planner-join.d.ts.map +1 -1
- package/out/zql/src/planner/planner-join.js +7 -0
- package/out/zql/src/planner/planner-join.js.map +1 -1
- package/out/zql/src/planner/planner-node.d.ts +2 -1
- package/out/zql/src/planner/planner-node.d.ts.map +1 -1
- package/out/zql/src/planner/planner-node.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +9 -1
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +129 -33
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-delegate.d.ts +50 -1
- package/out/zql/src/query/query-delegate.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +13 -11
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +383 -60
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-transitions.d.ts +171 -0
- package/out/zql/src/query/query-transitions.d.ts.map +1 -0
- package/out/zql/src/query/query-transitions.js +207 -0
- package/out/zql/src/query/query-transitions.js.map +1 -0
- package/out/zql/src/query/query.d.ts +11 -2
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +1 -0
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +21 -1
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/typed-view.d.ts +1 -1
- package/out/zql/src/query/typed-view.d.ts.map +1 -1
- package/out/zqlite/src/db.d.ts +9 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +8 -2
- package/out/zqlite/src/db.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts +1 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +2 -1
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +2 -30
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +1 -0
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +20 -8
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +3 -4
|
@@ -10,12 +10,11 @@ import { manualSpan, startAsyncSpan, startSpan } from "../../../../otel/src/span
|
|
|
10
10
|
import { ZERO_VERSION_COLUMN_NAME } from "../replicator/schema/constants.js";
|
|
11
11
|
import { transformAndHashQuery } from "../../auth/read-authorizer.js";
|
|
12
12
|
import { randInt } from "../../../../shared/src/rand.js";
|
|
13
|
-
import { getOrCreateCounter, getOrCreateLatencyHistogram, getOrCreateNativeHistogram, getOrCreateUpDownCounter } from "../../observability/metrics.js";
|
|
13
|
+
import { getOrCreateCounter, getOrCreateLatencyHistogram, getOrCreateNativeHistogram, getOrCreateUpDownCounter, getOrCreateValueHistogram } from "../../observability/metrics.js";
|
|
14
14
|
import { rowIDString } from "../../types/row-key.js";
|
|
15
15
|
import "../replicator/schema/replication-state.js";
|
|
16
16
|
import { parseSignature } from "./row-set-signature.js";
|
|
17
17
|
import { ResetPipelinesSignal } from "./snapshotter.js";
|
|
18
|
-
import "./pipeline-driver.js";
|
|
19
18
|
import { Subscription } from "../../types/subscription.js";
|
|
20
19
|
import { CustomKeyMap } from "../../../../shared/src/custom-key-map.js";
|
|
21
20
|
import { ttlClockAsNumber, ttlClockFromNumber } from "./ttl-clock.js";
|
|
@@ -25,8 +24,10 @@ import { isAuthErrorBody } from "../../auth/auth.js";
|
|
|
25
24
|
import { ClientHandler, startPoke } from "./client-handler.js";
|
|
26
25
|
import { tracer } from "./tracer.js";
|
|
27
26
|
import { CVRStore, ClientNotFoundError } from "./cvr-store.js";
|
|
28
|
-
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, nextEvictionTime } from "./cvr.js";
|
|
27
|
+
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, classifyQueriesForHydration, nextEvictionTime } from "./cvr.js";
|
|
29
28
|
import { E2EServingLagTracker } from "./e2e-serving-lag.js";
|
|
29
|
+
import { HydrationBudget } from "./hydration-budget.js";
|
|
30
|
+
import { HydrationCircuitBreaker } from "./hydration-circuit-breaker.js";
|
|
30
31
|
import { handleInspect } from "./inspect-handler.js";
|
|
31
32
|
import { QueryCoveringIndex } from "./query-covering.js";
|
|
32
33
|
import { resolver } from "@rocicorp/resolver";
|
|
@@ -61,6 +62,7 @@ var ViewSyncerService = class {
|
|
|
61
62
|
#drainCoordinator;
|
|
62
63
|
#keepaliveMs;
|
|
63
64
|
#slowHydrateThreshold;
|
|
65
|
+
#hydrationCircuitBreaker;
|
|
64
66
|
#lastConnectTime = Date.now();
|
|
65
67
|
/**
|
|
66
68
|
* The TTL clock is used to determine the time at which queries are considered
|
|
@@ -88,14 +90,37 @@ var ViewSyncerService = class {
|
|
|
88
90
|
#lock = new Lock();
|
|
89
91
|
#cvrStore;
|
|
90
92
|
#stopped = resolver();
|
|
93
|
+
/**
|
|
94
|
+
* Set when {@link #cleanup} begins. Lock tasks that were in flight when the
|
|
95
|
+
* view-syncer was stopped may still complete after the timers have been
|
|
96
|
+
* cleared; this flag prevents them from scheduling new timers, which would
|
|
97
|
+
* otherwise outlive the service (and retain everything it references).
|
|
98
|
+
*/
|
|
99
|
+
#shuttingDown = false;
|
|
91
100
|
#initialized = resolver();
|
|
92
101
|
#cvr;
|
|
93
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Indicates whether the query pipelines have completed initial catch-up and
|
|
104
|
+
* hydration with the CVR snapshot, and are ready for steady-state operation.
|
|
105
|
+
*
|
|
106
|
+
* - When `false`: The syncer is in its initial catch-up phase. The replica
|
|
107
|
+
* advances without diffs until it reaches `cvr.version.stateVersion`,
|
|
108
|
+
* after which `#maybeHydratePipelines` hydrates queries.
|
|
109
|
+
* - When `true`: Pipelines are fully populated and in steady-state; replica
|
|
110
|
+
* changes advance incrementally via `#advancePipelines`, and client query
|
|
111
|
+
* updates are processed via `#syncQueryPipelineSet`.
|
|
112
|
+
*
|
|
113
|
+
* Resets to `false` if `#advancePipelines` returns a `ResetPipelinesSignal`
|
|
114
|
+
* and pipelines must be reset and rehydrated, or if a reloaded CVR is ahead
|
|
115
|
+
* of the pipelines (see `#resetPipelinesIfBehindCVR`).
|
|
116
|
+
*/
|
|
117
|
+
#pipelinesHydrated = false;
|
|
94
118
|
#servedVersion = null;
|
|
95
119
|
#e2eServingLagTracker = new E2EServingLagTracker();
|
|
96
120
|
#expiredQueriesTimer = 0;
|
|
97
121
|
#authMaintenanceTimer = 0;
|
|
98
122
|
#setTimeout;
|
|
123
|
+
#now;
|
|
99
124
|
#customQueryTransformer;
|
|
100
125
|
#queryReplacements = /* @__PURE__ */ new Map();
|
|
101
126
|
#activeClients = getOrCreateUpDownCounter("sync", "active-clients", "Number of active sync clients");
|
|
@@ -122,10 +147,64 @@ var ViewSyncerService = class {
|
|
|
122
147
|
#pipelineResets = getOrCreateCounter("sync", "pipeline-resets", "Number of pipeline resets");
|
|
123
148
|
#rowSetSignatureDrifts = getOrCreateCounter("sync", "query.row-set-signature-drifts", "Number of times re-hydration of an unchanged query produced a different row-set signature than what is stored in the CVR (forcing a configVersion bump and full re-execution). Expected to be near-zero in steady state; persistent non-zero values indicate non-deterministic query execution (e.g. Cap operator picking different N-row subsets).");
|
|
124
149
|
#sameHashRehydrationVersionBumps = getOrCreateCounter("sync", "query.same-hash-rehydrations-forced-bump", "Number of times query-set reconciliation forced a configVersion bump for already-gotten same-transformation-hash query rehydration because trackQueries would not otherwise bump. Expected to be near-zero; non-zero values indicate pipeline/CVR row-set drift reached query-set reconciliation.");
|
|
150
|
+
#hydrationBudgetExhaustions = getOrCreateCounter("sync", "hydration_budget_exhaustions", {
|
|
151
|
+
description: "Number of hydration passes that exhaust their budget.",
|
|
152
|
+
unit: "{pass}"
|
|
153
|
+
});
|
|
154
|
+
#hydrationBudgetEvictions = getOrCreateCounter("sync", "hydration_budget_evictions", {
|
|
155
|
+
description: "Number of inactive queries removed after hydration budget exhaustion.",
|
|
156
|
+
unit: "{query}"
|
|
157
|
+
});
|
|
158
|
+
#hydrationBudgetElapsed = getOrCreateValueHistogram("sync", "hydration_budget_elapsed", {
|
|
159
|
+
description: "Elapsed milliseconds when optional query hydration stopped.",
|
|
160
|
+
unit: "ms",
|
|
161
|
+
bucketBoundaries: [
|
|
162
|
+
1,
|
|
163
|
+
2,
|
|
164
|
+
5,
|
|
165
|
+
10,
|
|
166
|
+
20,
|
|
167
|
+
50,
|
|
168
|
+
100,
|
|
169
|
+
200,
|
|
170
|
+
500,
|
|
171
|
+
1e3,
|
|
172
|
+
5e3
|
|
173
|
+
]
|
|
174
|
+
});
|
|
175
|
+
#hydrationBudgetOvershoot = getOrCreateValueHistogram("sync", "hydration_budget_overshoot", {
|
|
176
|
+
description: "Milliseconds elapsed beyond the configured hydration budget.",
|
|
177
|
+
unit: "ms",
|
|
178
|
+
bucketBoundaries: [
|
|
179
|
+
0,
|
|
180
|
+
1,
|
|
181
|
+
2,
|
|
182
|
+
5,
|
|
183
|
+
10,
|
|
184
|
+
20,
|
|
185
|
+
50,
|
|
186
|
+
100,
|
|
187
|
+
200,
|
|
188
|
+
500,
|
|
189
|
+
1e3
|
|
190
|
+
]
|
|
191
|
+
});
|
|
192
|
+
#queryEvictions = getOrCreateCounter("sync", "query_evictions", {
|
|
193
|
+
description: "Number of queries evicted from the CVR ahead of their removal by the client, grouped by reason. Inactive queries are evicted by ttl and hydration-budget; hydration-timeout and hydration-circuit-breaker evict active queries as well.",
|
|
194
|
+
unit: "{query}"
|
|
195
|
+
});
|
|
196
|
+
#hydrationTimeouts = getOrCreateCounter("sync", "hydration_timeouts", {
|
|
197
|
+
description: "Number of query hydrations aborted for exceeding the query hydration timeout.",
|
|
198
|
+
unit: "{query}"
|
|
199
|
+
});
|
|
200
|
+
#hydrationCircuitBreakerRejections = getOrCreateCounter("sync", "hydration_circuit_breaker_rejections", {
|
|
201
|
+
description: "Number of queries rejected without hydration because their hydration circuit breaker was open.",
|
|
202
|
+
unit: "{query}"
|
|
203
|
+
});
|
|
125
204
|
#inspectorDelegate;
|
|
126
205
|
#config;
|
|
127
206
|
#runPriorityOp;
|
|
128
|
-
constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, connContextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis)) {
|
|
207
|
+
constructor(config, lc, shard, taskID, clientGroupID, cvrDb, pipelineDriver, versionChanges, drainCoordinator, slowHydrateThreshold, inspectorDelegate, connContextManager, customQueryTransformer, runPriorityOp, keepaliveMs = DEFAULT_KEEPALIVE_MS, setTimeoutFn = setTimeout.bind(globalThis), now = performance.now.bind(performance)) {
|
|
129
208
|
this.#config = config;
|
|
130
209
|
this.id = clientGroupID;
|
|
131
210
|
this.connContextManager = connContextManager;
|
|
@@ -140,6 +219,8 @@ var ViewSyncerService = class {
|
|
|
140
219
|
this.#customQueryTransformer = customQueryTransformer;
|
|
141
220
|
this.#cvrStore = new CVRStore(lc, cvrDb, shard, taskID, clientGroupID, () => this.#stateChanges.cancel());
|
|
142
221
|
this.#setTimeout = setTimeoutFn;
|
|
222
|
+
this.#now = now;
|
|
223
|
+
this.#hydrationCircuitBreaker = new HydrationCircuitBreaker(config.viewSyncerQueryHydrationTimeoutMs ?? 0, void 0, now);
|
|
143
224
|
this.#runPriorityOp = runPriorityOp;
|
|
144
225
|
this.keepalive();
|
|
145
226
|
}
|
|
@@ -166,11 +247,13 @@ var ViewSyncerService = class {
|
|
|
166
247
|
this.#stateChanges.cancel();
|
|
167
248
|
return;
|
|
168
249
|
}
|
|
250
|
+
let reloaded = false;
|
|
169
251
|
if (!this.#cvr) {
|
|
170
252
|
this.#lc.debug?.("loading cvr");
|
|
171
253
|
this.#cvr = await this.#runPriorityOp(lc, "loading cvr", () => this.#cvrStore.load(lc, this.#lastConnectTime));
|
|
172
254
|
this.#ttlClock = this.#cvr.ttlClock;
|
|
173
255
|
this.#ttlClockBase = Date.now();
|
|
256
|
+
reloaded = true;
|
|
174
257
|
} else {
|
|
175
258
|
const now = Date.now();
|
|
176
259
|
this.#cvr = {
|
|
@@ -179,6 +262,10 @@ var ViewSyncerService = class {
|
|
|
179
262
|
};
|
|
180
263
|
}
|
|
181
264
|
try {
|
|
265
|
+
if (reloaded && this.#resetPipelinesIfBehindCVR(lc, this.#cvr)) {
|
|
266
|
+
const connCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
267
|
+
if (connCtx) await this.#maybeHydratePipelines(lc, this.#cvr, connCtx);
|
|
268
|
+
}
|
|
182
269
|
await fn(lc, this.#cvr);
|
|
183
270
|
} catch (e) {
|
|
184
271
|
this.#cvr = void 0;
|
|
@@ -188,11 +275,47 @@ var ViewSyncerService = class {
|
|
|
188
275
|
}
|
|
189
276
|
});
|
|
190
277
|
}
|
|
278
|
+
/**
|
|
279
|
+
* The CVR is reloaded after an error clears the cached copy. By then another
|
|
280
|
+
* view-syncer may have taken over the client group and flushed the CVR at a
|
|
281
|
+
* version ahead of this instance's hydrated pipelines (e.g. its replica was
|
|
282
|
+
* further ahead). The pipelines can no longer be diffed against the CVR, so
|
|
283
|
+
* reset them and let `#maybeHydratePipelines` rehydrate once the replica has
|
|
284
|
+
* caught up to the CVR.
|
|
285
|
+
*
|
|
286
|
+
* A CVR behind the pipelines is expected (advancements that do not change
|
|
287
|
+
* the CVR are not flushed) and is handled by the normal update path.
|
|
288
|
+
*
|
|
289
|
+
* Returns whether the pipelines were reset.
|
|
290
|
+
*
|
|
291
|
+
* Must be called from within the #lock.
|
|
292
|
+
*/
|
|
293
|
+
#resetPipelinesIfBehindCVR(lc, cvr) {
|
|
294
|
+
if (!this.#pipelinesHydrated) return false;
|
|
295
|
+
const pipelineVersion = this.#pipelines.currentVersion();
|
|
296
|
+
if (pipelineVersion >= cvr.version.stateVersion) return false;
|
|
297
|
+
lc.info?.(`resetting pipelines: pipelines@${pipelineVersion} are behind reloaded cvr@${versionString(cvr.version)}`);
|
|
298
|
+
this.#pipelineResets.add(1, { reason: "behind-cvr" });
|
|
299
|
+
this.#pipelinesHydrated = false;
|
|
300
|
+
this.connContextManager.setSharedRetransformReady(false);
|
|
301
|
+
this.#pipelines.reset(must(cvr.clientSchema, "cvr.clientSchema missing after initialization"));
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
191
304
|
readyState() {
|
|
192
|
-
return Promise
|
|
305
|
+
return new Promise((resolve, reject) => {
|
|
306
|
+
const unsubscribe = this.#drainCoordinator.onDraining(() => resolve("draining"));
|
|
307
|
+
this.#initialized.promise.then((state) => {
|
|
308
|
+
unsubscribe();
|
|
309
|
+
resolve(state);
|
|
310
|
+
}, (err) => {
|
|
311
|
+
unsubscribe();
|
|
312
|
+
reject(err);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
193
315
|
}
|
|
194
316
|
async run() {
|
|
195
317
|
try {
|
|
318
|
+
this.#scheduleShutdown(this.#keepaliveMs);
|
|
196
319
|
if (await this.readyState() === "draining") {
|
|
197
320
|
this.#lc.debug?.(`draining view-syncer ${this.id} before running`);
|
|
198
321
|
this.stop();
|
|
@@ -213,26 +336,29 @@ var ViewSyncerService = class {
|
|
|
213
336
|
lc.info?.(`resetting CVR: ${message}`);
|
|
214
337
|
throw new ClientNotFoundError(message);
|
|
215
338
|
}
|
|
216
|
-
|
|
339
|
+
let previousQueries;
|
|
340
|
+
if (this.#pipelinesHydrated) {
|
|
217
341
|
const result = await this.#advancePipelines(lc, cvr);
|
|
218
342
|
if (result === "success") return;
|
|
219
343
|
lc.info?.(`resetting pipelines: ${result.message}`);
|
|
220
344
|
this.#pipelineResets.add(1, { reason: result.reason });
|
|
345
|
+
switch (result.reason) {
|
|
346
|
+
case "advancement-timeout":
|
|
347
|
+
case "scalar-subquery":
|
|
348
|
+
case "truncation":
|
|
349
|
+
case "schema-change":
|
|
350
|
+
if (!Object.values(cvr.queries).some((q) => q.type === "client")) previousQueries = new Map(this.#pipelines.queries());
|
|
351
|
+
break;
|
|
352
|
+
case "permissions-change": break;
|
|
353
|
+
default: unreachable(result.reason);
|
|
354
|
+
}
|
|
221
355
|
this.#pipelines.reset(clientSchema);
|
|
222
|
-
this.#
|
|
356
|
+
this.#pipelinesHydrated = false;
|
|
223
357
|
this.connContextManager.setSharedRetransformReady(false);
|
|
224
358
|
}
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
lc.debug?.(`replica@${version} is behind cvr@${cvrVer}`);
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
|
|
232
|
-
const driftedQueryIDs = await this.#hydrateUnchangedQueries(lc, cvr);
|
|
233
|
-
await this.#syncQueryPipelineSet(lc, cvr, "missing", void 0, driftedQueryIDs);
|
|
234
|
-
this.#pipelinesSynced = true;
|
|
235
|
-
this.connContextManager.setSharedRetransformReady(true);
|
|
359
|
+
const backgroundConnCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
360
|
+
if (backgroundConnCtx) await this.#maybeHydratePipelines(lc, cvr, backgroundConnCtx, previousQueries);
|
|
361
|
+
else lc.info?.("No validated background connection; deferring pipeline init");
|
|
236
362
|
});
|
|
237
363
|
}
|
|
238
364
|
if (this.#drainCoordinator.shouldDrain()) this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
|
|
@@ -246,11 +372,57 @@ var ViewSyncerService = class {
|
|
|
246
372
|
this.#stopped.resolve();
|
|
247
373
|
}
|
|
248
374
|
}
|
|
375
|
+
/**
|
|
376
|
+
* Ensures that query pipelines are hydrated and ready for steady-state
|
|
377
|
+
* operation.
|
|
378
|
+
*
|
|
379
|
+
* Preconditions:
|
|
380
|
+
* 1. Must be called from within the `#lock`.
|
|
381
|
+
* 2. The caller must provide an active, validated `ConnectionContext` for
|
|
382
|
+
* evaluating custom query transforms and permissions.
|
|
383
|
+
*
|
|
384
|
+
* Readiness prerequisites:
|
|
385
|
+
* - The underlying `QueryPipelineDriver` must be initialized with the schema
|
|
386
|
+
* (i.e. `this.#pipelines.initialized()` is true).
|
|
387
|
+
* - The SQLite replica must have caught up to at least the CVR's
|
|
388
|
+
* `stateVersion` (`version >= cvr.version.stateVersion`).
|
|
389
|
+
*
|
|
390
|
+
* If either prerequisite is not met, this method returns early as a no-op,
|
|
391
|
+
* waiting for the replica to catch up or the driver to initialize.
|
|
392
|
+
*
|
|
393
|
+
* Once ready:
|
|
394
|
+
* - Hydrates unchanged queries from the CVR snapshot without full row diffing.
|
|
395
|
+
* - Syncs missing, errored, or drifted queries via `#syncQueryPipelineSet`.
|
|
396
|
+
* - Sets `#pipelinesHydrated = true` and enables shared retransformations.
|
|
397
|
+
*/
|
|
398
|
+
async #maybeHydratePipelines(lc, cvr, connCtx, previousQueries) {
|
|
399
|
+
if (!this.#pipelines.initialized()) return;
|
|
400
|
+
const version = this.#pipelines.advanceWithoutDiff();
|
|
401
|
+
const cvrVer = versionString(cvr.version);
|
|
402
|
+
if (version < cvr.version.stateVersion) {
|
|
403
|
+
lc.debug?.(`replica@${version} is behind cvr@${cvrVer}`);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
lc.info?.(`init pipelines@${version} (cvr@${cvrVer})`);
|
|
407
|
+
const hydrationBudget = new HydrationBudget(this.#config.viewSyncerHydrationBudgetMs ?? 0, this.#now);
|
|
408
|
+
const hydrationPassStats = {
|
|
409
|
+
activeHydratedQueries: 0,
|
|
410
|
+
inactiveHydratedQueries: 0
|
|
411
|
+
};
|
|
412
|
+
const driftedQueryIDs = await this.#hydrateUnchangedQueries(lc, cvr, connCtx, hydrationPassStats, hydrationBudget, previousQueries);
|
|
413
|
+
await this.#syncQueryPipelineSet(lc, cvr, "missing", connCtx, driftedQueryIDs, hydrationBudget, hydrationPassStats, previousQueries);
|
|
414
|
+
this.#pipelinesHydrated = true;
|
|
415
|
+
this.connContextManager.setSharedRetransformReady(true);
|
|
416
|
+
}
|
|
249
417
|
#removeExpiredQueries = async (lc, cvr) => {
|
|
250
418
|
if (hasExpiredQueries(cvr)) {
|
|
251
419
|
lc = lc.withContext("method", "#removeExpiredQueries");
|
|
252
420
|
lc.debug?.("Queries have expired");
|
|
253
|
-
if (this.#
|
|
421
|
+
if (this.#pipelinesHydrated) {
|
|
422
|
+
const connCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
423
|
+
if (connCtx) await this.#syncQueryPipelineSet(lc, cvr, "missing", connCtx);
|
|
424
|
+
else lc.info?.("No validated background connection to remove expired queries; deferring");
|
|
425
|
+
}
|
|
254
426
|
}
|
|
255
427
|
this.#scheduleExpireEviction(lc, cvr);
|
|
256
428
|
};
|
|
@@ -332,7 +504,14 @@ var ViewSyncerService = class {
|
|
|
332
504
|
return true;
|
|
333
505
|
}
|
|
334
506
|
#shutdownTimer = null;
|
|
507
|
+
#stopShutdownTimer() {
|
|
508
|
+
if (this.#shutdownTimer !== null) {
|
|
509
|
+
clearTimeout(this.#shutdownTimer);
|
|
510
|
+
this.#shutdownTimer = null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
335
513
|
#scheduleShutdown(delayMs = 0) {
|
|
514
|
+
if (this.#shuttingDown) return;
|
|
336
515
|
this.#shutdownTimer ??= this.#setTimeout(() => {
|
|
337
516
|
this.#shutdownTimer = null;
|
|
338
517
|
this.#runInLockWithCVR(() => {}).catch((e) => this.#stateChanges.fail(e));
|
|
@@ -379,6 +558,7 @@ var ViewSyncerService = class {
|
|
|
379
558
|
*/
|
|
380
559
|
#scheduleAuthMaintenance(lc) {
|
|
381
560
|
this.#stopAuthMaintenanceTimer();
|
|
561
|
+
if (this.#shuttingDown) return;
|
|
382
562
|
const plan = this.connContextManager.planMaintenance();
|
|
383
563
|
if (plan.earliestDeadlineAt === void 0) {
|
|
384
564
|
lc.debug?.("No auth maintenance wakeup scheduled");
|
|
@@ -466,7 +646,7 @@ var ViewSyncerService = class {
|
|
|
466
646
|
}
|
|
467
647
|
lc.debug?.("Auth changed, re-validating and re-transforming queries");
|
|
468
648
|
const connCtx = this.connContextManager.mustGetConnectionContext(selector);
|
|
469
|
-
if (!this.#
|
|
649
|
+
if (!this.#pipelinesHydrated) {
|
|
470
650
|
if (!await this.#validateConnection(connCtx)) return;
|
|
471
651
|
}
|
|
472
652
|
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connCtx);
|
|
@@ -495,6 +675,7 @@ var ViewSyncerService = class {
|
|
|
495
675
|
}
|
|
496
676
|
#startTTLClockInterval(lc) {
|
|
497
677
|
this.#stopTTLClockInterval();
|
|
678
|
+
if (this.#shuttingDown) return;
|
|
498
679
|
this.#ttlClockInterval = this.#setTimeout(() => {
|
|
499
680
|
this.#updateTTLClockInCVRWithoutLock(lc);
|
|
500
681
|
this.#startTTLClockInterval(lc);
|
|
@@ -523,12 +704,13 @@ var ViewSyncerService = class {
|
|
|
523
704
|
if (cmpVersions(cvr.version, this.#cvr.version) < 0) {
|
|
524
705
|
const newCVR = this.#cvr;
|
|
525
706
|
await startAsyncSpan(tracer, "vs.#updateCVRConfig.pokeClients", async () => {
|
|
526
|
-
const pokers = startPoke(this.#getClients(cvr.version), newCVR.version);
|
|
707
|
+
const pokers = startPoke(lc, this.#getClients(cvr.version), newCVR.version);
|
|
527
708
|
for (const patch of patches) await pokers.addPatch(patch);
|
|
528
709
|
await pokers.end(newCVR.version);
|
|
529
710
|
});
|
|
530
711
|
}
|
|
531
|
-
if (this.#
|
|
712
|
+
if (!this.#pipelinesHydrated) await this.#maybeHydratePipelines(lc, this.#cvr, connCtx);
|
|
713
|
+
else await this.#syncQueryPipelineSet(lc, this.#cvr, customQueryTransformMode, connCtx);
|
|
532
714
|
return this.#cvr;
|
|
533
715
|
}
|
|
534
716
|
/**
|
|
@@ -624,6 +806,7 @@ var ViewSyncerService = class {
|
|
|
624
806
|
#scheduleExpireEviction(lc, cvr) {
|
|
625
807
|
const { ttlClock } = cvr;
|
|
626
808
|
this.#stopExpireTimer();
|
|
809
|
+
if (this.#shuttingDown) return;
|
|
627
810
|
const next = nextEvictionTime(cvr);
|
|
628
811
|
if (next === void 0) {
|
|
629
812
|
lc.debug?.("no inactive queries with ttl");
|
|
@@ -651,7 +834,7 @@ var ViewSyncerService = class {
|
|
|
651
834
|
*
|
|
652
835
|
* This must be called from within the #lock.
|
|
653
836
|
*/
|
|
654
|
-
async #hydrateUnchangedQueries(lc, cvr) {
|
|
837
|
+
async #hydrateUnchangedQueries(lc, cvr, connCtx, hydrationPassStats, hydrationBudget, previousQueries) {
|
|
655
838
|
assert(this.#pipelines.initialized(), "pipelines must be initialized");
|
|
656
839
|
const dbVersion = this.#pipelines.currentVersion();
|
|
657
840
|
const cvrVersion = cvr.version;
|
|
@@ -660,33 +843,34 @@ var ViewSyncerService = class {
|
|
|
660
843
|
return /* @__PURE__ */ new Set();
|
|
661
844
|
}
|
|
662
845
|
const gotQueries = Object.entries(cvr.queries).filter(([_, state]) => state.transformationHash !== void 0);
|
|
846
|
+
const { required: requiredGotQueries } = classifyQueriesForHydration(gotQueries.map(([, query]) => query));
|
|
663
847
|
const customQueries = /* @__PURE__ */ new Map();
|
|
664
848
|
const otherQueries = [];
|
|
665
|
-
|
|
666
|
-
for (const [, query] of gotQueries) {
|
|
667
|
-
if (query.type !== "internal" && Object.values(query.clientState).every(({ inactivatedAt }) => inactivatedAt !== void 0)) {
|
|
668
|
-
inactivatedCount++;
|
|
669
|
-
continue;
|
|
670
|
-
}
|
|
671
|
-
if (query.type === "custom") customQueries.set(query.id, query);
|
|
672
|
-
else otherQueries.push(query);
|
|
673
|
-
}
|
|
849
|
+
const inactivatedCount = gotQueries.length - requiredGotQueries.length;
|
|
674
850
|
const transformedQueries = [];
|
|
851
|
+
for (const query of requiredGotQueries) if (query.type === "custom") {
|
|
852
|
+
const previous = previousQueries?.get(query.id);
|
|
853
|
+
if (previous && previous.transformationHash === query.transformationHash) transformedQueries.push({
|
|
854
|
+
id: query.id,
|
|
855
|
+
transformationHash: previous.transformationHash,
|
|
856
|
+
transformedAst: previous.originalAst ?? previous.transformedAst
|
|
857
|
+
});
|
|
858
|
+
else customQueries.set(query.id, query);
|
|
859
|
+
} else otherQueries.push(query);
|
|
675
860
|
let customErrorCount = 0;
|
|
676
861
|
let customHashMismatchCount = 0;
|
|
677
862
|
let otherHashMismatchCount = 0;
|
|
678
863
|
if (customQueries.size > 0 && !this.#customQueryTransformer) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
|
|
679
|
-
const backgroundContext = this.connContextManager.mustGetBackgroundConnectionContext();
|
|
680
864
|
const customQueryTransformer = this.#customQueryTransformer;
|
|
681
865
|
if (customQueryTransformer && customQueries.size > 0) {
|
|
682
|
-
const transformedCustomQueries = await this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(
|
|
683
|
-
if (transformedCustomQueries.kind === "success" && !transformedCustomQueries.cached) this.connContextManager.validateConnection(
|
|
866
|
+
const transformedCustomQueries = await hydrationBudget.excluding(() => this.#runPriorityOp(lc, "#hydrateUnchangedQueries transforming custom queries", () => customQueryTransformer.transform(connCtx, customQueries.values())));
|
|
867
|
+
if (transformedCustomQueries.kind === "success" && !transformedCustomQueries.cached) this.connContextManager.validateConnection(connCtx, connCtx.revision, transformedCustomQueries.validation);
|
|
684
868
|
if (Array.isArray(transformedCustomQueries.result)) for (const q of transformedCustomQueries.result) if ("error" in q) customErrorCount++;
|
|
685
869
|
else if (q.transformationHash !== customQueries.get(q.id)?.transformationHash) customHashMismatchCount++;
|
|
686
870
|
else transformedQueries.push(q);
|
|
687
871
|
}
|
|
688
872
|
for (const q of otherQueries) {
|
|
689
|
-
const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} },
|
|
873
|
+
const transformed = transformAndHashQuery(lc, q.id, q.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, connCtx.auth?.type === "jwt" ? connCtx.auth : void 0, q.type === "internal");
|
|
690
874
|
if (transformed.transformationHash === q.transformationHash) transformedQueries.push(transformed);
|
|
691
875
|
else otherHashMismatchCount++;
|
|
692
876
|
}
|
|
@@ -699,6 +883,10 @@ var ViewSyncerService = class {
|
|
|
699
883
|
for (const { id: queryID, transformationHash, transformedAst } of transformedQueries) {
|
|
700
884
|
const query = cvr.queries[queryID];
|
|
701
885
|
const queryName = query.type === "custom" ? query.name : void 0;
|
|
886
|
+
if (query.type !== "internal" && this.#hydrationCircuitBreaker.isOpen(transformationHash)) {
|
|
887
|
+
lc.info?.(`skipping hydration of ${queryID}: hydration circuit breaker open`);
|
|
888
|
+
continue;
|
|
889
|
+
}
|
|
702
890
|
const covered = queryCoveringIndex ? this.#findQueryCoverageShadowHit(queryCoveringIndex, queryID, transformationHash, transformedAst, queryName) : void 0;
|
|
703
891
|
totalHydratedQueries++;
|
|
704
892
|
if (covered) {
|
|
@@ -707,19 +895,35 @@ var ViewSyncerService = class {
|
|
|
707
895
|
}
|
|
708
896
|
const timer = new TimeSliceTimer(lc);
|
|
709
897
|
let count = 0;
|
|
898
|
+
let timedOut = false;
|
|
710
899
|
await startAsyncSpan(tracer, "vs.#hydrateUnchangedQueries.addQuery", async (span) => {
|
|
711
900
|
span.setAttribute("queryHash", queryID);
|
|
712
901
|
span.setAttribute("transformationHash", transformationHash);
|
|
713
902
|
span.setAttribute("table", transformedAst.table);
|
|
714
903
|
if (queryName !== void 0) span.setAttribute("queryName", queryName);
|
|
715
|
-
for (const change of this.#pipelines.addQuery(transformationHash, queryID, transformedAst, await timer.start(), queryName, "unchanged-query-rehydrate")) if (change === "yield")
|
|
716
|
-
|
|
904
|
+
for (const change of this.#pipelines.addQuery(transformationHash, queryID, transformedAst, await timer.start(), queryName, "unchanged-query-rehydrate")) if (change === "yield") {
|
|
905
|
+
if (query.type !== "internal" && this.#hydrationCircuitBreaker.exceeded(timer.totalElapsed())) {
|
|
906
|
+
timedOut = true;
|
|
907
|
+
await timer.yieldProcess("yield in hydrateUnchangedQueries");
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
await timer.yieldProcess("yield in hydrateUnchangedQueries");
|
|
911
|
+
} else count++;
|
|
717
912
|
});
|
|
718
913
|
const elapsed = timer.totalElapsed();
|
|
914
|
+
if (timedOut) {
|
|
915
|
+
this.#recordHydrationTimeout(lc, {
|
|
916
|
+
id: queryID,
|
|
917
|
+
transformationHash,
|
|
918
|
+
name: queryName
|
|
919
|
+
}, elapsed, count);
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
hydrationPassStats.activeHydratedQueries++;
|
|
719
923
|
this.#hydrations.add(1);
|
|
720
924
|
this.#hydrationTime.recordMs(elapsed);
|
|
721
|
-
this.#addQueryMaterializationServerMetric(
|
|
722
|
-
this.#inspectorDelegate.addQuery(
|
|
925
|
+
this.#addQueryMaterializationServerMetric(queryID, elapsed);
|
|
926
|
+
this.#inspectorDelegate.addQuery(queryID, transformedAst);
|
|
723
927
|
lc.debug?.(`hydrated ${count} rows for ${queryID} (${elapsed} ms)`);
|
|
724
928
|
let drifted = false;
|
|
725
929
|
const storedSigHex = cvr.queries[queryID]?.rowSetSignature;
|
|
@@ -820,7 +1024,10 @@ var ViewSyncerService = class {
|
|
|
820
1024
|
*
|
|
821
1025
|
* This must be called from within the #lock.
|
|
822
1026
|
*/
|
|
823
|
-
#syncQueryPipelineSet(lc, cvr, customQueryTransformMode, connCtx, driftedQueryIDs = /* @__PURE__ */ new Set()) {
|
|
1027
|
+
#syncQueryPipelineSet(lc, cvr, customQueryTransformMode, connCtx, driftedQueryIDs = /* @__PURE__ */ new Set(), hydrationBudget = new HydrationBudget(this.#config.viewSyncerHydrationBudgetMs ?? 0, this.#now), hydrationPassStats = {
|
|
1028
|
+
activeHydratedQueries: 0,
|
|
1029
|
+
inactiveHydratedQueries: 0
|
|
1030
|
+
}, previousQueries) {
|
|
824
1031
|
return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
|
|
825
1032
|
const start = performance.now();
|
|
826
1033
|
span.setAttribute("clientGroupID", this.id);
|
|
@@ -829,38 +1036,45 @@ var ViewSyncerService = class {
|
|
|
829
1036
|
const now = Date.now();
|
|
830
1037
|
const ttlClock = this.#getTTLClock(now);
|
|
831
1038
|
const cvrQueryEntires = Object.entries(cvr.queries);
|
|
832
|
-
const customQueries = /* @__PURE__ */ new Map();
|
|
833
|
-
const otherQueries = [];
|
|
834
1039
|
const transformedQueries = [];
|
|
835
|
-
const
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
});
|
|
843
|
-
for (const { id, query: origQuery } of otherQueries) {
|
|
844
|
-
assert(id === origQuery.id, "query id mismatch");
|
|
845
|
-
const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, resolvedConnCtx.auth?.type === "jwt" ? resolvedConnCtx.auth : void 0, origQuery.type === "internal");
|
|
846
|
-
transformedQueries.push({
|
|
847
|
-
id,
|
|
848
|
-
origQuery,
|
|
849
|
-
transformed
|
|
850
|
-
});
|
|
851
|
-
}
|
|
852
|
-
if (customQueries.size > 0 && !this.#customQueryTransformer) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
|
|
853
|
-
let erroredQueryIDs;
|
|
854
|
-
const customQueriesToTransform = customQueryTransformMode === "all" ? [...customQueries.values()] : customQueryTransformMode && [...customQueries.values()].filter((q) => !this.#pipelines.queries().has(q.id));
|
|
1040
|
+
const naturallyExpiredQueryIDs = new Set(cvrQueryEntires.map(([, query]) => query).filter((query) => expired(ttlClock, query)).map((query) => query.id));
|
|
1041
|
+
if (naturallyExpiredQueryIDs.size > 0) this.#queryEvictions.add(naturallyExpiredQueryIDs.size, { reason: "ttl" });
|
|
1042
|
+
const hydrationCandidates = cvrQueryEntires.map(([, query]) => query).filter((query) => !naturallyExpiredQueryIDs.has(query.id));
|
|
1043
|
+
const { required, optional } = classifyQueriesForHydration(hydrationCandidates);
|
|
1044
|
+
const requiredQueryIDs = new Set(required.map((query) => query.id));
|
|
1045
|
+
const optionalToHydrate = hydrationBudget.limitMs === 0 ? optional : optional.filter((query) => query.patchVersion !== void 0);
|
|
1046
|
+
if (!this.#customQueryTransformer && hydrationCandidates.some((query) => query.type === "custom")) lc.warn?.("Custom/named queries were requested but no `ZERO_QUERY_URL` is configured for Zero Cache.");
|
|
855
1047
|
const customQueryTransformer = this.#customQueryTransformer;
|
|
856
|
-
|
|
1048
|
+
const erroredQueryIDs = [];
|
|
1049
|
+
let transformedCustomQueryCount = 0;
|
|
1050
|
+
const transformOtherQueries = (queries) => {
|
|
1051
|
+
for (const origQuery of queries) {
|
|
1052
|
+
if (origQuery.type === "custom") continue;
|
|
1053
|
+
const transformed = transformAndHashQuery(lc, origQuery.id, origQuery.ast, must(this.#pipelines.currentPermissions()).permissions ?? { tables: {} }, connCtx.auth?.type === "jwt" ? connCtx.auth : void 0, origQuery.type === "internal");
|
|
1054
|
+
transformedQueries.push({
|
|
1055
|
+
id: origQuery.id,
|
|
1056
|
+
origQuery,
|
|
1057
|
+
transformed
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
const shouldTransformCustomQuery = (query) => {
|
|
1062
|
+
if (customQueryTransformMode === "all") return true;
|
|
1063
|
+
if (this.#pipelines.queries().has(query.id)) return false;
|
|
1064
|
+
const previous = previousQueries?.get(query.id);
|
|
1065
|
+
if (previous && previous.transformationHash === query.transformationHash) return false;
|
|
1066
|
+
return true;
|
|
1067
|
+
};
|
|
1068
|
+
const transformCustomQueries = async (queries) => {
|
|
1069
|
+
if (!customQueryTransformer || queries.length === 0) return;
|
|
1070
|
+
transformedCustomQueryCount += queries.length;
|
|
857
1071
|
const transformStart = performance.now();
|
|
858
1072
|
let transformedCustomQueries;
|
|
859
1073
|
try {
|
|
860
|
-
transformedCustomQueries = await this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(
|
|
1074
|
+
transformedCustomQueries = await hydrationBudget.excluding(() => this.#runPriorityOp(lc, "#syncQueryPipelineSet transforming custom queries", () => customQueryTransformer.transform(connCtx, queries)));
|
|
861
1075
|
if (transformedCustomQueries.kind === "failed") throw new ProtocolErrorWithLevel(transformedCustomQueries.result, "warn");
|
|
862
1076
|
else {
|
|
863
|
-
if (!transformedCustomQueries.cached) this.connContextManager.validateConnection(
|
|
1077
|
+
if (!transformedCustomQueries.cached) this.connContextManager.validateConnection(connCtx, connCtx.revision, transformedCustomQueries.validation);
|
|
864
1078
|
this.#queryTransformations.add(1, { result: "success" });
|
|
865
1079
|
}
|
|
866
1080
|
} catch (e) {
|
|
@@ -871,8 +1085,9 @@ var ViewSyncerService = class {
|
|
|
871
1085
|
this.#queryTransformationTime.recordMs(transformDuration);
|
|
872
1086
|
}
|
|
873
1087
|
const successfullyTransformedCustomQueries = /* @__PURE__ */ new Map();
|
|
874
|
-
|
|
875
|
-
|
|
1088
|
+
const customQueryMap = new Map(queries.map((query) => [query.id, query]));
|
|
1089
|
+
erroredQueryIDs.push(...this.#processTransformedCustomQueries(lc, transformedCustomQueries.result, (q) => {
|
|
1090
|
+
const origQuery = customQueryMap.get(q.id);
|
|
876
1091
|
if (origQuery) {
|
|
877
1092
|
successfullyTransformedCustomQueries.set(q.id, q);
|
|
878
1093
|
transformedQueries.push({
|
|
@@ -881,7 +1096,7 @@ var ViewSyncerService = class {
|
|
|
881
1096
|
transformed: q
|
|
882
1097
|
});
|
|
883
1098
|
}
|
|
884
|
-
},
|
|
1099
|
+
}, customQueryMap));
|
|
885
1100
|
for (const [queryID, newTransform] of successfullyTransformedCustomQueries) {
|
|
886
1101
|
const existingTransformHash = cvr.queries[queryID]?.transformationHash;
|
|
887
1102
|
if (existingTransformHash) {
|
|
@@ -894,21 +1109,55 @@ var ViewSyncerService = class {
|
|
|
894
1109
|
} else this.#queryTransformationNoOps.add(1);
|
|
895
1110
|
}
|
|
896
1111
|
}
|
|
1112
|
+
};
|
|
1113
|
+
const queriesToTransform = [...required, ...optionalToHydrate];
|
|
1114
|
+
transformOtherQueries(queriesToTransform);
|
|
1115
|
+
if (customQueryTransformMode === "missing" && previousQueries) {
|
|
1116
|
+
for (const query of queriesToTransform) if (query.type === "custom" && !this.#pipelines.queries().has(query.id)) {
|
|
1117
|
+
const previous = previousQueries.get(query.id);
|
|
1118
|
+
if (previous && previous.transformationHash === query.transformationHash) {
|
|
1119
|
+
this.#queryTransformationNoOps.add(1);
|
|
1120
|
+
transformedQueries.push({
|
|
1121
|
+
id: query.id,
|
|
1122
|
+
origQuery: query,
|
|
1123
|
+
transformed: {
|
|
1124
|
+
id: query.id,
|
|
1125
|
+
transformationHash: previous.transformationHash,
|
|
1126
|
+
transformedAst: previous.originalAst ?? previous.transformedAst
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
897
1131
|
}
|
|
898
|
-
|
|
1132
|
+
await transformCustomQueries(queriesToTransform.filter((query) => query.type === "custom" && shouldTransformCustomQuery(query)));
|
|
1133
|
+
const circuitBrokenQueries = transformedQueries.filter(({ id, origQuery, transformed }) => origQuery.type !== "internal" && this.#pipelines.queries().get(id)?.transformationHash !== transformed.transformationHash && this.#hydrationCircuitBreaker.isOpen(transformed.transformationHash)).map(({ id, origQuery, transformed }) => ({
|
|
1134
|
+
id,
|
|
1135
|
+
transformationHash: transformed.transformationHash,
|
|
1136
|
+
name: origQuery.type === "custom" ? origQuery.name : void 0
|
|
1137
|
+
}));
|
|
1138
|
+
if (circuitBrokenQueries.length > 0) this.#rejectCircuitBrokenQueries(lc, cvr, circuitBrokenQueries);
|
|
1139
|
+
const removeQueriesQueryIds = new Set([
|
|
1140
|
+
...naturallyExpiredQueryIDs,
|
|
1141
|
+
...erroredQueryIDs,
|
|
1142
|
+
...circuitBrokenQueries.map(({ id }) => id)
|
|
1143
|
+
]);
|
|
899
1144
|
const addQueries = transformedQueries.map(({ id, origQuery, transformed }) => ({
|
|
900
1145
|
id,
|
|
901
1146
|
ast: transformed.transformedAst,
|
|
902
1147
|
transformationHash: transformed.transformationHash,
|
|
903
1148
|
name: origQuery.type === "custom" ? origQuery.name : void 0
|
|
904
1149
|
})).filter((q) => !removeQueriesQueryIds.has(q.id) && this.#pipelines.queries().get(q.id)?.transformationHash !== q.transformationHash);
|
|
905
|
-
|
|
1150
|
+
const hydrationOrder = new Map([...required, ...optional].map((query, index) => [query.id, index]));
|
|
1151
|
+
addQueries.sort((a, b) => must(hydrationOrder.get(a.id)) - must(hydrationOrder.get(b.id)));
|
|
1152
|
+
const requiredAddQueries = addQueries.filter((query) => requiredQueryIDs.has(query.id));
|
|
1153
|
+
const optionalAddQueries = addQueries.filter((query) => !requiredQueryIDs.has(query.id));
|
|
1154
|
+
lc.info?.(`syncQueryPipelineSet: ${cvrQueryEntires.length} CVR queries, ${transformedCustomQueryCount} custom re-transformed, ${erroredQueryIDs.length} errored, ${circuitBrokenQueries.length} circuit-broken, ${removeQueriesQueryIds.size} to remove, ${addQueries.length} to add`);
|
|
906
1155
|
for (const q of addQueries) {
|
|
907
1156
|
const orig = cvr.queries[q.id];
|
|
908
1157
|
lc.debug?.("ViewSyncer adding query", q.ast, "transformed from", orig.type === "custom" ? orig.name : orig.ast);
|
|
909
1158
|
}
|
|
910
1159
|
if (addQueries.length > 0 || removeQueriesQueryIds.size > 0) {
|
|
911
|
-
await this.#addAndRemoveQueries(lc, cvr,
|
|
1160
|
+
await this.#addAndRemoveQueries(lc, cvr, requiredAddQueries, optionalAddQueries, Array.from(removeQueriesQueryIds, (id) => ({ id })), hydrationBudget, hydrationPassStats, driftedQueryIDs);
|
|
912
1161
|
if (addQueries.length > 0) this.#viewSyncerHydration.recordMs(performance.now() - start);
|
|
913
1162
|
} else await this.#catchupClients(lc, cvr);
|
|
914
1163
|
});
|
|
@@ -941,8 +1190,100 @@ var ViewSyncerService = class {
|
|
|
941
1190
|
record.count++;
|
|
942
1191
|
if (record.count >= THRASH_THRESHOLD) this.#lc.warn?.(`Query thrashing detected for query ${queryID}. ${record.count} replacements in 60s. This may indicate clients with different auth contexts connecting to the same client group.`);
|
|
943
1192
|
}
|
|
944
|
-
|
|
1193
|
+
/**
|
|
1194
|
+
* Records that hydrating `query` was aborted for exceeding the query
|
|
1195
|
+
* hydration timeout, and opens its circuit breaker.
|
|
1196
|
+
*/
|
|
1197
|
+
#recordHydrationTimeout(lc, query, elapsedMs, rowCount) {
|
|
1198
|
+
this.#hydrationCircuitBreaker.trip(query.transformationHash);
|
|
1199
|
+
this.#hydrationTimeouts.add(1);
|
|
1200
|
+
lc.warn?.("Query hydration aborted for exceeding the hydration timeout", {
|
|
1201
|
+
clientGroupID: this.id,
|
|
1202
|
+
queryHash: query.id,
|
|
1203
|
+
transformationHash: query.transformationHash,
|
|
1204
|
+
...query.name !== void 0 && { queryName: query.name },
|
|
1205
|
+
hydrationTimeoutMs: this.#hydrationCircuitBreaker.timeoutMs,
|
|
1206
|
+
hydrationElapsedMs: elapsedMs,
|
|
1207
|
+
...rowCount !== void 0 && { hydrationRowCount: rowCount },
|
|
1208
|
+
circuitBreakerOpenMs: this.#hydrationCircuitBreaker.openMs
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
/** Records that `query` was rejected without hydration by its open breaker. */
|
|
1212
|
+
#recordCircuitBreakerRejection(lc, query) {
|
|
1213
|
+
this.#hydrationCircuitBreakerRejections.add(1);
|
|
1214
|
+
lc.warn?.("Query rejected by its open hydration circuit breaker", {
|
|
1215
|
+
clientGroupID: this.id,
|
|
1216
|
+
queryHash: query.id,
|
|
1217
|
+
transformationHash: query.transformationHash,
|
|
1218
|
+
...query.name !== void 0 && { queryName: query.name },
|
|
1219
|
+
hydrationTimeoutMs: this.#hydrationCircuitBreaker.timeoutMs,
|
|
1220
|
+
circuitBreakerOpenMs: this.#hydrationCircuitBreaker.openMs
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Handles queries whose hydration circuit breaker is open: they are counted,
|
|
1225
|
+
* logged, and errored to the affected clients. The caller removes them from
|
|
1226
|
+
* the CVR.
|
|
1227
|
+
*/
|
|
1228
|
+
#rejectCircuitBrokenQueries(lc, cvr, queries) {
|
|
1229
|
+
for (const query of queries) this.#recordCircuitBreakerRejection(lc, query);
|
|
1230
|
+
this.#queryEvictions.add(queries.length, { reason: "hydration-circuit-breaker" });
|
|
1231
|
+
this.#sendHydrationTimeoutErrors(cvr, queries);
|
|
1232
|
+
}
|
|
1233
|
+
/**
|
|
1234
|
+
* Sends a per-query error to every client that desires one of `queries`.
|
|
1235
|
+
* The error goes out as a `transformError` application error, which every
|
|
1236
|
+
* client understands as "this query errored" without affecting the
|
|
1237
|
+
* connection or the client's other queries.
|
|
1238
|
+
*/
|
|
1239
|
+
#sendHydrationTimeoutErrors(cvr, queries) {
|
|
1240
|
+
const timeoutMs = this.#hydrationCircuitBreaker.timeoutMs;
|
|
1241
|
+
const errorsByClient = /* @__PURE__ */ new Map();
|
|
1242
|
+
for (const { id, name } of queries) {
|
|
1243
|
+
const query = cvr.queries[id];
|
|
1244
|
+
if (query === void 0 || query.type === "internal") continue;
|
|
1245
|
+
const error = {
|
|
1246
|
+
error: "app",
|
|
1247
|
+
id,
|
|
1248
|
+
name: name ?? (query.type === "custom" ? query.name : "legacy"),
|
|
1249
|
+
message: `Query hydration exceeded the ${timeoutMs}ms limit (ZERO_VIEW_SYNCER_QUERY_HYDRATION_TIMEOUT_MS) and was aborted`,
|
|
1250
|
+
details: {
|
|
1251
|
+
kind: "HydrationTimeout",
|
|
1252
|
+
timeoutMs
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
for (const clientID of Object.keys(query.clientState)) {
|
|
1256
|
+
let errors = errorsByClient.get(clientID);
|
|
1257
|
+
if (!errors) {
|
|
1258
|
+
errors = [];
|
|
1259
|
+
errorsByClient.set(clientID, errors);
|
|
1260
|
+
}
|
|
1261
|
+
errors.push(error);
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
for (const [clientID, errors] of errorsByClient) this.#clients.get(clientID)?.sendQueryTransformApplicationErrors(errors);
|
|
1265
|
+
}
|
|
1266
|
+
#recordHydrationBudgetExhaustion(lc, hydrationBudget, activeHydratedQueries, inactiveHydratedQueries, inactiveEvictedQueryIDs) {
|
|
1267
|
+
const elapsedMs = hydrationBudget.exhaustedAtMs;
|
|
1268
|
+
if (elapsedMs === void 0) return;
|
|
1269
|
+
this.#hydrationBudgetExhaustions.add(1);
|
|
1270
|
+
this.#hydrationBudgetEvictions.add(inactiveEvictedQueryIDs.length);
|
|
1271
|
+
this.#hydrationBudgetElapsed.record(elapsedMs);
|
|
1272
|
+
this.#hydrationBudgetOvershoot.record(Math.max(0, elapsedMs - hydrationBudget.limitMs));
|
|
1273
|
+
if (inactiveEvictedQueryIDs.length > 0) this.#queryEvictions.add(inactiveEvictedQueryIDs.length, { reason: "hydration-budget" });
|
|
1274
|
+
lc.info?.("view-syncer hydration budget exhausted", {
|
|
1275
|
+
clientGroupID: this.id,
|
|
1276
|
+
hydrationBudgetMs: hydrationBudget.limitMs,
|
|
1277
|
+
hydrationElapsedMs: elapsedMs,
|
|
1278
|
+
activeHydratedQueries,
|
|
1279
|
+
inactiveHydratedQueries,
|
|
1280
|
+
inactiveEvictedQueries: inactiveEvictedQueryIDs.length,
|
|
1281
|
+
firstEvictedQueryHash: inactiveEvictedQueryIDs[0] ?? null
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
#addAndRemoveQueries(lc, cvr, requiredQueries, optionalQueries, removeQueries, hydrationBudget, hydrationPassStats, driftedQueryIDs = /* @__PURE__ */ new Set()) {
|
|
945
1285
|
return startAsyncSpan(tracer, "vs.#addAndRemoveQueries", async () => {
|
|
1286
|
+
const addQueries = [...requiredQueries, ...optionalQueries];
|
|
946
1287
|
assert(addQueries.length > 0 || removeQueries.length > 0, "Must have queries to add or remove");
|
|
947
1288
|
const start = performance.now();
|
|
948
1289
|
const stateVersion = this.#pipelines.currentVersion();
|
|
@@ -959,7 +1300,9 @@ var ViewSyncerService = class {
|
|
|
959
1300
|
updater.ensureNewVersion();
|
|
960
1301
|
}
|
|
961
1302
|
const { queryPatches, newVersion } = updater.trackQueries(lc, addQueries, removeQueries);
|
|
962
|
-
|
|
1303
|
+
if (hydrationBudget.limitMs !== 0 && optionalQueries.length > 0) assert(cmpVersions(cvr.version, newVersion) < 0, "Optional hydration requires a final poke version before row processing so a removal is actually poked");
|
|
1304
|
+
const clients = this.#getClients();
|
|
1305
|
+
const pokers = startPoke(lc, clients, newVersion);
|
|
963
1306
|
for (const patch of queryPatches) await pokers.addPatch(patch);
|
|
964
1307
|
for (const q of removeQueries) {
|
|
965
1308
|
this.#pipelines.removeQuery(q.id);
|
|
@@ -975,22 +1318,54 @@ var ViewSyncerService = class {
|
|
|
975
1318
|
let totalHydratedQueries = 0;
|
|
976
1319
|
let coveredHydratedQueries = 0;
|
|
977
1320
|
let firstCoveredQuery;
|
|
1321
|
+
const hydratedQueryIDs = [];
|
|
1322
|
+
const budgetEvictedQueryIDs = [];
|
|
1323
|
+
const timedOutQueries = [];
|
|
1324
|
+
const rejectedQueries = [];
|
|
1325
|
+
const circuitBreaker = this.#hydrationCircuitBreaker;
|
|
978
1326
|
const self = this;
|
|
979
1327
|
await yieldProcess(lc);
|
|
980
|
-
function*
|
|
981
|
-
for (
|
|
1328
|
+
function* hydrateQueries(queries, optional, slowHydrateThreshold) {
|
|
1329
|
+
for (let i = 0; i < queries.length; i++) {
|
|
1330
|
+
if (optional && hydrationBudget.exhausted()) {
|
|
1331
|
+
budgetEvictedQueryIDs.push(...queries.slice(i).map((query) => query.id));
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
const q = must(queries[i]);
|
|
982
1335
|
let queryLC = lc.withContext("hash", q.id).withContext("queryHash", q.id).withContext("transformationHash", q.transformationHash);
|
|
983
1336
|
if (q.name !== void 0) queryLC = queryLC.withContext("queryName", q.name);
|
|
984
1337
|
queryLC.debug?.(`adding pipeline for query`, q.ast);
|
|
1338
|
+
const breakable = cvr.queries[q.id]?.type !== "internal";
|
|
1339
|
+
if (breakable && circuitBreaker.isOpen(q.transformationHash)) {
|
|
1340
|
+
rejectedQueries.push(q);
|
|
1341
|
+
self.#recordCircuitBreakerRejection(queryLC, q);
|
|
1342
|
+
continue;
|
|
1343
|
+
}
|
|
985
1344
|
const covered = queryCoveringIndex ? self.#findQueryCoverageShadowHit(queryCoveringIndex, q.id, q.transformationHash, q.ast, q.name) : void 0;
|
|
986
1345
|
totalHydratedQueries++;
|
|
987
1346
|
if (covered) {
|
|
988
1347
|
coveredHydratedQueries++;
|
|
989
1348
|
firstCoveredQuery ??= covered;
|
|
990
1349
|
}
|
|
991
|
-
|
|
1350
|
+
let timedOut = false;
|
|
1351
|
+
for (const change of pipelines.addQuery(q.transformationHash, q.id, q.ast, timer.startWithoutYielding(), q.name, "query-set-sync")) {
|
|
1352
|
+
if (change === "yield" && breakable && circuitBreaker.exceeded(timer.totalElapsed())) {
|
|
1353
|
+
timedOut = true;
|
|
1354
|
+
yield change;
|
|
1355
|
+
break;
|
|
1356
|
+
}
|
|
1357
|
+
yield change;
|
|
1358
|
+
}
|
|
992
1359
|
const elapsed = timer.stop();
|
|
993
1360
|
totalProcessTime += elapsed;
|
|
1361
|
+
if (timedOut) {
|
|
1362
|
+
timedOutQueries.push(q);
|
|
1363
|
+
self.#recordHydrationTimeout(queryLC, q, elapsed);
|
|
1364
|
+
continue;
|
|
1365
|
+
}
|
|
1366
|
+
hydratedQueryIDs.push(q.id);
|
|
1367
|
+
if (optional) hydrationPassStats.inactiveHydratedQueries++;
|
|
1368
|
+
else hydrationPassStats.activeHydratedQueries++;
|
|
994
1369
|
self.#addQueryMaterializationServerMetric(q.id, elapsed);
|
|
995
1370
|
self.#inspectorDelegate.addQuery(q.id, q.ast);
|
|
996
1371
|
queryCoveringIndex?.add(q.id, {
|
|
@@ -1004,18 +1379,43 @@ var ViewSyncerService = class {
|
|
|
1004
1379
|
transformationHash: q.transformationHash,
|
|
1005
1380
|
...q.name !== void 0 && { name: q.name }
|
|
1006
1381
|
});
|
|
1382
|
+
hydrations.add(1);
|
|
1383
|
+
hydrationTime.recordMs(elapsed);
|
|
1007
1384
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1385
|
+
}
|
|
1386
|
+
function* generateRowChanges(slowHydrateThreshold) {
|
|
1387
|
+
yield* hydrateQueries(requiredQueries, false, slowHydrateThreshold);
|
|
1388
|
+
yield* hydrateQueries(optionalQueries, true, slowHydrateThreshold);
|
|
1010
1389
|
}
|
|
1011
1390
|
await this.#processChanges(lc, timer, generateRowChanges(this.#slowHydrateThreshold), updater, pokers);
|
|
1391
|
+
const abortedQueries = [...timedOutQueries, ...rejectedQueries];
|
|
1392
|
+
if (abortedQueries.length > 0) {
|
|
1393
|
+
const abortedQueryIDs = abortedQueries.map(({ id }) => id);
|
|
1394
|
+
for (const patch of await updater.abortExecutedQueries(lc, abortedQueryIDs)) await pokers.addPatch(patch);
|
|
1395
|
+
for (const queryID of abortedQueryIDs) {
|
|
1396
|
+
this.#pipelines.removeQuery(queryID);
|
|
1397
|
+
this.#inspectorDelegate.removeQuery(queryID);
|
|
1398
|
+
this.#queryReplacements.delete(queryID);
|
|
1399
|
+
}
|
|
1400
|
+
if (timedOutQueries.length > 0) this.#queryEvictions.add(timedOutQueries.length, { reason: "hydration-timeout" });
|
|
1401
|
+
if (rejectedQueries.length > 0) this.#queryEvictions.add(rejectedQueries.length, { reason: "hydration-circuit-breaker" });
|
|
1402
|
+
this.#sendHydrationTimeoutErrors(cvr, abortedQueries);
|
|
1403
|
+
}
|
|
1404
|
+
for (const patch of updater.removeTrackedQueries(budgetEvictedQueryIDs)) await pokers.addPatch(patch);
|
|
1405
|
+
for (const queryID of budgetEvictedQueryIDs) {
|
|
1406
|
+
this.#pipelines.removeQuery(queryID);
|
|
1407
|
+
this.#inspectorDelegate.removeQuery(queryID);
|
|
1408
|
+
this.#queryReplacements.delete(queryID);
|
|
1409
|
+
}
|
|
1410
|
+
this.#recordHydrationBudgetExhaustion(lc, hydrationBudget, hydrationPassStats.activeHydratedQueries, hydrationPassStats.inactiveHydratedQueries, budgetEvictedQueryIDs);
|
|
1012
1411
|
this.#logQueryCoverageShadowSummary(lc, "add", totalHydratedQueries, coveredHydratedQueries, firstCoveredQuery);
|
|
1013
1412
|
await startAsyncSpan(tracer, "vs.#syncQueryPipelineSet.deleteUnreferencedRows", async () => {
|
|
1014
1413
|
for (const patch of await updater.deleteUnreferencedRows(lc)) await pokers.addPatch(patch);
|
|
1015
1414
|
});
|
|
1016
1415
|
this.#cvr = await this.#flushUpdater(lc, updater);
|
|
1416
|
+
if (budgetEvictedQueryIDs.length > 0) this.#scheduleExpireEviction(lc, this.#cvr);
|
|
1017
1417
|
const finalVersion = this.#cvr.version;
|
|
1018
|
-
await this.#catchupClients(lc, cvr, finalVersion,
|
|
1418
|
+
await this.#catchupClients(lc, cvr, finalVersion, hydratedQueryIDs, pokers);
|
|
1019
1419
|
await startAsyncSpan(tracer, "vs.#syncQueryPipelineSet.pokeEnd", () => pokers.end(finalVersion));
|
|
1020
1420
|
this.#markVersionServed(stateVersion);
|
|
1021
1421
|
const wallTime = performance.now() - start;
|
|
@@ -1044,7 +1444,7 @@ var ViewSyncerService = class {
|
|
|
1044
1444
|
return startAsyncSpan(tracer, "vs.#catchupClients", async (span) => {
|
|
1045
1445
|
current ??= cvr.version;
|
|
1046
1446
|
const clients = this.#getClients();
|
|
1047
|
-
const pokers = usePokers ?? startPoke(clients, cvr.version);
|
|
1447
|
+
const pokers = usePokers ?? startPoke(lc, clients, cvr.version);
|
|
1048
1448
|
span.setAttribute("numClients", clients.length);
|
|
1049
1449
|
const catchupFrom = clients.map((c) => c.version()).reduce((a, b) => cmpVersions(a, b) < 0 ? a : b, cvr.version);
|
|
1050
1450
|
const rowPatches = this.#cvrStore.catchupRowPatches(lc, catchupFrom, cvr, current, excludeQueryHashes);
|
|
@@ -1156,7 +1556,9 @@ var ViewSyncerService = class {
|
|
|
1156
1556
|
*
|
|
1157
1557
|
* Must be called from within the #lock.
|
|
1158
1558
|
*
|
|
1159
|
-
* Returns
|
|
1559
|
+
* Returns 'success' if changes were successfully processed and poked,
|
|
1560
|
+
* or a `ResetPipelinesSignal` if advancement aborted (e.g. schema change,
|
|
1561
|
+
* timeout) and pipelines need to be reset and rehydrated.
|
|
1160
1562
|
*/
|
|
1161
1563
|
#advancePipelines(lc, cvr) {
|
|
1162
1564
|
return startAsyncSpan(tracer, "vs.#advancePipelines", async (span) => {
|
|
@@ -1164,20 +1566,27 @@ var ViewSyncerService = class {
|
|
|
1164
1566
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (advancePipelines");
|
|
1165
1567
|
const start = performance.now();
|
|
1166
1568
|
const timer = new TimeSliceTimer(lc);
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
lc.debug?.(`applying ${numChanges} to advance to ${version}`);
|
|
1569
|
+
let pokers;
|
|
1570
|
+
let updater;
|
|
1571
|
+
let version;
|
|
1572
|
+
let numChanges = 0;
|
|
1172
1573
|
try {
|
|
1173
|
-
|
|
1574
|
+
const advancement = this.#pipelines.advance(timer);
|
|
1575
|
+
version = advancement.version;
|
|
1576
|
+
numChanges = advancement.numChanges;
|
|
1577
|
+
lc = lc.withContext("newVersion", version);
|
|
1578
|
+
updater = new CVRQueryDrivenUpdater(this.#cvrStore, cvr, version, this.#pipelines.replicaVersion, (queryID) => this.#pipelines.rowSetSignature(queryID));
|
|
1579
|
+
pokers = startPoke(lc, this.#getClients(cvr.version), updater.updatedVersion());
|
|
1580
|
+
lc.debug?.(`applying ${numChanges} to advance to ${version}`);
|
|
1581
|
+
await this.#processChanges(lc, await timer.start(), advancement.changes, updater, pokers);
|
|
1174
1582
|
} catch (e) {
|
|
1175
1583
|
if (e instanceof ResetPipelinesSignal) {
|
|
1176
|
-
await pokers
|
|
1584
|
+
await pokers?.cancel();
|
|
1177
1585
|
return e;
|
|
1178
1586
|
}
|
|
1179
1587
|
throw e;
|
|
1180
1588
|
}
|
|
1589
|
+
assert(updater && pokers && version !== void 0, "advancement state missing");
|
|
1181
1590
|
this.#cvr = await this.#flushUpdater(lc, updater);
|
|
1182
1591
|
const finalVersion = this.#cvr.version;
|
|
1183
1592
|
await startAsyncSpan(tracer, "vs.#advancePipelines.pokeEnd", () => pokers.end(finalVersion));
|
|
@@ -1198,7 +1607,7 @@ var ViewSyncerService = class {
|
|
|
1198
1607
|
clientID,
|
|
1199
1608
|
wsID: client.wsID
|
|
1200
1609
|
});
|
|
1201
|
-
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, connCtx);
|
|
1610
|
+
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this, this.#cvrStore, this.#config, connCtx);
|
|
1202
1611
|
};
|
|
1203
1612
|
async #runBackgroundRetransform(lc) {
|
|
1204
1613
|
const attemptRetransform = async (connCtx) => {
|
|
@@ -1285,15 +1694,18 @@ var ViewSyncerService = class {
|
|
|
1285
1694
|
return this.#stopped.promise;
|
|
1286
1695
|
}
|
|
1287
1696
|
async #cleanup(err) {
|
|
1697
|
+
this.#shuttingDown = true;
|
|
1288
1698
|
this.connContextManager.setSharedRetransformReady(false);
|
|
1289
1699
|
this.#stopTTLClockInterval();
|
|
1290
1700
|
this.#stopExpireTimer();
|
|
1291
1701
|
this.#stopAuthMaintenanceTimer();
|
|
1702
|
+
this.#stopShutdownTimer();
|
|
1292
1703
|
this.#customQueryTransformer?.destroy();
|
|
1293
1704
|
for (const client of this.#clients.values()) if (err) client.fail(err);
|
|
1294
1705
|
else client.close(`closed clientGroupID=${this.id}`);
|
|
1295
1706
|
await this.#lock.withLock(() => {});
|
|
1296
1707
|
this.#pipelines.destroy();
|
|
1708
|
+
this.#inspectorDelegate.clearAuthenticated(this.id, this);
|
|
1297
1709
|
}
|
|
1298
1710
|
/**
|
|
1299
1711
|
* Test helper: Manually mark initialization as complete.
|
|
@@ -1329,8 +1741,10 @@ function isTransformFailedError(error) {
|
|
|
1329
1741
|
return error.errorBody.kind === "TransformFailed" && !isAuthErrorBody(error.errorBody);
|
|
1330
1742
|
}
|
|
1331
1743
|
/**
|
|
1332
|
-
* A query must be expired for all clients
|
|
1333
|
-
* expired.
|
|
1744
|
+
* Whether a query's TTL has elapsed. A query must be expired for all clients
|
|
1745
|
+
* in order to be considered expired.
|
|
1746
|
+
*
|
|
1747
|
+
* Exported for testing.
|
|
1334
1748
|
*/
|
|
1335
1749
|
function expired(ttlClock, q) {
|
|
1336
1750
|
if (q.type === "internal") return false;
|