@rocicorp/zero 1.12.0-canary.0 → 1.12.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/_virtual/{_@oxc-project_runtime@0.130.0/helpers → _@oxc-project_runtime@0.154.0/helpers/esm}/usingCtx.js +2 -2
- package/out/analyze-query/src/analyze-cli.d.ts.map +1 -1
- package/out/analyze-query/src/analyze-cli.js +4 -2
- package/out/analyze-query/src/analyze-cli.js.map +1 -1
- package/out/analyze-query/src/bin-transform.js +4 -3
- package/out/analyze-query/src/bin-transform.js.map +1 -1
- package/out/analyze-query/src/zql-chain.d.ts +23 -0
- package/out/analyze-query/src/zql-chain.d.ts.map +1 -0
- package/out/analyze-query/src/zql-chain.js +162 -0
- package/out/analyze-query/src/zql-chain.js.map +1 -0
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/ast-to-zql/src/bin.js +4 -3
- package/out/ast-to-zql/src/bin.js.map +1 -1
- package/out/ast-to-zql/src/format.js.map +1 -1
- package/out/datadog/src/datadog-log-sink.js +5 -4
- package/out/datadog/src/datadog-log-sink.js.map +1 -1
- package/out/otel/src/log-options.js.map +1 -1
- package/out/replicache/src/btree/node.d.ts +0 -2
- package/out/replicache/src/btree/node.d.ts.map +1 -1
- package/out/replicache/src/btree/node.js +14 -12
- package/out/replicache/src/btree/node.js.map +1 -1
- package/out/replicache/src/btree/read.js +4 -2
- package/out/replicache/src/btree/read.js.map +1 -1
- package/out/replicache/src/btree/splice.js.map +1 -1
- package/out/replicache/src/btree/write.js +9 -5
- package/out/replicache/src/btree/write.js.map +1 -1
- package/out/replicache/src/config.js +1 -2
- package/out/replicache/src/connection-loop.d.ts.map +1 -1
- package/out/replicache/src/connection-loop.js +1 -1
- package/out/replicache/src/connection-loop.js.map +1 -1
- package/out/replicache/src/dag/chunk.js +1 -1
- package/out/replicache/src/dag/gc.js.map +1 -1
- package/out/replicache/src/dag/lazy-store.js +8 -7
- package/out/replicache/src/dag/lazy-store.js.map +1 -1
- package/out/replicache/src/dag/store-impl.js +1 -1
- package/out/replicache/src/dag/store-impl.js.map +1 -1
- package/out/replicache/src/dag/visitor.js.map +1 -1
- package/out/replicache/src/db/commit.d.ts +0 -1
- package/out/replicache/src/db/commit.d.ts.map +1 -1
- package/out/replicache/src/db/commit.js +5 -3
- package/out/replicache/src/db/commit.js.map +1 -1
- package/out/replicache/src/db/read.js +1 -1
- package/out/replicache/src/db/read.js.map +1 -1
- package/out/replicache/src/db/rebase.js.map +1 -1
- package/out/replicache/src/db/write.d.ts +0 -2
- package/out/replicache/src/db/write.d.ts.map +1 -1
- package/out/replicache/src/db/write.js +5 -2
- package/out/replicache/src/db/write.js.map +1 -1
- package/out/replicache/src/deleted-clients.d.ts +0 -2
- package/out/replicache/src/deleted-clients.d.ts.map +1 -1
- package/out/replicache/src/deleted-clients.js +5 -3
- package/out/replicache/src/deleted-clients.js.map +1 -1
- package/out/replicache/src/expo-sqlite.js +1 -2
- package/out/replicache/src/frozen-json.d.ts +0 -1
- package/out/replicache/src/frozen-json.d.ts.map +1 -1
- package/out/replicache/src/frozen-json.js +1 -1
- package/out/replicache/src/frozen-json.js.map +1 -1
- package/out/replicache/src/get-default-puller.js +1 -1
- package/out/replicache/src/hash.js +1 -1
- package/out/replicache/src/hash.js.map +1 -1
- package/out/replicache/src/impl.js +1 -2
- package/out/replicache/src/index-defs.d.ts +0 -2
- package/out/replicache/src/index-defs.d.ts.map +1 -1
- package/out/replicache/src/index-defs.js +5 -3
- package/out/replicache/src/index-defs.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts +0 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/idb-store.js +2 -2
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-fallback-store.js +1 -1
- package/out/replicache/src/kv/mem-fallback-store.js.map +1 -1
- package/out/replicache/src/kv/mem-store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/types.js.map +1 -1
- package/out/replicache/src/kv/read-impl.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +8 -4
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/throw-if-closed.d.ts +0 -3
- package/out/replicache/src/kv/throw-if-closed.d.ts.map +1 -1
- package/out/replicache/src/kv/throw-if-closed.js.map +1 -1
- package/out/replicache/src/kv/write-impl-base.js +4 -1
- package/out/replicache/src/kv/write-impl-base.js.map +1 -1
- package/out/replicache/src/kv/write-impl.js.map +1 -1
- package/out/replicache/src/log-options.js +2 -1
- package/out/replicache/src/log-options.js.map +1 -1
- package/out/replicache/src/make-idb-name.js +1 -1
- package/out/replicache/src/new-client-channel.js +9 -7
- package/out/replicache/src/new-client-channel.js.map +1 -1
- package/out/replicache/src/on-persist-channel.js +1 -1
- package/out/replicache/src/on-persist-channel.js.map +1 -1
- package/out/replicache/src/op-sqlite.js +1 -2
- package/out/replicache/src/pending-mutations.js +2 -1
- package/out/replicache/src/pending-mutations.js.map +1 -1
- package/out/replicache/src/persist/client-gc.js +2 -2
- package/out/replicache/src/persist/client-gc.js.map +1 -1
- package/out/replicache/src/persist/client-group-gc.d.ts +0 -7
- package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
- package/out/replicache/src/persist/client-group-gc.js +1 -1
- package/out/replicache/src/persist/client-group-gc.js.map +1 -1
- package/out/replicache/src/persist/client-groups.js +1 -1
- package/out/replicache/src/persist/client-groups.js.map +1 -1
- package/out/replicache/src/persist/clients.js +1 -1
- package/out/replicache/src/persist/clients.js.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +5 -4
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/gather-mem-only-visitor.js.map +1 -1
- package/out/replicache/src/persist/gather-not-cached-visitor.js.map +1 -1
- package/out/replicache/src/persist/heartbeat.js +2 -2
- package/out/replicache/src/persist/heartbeat.js.map +1 -1
- package/out/replicache/src/persist/idb-databases-store.js +1 -1
- package/out/replicache/src/persist/idb-databases-store.js.map +1 -1
- package/out/replicache/src/persist/make-client-id.js +1 -1
- package/out/replicache/src/persist/make-client-id.js.map +1 -1
- package/out/replicache/src/persist/persist.js +3 -2
- package/out/replicache/src/persist/persist.js.map +1 -1
- package/out/replicache/src/persist/refresh.js +8 -5
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/process-scheduler.js +1 -1
- package/out/replicache/src/process-scheduler.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +2 -7
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +21 -18
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/scan-iterator.js.map +1 -1
- package/out/replicache/src/scan-options.js +7 -6
- package/out/replicache/src/scan-options.js.map +1 -1
- package/out/replicache/src/sqlite.js +1 -2
- package/out/replicache/src/subscriptions.js +1 -1
- package/out/replicache/src/subscriptions.js.map +1 -1
- package/out/replicache/src/sync/diff.js +3 -1
- package/out/replicache/src/sync/diff.js.map +1 -1
- package/out/replicache/src/sync/ids.js.map +1 -1
- package/out/replicache/src/sync/patch.d.ts +0 -5
- package/out/replicache/src/sync/patch.d.ts.map +1 -1
- package/out/replicache/src/sync/patch.js +2 -4
- package/out/replicache/src/sync/patch.js.map +1 -1
- package/out/replicache/src/sync/pull.d.ts +0 -1
- package/out/replicache/src/sync/pull.d.ts.map +1 -1
- package/out/replicache/src/sync/pull.js +3 -1
- package/out/replicache/src/sync/pull.js.map +1 -1
- package/out/replicache/src/sync/push.d.ts +2 -1
- package/out/replicache/src/sync/push.d.ts.map +1 -1
- package/out/replicache/src/sync/push.js.map +1 -1
- package/out/replicache/src/sync/request-id.js +1 -1
- package/out/replicache/src/sync/request-id.js.map +1 -1
- package/out/replicache/src/transactions.js +1 -1
- package/out/replicache/src/transactions.js.map +1 -1
- package/out/replicache/src/types.d.ts +2 -1
- package/out/replicache/src/types.d.ts.map +1 -1
- package/out/shared/src/arrays.js +4 -1
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/asserts.d.ts +0 -5
- package/out/shared/src/asserts.d.ts.map +1 -1
- package/out/shared/src/asserts.js.map +1 -1
- package/out/shared/src/bigint-json.d.ts +9 -0
- package/out/shared/src/bigint-json.d.ts.map +1 -1
- package/out/shared/src/bigint-json.js +27 -2
- package/out/shared/src/bigint-json.js.map +1 -1
- package/out/shared/src/broadcast-channel.js +1 -1
- package/out/shared/src/browser-env.d.ts +0 -17
- package/out/shared/src/browser-env.d.ts.map +1 -1
- package/out/shared/src/browser-env.js.map +1 -1
- package/out/shared/src/btree-set.js +11 -8
- package/out/shared/src/btree-set.js.map +1 -1
- package/out/shared/src/cache.js.map +1 -1
- package/out/shared/src/config.js +1 -1
- package/out/shared/src/custom-key-map.js.map +1 -1
- package/out/shared/src/custom-key-set.js.map +1 -1
- package/out/shared/src/deep-clone.d.ts +0 -1
- package/out/shared/src/deep-clone.d.ts.map +1 -1
- package/out/shared/src/deep-clone.js.map +1 -1
- package/out/shared/src/document-visible.js +1 -1
- package/out/shared/src/document-visible.js.map +1 -1
- package/out/shared/src/dotenv.js.map +1 -1
- package/out/shared/src/error.js +1 -1
- package/out/shared/src/error.js.map +1 -1
- package/out/shared/src/expand.d.ts +0 -3
- package/out/shared/src/expand.d.ts.map +1 -1
- package/out/shared/src/hash.js +2 -2
- package/out/shared/src/hash.js.map +1 -1
- package/out/shared/src/immutable.d.ts +1 -1
- package/out/shared/src/immutable.d.ts.map +1 -1
- package/out/shared/src/iterables.d.ts +0 -1
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/json-schema.js.map +1 -1
- package/out/shared/src/json.js.map +1 -1
- package/out/shared/src/logging-test-utils.js.map +1 -1
- package/out/shared/src/logging.js +1 -1
- package/out/shared/src/logging.js.map +1 -1
- package/out/shared/src/navigator.js +1 -1
- package/out/shared/src/options-types.d.ts +1 -1
- package/out/shared/src/options-types.d.ts.map +1 -1
- package/out/shared/src/options.d.ts +2 -3
- package/out/shared/src/options.d.ts.map +1 -1
- package/out/shared/src/options.js +8 -11
- package/out/shared/src/options.js.map +1 -1
- package/out/shared/src/promise-race.js +1 -1
- package/out/shared/src/promise-race.js.map +1 -1
- package/out/shared/src/queue.js +1 -1
- package/out/shared/src/queue.js.map +1 -1
- package/out/shared/src/record-proxy.js.map +1 -1
- package/out/shared/src/resolved-promises.d.ts +0 -4
- package/out/shared/src/resolved-promises.d.ts.map +1 -1
- package/out/shared/src/resolved-promises.js +0 -1
- package/out/shared/src/resolved-promises.js.map +1 -1
- package/out/shared/src/resolver.d.ts +9 -0
- package/out/shared/src/resolver.d.ts.map +1 -0
- package/out/shared/src/resolver.js +6 -0
- package/out/shared/src/resolver.js.map +1 -0
- package/out/shared/src/ring-buffer.js.map +1 -1
- package/out/shared/src/size-of-value.js +7 -10
- package/out/shared/src/size-of-value.js.map +1 -1
- package/out/shared/src/sleep.js +1 -1
- package/out/shared/src/sleep.js.map +1 -1
- package/out/shared/src/sorted-entries.js.map +1 -1
- package/out/shared/src/tdigest-schema.js.map +1 -1
- package/out/shared/src/tdigest.d.ts +0 -1
- package/out/shared/src/tdigest.d.ts.map +1 -1
- package/out/shared/src/tdigest.js.map +1 -1
- package/out/shared/src/valita.js +1 -1
- package/out/shared/src/valita.js.map +1 -1
- package/out/z2s/src/compiler.js +5 -7
- package/out/z2s/src/compiler.js.map +1 -1
- package/out/z2s/src/sql.d.ts +1 -5
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +1 -1
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +210 -189
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/adapters/drizzle.js +1 -2
- package/out/zero/src/adapters/kysely.js +1 -2
- package/out/zero/src/adapters/pg.js +1 -2
- package/out/zero/src/adapters/postgresjs.js +1 -2
- package/out/zero/src/adapters/prisma.js +1 -2
- package/out/zero/src/analyze.js +1 -2
- package/out/zero/src/change-protocol/v0.js +1 -2
- package/out/zero/src/expo-sqlite.js +1 -2
- package/out/zero/src/op-sqlite.js +1 -2
- package/out/zero/src/react-native.js.map +1 -1
- package/out/zero/src/sqlite.js +1 -2
- package/out/zero/src/zero-cache-dev.js +11 -10
- package/out/zero/src/zero-cache-dev.js.map +1 -1
- package/out/zero/src/zero-out.js +2 -1
- package/out/zero/src/zero-out.js.map +1 -1
- package/out/zero-cache/src/auth/auth.js +1 -1
- package/out/zero-cache/src/auth/auth.js.map +1 -1
- package/out/zero-cache/src/auth/jwt.js +4 -1
- package/out/zero-cache/src/auth/jwt.js.map +1 -1
- package/out/zero-cache/src/auth/load-permissions.js +1 -1
- package/out/zero-cache/src/auth/load-permissions.js.map +1 -1
- package/out/zero-cache/src/auth/read-authorizer.js +3 -2
- package/out/zero-cache/src/auth/read-authorizer.js.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +15 -19
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/network.js +1 -1
- package/out/zero-cache/src/config/network.js.map +1 -1
- package/out/zero-cache/src/config/server-context.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +19 -11
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +47 -10
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom/fetch.js +1 -1
- package/out/zero-cache/src/custom/fetch.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/db/create.js.map +1 -1
- package/out/zero-cache/src/db/index-predicate.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.d.ts +2 -2
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/db/migration-lite.js +1 -1
- package/out/zero-cache/src/db/migration-lite.js.map +1 -1
- package/out/zero-cache/src/db/migration.js +5 -3
- package/out/zero-cache/src/db/migration.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy-binary.js +4 -3
- package/out/zero-cache/src/db/pg-copy-binary.js.map +1 -1
- package/out/zero-cache/src/db/pg-copy.js +0 -1
- package/out/zero-cache/src/db/pg-copy.js.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
- package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
- package/out/zero-cache/src/db/run-transaction.js.map +1 -1
- package/out/zero-cache/src/db/specs.d.ts +3 -4
- package/out/zero-cache/src/db/specs.d.ts.map +1 -1
- package/out/zero-cache/src/db/specs.js +1 -1
- package/out/zero-cache/src/db/specs.js.map +1 -1
- package/out/zero-cache/src/db/sqlite-corruption.js.map +1 -1
- package/out/zero-cache/src/db/statements.d.ts.map +1 -1
- package/out/zero-cache/src/db/statements.js +9 -2
- package/out/zero-cache/src/db/statements.js.map +1 -1
- package/out/zero-cache/src/db/transaction-pool.js +6 -4
- package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
- package/out/zero-cache/src/db/warmup.js.map +1 -1
- package/out/zero-cache/src/observability/events.js +1 -1
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/observability/log-throttle.js.map +1 -1
- package/out/zero-cache/src/observability/metrics.js.map +1 -1
- package/out/zero-cache/src/scripts/decommission.js +1 -1
- package/out/zero-cache/src/scripts/deploy-permissions.js +5 -3
- package/out/zero-cache/src/scripts/deploy-permissions.js.map +1 -1
- package/out/zero-cache/src/scripts/permissions.js.map +1 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js +2 -1
- package/out/zero-cache/src/server/anonymous-otel-start.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +49 -16
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/logging.js +1 -1
- package/out/zero-cache/src/server/logging.js.map +1 -1
- package/out/zero-cache/src/server/main.js +2 -2
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/otel-log-sink.js.map +1 -1
- package/out/zero-cache/src/server/otel-start.js.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -2
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.js +1 -1
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/run-worker.js +4 -3
- package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
- package/out/zero-cache/src/server/runner/runtime.js +2 -1
- package/out/zero-cache/src/server/runner/runtime.js.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts +9 -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 +29 -2
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js +1 -1
- package/out/zero-cache/src/server/shadow-syncer.js.map +1 -1
- package/out/zero-cache/src/server/slot-keeper.js.map +1 -1
- package/out/zero-cache/src/server/syncer-assigner.js.map +1 -1
- package/out/zero-cache/src/server/syncer.js +10 -5
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/worker-urls.js.map +1 -1
- package/out/zero-cache/src/services/analyze.js +2 -2
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +3 -3
- 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.js +1 -1
- 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/init-cleanup.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +4 -4
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +4 -4
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +52 -27
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +70 -15
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js +2 -1
- package/out/zero-cache/src/services/change-source/pg/decommission.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/fork-request.js +54 -0
- package/out/zero-cache/src/services/change-source/pg/fork-request.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +9 -7
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +5 -4
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/lsn.d.ts +0 -2
- package/out/zero-cache/src/services/change-source/pg/lsn.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/lsn.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js +9 -3
- 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/ddl.d.ts +0 -12
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +6 -4
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts +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 +13 -12
- 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.js +1 -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/published.js +2 -2
- package/out/zero-cache/src/services/change-source/pg/schema/published.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +10 -7
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts +0 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/validation.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/downstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts +3 -0
- package/out/zero-cache/src/services/change-source/protocol/current/status.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.js +2 -1
- package/out/zero-cache/src/services/change-source/protocol/current/status.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/upstream.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current.js +1 -1
- package/out/zero-cache/src/services/change-source/protocol/mod.js +1 -2
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.js +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +6 -6
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js +56 -21
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +2 -2
- package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js +2 -3
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +3 -3
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +8 -4
- 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.js +85 -59
- 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.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/drain-tracker.js +1 -1
- package/out/zero-cache/src/services/change-streamer/drain-tracker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.js +11 -10
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +81 -12
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js +4 -4
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/replica-poller.js +2 -2
- package/out/zero-cache/src/services/change-streamer/replica-poller.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.js +12 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.js +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/server-start-metrics.js +42 -0
- package/out/zero-cache/src/services/change-streamer/server-start-metrics.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js +1 -2
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js +2 -2
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js +2 -2
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js +4 -6
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +3 -5
- 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.js +4 -4
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +8 -7
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js +0 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
- package/out/zero-cache/src/services/heapz.js +2 -1
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/http-service.d.ts +2 -2
- package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/http-service.js +6 -4
- package/out/zero-cache/src/services/http-service.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +3 -3
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.js +4 -2
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +4 -4
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +2 -2
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
- package/out/zero-cache/src/services/litestream/metrics.js.map +1 -1
- package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +3 -4
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +61 -17
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.d.ts +4 -12
- package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
- package/out/zero-cache/src/services/plannerz.js +6 -7
- package/out/zero-cache/src/services/plannerz.js.map +1 -1
- package/out/zero-cache/src/services/profz.js +5 -3
- package/out/zero-cache/src/services/profz.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-cookies.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-db.js +4 -3
- 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.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/drain-handler.js +1 -1
- package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +4 -4
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/notifier.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +4 -3
- 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/reporter/recorder.js +2 -2
- package/out/zero-cache/src/services/replicator/reporter/recorder.js.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts +2 -11
- package/out/zero-cache/src/services/replicator/reporter/report-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/reporter/report-schema.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.js +2 -2
- package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts +19 -17
- package/out/zero-cache/src/services/replicator/schema/change-log.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/change-log.js +31 -15
- package/out/zero-cache/src/services/replicator/schema/change-log.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts +0 -7
- package/out/zero-cache/src/services/replicator/schema/column-metadata.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js +1 -1
- package/out/zero-cache/src/services/replicator/schema/column-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/replication-state.js +10 -7
- package/out/zero-cache/src/services/replicator/schema/replication-state.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/table-metadata.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js +2 -2
- package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker.js +3 -3
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +1 -1
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/runner.js.map +1 -1
- package/out/zero-cache/src/services/running-state.js +1 -1
- package/out/zero-cache/src/services/running-state.js.map +1 -1
- package/out/zero-cache/src/services/shadow-sync/shadow-sync-service.js.map +1 -1
- package/out/zero-cache/src/services/statz.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +5 -4
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js +2 -2
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +71 -24
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.js +46 -6
- package/out/zero-cache/src/services/view-syncer/client-schema.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js +2 -2
- package/out/zero-cache/src/services/view-syncer/cvr-purger.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +12 -7
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +12 -4
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +2 -2
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +2 -2
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +6 -4
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +13 -10
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.js +1 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +2 -2
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.js +2 -16
- package/out/zero-cache/src/services/view-syncer/schema/types.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +7 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +12 -8
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/ttl-clock.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +52 -28
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/error-with-level.js.map +1 -1
- package/out/zero-cache/src/types/lexi-version.js.map +1 -1
- package/out/zero-cache/src/types/lite.d.ts +0 -1
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +1 -1
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/pg-data-type.js +1 -1
- package/out/zero-cache/src/types/pg-data-type.js.map +1 -1
- package/out/zero-cache/src/types/pg-types.d.ts +0 -40
- package/out/zero-cache/src/types/pg-types.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg-types.js.map +1 -1
- package/out/zero-cache/src/types/pg.js +6 -4
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.d.ts +0 -1
- package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.js +1 -1
- package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
- package/out/zero-cache/src/types/processes.js +1 -1
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/profiler.js +1 -1
- package/out/zero-cache/src/types/profiler.js.map +1 -1
- package/out/zero-cache/src/types/row-key.d.ts +0 -5
- package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/types/sql.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts.map +1 -1
- package/out/zero-cache/src/types/streams.js +11 -10
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/types/strings.js.map +1 -1
- package/out/zero-cache/src/types/subscription.js +1 -1
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/types/timeout.js +1 -1
- package/out/zero-cache/src/types/websocket-handoff.d.ts +4 -7
- package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js +16 -2
- package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
- package/out/zero-cache/src/types/ws.d.ts +2 -1
- package/out/zero-cache/src/types/ws.d.ts.map +1 -1
- package/out/zero-cache/src/types/ws.js.map +1 -1
- package/out/zero-cache/src/workers/connection.d.ts +1 -2
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js +5 -3
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/mutator.js +1 -1
- package/out/zero-cache/src/workers/mutator.js.map +1 -1
- package/out/zero-cache/src/workers/rehome.d.ts +15 -0
- package/out/zero-cache/src/workers/rehome.d.ts.map +1 -0
- package/out/zero-cache/src/workers/rehome.js +36 -0
- package/out/zero-cache/src/workers/rehome.js.map +1 -0
- package/out/zero-cache/src/workers/replicator.js +5 -4
- package/out/zero-cache/src/workers/replicator.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +9 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +30 -5
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/active-clients-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/active-clients-manager.js +2 -2
- package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/bindings.js +11 -11
- package/out/zero-client/src/client/connection-manager.js +1 -1
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection.js +1 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/crud-impl.js +1 -1
- package/out/zero-client/src/client/crud-impl.js.map +1 -1
- package/out/zero-client/src/client/crud.d.ts +2 -8
- package/out/zero-client/src/client/crud.d.ts.map +1 -1
- package/out/zero-client/src/client/crud.js.map +1 -1
- package/out/zero-client/src/client/custom.d.ts +0 -2
- package/out/zero-client/src/client/custom.d.ts.map +1 -1
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/delete-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/enable-analytics.d.ts +0 -1
- package/out/zero-client/src/client/enable-analytics.d.ts.map +1 -1
- package/out/zero-client/src/client/enable-analytics.js +1 -0
- package/out/zero-client/src/client/enable-analytics.js.map +1 -1
- package/out/zero-client/src/client/error.d.ts +4 -5
- package/out/zero-client/src/client/error.d.ts.map +1 -1
- package/out/zero-client/src/client/error.js.map +1 -1
- package/out/zero-client/src/client/inspector/client-group.js.map +1 -1
- package/out/zero-client/src/client/inspector/client.js.map +1 -1
- package/out/zero-client/src/client/inspector/html-dialog-prompt.js +1 -1
- package/out/zero-client/src/client/inspector/html-dialog-prompt.js.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/query.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +1 -3
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/keys.d.ts +0 -1
- package/out/zero-client/src/client/keys.d.ts.map +1 -1
- package/out/zero-client/src/client/keys.js +6 -3
- package/out/zero-client/src/client/keys.js.map +1 -1
- package/out/zero-client/src/client/log-options.js.map +1 -1
- package/out/zero-client/src/client/make-replicache-mutators.js +5 -3
- package/out/zero-client/src/client/make-replicache-mutators.js.map +1 -1
- package/out/zero-client/src/client/metrics.js +3 -5
- package/out/zero-client/src/client/metrics.js.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.d.ts.map +1 -1
- package/out/zero-client/src/client/mutation-tracker.js +1 -1
- package/out/zero-client/src/client/mutation-tracker.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +0 -4
- 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.js +2 -2
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/reload-error-handler.js +4 -3
- package/out/zero-client/src/client/reload-error-handler.js.map +1 -1
- package/out/zero-client/src/client/replicache-types.d.ts +3 -2
- package/out/zero-client/src/client/replicache-types.d.ts.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.d.ts +1 -2
- package/out/zero-client/src/client/zero-poke-handler.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js +1 -1
- package/out/zero-client/src/client/zero-poke-handler.js.map +1 -1
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +1 -5
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +20 -12
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.js +23 -23
- package/out/zero-client/src/types/client-state.d.ts +0 -6
- package/out/zero-client/src/types/client-state.d.ts.map +1 -1
- package/out/zero-client/src/util/nanoid.js.map +1 -1
- package/out/zero-permissions/src/permissions.d.ts +1 -12
- package/out/zero-permissions/src/permissions.d.ts.map +1 -1
- package/out/zero-permissions/src/permissions.js +3 -3
- package/out/zero-permissions/src/permissions.js.map +1 -1
- package/out/zero-pg/src/mod.js +9 -9
- 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/application-error.js.map +1 -1
- package/out/zero-protocol/src/ast.d.ts +0 -4
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +21 -11
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.d.ts +0 -20
- package/out/zero-protocol/src/change-desired-queries.d.ts.map +1 -1
- package/out/zero-protocol/src/change-desired-queries.js.map +1 -1
- package/out/zero-protocol/src/client-schema.d.ts +2 -5
- package/out/zero-protocol/src/client-schema.d.ts.map +1 -1
- package/out/zero-protocol/src/client-schema.js.map +1 -1
- package/out/zero-protocol/src/close-connection.d.ts +0 -8
- package/out/zero-protocol/src/close-connection.d.ts.map +1 -1
- package/out/zero-protocol/src/close-connection.js.map +1 -1
- package/out/zero-protocol/src/connect.d.ts +0 -12
- package/out/zero-protocol/src/connect.d.ts.map +1 -1
- package/out/zero-protocol/src/connect.js.map +1 -1
- package/out/zero-protocol/src/custom-queries.d.ts +3 -17
- package/out/zero-protocol/src/custom-queries.d.ts.map +1 -1
- package/out/zero-protocol/src/custom-queries.js.map +1 -1
- package/out/zero-protocol/src/data.d.ts +0 -1
- package/out/zero-protocol/src/data.d.ts.map +1 -1
- package/out/zero-protocol/src/data.js +3 -1
- package/out/zero-protocol/src/data.js.map +1 -1
- package/out/zero-protocol/src/delete-clients.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +2 -2
- package/out/zero-protocol/src/down.js.map +1 -1
- package/out/zero-protocol/src/error.js.map +1 -1
- package/out/zero-protocol/src/inspect-down.d.ts +82 -84
- package/out/zero-protocol/src/inspect-down.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-down.js.map +1 -1
- package/out/zero-protocol/src/inspect-up.d.ts +0 -28
- package/out/zero-protocol/src/inspect-up.d.ts.map +1 -1
- package/out/zero-protocol/src/inspect-up.js.map +1 -1
- package/out/zero-protocol/src/mutate-server.d.ts +0 -21
- package/out/zero-protocol/src/mutate-server.d.ts.map +1 -1
- package/out/zero-protocol/src/mutate-server.js.map +1 -1
- package/out/zero-protocol/src/mutation-id.js.map +1 -1
- package/out/zero-protocol/src/mutation-type-enum.d.ts +0 -1
- package/out/zero-protocol/src/mutation-type-enum.d.ts.map +1 -1
- package/out/zero-protocol/src/mutation-type-enum.js.map +1 -1
- package/out/zero-protocol/src/mutation.d.ts +2 -4
- package/out/zero-protocol/src/mutation.d.ts.map +1 -1
- package/out/zero-protocol/src/mutation.js.map +1 -1
- package/out/zero-protocol/src/mutations-patch.d.ts +0 -33
- package/out/zero-protocol/src/mutations-patch.d.ts.map +1 -1
- package/out/zero-protocol/src/mutations-patch.js.map +1 -1
- package/out/zero-protocol/src/ping.d.ts +0 -2
- package/out/zero-protocol/src/ping.d.ts.map +1 -1
- package/out/zero-protocol/src/ping.js.map +1 -1
- package/out/zero-protocol/src/poke.d.ts +3 -2
- package/out/zero-protocol/src/poke.d.ts.map +1 -1
- package/out/zero-protocol/src/poke.js +1 -1
- package/out/zero-protocol/src/poke.js.map +1 -1
- package/out/zero-protocol/src/pong.d.ts +0 -2
- package/out/zero-protocol/src/pong.d.ts.map +1 -1
- package/out/zero-protocol/src/pong.js.map +1 -1
- package/out/zero-protocol/src/primary-key.js.map +1 -1
- package/out/zero-protocol/src/protocol-version.js +1 -0
- package/out/zero-protocol/src/protocol-version.js.map +1 -1
- package/out/zero-protocol/src/pull.d.ts +2 -7
- package/out/zero-protocol/src/pull.d.ts.map +1 -1
- package/out/zero-protocol/src/pull.js.map +1 -1
- package/out/zero-protocol/src/push.d.ts +1 -3
- package/out/zero-protocol/src/push.d.ts.map +1 -1
- package/out/zero-protocol/src/push.js.map +1 -1
- package/out/zero-protocol/src/queries-patch.d.ts +0 -16
- package/out/zero-protocol/src/queries-patch.d.ts.map +1 -1
- package/out/zero-protocol/src/queries-patch.js +1 -1
- package/out/zero-protocol/src/queries-patch.js.map +1 -1
- package/out/zero-protocol/src/query-hash-visitor.js.map +1 -1
- package/out/zero-protocol/src/query-hash.js +2 -2
- package/out/zero-protocol/src/query-server.d.ts +2 -41
- package/out/zero-protocol/src/query-server.d.ts.map +1 -1
- package/out/zero-protocol/src/query-server.js.map +1 -1
- package/out/zero-protocol/src/row-patch.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +60 -60
- package/out/zero-protocol/src/up.js +1 -1
- package/out/zero-protocol/src/up.js.map +1 -1
- package/out/zero-protocol/src/update-auth.js.map +1 -1
- package/out/zero-protocol/src/version.d.ts +0 -1
- package/out/zero-protocol/src/version.d.ts.map +1 -1
- package/out/zero-protocol/src/version.js.map +1 -1
- package/out/zero-react/src/bindings.js +11 -11
- package/out/zero-react/src/mod.js +5 -5
- package/out/zero-react/src/use-query.js +2 -2
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/zero-provider.d.ts +1 -1
- package/out/zero-react/src/zero-provider.d.ts.map +1 -1
- package/out/zero-react/src/zero-provider.js +2 -1
- package/out/zero-react/src/zero-provider.js.map +1 -1
- package/out/zero-react/src/zero.js +23 -23
- package/out/zero-schema/src/builder/relationship-builder.d.ts +0 -2
- package/out/zero-schema/src/builder/relationship-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/relationship-builder.js.map +1 -1
- package/out/zero-schema/src/builder/schema-builder.js +3 -2
- package/out/zero-schema/src/builder/schema-builder.js.map +1 -1
- package/out/zero-schema/src/builder/table-builder.d.ts +1 -1
- package/out/zero-schema/src/builder/table-builder.d.ts.map +1 -1
- package/out/zero-schema/src/builder/table-builder.js +1 -1
- package/out/zero-schema/src/builder/table-builder.js.map +1 -1
- package/out/zero-schema/src/compiled-permissions.js.map +1 -1
- package/out/zero-schema/src/name-mapper.js +7 -5
- package/out/zero-schema/src/name-mapper.js.map +1 -1
- package/out/zero-schema/src/schema-config.d.ts +0 -1
- package/out/zero-schema/src/schema-config.d.ts.map +1 -1
- package/out/zero-schema/src/schema-config.js +1 -1
- package/out/zero-schema/src/schema-config.js.map +1 -1
- package/out/zero-schema/src/table-schema.d.ts +3 -11
- package/out/zero-schema/src/table-schema.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/kysely.js.map +1 -1
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.js.map +1 -1
- package/out/zero-server/src/closable-db-transaction.js.map +1 -1
- package/out/zero-server/src/custom.js +1 -1
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/mod.js +8 -8
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/queries/process-queries.d.ts +2 -4
- package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
- package/out/zero-server/src/queries/process-queries.js +2 -1
- package/out/zero-server/src/queries/process-queries.js.map +1 -1
- package/out/zero-server/src/schema.js +7 -7
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/bindings.js +11 -11
- package/out/zero-solid/src/mod.js +5 -5
- package/out/zero-solid/src/solid-view.d.ts +0 -2
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +1 -1
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-connection-state.js +2 -1
- package/out/zero-solid/src/use-connection-state.js.map +1 -1
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/use-zero-online.js +2 -1
- package/out/zero-solid/src/use-zero-online.js.map +1 -1
- package/out/zero-solid/src/use-zero.js +3 -2
- package/out/zero-solid/src/use-zero.js.map +1 -1
- package/out/zero-solid/src/zero.js +23 -23
- package/out/zero-types/src/name-mapper.d.ts +2 -1
- package/out/zero-types/src/name-mapper.d.ts.map +1 -1
- package/out/zero-types/src/name-mapper.js.map +1 -1
- package/out/zero-types/src/schema-value.d.ts +3 -2
- package/out/zero-types/src/schema-value.d.ts.map +1 -1
- package/out/zero-types/src/schema.d.ts +1 -1
- package/out/zero-types/src/schema.d.ts.map +1 -1
- package/out/zql/src/builder/builder.d.ts +1 -11
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +15 -13
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -1
- package/out/zql/src/builder/debug-delegate.js.map +1 -1
- package/out/zql/src/builder/filter.d.ts +0 -1
- package/out/zql/src/builder/filter.d.ts.map +1 -1
- package/out/zql/src/builder/filter.js.map +1 -1
- package/out/zql/src/builder/like.js +0 -1
- package/out/zql/src/builder/like.js.map +1 -1
- package/out/zql/src/error.d.ts +0 -5
- package/out/zql/src/error.d.ts.map +1 -1
- package/out/zql/src/error.js.map +1 -1
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.d.ts +1 -1
- package/out/zql/src/ivm/cap.d.ts.map +1 -1
- package/out/zql/src/ivm/cap.js +12 -4
- package/out/zql/src/ivm/cap.js.map +1 -1
- package/out/zql/src/ivm/constraint.d.ts +0 -7
- package/out/zql/src/ivm/constraint.d.ts.map +1 -1
- package/out/zql/src/ivm/constraint.js +1 -1
- package/out/zql/src/ivm/constraint.js.map +1 -1
- package/out/zql/src/ivm/data.d.ts +15 -2
- package/out/zql/src/ivm/data.d.ts.map +1 -1
- package/out/zql/src/ivm/data.js +15 -1
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +32 -22
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +5 -0
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +1 -1
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter-push.js.map +1 -1
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +1 -3
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join-index-tap.js.map +1 -1
- package/out/zql/src/ivm/join-index.js.map +1 -1
- package/out/zql/src/ivm/join-utils.js +11 -13
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +6 -3
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +1 -2
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +27 -23
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/memory-storage.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +6 -0
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js +2 -2
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +0 -1
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/skip-yields.js.map +1 -1
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/stream.d.ts +0 -1
- package/out/zql/src/ivm/stream.d.ts.map +1 -1
- package/out/zql/src/ivm/stream.js.map +1 -1
- package/out/zql/src/ivm/take-gate.js.map +1 -1
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +7 -8
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +0 -1
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts +5 -35
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/mutate/crud.d.ts +1 -3
- package/out/zql/src/mutate/crud.d.ts.map +1 -1
- package/out/zql/src/mutate/crud.js +2 -1
- package/out/zql/src/mutate/crud.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/mutate/mutator.d.ts +1 -1
- package/out/zql/src/mutate/mutator.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator.js.map +1 -1
- package/out/zql/src/planner/planner-builder.js +1 -1
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts +10 -9
- 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-in.js.map +1 -1
- package/out/zql/src/planner/planner-fan-out.js.map +1 -1
- package/out/zql/src/planner/planner-filter.js.map +1 -1
- package/out/zql/src/planner/planner-graph.js +1 -5
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/planner/planner-join.js +1 -1
- package/out/zql/src/planner/planner-join.js.map +1 -1
- package/out/zql/src/planner/planner-node.d.ts +0 -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/planner/planner-source.js.map +1 -1
- package/out/zql/src/planner/planner-terminus.js.map +1 -1
- package/out/zql/src/planner/planner-warnings.d.ts +3 -3
- package/out/zql/src/planner/planner-warnings.d.ts.map +1 -1
- package/out/zql/src/planner/planner-warnings.js.map +1 -1
- package/out/zql/src/query/create-builder.js +2 -1
- package/out/zql/src/query/create-builder.js.map +1 -1
- package/out/zql/src/query/expression.d.ts +0 -22
- package/out/zql/src/query/expression.d.ts.map +1 -1
- package/out/zql/src/query/expression.js +1 -1
- package/out/zql/src/query/expression.js.map +1 -1
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/named.js +2 -1
- package/out/zql/src/query/named.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +0 -7
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +1 -1
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-delegate.d.ts +1 -4
- package/out/zql/src/query/query-delegate.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +3 -2
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-internals.d.ts +0 -3
- package/out/zql/src/query/query-internals.d.ts.map +1 -1
- package/out/zql/src/query/query-internals.js.map +1 -1
- package/out/zql/src/query/query-registry.d.ts +5 -5
- package/out/zql/src/query/query-registry.d.ts.map +1 -1
- package/out/zql/src/query/query-registry.js +1 -1
- package/out/zql/src/query/query-registry.js.map +1 -1
- package/out/zql/src/query/query-transitions.js +1 -1
- package/out/zql/src/query/query-transitions.js.map +1 -1
- package/out/zql/src/query/query.d.ts +2 -13
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +1 -19
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +2 -1
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/static-query.js.map +1 -1
- package/out/zql/src/query/ttl.d.ts +2 -3
- package/out/zql/src/query/ttl.d.ts.map +1 -1
- package/out/zql/src/query/ttl.js +8 -8
- package/out/zql/src/query/ttl.js.map +1 -1
- package/out/zql/src/query/validate-input.js.map +1 -1
- package/out/zqlite/src/database-storage.js +195 -26
- package/out/zqlite/src/database-storage.js.map +1 -1
- package/out/zqlite/src/db.d.ts +47 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +121 -21
- package/out/zqlite/src/db.js.map +1 -1
- package/out/zqlite/src/explain-queries.js.map +1 -1
- package/out/zqlite/src/fetch-sql.d.ts +27 -0
- package/out/zqlite/src/fetch-sql.d.ts.map +1 -0
- package/out/zqlite/src/fetch-sql.js +112 -0
- package/out/zqlite/src/fetch-sql.js.map +1 -0
- package/out/zqlite/src/index-usage.js.map +1 -1
- package/out/zqlite/src/internal/sql-inline.js.map +1 -1
- package/out/zqlite/src/internal/sql.js.map +1 -1
- package/out/zqlite/src/internal/statement-cache.d.ts +7 -0
- package/out/zqlite/src/internal/statement-cache.d.ts.map +1 -1
- package/out/zqlite/src/internal/statement-cache.js +11 -4
- package/out/zqlite/src/internal/statement-cache.js.map +1 -1
- package/out/zqlite/src/mod.js +5 -5
- package/out/zqlite/src/pending-delta.js.map +1 -1
- package/out/zqlite/src/query-builder.d.ts +11 -3
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +22 -7
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/query-delegate.js.map +1 -1
- package/out/zqlite/src/resolve-scalar-subqueries.js +2 -5
- package/out/zqlite/src/resolve-scalar-subqueries.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +3 -2
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/table-source.d.ts +20 -3
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +74 -40
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +39 -39
- package/out/analyze-query/src/bin-analyze.d.ts +0 -2
- package/out/analyze-query/src/bin-analyze.d.ts.map +0 -1
- package/out/analyze-query/src/bin-analyze.js +0 -283
- package/out/analyze-query/src/bin-analyze.js.map +0 -1
- package/out/otel/src/maybe-time.d.ts +0 -3
- package/out/otel/src/maybe-time.d.ts.map +0 -1
- package/out/otel/src/maybe-time.js +0 -15
- package/out/otel/src/maybe-time.js.map +0 -1
- package/out/shared/src/cache.d.ts +0 -22
- package/out/shared/src/cache.d.ts.map +0 -1
- package/out/shared/src/custom-key-map.d.ts +0 -26
- package/out/shared/src/custom-key-map.d.ts.map +0 -1
- package/out/shared/src/custom-key-set.d.ts +0 -25
- package/out/shared/src/custom-key-set.d.ts.map +0 -1
- package/out/shared/src/logging-test-utils.d.ts +0 -12
- package/out/shared/src/logging-test-utils.d.ts.map +0 -1
- package/out/shared/src/sorted-entries.d.ts +0 -2
- package/out/shared/src/sorted-entries.d.ts.map +0 -1
- package/out/zero/src/analyze-query.d.ts +0 -3
- package/out/zero/src/analyze-query.d.ts.map +0 -1
- package/out/zero/src/analyze-query.js +0 -3
- package/out/zero/src/server/change-streamer.d.ts +0 -2
- package/out/zero/src/server/change-streamer.d.ts.map +0 -1
- package/out/zero/src/server/main.d.ts +0 -2
- package/out/zero/src/server/main.d.ts.map +0 -1
- package/out/zero/src/server/reaper.d.ts +0 -2
- package/out/zero/src/server/reaper.d.ts.map +0 -1
- package/out/zero/src/server/replicator.d.ts +0 -2
- package/out/zero/src/server/replicator.d.ts.map +0 -1
- package/out/zero/src/server/syncer.d.ts +0 -2
- package/out/zero/src/server/syncer.d.ts.map +0 -1
- package/out/zero-cache/src/auth/jwt.d.ts +0 -12
- package/out/zero-cache/src/auth/jwt.d.ts.map +0 -1
- package/out/zero-cache/src/auth/load-permissions.d.ts +0 -17
- package/out/zero-cache/src/auth/load-permissions.d.ts.map +0 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts +0 -28
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +0 -1
- package/out/zero-cache/src/config/server-context.d.ts +0 -16
- package/out/zero-cache/src/config/server-context.d.ts.map +0 -1
- package/out/zero-cache/src/custom/fetch.d.ts +0 -38
- package/out/zero-cache/src/custom/fetch.d.ts.map +0 -1
- package/out/zero-cache/src/custom/metrics.d.ts +0 -31
- package/out/zero-cache/src/custom/metrics.d.ts.map +0 -1
- package/out/zero-cache/src/custom-queries/transform-query.d.ts +0 -68
- package/out/zero-cache/src/custom-queries/transform-query.d.ts.map +0 -1
- package/out/zero-cache/src/db/create.d.ts +0 -12
- package/out/zero-cache/src/db/create.d.ts.map +0 -1
- package/out/zero-cache/src/db/delete-lite-db.d.ts +0 -2
- package/out/zero-cache/src/db/delete-lite-db.d.ts.map +0 -1
- package/out/zero-cache/src/db/index-predicate.d.ts +0 -4
- package/out/zero-cache/src/db/index-predicate.d.ts.map +0 -1
- package/out/zero-cache/src/db/migration-lite.d.ts +0 -78
- package/out/zero-cache/src/db/migration-lite.d.ts.map +0 -1
- package/out/zero-cache/src/db/migration.d.ts +0 -80
- package/out/zero-cache/src/db/migration.d.ts.map +0 -1
- package/out/zero-cache/src/db/pg-copy-binary.d.ts +0 -101
- package/out/zero-cache/src/db/pg-copy-binary.d.ts.map +0 -1
- package/out/zero-cache/src/db/pg-copy.d.ts +0 -30
- package/out/zero-cache/src/db/pg-copy.d.ts.map +0 -1
- package/out/zero-cache/src/db/pg-type-parser.d.ts +0 -15
- package/out/zero-cache/src/db/pg-type-parser.d.ts.map +0 -1
- package/out/zero-cache/src/db/transaction-pool.d.ts +0 -205
- package/out/zero-cache/src/db/transaction-pool.d.ts.map +0 -1
- package/out/zero-cache/src/db/warmup.d.ts +0 -4
- package/out/zero-cache/src/db/warmup.d.ts.map +0 -1
- package/out/zero-cache/src/observability/events.d.ts +0 -15
- package/out/zero-cache/src/observability/events.d.ts.map +0 -1
- package/out/zero-cache/src/observability/log-throttle.d.ts +0 -44
- package/out/zero-cache/src/observability/log-throttle.d.ts.map +0 -1
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts +0 -21
- package/out/zero-cache/src/server/anonymous-otel-start.d.ts.map +0 -1
- package/out/zero-cache/src/server/change-streamer.d.ts +0 -3
- package/out/zero-cache/src/server/change-streamer.d.ts.map +0 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +0 -71
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +0 -1
- package/out/zero-cache/src/server/main.d.ts +0 -3
- package/out/zero-cache/src/server/main.d.ts.map +0 -1
- package/out/zero-cache/src/server/otel-diag-logger.d.ts +0 -16
- package/out/zero-cache/src/server/otel-diag-logger.d.ts.map +0 -1
- package/out/zero-cache/src/server/otel-start.d.ts +0 -3
- package/out/zero-cache/src/server/otel-start.d.ts.map +0 -1
- package/out/zero-cache/src/server/priority-op.d.ts +0 -8
- package/out/zero-cache/src/server/priority-op.d.ts.map +0 -1
- package/out/zero-cache/src/server/reaper.d.ts +0 -3
- package/out/zero-cache/src/server/reaper.d.ts.map +0 -1
- package/out/zero-cache/src/server/replicator.d.ts +0 -10
- package/out/zero-cache/src/server/replicator.d.ts.map +0 -1
- package/out/zero-cache/src/server/slot-keeper.d.ts +0 -26
- package/out/zero-cache/src/server/slot-keeper.d.ts.map +0 -1
- package/out/zero-cache/src/server/syncer.d.ts +0 -3
- package/out/zero-cache/src/server/syncer.d.ts.map +0 -1
- package/out/zero-cache/src/services/analyze.d.ts +0 -9
- package/out/zero-cache/src/services/analyze.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/change-source.d.ts +0 -32
- package/out/zero-cache/src/services/change-source/change-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts +0 -57
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts +0 -55
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +0 -24
- package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +0 -115
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +0 -14
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +0 -25
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts +0 -14
- package/out/zero-cache/src/services/change-source/pg/backfill-metadata.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +0 -36
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +0 -65
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +0 -115
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +0 -155
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts +0 -17
- package/out/zero-cache/src/services/change-source/pg/logical-replication/binary-reader.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts +0 -28
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput-parser.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts +0 -76
- package/out/zero-cache/src/services/change-source/pg/logical-replication/pgoutput.types.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +0 -169
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +0 -16
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts +0 -15
- package/out/zero-cache/src/services/change-source/pg/replication-slot-health.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +0 -127
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts +0 -9
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +0 -68
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +0 -72
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +0 -50
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts +0 -14
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts +0 -18
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +0 -98
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +0 -34
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts +0 -34
- package/out/zero-cache/src/services/change-streamer/change-log-compare-digest.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +0 -158
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts +0 -19
- package/out/zero-cache/src/services/change-streamer/change-log-transaction-hash.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -78
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +0 -139
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +0 -586
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts +0 -24
- package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts +0 -15
- package/out/zero-cache/src/services/change-streamer/error-type-enum.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +0 -49
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +0 -53
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts +0 -88
- package/out/zero-cache/src/services/change-streamer/litestream3-prometheus-poller.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts +0 -15
- package/out/zero-cache/src/services/change-streamer/replica-poller.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts +0 -243
- package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/schema/init.d.ts +0 -6
- package/out/zero-cache/src/services/change-streamer/schema/init.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +0 -152
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts +0 -11
- package/out/zero-cache/src/services/change-streamer/shard-sampling.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +0 -92
- package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +0 -36
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +0 -22
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts +0 -99
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-catchup.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts +0 -83
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-comparator.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts +0 -121
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-purge-scheduler.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts +0 -73
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-read-router.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts +0 -62
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-reader.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +0 -114
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +0 -276
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +0 -485
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +0 -194
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +0 -52
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +0 -1
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts +0 -57
- package/out/zero-cache/src/services/limiter/sliding-window-limiter.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +0 -77
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +0 -78
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/metrics.d.ts +0 -31
- package/out/zero-cache/src/services/litestream/metrics.d.ts.map +0 -1
- package/out/zero-cache/src/services/litestream/restore-progress.d.ts +0 -24
- package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +0 -1
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +0 -40
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +0 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts +0 -63
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/change-log-db.d.ts +0 -368
- package/out/zero-cache/src/services/replicator/change-log-db.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts +0 -56
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts +0 -37
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/drain-handler.d.ts +0 -82
- package/out/zero-cache/src/services/replicator/drain-handler.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +0 -25
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/notifier.d.ts +0 -9
- package/out/zero-cache/src/services/replicator/notifier.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts +0 -71
- package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts +0 -86
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts +0 -55
- package/out/zero-cache/src/services/replicator/reporter/recorder.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +0 -132
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts +0 -120
- package/out/zero-cache/src/services/replicator/sqlite-change-log-purger.d.ts.map +0 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +0 -111
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +0 -1
- package/out/zero-cache/src/services/run-ast.d.ts +0 -39
- package/out/zero-cache/src/services/run-ast.d.ts.map +0 -1
- package/out/zero-cache/src/services/runner.d.ts +0 -19
- package/out/zero-cache/src/services/runner.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts +0 -17
- package/out/zero-cache/src/services/view-syncer/active-users-gauge.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +0 -26
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts +0 -79
- package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +0 -79
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts +0 -5
- package/out/zero-cache/src/services/view-syncer/client-schema.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts +0 -184
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts +0 -22
- package/out/zero-cache/src/services/view-syncer/cvr-purger.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +0 -128
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +0 -294
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +0 -81
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +0 -45
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts +0 -53
- package/out/zero-cache/src/services/view-syncer/e2e-serving-lag.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +0 -33
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +0 -51
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +0 -34
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +0 -296
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +0 -7
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/push-cost.d.ts +0 -132
- package/out/zero-cache/src/services/view-syncer/push-cost.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts +0 -55
- package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.d.ts +0 -28
- package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +0 -25
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +0 -89
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts +0 -90
- package/out/zero-cache/src/services/view-syncer/row-record-cache.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts +0 -17
- package/out/zero-cache/src/services/view-syncer/row-set-signature.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts +0 -86
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.d.ts +0 -5
- package/out/zero-cache/src/services/view-syncer/schema/init.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts +0 -563
- package/out/zero-cache/src/services/view-syncer/schema/types.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +0 -95
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +0 -412
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/tracer.d.ts +0 -2
- package/out/zero-cache/src/services/view-syncer/tracer.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts +0 -10
- package/out/zero-cache/src/services/view-syncer/ttl-clock.d.ts.map +0 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +0 -133
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +0 -1
- package/out/zero-cache/src/types/pg-patch.d.ts +0 -21
- package/out/zero-cache/src/types/pg-patch.d.ts.map +0 -1
- package/out/zero-cache/src/types/pg-versions.d.ts +0 -3
- package/out/zero-cache/src/types/pg-versions.d.ts.map +0 -1
- package/out/zero-cache/src/workers/replicator.d.ts +0 -57
- package/out/zero-cache/src/workers/replicator.d.ts.map +0 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts +0 -14
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +0 -1
- package/out/zero-cache/src/workers/syncer.d.ts +0 -67
- package/out/zero-cache/src/workers/syncer.d.ts.map +0 -1
- package/out/zero-events/src/index.d.ts +0 -27
- package/out/zero-events/src/index.d.ts.map +0 -1
- package/out/zero-events/src/json.d.ts +0 -20
- package/out/zero-events/src/json.d.ts.map +0 -1
- package/out/zero-events/src/status.d.ts +0 -144
- package/out/zero-events/src/status.d.ts.map +0 -1
- package/out/zqlite/src/database-storage.d.ts +0 -24
- package/out/zqlite/src/database-storage.d.ts.map +0 -1
- package/out/zqlite/src/explain-queries.d.ts +0 -4
- package/out/zqlite/src/explain-queries.d.ts.map +0 -1
- package/out/zqlite/src/internal/sql-inline.d.ts +0 -13
- package/out/zqlite/src/internal/sql-inline.d.ts.map +0 -1
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts +0 -72
- package/out/zqlite/src/resolve-scalar-subqueries.d.ts.map +0 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts +0 -17
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +0 -1
- package/out/zqlite/src/sqlite-stat-fanout.d.ts +0 -121
- package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-dispatcher.js","names":[
|
|
1
|
+
{"version":3,"file":"worker-dispatcher.js","names":[],"sources":["../../../../../zero-cache/src/server/worker-dispatcher.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport UrlPattern from 'url-pattern';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport {\n getOrCreateCounter,\n getOrCreateGauge,\n} from '../observability/metrics.ts';\nimport {RunningState} from '../services/running-state.ts';\nimport type {Service} from '../services/service.ts';\nimport type {IncomingMessageSubset} from '../types/http.ts';\nimport type {ClientGroupStatusMessage, Worker} from '../types/processes.ts';\nimport {installWebSocketHandoff} from '../types/websocket-handoff.ts';\nimport {getConnectParams} from '../workers/connect-params.ts';\nimport {SyncerAssigner} from './syncer-assigner.ts';\n\nexport class WorkerDispatcher implements Service {\n readonly id = 'worker-dispatcher';\n readonly #lc: LogContext;\n readonly #state = new RunningState(this.id);\n readonly #assigner: SyncerAssigner;\n\n constructor(\n lc: LogContext,\n taskID: string,\n parent: Worker,\n syncers: Worker[],\n mutator: Worker | undefined,\n changeStreamer: Worker | undefined,\n ) {\n this.#lc = lc;\n\n const assigner = new SyncerAssigner(taskID, syncers.length);\n this.#assigner = assigner;\n\n const workerDispatchesCounter = getOrCreateCounter(\n 'sync',\n 'worker-dispatches',\n 'Dispatched client group connections to worker',\n );\n\n getOrCreateGauge(\n 'sync',\n 'worker-client-groups',\n 'Number of active client groups assigned to worker',\n ).addCallback(result => {\n for (let i = 0; i < syncers.length; i++) {\n result.observe(assigner.getWorkerLoad(i), {worker: String(i)});\n }\n });\n\n syncers.forEach((syncer, index) => {\n syncer.onMessageType<ClientGroupStatusMessage>(\n 'clientGroupStatus',\n ({clientGroupID, active, generation}) => {\n if (!active) {\n assigner.release(clientGroupID, index, generation);\n }\n },\n );\n });\n\n function connectParams(req: IncomingMessageSubset) {\n const {headers, url: u} = req;\n const url = new URL(u ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${u}`);\n }\n const version = Number(path.version);\n if (Number.isNaN(version)) {\n throw new Error(`Invalid version: ${u}`);\n }\n const {params, error} = getConnectParams(version, url, headers);\n if (error !== null) {\n throw new Error(error);\n }\n return params;\n }\n\n const handlePush = (req: IncomingMessageSubset) => {\n assert(\n mutator !== undefined,\n 'Received a push for a custom mutation but no `push.url` was configured.',\n );\n return {payload: connectParams(req), sender: mutator};\n };\n\n let maxProtocolVersion = 0;\n getOrCreateGauge(\n 'sync',\n 'max-protocol-version',\n 'Latest sync protocol version from a connecting client',\n ).addCallback(result => {\n if (maxProtocolVersion) {\n result.observe(maxProtocolVersion);\n }\n });\n\n const handleSync = (req: IncomingMessageSubset) => {\n assert(syncers.length, 'Received a sync request with no sync workers.');\n const params = connectParams(req);\n const {clientGroupID, protocolVersion} = params;\n maxProtocolVersion = Math.max(maxProtocolVersion, protocolVersion);\n\n const {worker: syncer, generation} = assigner.assign(clientGroupID);\n workerDispatchesCounter.add(1, {worker: String(syncer)});\n\n lc.debug?.(`connecting ${clientGroupID} to syncer ${syncer}`);\n return {payload: {...params, generation}, sender: syncers[syncer]};\n };\n\n const handleChangeStream = (req: IncomingMessageSubset) => {\n // Note: The change-streamer is generally not dispatched via the main\n // port, and in particular, should *not* be accessible via that\n // port in single-node mode. However, this plumbing is maintained\n // for the purpose of allowing --lazy-startup of the\n // replication-manager as a possible future feature.\n assert(\n syncers.length === 0 && mutator === undefined,\n 'Dispatch to the change-streamer via the main port ' +\n 'is only allowed in multi-node mode',\n );\n assert(\n changeStreamer,\n 'Received a change-streamer request without a change-streamer worker',\n );\n const url = new URL(req.url ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${req.url}`);\n }\n\n return {\n payload: path.action,\n sender: changeStreamer,\n };\n };\n\n // handoff messages from this ZeroDispatcher to the appropriate worker (pool).\n installWebSocketHandoff<unknown>(\n lc,\n request => {\n const {url: u} = request;\n const url = new URL(u ?? '', 'http://unused/');\n const path = parsePath(url);\n if (!path) {\n throw new Error(`Invalid URL: ${u}`);\n }\n switch (path.worker) {\n case 'sync':\n return handleSync(request);\n case 'replication':\n return handleChangeStream(request);\n case 'mutate':\n return handlePush(request);\n default:\n throw new Error(`Invalid URL: ${u}`);\n }\n },\n parent,\n );\n }\n\n run() {\n const readyStart = Date.now();\n getOrCreateGauge('server', 'uptime', {\n description: 'Cumulative uptime, starting from when requests are served',\n unit: 's',\n }).addCallback(result => result.observe((Date.now() - readyStart) / 1000));\n\n return this.#state.stopped();\n }\n\n stop() {\n this.#assigner.destroy();\n this.#state.stop(this.#lc);\n return this.#state.stopped();\n }\n}\n\nconst URL_PATTERN = new UrlPattern('(/:base)/:worker/v:version/:action');\n\nexport function parsePath(url: URL):\n | {\n base?: string;\n worker: 'sync' | 'mutate' | 'replication';\n version: string;\n action: string;\n }\n | undefined {\n // The match() returns both null and undefined.\n return URL_PATTERN.match(url.pathname) || undefined;\n} // The server allows the client to use any /:base/ path to facilitate\n// servicing requests on the same domain as the application.\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worker-urls.js","names":[],"sources":["../../../../../zero-cache/src/server/worker-urls.ts"],"sourcesContent":["// This module provides URLs for worker files.\n\nconst tsRe = /\\.ts$/;\n\nfunction resolve(path: string): URL {\n const {url} = import.meta;\n if (url.endsWith('.js')) {\n // When compiled, change .ts to .js\n path = path.replace(tsRe, '.js');\n }\n return new URL(path, url);\n}\n\n// These URLs are part of the build process. See ../../zero/tool/build.ts\n// All these urls must be relative to this file and be located in the same directory.\n\nexport const CHANGE_STREAMER_URL = resolve('./change-streamer.ts');\nexport const MAIN_URL = resolve('./main.ts');\nexport const MUTATOR_URL = resolve('./mutator.ts');\nexport const REAPER_URL = resolve('./reaper.ts');\nexport const REPLICATOR_URL = resolve('./replicator.ts');\nexport const SHADOW_SYNCER_URL = resolve('./shadow-syncer.ts');\nexport const SLOT_KEEPER_URL = resolve('./slot-keeper.ts');\nexport const SYNCER_URL = resolve('./syncer.ts');\nexport const WRITE_WORKER_URL = resolve('./write-worker.ts');\n"],"mappings":";AAEA,IAAM,OAAO;AAEb,SAAS,QAAQ,MAAmB;CAClC,MAAM,EAAC,QAAO
|
|
1
|
+
{"version":3,"file":"worker-urls.js","names":[],"sources":["../../../../../zero-cache/src/server/worker-urls.ts"],"sourcesContent":["// This module provides URLs for worker files.\n\nconst tsRe = /\\.ts$/;\n\nfunction resolve(path: string): URL {\n const {url} = import.meta;\n if (url.endsWith('.js')) {\n // When compiled, change .ts to .js\n path = path.replace(tsRe, '.js');\n }\n return new URL(path, url);\n}\n\n// These URLs are part of the build process. See ../../zero/tool/build.ts\n// All these urls must be relative to this file and be located in the same directory.\n\nexport const CHANGE_STREAMER_URL = resolve('./change-streamer.ts');\nexport const MAIN_URL = resolve('./main.ts');\nexport const MUTATOR_URL = resolve('./mutator.ts');\nexport const REAPER_URL = resolve('./reaper.ts');\nexport const REPLICATOR_URL = resolve('./replicator.ts');\nexport const SHADOW_SYNCER_URL = resolve('./shadow-syncer.ts');\nexport const SLOT_KEEPER_URL = resolve('./slot-keeper.ts');\nexport const SYNCER_URL = resolve('./syncer.ts');\nexport const WRITE_WORKER_URL = resolve('./write-worker.ts');\n"],"mappings":";AAEA,IAAM,OAAO;AAEb,SAAS,QAAQ,MAAmB;CAClC,MAAM,EAAC,QAAO;CACd,IAAI,IAAI,SAAS,KAAK,GAEpB,OAAO,KAAK,QAAQ,MAAM,KAAK;CAEjC,OAAO,IAAI,IAAI,MAAM,GAAG;AAC1B;AAKA,IAAa,sBAAsB,QAAQ,sBAAsB;AACjE,IAAa,WAAW,QAAQ,WAAW;AAChB,QAAQ,cAAc;AACjD,IAAa,aAAa,QAAQ,aAAa;AAC/C,IAAa,iBAAiB,QAAQ,iBAAiB;AACvD,IAAa,oBAAoB,QAAQ,oBAAoB;AAC7D,IAAa,kBAAkB,QAAQ,kBAAkB;AACzD,IAAa,aAAa,QAAQ,aAAa;AAC/C,IAAa,mBAAmB,QAAQ,mBAAmB"}
|
|
@@ -5,10 +5,10 @@ import { Debug } from "../../../zql/src/builder/debug-delegate.js";
|
|
|
5
5
|
import { Database } from "../../../zqlite/src/db.js";
|
|
6
6
|
import { TableSource } from "../../../zqlite/src/table-source.js";
|
|
7
7
|
import { computeZqlSpecs, mustGetTableSpec } from "../db/lite-tables.js";
|
|
8
|
+
import _usingCtx from "../../../_virtual/_@oxc-project_runtime@0.154.0/helpers/esm/usingCtx.js";
|
|
8
9
|
import { createSQLiteCostModel } from "../../../zqlite/src/sqlite-cost-model.js";
|
|
9
|
-
import { MAX_ANALYZE_ROWS, runAst } from "./run-ast.js";
|
|
10
10
|
import { explainQueries } from "../../../zqlite/src/explain-queries.js";
|
|
11
|
-
import {
|
|
11
|
+
import { MAX_ANALYZE_ROWS, runAst } from "./run-ast.js";
|
|
12
12
|
import { TimeSliceTimer } from "./view-syncer/view-syncer.js";
|
|
13
13
|
//#region ../zero-cache/src/services/analyze.ts
|
|
14
14
|
var TIME_SLICE_LAP_THRESHOLD_MS = 200;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.js","names":[],"sources":["../../../../../zero-cache/src/services/analyze.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {getOrInsertComputed} from '../../../shared/src/map.ts';\nimport type {AnalyzeQueryResult} from '../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../zero-protocol/src/client-schema.ts';\nimport type {PermissionsConfig} from '../../../zero-schema/src/compiled-permissions.ts';\nimport {Debug} from '../../../zql/src/builder/debug-delegate.ts';\nimport {MemoryStorage} from '../../../zql/src/ivm/memory-storage.ts';\nimport {\n AccumulatorDebugger,\n serializePlanDebugEvents,\n} from '../../../zql/src/planner/planner-debug.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport {explainQueries} from '../../../zqlite/src/explain-queries.ts';\nimport {createSQLiteCostModel} from '../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../zqlite/src/table-source.ts';\nimport type {JWTAuth} from '../auth/auth.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../db/specs.ts';\nimport {MAX_ANALYZE_ROWS, runAst} from './run-ast.ts';\nimport {TimeSliceTimer} from './view-syncer/view-syncer.ts';\n\nconst TIME_SLICE_LAP_THRESHOLD_MS = 200;\n\nexport async function analyzeQuery(\n lc: LogContext,\n config: NormalizedZeroConfig,\n clientSchema: ClientSchema,\n ast: AST,\n syncedRows = true,\n vendedRows = false,\n permissions?: PermissionsConfig,\n auth?: JWTAuth,\n joinPlans = false,\n): Promise<AnalyzeQueryResult> {\n using db = new Database(lc, config.replica.file);\n const fullTables = new Map<string, LiteTableSpec>();\n const tableSpecs = new Map<string, LiteAndZqlSpec>();\n const tables = new Map<string, TableSource>();\n\n computeZqlSpecs(\n lc,\n db,\n {includeBackfillingColumns: false},\n tableSpecs,\n fullTables,\n );\n\n // Mirror production: the planner runs iff ZERO_ENABLE_QUERY_PLANNER is set\n // on the server, so the analysis reflects what actually executes. Diagnostic\n // event collection is orthogonal and opt-in via `joinPlans`.\n const costModel = config.enableQueryPlanner\n ? createSQLiteCostModel(db, tableSpecs)\n : undefined;\n const planDebugger = joinPlans ? new AccumulatorDebugger() : undefined;\n const timer = await new TimeSliceTimer(lc).start();\n const shouldYield = () => timer.elapsedLap() > TIME_SLICE_LAP_THRESHOLD_MS;\n const yieldProcess = () => timer.yieldProcess();\n const result = await runAst(\n lc,\n clientSchema,\n ast,\n true,\n {\n applyPermissions: permissions !== undefined,\n syncedRows,\n vendedRows,\n auth,\n db,\n tableSpecs,\n permissions,\n costModel,\n planDebugger,\n maxSyncedRowsPerTable: MAX_ANALYZE_ROWS,\n host: {\n debug: new Debug(vendedRows, MAX_ANALYZE_ROWS),\n enableNotExists: true,\n // Mirror production, as with the planner above.\n disableCorrelatedPredicatePushdown:\n config.enableCorrelatedPredicatePushdown === false,\n enablePlannerAwarePushdown: config.enablePlannerAwarePushdown !== false,\n getSource(tableName: string) {\n return getOrInsertComputed(tables, tableName, tableName => {\n const tableSpec = mustGetTableSpec(tableSpecs, tableName);\n const {primaryKey} = tableSpec.tableSpec;\n\n return new TableSource(\n lc,\n config.log,\n db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n shouldYield,\n );\n });\n },\n createStorage() {\n return new MemoryStorage();\n },\n decorateSourceInput: input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n },\n yieldProcess,\n );\n\n // Fill in plans for any queries SQLite did not actually execute (and thus\n // did not populate scanStatus EXPLAIN for) using the substituted-binding\n // fallback. Plans captured at execution time use the real bindings and win.\n const fallback = explainQueries(result.readRowCountsByQuery ?? {}, db);\n const captured = result.sqlitePlans ?? {};\n for (const [query, plan] of Object.entries(fallback)) {\n if (!captured[query]) {\n captured[query] = plan;\n }\n }\n result.sqlitePlans = captured;\n\n if (planDebugger) {\n result.joinPlans = serializePlanDebugEvents(planDebugger.events);\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,8BAA8B;AAEpC,eAAsB,aACpB,IACA,QACA,cACA,KACA,aAAa,MACb,aAAa,OACb,aACA,MACA,YAAY,OACiB;;;EAC7B,MAAM,KAAA,YAAA,EAAK,IAAI,SAAS,IAAI,OAAO,QAAQ,IAAI,CAAA;EAC/C,MAAM,6BAAa,IAAI,IAA2B;EAClD,MAAM,6BAAa,IAAI,IAA4B;EACnD,MAAM,yBAAS,IAAI,IAAyB;EAE5C,gBACE,IACA,IACA,EAAC,2BAA2B,MAAK,GACjC,YACA,UACF;EAKA,MAAM,YAAY,OAAO,qBACrB,sBAAsB,IAAI,UAAU,IACpC,KAAA;EACJ,MAAM,eAAe,YAAY,IAAI,oBAAoB,IAAI,KAAA;EAC7D,MAAM,QAAQ,MAAM,IAAI,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"analyze.js","names":[],"sources":["../../../../../zero-cache/src/services/analyze.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {getOrInsertComputed} from '../../../shared/src/map.ts';\nimport type {AnalyzeQueryResult} from '../../../zero-protocol/src/analyze-query-result.ts';\nimport type {AST} from '../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../zero-protocol/src/client-schema.ts';\nimport type {PermissionsConfig} from '../../../zero-schema/src/compiled-permissions.ts';\nimport {Debug} from '../../../zql/src/builder/debug-delegate.ts';\nimport {MemoryStorage} from '../../../zql/src/ivm/memory-storage.ts';\nimport {\n AccumulatorDebugger,\n serializePlanDebugEvents,\n} from '../../../zql/src/planner/planner-debug.ts';\nimport {Database} from '../../../zqlite/src/db.ts';\nimport {explainQueries} from '../../../zqlite/src/explain-queries.ts';\nimport {createSQLiteCostModel} from '../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../zqlite/src/table-source.ts';\nimport type {JWTAuth} from '../auth/auth.ts';\nimport type {NormalizedZeroConfig} from '../config/normalize.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../db/specs.ts';\nimport {MAX_ANALYZE_ROWS, runAst} from './run-ast.ts';\nimport {TimeSliceTimer} from './view-syncer/view-syncer.ts';\n\nconst TIME_SLICE_LAP_THRESHOLD_MS = 200;\n\nexport async function analyzeQuery(\n lc: LogContext,\n config: NormalizedZeroConfig,\n clientSchema: ClientSchema,\n ast: AST,\n syncedRows = true,\n vendedRows = false,\n permissions?: PermissionsConfig,\n auth?: JWTAuth,\n joinPlans = false,\n): Promise<AnalyzeQueryResult> {\n using db = new Database(lc, config.replica.file);\n const fullTables = new Map<string, LiteTableSpec>();\n const tableSpecs = new Map<string, LiteAndZqlSpec>();\n const tables = new Map<string, TableSource>();\n\n computeZqlSpecs(\n lc,\n db,\n {includeBackfillingColumns: false},\n tableSpecs,\n fullTables,\n );\n\n // Mirror production: the planner runs iff ZERO_ENABLE_QUERY_PLANNER is set\n // on the server, so the analysis reflects what actually executes. Diagnostic\n // event collection is orthogonal and opt-in via `joinPlans`.\n const costModel = config.enableQueryPlanner\n ? createSQLiteCostModel(db, tableSpecs)\n : undefined;\n const planDebugger = joinPlans ? new AccumulatorDebugger() : undefined;\n const timer = await new TimeSliceTimer(lc).start();\n const shouldYield = () => timer.elapsedLap() > TIME_SLICE_LAP_THRESHOLD_MS;\n const yieldProcess = () => timer.yieldProcess();\n const result = await runAst(\n lc,\n clientSchema,\n ast,\n true,\n {\n applyPermissions: permissions !== undefined,\n syncedRows,\n vendedRows,\n auth,\n db,\n tableSpecs,\n permissions,\n costModel,\n planDebugger,\n maxSyncedRowsPerTable: MAX_ANALYZE_ROWS,\n host: {\n debug: new Debug(vendedRows, MAX_ANALYZE_ROWS),\n enableNotExists: true,\n // Mirror production, as with the planner above.\n disableCorrelatedPredicatePushdown:\n config.enableCorrelatedPredicatePushdown === false,\n enablePlannerAwarePushdown: config.enablePlannerAwarePushdown !== false,\n getSource(tableName: string) {\n return getOrInsertComputed(tables, tableName, tableName => {\n const tableSpec = mustGetTableSpec(tableSpecs, tableName);\n const {primaryKey} = tableSpec.tableSpec;\n\n return new TableSource(\n lc,\n config.log,\n db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n shouldYield,\n );\n });\n },\n createStorage() {\n return new MemoryStorage();\n },\n decorateSourceInput: input => input,\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n },\n yieldProcess,\n );\n\n // Fill in plans for any queries SQLite did not actually execute (and thus\n // did not populate scanStatus EXPLAIN for) using the substituted-binding\n // fallback. Plans captured at execution time use the real bindings and win.\n const fallback = explainQueries(result.readRowCountsByQuery ?? {}, db);\n const captured = result.sqlitePlans ?? {};\n for (const [query, plan] of Object.entries(fallback)) {\n if (!captured[query]) {\n captured[query] = plan;\n }\n }\n result.sqlitePlans = captured;\n\n if (planDebugger) {\n result.joinPlans = serializePlanDebugEvents(planDebugger.events);\n }\n\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;AAuBA,IAAM,8BAA8B;AAEpC,eAAsB,aACpB,IACA,QACA,cACA,KACA,aAAa,MACb,aAAa,OACb,aACA,MACA,YAAY,OACiB;;;EAC7B,MAAM,KAAA,YAAA,EAAK,IAAI,SAAS,IAAI,OAAO,QAAQ,IAAI,CAAA;EAC/C,MAAM,6BAAa,IAAI,IAA2B;EAClD,MAAM,6BAAa,IAAI,IAA4B;EACnD,MAAM,yBAAS,IAAI,IAAyB;EAE5C,gBACE,IACA,IACA,EAAC,2BAA2B,MAAK,GACjC,YACA,UACF;EAKA,MAAM,YAAY,OAAO,qBACrB,sBAAsB,IAAI,UAAU,IACpC,KAAA;EACJ,MAAM,eAAe,YAAY,IAAI,oBAAoB,IAAI,KAAA;EAC7D,MAAM,QAAQ,MAAM,IAAI,eAAe,EAAE,CAAC,CAAC,MAAM;EACjD,MAAM,oBAAoB,MAAM,WAAW,IAAI;EAC/C,MAAM,qBAAqB,MAAM,aAAa;EAC9C,MAAM,SAAS,MAAM,OACnB,IACA,cACA,KACA,MACA;GACE,kBAAkB,gBAAgB,KAAA;GAClC;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA,uBAAuB;GACvB,MAAM;IACJ,OAAO,IAAI,MAAM,YAAY,gBAAgB;IAC7C,iBAAiB;IAEjB,oCACE,OAAO,sCAAsC;IAC/C,4BAA4B,OAAO,+BAA+B;IAClE,UAAU,WAAmB;KAC3B,OAAO,oBAAoB,QAAQ,YAAW,cAAa;MACzD,MAAM,YAAY,iBAAiB,YAAY,SAAS;MACxD,MAAM,EAAC,eAAc,UAAU;MAE/B,OAAO,IAAI,YACT,IACA,OAAO,KACP,IACA,WACA,UAAU,SACV,YACA,WACF;KACF,CAAC;IACH;IACA,gBAAgB;KACd,OAAO,IAAI,cAAc;IAC3B;IACA,sBAAqB,UAAS;IAC9B,gBAAe,UAAS;IACxB,UAAU,CAAC;IACX,sBAAqB,UAAS;GAChC;EACF,GACA,YACF;EAKA,MAAM,WAAW,eAAe,OAAO,wBAAwB,CAAC,GAAG,EAAE;EACrE,MAAM,WAAW,OAAO,eAAe,CAAC;EACxC,KAAK,MAAM,CAAC,OAAO,SAAS,OAAO,QAAQ,QAAQ,GACjD,IAAI,CAAC,SAAS,QACZ,SAAS,SAAS;EAGtB,OAAO,cAAc;EAErB,IAAI,cACF,OAAO,YAAY,yBAAyB,aAAa,MAAM;EAGjE,OAAO;;;;;;AACT"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { assert } from "../../../../../shared/src/asserts.js";
|
|
2
|
+
import { resolver } from "../../../../../shared/src/resolver.js";
|
|
2
3
|
import { AbortError } from "../../../../../shared/src/abort-error.js";
|
|
3
4
|
import { must } from "../../../../../shared/src/must.js";
|
|
4
5
|
import { promiseOrAbort } from "../../../../../shared/src/promise-race.js";
|
|
5
6
|
import { stringify } from "../../../../../shared/src/bigint-json.js";
|
|
6
|
-
import "../../../types/lite.js";
|
|
7
7
|
import { randInt } from "../../../../../shared/src/rand.js";
|
|
8
|
+
import "../../../types/lite.js";
|
|
8
9
|
import { stateVersionFromString, stateVersionToString } from "../../../types/state-version.js";
|
|
9
10
|
import { Queue } from "../../../../../shared/src/queue.js";
|
|
10
11
|
import { CustomKeyMap } from "../../../../../shared/src/custom-key-map.js";
|
|
11
|
-
import { resolver } from "@rocicorp/resolver";
|
|
12
12
|
//#region ../zero-cache/src/services/change-source/common/backfill-manager.ts
|
|
13
13
|
function tableKey({ schema, name }) {
|
|
14
14
|
return `${schema}.${name}`;
|
|
@@ -18,7 +18,7 @@ function tableKey({ schema, name }) {
|
|
|
18
18
|
* backfill data have accumulated in it. Bounds the size of a single replica
|
|
19
19
|
* COMMIT/checkpoint so it can't monopolize the replica.
|
|
20
20
|
*/
|
|
21
|
-
var COMMIT_THRESHOLD_BYTES =
|
|
21
|
+
var COMMIT_THRESHOLD_BYTES = 8388608;
|
|
22
22
|
/**
|
|
23
23
|
* How many backfill messages the prefetch producer may read ahead of the
|
|
24
24
|
* reservation-holding consumer loop. This bounds the in-memory buffer (~this
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backfill-manager.js","names":["#lc","#requiredBackfills","#changeStreamer","#backfillStreamer","#jsonFormat","#awaitingStatusWatermarks","#commitThresholdBytes","#controller","#canceled","#minBackoffMs","#maxBackoffMs","#retryDelayMs","#lastStatusWatermark","#setRequiredBackfill","#checkAndStartBackfill","#backfillRetryTimer","#runningBackfill","#runBackfill","#stopRunningBackfill","#retryBackfillWithBackoff","#changeStreamReached","#maybeLogBackfillStats","#logBackfillStats","#currentTxWatermark","#setLastStatusWatermark","#backfillRunningFor","#deleteRequiredBackfill"],"sources":["../../../../../../../zero-cache/src/services/change-source/common/backfill-manager.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {resolver} from '@rocicorp/resolver';\nimport {AbortError} from '../../../../../shared/src/abort-error.ts';\nimport {assert} from '../../../../../shared/src/asserts.ts';\nimport {stringify} from '../../../../../shared/src/bigint-json.ts';\nimport {CustomKeyMap} from '../../../../../shared/src/custom-key-map.ts';\nimport {must} from '../../../../../shared/src/must.ts';\nimport {promiseOrAbort} from '../../../../../shared/src/promise-race.ts';\nimport {Queue} from '../../../../../shared/src/queue.ts';\nimport {randInt} from '../../../../../shared/src/rand.ts';\nimport {JSON_STRINGIFIED, type JSONFormat} from '../../../types/lite.ts';\nimport {\n stateVersionFromString,\n stateVersionToString,\n} from '../../../types/state-version.ts';\nimport type {\n BackfillCompleted,\n BackfillRequest,\n ChangeStreamMessage,\n Identifier,\n MessageBackfill,\n} from '../protocol/current.ts';\nimport type {\n Cancelable,\n ChangeStreamMultiplexer,\n Listener,\n} from './change-stream-multiplexer.ts';\n\nfunction tableKey({schema, name}: Identifier) {\n return `${schema}.${name}`;\n}\n\n/**\n * A {@link MessageBackfill} or {@link BackfillCompleted} paired with the\n * approximate number of upstream bytes it represents. The BackfillManager uses\n * `byteSize` to bound the size of each replica transaction, committing and\n * reopening once {@link COMMIT_THRESHOLD_BYTES} is reached.\n */\nexport type BackfillMessage = {\n message: MessageBackfill | BackfillCompleted;\n byteSize: number;\n};\n\ntype BackfillStreamer = (\n req: BackfillRequest,\n) => AsyncGenerator<BackfillMessage>;\n\n/**\n * Commit (and reopen) the current backfill transaction once this many bytes of\n * backfill data have accumulated in it. Bounds the size of a single replica\n * COMMIT/checkpoint so it can't monopolize the replica.\n */\nconst COMMIT_THRESHOLD_BYTES = 8 * 1024 * 1024;\n\n/**\n * How many backfill messages the prefetch producer may read ahead of the\n * reservation-holding consumer loop. This bounds the in-memory buffer (~this\n * many {@link BackfillMessage}s, each up to the stream's flush threshold, e.g.\n * 64 KiB) while giving the consumer a supply of ready messages so it never\n * has to wait on the upstream COPY while holding the change-stream reservation.\n */\nconst BACKFILL_PREFETCH_CREDITS = 16;\n\n/**\n * While the backfill holds an open transaction but its prefetch queue is empty\n * (i.e. the upstream is momentarily behind), the consumer polls for the next\n * message at this interval so that a replication transaction that begins\n * waiting mid-fetch can preempt the backfill within this bound, rather than\n * being blocked for the entire (possibly slow) upstream read.\n *\n * If stats indicate that these stalls are highly correlative with replication\n * lag (indicating that replication changes are waiting on these polls), we\n * can address this by adding an API to the change stream multiplexer that\n * would allow backfill to relinquish an in-progress commit on demand (i.e.\n * only if replication asks for a reservation).\n */\nconst BACKFILL_WAITER_POLL_MS = 10;\n\n/** Interval at which in-progress backfill timing stats are logged. */\nconst BACKFILL_STATS_LOG_INTERVAL_MS = 10_000;\n\n/** Sentinel enqueued by the prefetch producer when the backfill stream ends. */\nconst DONE = Symbol('backfill-done');\n/** Sentinel returned by a polled dequeue that timed out (see {@link BACKFILL_WAITER_POLL_MS}). */\nconst POLL = Symbol('backfill-poll');\n\ntype Pull = BackfillMessage | typeof DONE | typeof POLL;\n\n/**\n * Accumulated timing attribution for a single backfill run, logged\n * periodically to reveal where the backfill spends its time (and, in\n * particular, where the change-stream reservation is held). `produceMs`\n * accrues on the prefetch producer task and thus overlaps with the consumer's\n * `pushMs`; the others accrue on the reservation-holding consumer loop.\n */\ntype BackfillTimingStats = {\n start: number;\n lastLogged: number;\n messages: number;\n bytes: number;\n commits: number;\n stalls: number;\n produceMs: number;\n pushMs: number;\n reserveMs: number;\n stallMs: number;\n waitMs: number;\n};\n\ntype RunningBackfillState = {\n request: BackfillRequest;\n minWatermark: string;\n /**\n * Aborted (with the reason, if any) when this backfill is stopped,\n * e.g. canceled.\n */\n stopped: AbortController;\n};\n\nconst MIN_BACKOFF_INTERVAL_MS = 2_000;\nconst MAX_BACKOFF_INTERVAL_MS = 60_000;\n\ntype AwaitingStatusWatermark = {\n watermark: string;\n reached: () => void;\n};\n\n/**\n * The BackfillManager initiates backfills for BackfillRequests from the\n * change-streamer (i.e. unfinished backfills from previous sessions)\n * or for new backfills signaled by `create-table` or `add-column` messages\n * from the change-source.\n *\n * The BackfillManager registers itself as a change stream listener in order\n * to track necessary backfills, and potentially invalidate the in-progress\n * backfill (e.g. due to a schema change) so that it can be retried at a\n * new snapshot.\n *\n * The manager also handles low priority streaming of the backfill messages\n * using the {@link ChangeStreamMultiplexer}, implementing a policy of always\n * releasing its reservation if another producer (i.e. the main change stream)\n * has messages to stream.\n */\nexport class BackfillManager implements Cancelable, Listener {\n readonly #lc: LogContext;\n\n /**\n * Tracks the metadata of required backfills based on schema changes\n * and initial backfill requests.\n */\n readonly #requiredBackfills = new CustomKeyMap<Identifier, BackfillRequest>(\n tableKey,\n );\n readonly #changeStreamer: ChangeStreamMultiplexer;\n readonly #backfillStreamer: BackfillStreamer;\n readonly #jsonFormat: JSONFormat;\n\n /**\n * The current running backfill. The backfill request is always also in\n * `#requiredBackfills` (technically, it can be a subset of what's in\n * `#requiredBackfills`); the request is removed from `#requiredBackfills`\n * upon completion.\n */\n #runningBackfill: RunningBackfillState | null = null;\n\n /** The last seen watermark in the change stream. */\n #lastStatusWatermark: string | null = null;\n\n readonly #awaitingStatusWatermarks: AwaitingStatusWatermark[] = [];\n\n /** The watermark of the current transaction in the change stream. */\n #currentTxWatermark: string | null = null;\n\n readonly #commitThresholdBytes: number;\n\n /**\n * Aborted when the change stream is canceled. No further backfills are run.\n *\n * TODO: Thread this into the backfillStream so that upstream I/O can be\n * aborted.\n */\n readonly #controller = new AbortController();\n\n get #canceled() {\n return this.#controller.signal.aborted;\n }\n\n constructor(\n lc: LogContext,\n changeStreamer: ChangeStreamMultiplexer,\n backfillStreamer: BackfillStreamer,\n jsonFormat: JSONFormat = JSON_STRINGIFIED,\n minBackoffMs = MIN_BACKOFF_INTERVAL_MS,\n maxBackoffMs = MAX_BACKOFF_INTERVAL_MS,\n commitThresholdBytes = COMMIT_THRESHOLD_BYTES,\n ) {\n this.#lc = lc.withContext('component', 'backfill-manager');\n this.#changeStreamer = changeStreamer;\n this.#backfillStreamer = backfillStreamer;\n this.#jsonFormat = jsonFormat;\n this.#minBackoffMs = minBackoffMs;\n this.#maxBackoffMs = maxBackoffMs;\n this.#retryDelayMs = minBackoffMs;\n this.#commitThresholdBytes = commitThresholdBytes;\n }\n\n run(lastWatermark: string, initialRequests: BackfillRequest[]) {\n this.#lc.info?.(\n `starting backfill manager with ${initialRequests.length} initial requests`,\n {requests: initialRequests},\n );\n this.#lastStatusWatermark = lastWatermark;\n initialRequests.forEach(req =>\n this.#setRequiredBackfill('initial-request', req),\n );\n this.#checkAndStartBackfill();\n }\n\n #setLastStatusWatermark({watermark}: {watermark: string}) {\n // Only allow the watermark to move forward. This prevents a backfill\n // transaction (whose watermark is unrelated to change-stream state)\n // from moving the watermark backwards.\n if ((this.#lastStatusWatermark ?? '') < watermark) {\n this.#lastStatusWatermark = watermark;\n for (let i = this.#awaitingStatusWatermarks.length - 1; i >= 0; i--) {\n const awaiting = this.#awaitingStatusWatermarks[i];\n if (watermark >= awaiting.watermark) {\n awaiting.reached();\n this.#awaitingStatusWatermarks.splice(i, 1);\n }\n }\n }\n }\n\n #changeStreamReached(\n lc: LogContext,\n watermark: string,\n ): Promise<void> | null {\n if ((this.#lastStatusWatermark ?? '') < watermark) {\n const {promise, resolve: reached} = resolver();\n this.#awaitingStatusWatermarks.push({watermark, reached});\n lc.info?.(\n `waiting for change stream (at ${this.#lastStatusWatermark}) to reach ${watermark}`,\n );\n return promise;\n }\n return null;\n }\n\n readonly #minBackoffMs: number;\n readonly #maxBackoffMs: number;\n #retryDelayMs: number;\n #backfillRetryTimer: NodeJS.Timeout | undefined;\n\n #checkAndStartBackfill() {\n if (\n !this.#canceled &&\n !this.#backfillRetryTimer &&\n !this.#runningBackfill &&\n this.#requiredBackfills.size\n ) {\n // Pick a random backfill to avoid head-of-line blocking by a\n // problematic backfill (e.g. awaiting a primary key). This is\n // simpler that adding logic to classify (and declassify)\n // problematic backfills.\n const candidates = [...this.#requiredBackfills.values()];\n const request = candidates[randInt(0, candidates.length - 1)];\n const state = {\n request,\n minWatermark: '',\n stopped: new AbortController(),\n };\n const lc = this.#lc.withContext('table', request.table.name);\n\n this.#runningBackfill = state;\n void this.#runBackfill(lc, state)\n .then(() => {\n this.#stopRunningBackfill('backfill exited', state);\n this.#retryDelayMs = this.#minBackoffMs; // reset on success\n })\n // For unexpected errors (e.g. upstream replication slot\n // unavailability), retry with exponential backoff.\n .catch(e => {\n this.#stopRunningBackfill(String(e), state);\n this.#retryBackfillWithBackoff(e);\n });\n }\n }\n\n #retryBackfillWithBackoff(e: unknown) {\n if (this.#canceled) {\n this.#lc.debug?.(`not retrying backfill: change stream canceled`, e);\n return;\n }\n this.#lc.warn?.(\n `Error running backfill. Retrying in ${this.#retryDelayMs} ms`,\n e,\n );\n this.#backfillRetryTimer = setTimeout(() => {\n this.#backfillRetryTimer = undefined;\n this.#checkAndStartBackfill();\n }, this.#retryDelayMs);\n\n this.#retryDelayMs = Math.min(this.#retryDelayMs * 2, this.#maxBackoffMs);\n }\n\n async #runBackfill(lc: LogContext, state: RunningBackfillState) {\n const changeStream = this.#changeStreamer; // Purely for readability\n\n // backfillTx is set if and only if a changeStreamer reservation has been\n // acquired and the backfill stream is inside a transaction.\n let backfillTx: string | null = null;\n let uncommittedBytes = 0;\n\n const stats: BackfillTimingStats = {\n start: performance.now(),\n lastLogged: performance.now(),\n messages: 0,\n bytes: 0,\n commits: 0,\n stalls: 0,\n produceMs: 0,\n pushMs: 0,\n reserveMs: 0,\n stallMs: 0,\n waitMs: 0,\n };\n\n /**\n * @returns the new tx watermark, or null if backfill was cancelled\n */\n const beginTxFor = async (\n msg: MessageBackfill | BackfillCompleted,\n ): Promise<string | null> => {\n assert(backfillTx === null, 'Expected no active backfill transaction');\n const lastWatermark = await changeStream.reserve('backfill');\n\n // After obtaining the changeStream reservation, check if the stream\n // had changes that resulted in invalidating / canceling this backfill.\n if (\n state.stopped.signal.aborted ||\n (msg.tag === 'backfill' && msg.watermark < state.minWatermark)\n ) {\n if (!state.stopped.signal.aborted) {\n assert(msg.tag === 'backfill', 'Expected backfill message tag'); // TypeScript should have figured this out.\n this.#stopRunningBackfill(\n `row key change at ${state.minWatermark} ` +\n `postdates backfill watermark at ${msg.watermark}`,\n state,\n );\n }\n changeStream.release(lastWatermark);\n return null;\n }\n\n const {major, minor = 0n} = stateVersionFromString(lastWatermark);\n let tx = stateVersionToString({\n major,\n minor: BigInt(minor) + 1n,\n });\n\n if (tx < msg.watermark) {\n // At this point it must be the case that the #changeStreamReached()\n // the backfill watermark (possibly via a status message, which does\n // not advance the reservation watermark). Given that guarantee,\n // ensure that the version of the backfill transaction is at least up\n // to the backfill watermark, so that the database state version is\n // never earlier than the version of any backfilled rows.\n tx = msg.watermark;\n }\n\n void changeStream.push([\n 'begin',\n {tag: 'begin', json: this.#jsonFormat, skipAck: true},\n {commitWatermark: tx},\n ]);\n return (backfillTx = tx);\n };\n\n const commitTx = () => {\n if (backfillTx) {\n void changeStream.push([\n 'commit',\n {tag: 'commit'},\n {watermark: backfillTx},\n ]);\n changeStream.release(backfillTx);\n stats.commits++;\n }\n backfillTx = null;\n uncommittedBytes = 0;\n };\n\n // === Prefetch producer ===\n //\n // The backfill stream (an upstream Postgres COPY) is drained on a separate\n // task into a bounded queue, so that the reservation-holding consumer loop\n // below never blocks on the upstream read while it holds the change-stream\n // reservation. `credits` bounds how far the producer runs ahead; the\n // consumer returns a credit for every message it takes.\n const ready = new Queue<Pull>();\n const credits = new Queue<1>();\n for (let i = 0; i < BACKFILL_PREFETCH_CREDITS; i++) {\n credits.enqueue(1);\n }\n let stopProducer = false;\n\n // Wakes a consumer blocked awaiting the next prefetched message so a\n // canceled backfill unwinds promptly.\n const onCancel = () =>\n ready.enqueueRejection(new AbortError('backfill canceled'));\n if (!this.#canceled) {\n this.#controller.signal.addEventListener('abort', onCancel);\n }\n\n const producer = (async () => {\n try {\n let t0 = performance.now();\n for await (const value of this.#backfillStreamer(state.request)) {\n stats.produceMs += performance.now() - t0;\n await credits.dequeue(); // wait for buffer space (flow control)\n if (stopProducer || this.#canceled) {\n ready.enqueueRejection(new AbortError('backfill canceled'));\n return;\n }\n ready.enqueue(value);\n t0 = performance.now();\n }\n ready.enqueue(DONE);\n } catch (e) {\n ready.enqueueRejection(e);\n }\n })();\n // The producer routes errors through `ready` and never rejects; guard\n // anyway so that leaving it un-awaited on the cancellation path (below)\n // cannot surface as an unhandled rejection.\n void producer.catch(() => {});\n\n // === Consumer ===\n\n // Fetches the next item from the prefetch queue. If a transaction is open\n // but the queue is empty (the producer/upstream is momentarily behind),\n // polls so that a replication transaction that begins waiting during the\n // upstream read can preempt the backfill: rather than hold the reservation\n // for the whole read, commit and release, letting replication proceed.\n const nextItem = async (): Promise<BackfillMessage | typeof DONE> => {\n // Fast path: a message is already buffered, or there's no reservation to\n // protect. Take it without altering transaction boundaries. `POLL` is\n // never enqueued (only used as a dequeue timeout value), so the result is\n // always a message or DONE.\n if (backfillTx === null || ready.size() > 0) {\n const n = ready.dequeue();\n const v = n instanceof Promise ? await n : n;\n return v as BackfillMessage | typeof DONE;\n }\n // Slow path: holding a reservation with an empty queue.\n for (;;) {\n if (backfillTx !== null && changeStream.waiterDelay() > 0) {\n commitTx(); // yield the stream to the waiting replication txn\n }\n const n =\n backfillTx !== null\n ? ready.dequeue(POLL, BACKFILL_WAITER_POLL_MS)\n : ready.dequeue(); // released: just wait for the next message\n const t0 = performance.now();\n const v = n instanceof Promise ? await n : n;\n if (v === POLL) {\n stats.stallMs += performance.now() - t0; // timed out; re-check waiter\n continue;\n }\n if (n instanceof Promise) {\n stats.stallMs += performance.now() - t0;\n stats.stalls++;\n }\n return v;\n }\n };\n\n try {\n for (;;) {\n const item = await nextItem();\n if (item === DONE) {\n break;\n }\n // Allow the producer to fetch the next message concurrently with the\n // processing (and downstream push) of this one.\n credits.enqueue(1);\n\n if (this.#canceled) {\n // Returning finalizes the backfill stream (and the upstream resources\n // it holds) via the producer's `finally`. The reservation, if held,\n // does not need to be released since the change stream is gone.\n lc.info?.(`backfill stream canceled: change stream canceled`);\n return;\n }\n const {message: msg, byteSize} = item;\n\n // Before sending any backfill message, the main replication stream\n // must reach the backfill (snapshot) watermark. Otherwise, snapshot\n // rows can constitute \"future\" state (e.g. phantom rows at keys that\n // the stream has yet to move or insert) that the subsequent\n // replication changes conflict with (e.g. on unique indexes).\n const waitForChangeStream = this.#changeStreamReached(\n lc,\n msg.watermark,\n );\n\n // Commit (and later reopen) the transaction if the main stream is\n // waiting on the reservation, if we must wait for the main stream, or\n // if the size of current transaction has reached the commit threshold.\n if (\n backfillTx &&\n (changeStream.waiterDelay() > 0 ||\n waitForChangeStream ||\n uncommittedBytes >= this.#commitThresholdBytes)\n ) {\n commitTx();\n }\n\n if (waitForChangeStream) {\n const t0 = performance.now();\n // Exit promptly (via the error path) if the backfill is canceled\n // while waiting, releasing its upstream resources.\n await promiseOrAbort(waitForChangeStream, state.stopped.signal);\n const elapsed = performance.now() - t0;\n stats.waitMs += elapsed;\n lc.info?.(\n `change stream reached ${msg.watermark} ` +\n `after waiting ${Math.round(elapsed)} ms`,\n );\n }\n\n if (\n msg.tag === 'backfill' &&\n msg.rowValues.length > 0 &&\n msg.relation.rowKey.columns.length === 0\n ) {\n throw new MissingRowKeyError(state.request);\n }\n\n // Reserve the changeStreamer if not in a transaction.\n if (backfillTx === null) {\n const t0 = performance.now();\n backfillTx = await beginTxFor(msg);\n stats.reserveMs += performance.now() - t0;\n if (backfillTx === null) {\n lc.info?.(\n `backfill stream canceled: ${state.stopped.signal.reason}`,\n state.request,\n );\n this.#checkAndStartBackfill(); // start the next backfill if present\n return; // this backfill is canceled\n }\n }\n\n // `await` to allow the change streamer to exert back pressure\n // on backfills.\n const t0 = performance.now();\n await changeStream.push(['data', msg]);\n stats.pushMs += performance.now() - t0;\n uncommittedBytes += byteSize;\n stats.messages++;\n stats.bytes += byteSize;\n\n this.#maybeLogBackfillStats(lc, stats);\n }\n\n // Flush any final tx and release the stream.\n if (backfillTx) {\n commitTx();\n }\n lc.debug?.(`backfill stream exited`);\n } finally {\n stopProducer = true;\n credits.enqueue(1);\n // The producer can potentially be hung on upstream I/O.\n // TODO: Thread AbortSignal logic into the backfillStreamer.\n if (!this.#canceled) {\n await producer;\n }\n this.#controller.signal.removeEventListener('abort', onCancel);\n this.#logBackfillStats(lc, stats);\n }\n }\n\n #maybeLogBackfillStats(lc: LogContext, stats: BackfillTimingStats) {\n const now = performance.now();\n if (now - stats.lastLogged >= BACKFILL_STATS_LOG_INTERVAL_MS) {\n this.#logBackfillStats(lc, stats);\n stats.lastLogged = now;\n }\n }\n\n /**\n * Logs where the backfill spent its time. `produceMs` (upstream read +\n * parse/decode) accrues on the prefetch producer concurrently with the\n * consumer's `pushMs` (downstream backpressure), so the two can overlap and\n * their sum can exceed `elapsedMs`. `reserveMs` is time spent (re)acquiring\n * the change-stream reservation, and `stallMs` is time the consumer waited on\n * an empty prefetch queue (i.e. blocked on the upstream) — a large `stallMs`\n * indicates an upstream-bound backfill. `waitMs` is time spent waiting\n * (without the reservation) for the change stream to reach the backfill\n * watermark, during which the upstream snapshot is held open.\n */\n #logBackfillStats(lc: LogContext, stats: BackfillTimingStats) {\n const elapsed = performance.now() - stats.start;\n lc.info?.(`backfill timing`, {\n messages: stats.messages,\n bytes: stats.bytes,\n commits: stats.commits,\n stalls: stats.stalls,\n elapsedMs: Math.round(elapsed),\n produceMs: Math.round(stats.produceMs),\n pushMs: Math.round(stats.pushMs),\n reserveMs: Math.round(stats.reserveMs),\n stallMs: Math.round(stats.stallMs),\n waitMs: Math.round(stats.waitMs),\n throughputKBps:\n elapsed > 0 ? Math.round(stats.bytes / 1024 / (elapsed / 1000)) : 0,\n });\n }\n\n #backfillRunningFor(table: Identifier): RunningBackfillState | null {\n const state = this.#runningBackfill;\n return state?.request.table.schema === table.schema &&\n state.request.table.name === table.name\n ? state\n : null;\n }\n\n /**\n * Stops the running backfill for the specified `reason`. If `instance` is\n * specified, the running backfill is stopped only if it is that instance.\n * This allows the running backfill itself to clear backfill state without\n * accidentally stopping a different (e.g. subsequent) backfill.\n */\n #stopRunningBackfill(reason?: string, instance?: RunningBackfillState) {\n const backfill = this.#runningBackfill;\n if (backfill && backfill === (instance ?? backfill)) {\n backfill.stopped.abort(reason);\n this.#runningBackfill = null;\n reason && this.#lc.info?.(`canceling backfill:`, reason);\n }\n }\n\n #setRequiredBackfill(source: string, req: BackfillRequest) {\n const action = this.#requiredBackfills.has(req.table) ? 'updated' : 'added';\n this.#lc.info?.(`Backfill ${action}: ${source}`, {backfill: req});\n this.#requiredBackfills.set(req.table, req);\n }\n\n #deleteRequiredBackfill(source: string, id: Identifier) {\n const req = this.#requiredBackfills.get(id);\n if (req) {\n const action = source === 'backfill-completed' ? 'completed' : 'dropped';\n this.#lc.info?.(`Backfill ${action}: ${source}`, {backfill: req});\n this.#requiredBackfills.delete(id);\n }\n }\n\n /**\n * Implements {@link Listener.onChange()}, invoked by the\n * {@link ChangeStreamMultiplexer}.\n */\n onChange(message: ChangeStreamMessage): void {\n if (message[0] === 'begin') {\n this.#currentTxWatermark = message[2].commitWatermark;\n return;\n }\n if (message[0] === 'commit') {\n this.#currentTxWatermark = null;\n this.#setLastStatusWatermark(message[2]);\n // Every commit is a candidate for starting the next backfill\n // (if one is not currently running).\n this.#checkAndStartBackfill();\n return;\n }\n if (message[0] === 'status') {\n this.#setLastStatusWatermark(message[2]);\n return;\n }\n if (message[0] !== 'data') {\n return;\n }\n const change = message[1];\n const {tag} = change;\n switch (tag) {\n case 'update-table-metadata': {\n const {table, new: metadata} = change;\n const backfillRequest = this.#requiredBackfills.get(table);\n if (backfillRequest) {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n table: {...backfillRequest.table, metadata},\n });\n if (this.#backfillRunningFor(table)) {\n this.#stopRunningBackfill(`TableMetadata updated`);\n }\n }\n break;\n }\n case 'create-table': {\n const {\n spec: {schema, name},\n metadata = null,\n backfill,\n } = change;\n\n if (backfill) {\n this.#setRequiredBackfill(tag, {\n table: {schema, name, metadata},\n columns: Object.fromEntries(\n Object.entries(backfill).map(([col, id]) => [col, {id}]),\n ),\n });\n }\n break;\n }\n case 'rename-table': {\n const {old, new: newTable} = change;\n const backfillRequest = this.#requiredBackfills.get(old);\n if (backfillRequest) {\n const {schema, name} = newTable;\n this.#deleteRequiredBackfill(tag, old);\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n table: {...backfillRequest.table, schema, name},\n });\n if (this.#backfillRunningFor(old)) {\n this.#stopRunningBackfill(`table renamed`);\n }\n }\n break;\n }\n case 'drop-table': {\n const {id} = change;\n const backfillRequest = this.#requiredBackfills.get(id);\n if (backfillRequest) {\n this.#deleteRequiredBackfill(tag, id);\n if (this.#backfillRunningFor(id)) {\n this.#stopRunningBackfill(`table dropped`);\n }\n }\n break;\n }\n case 'add-column': {\n const {\n table,\n tableMetadata: metadata = null,\n column,\n backfill,\n } = change;\n if (backfill) {\n const backfillRequest = this.#requiredBackfills.get(table);\n if (!backfillRequest) {\n this.#setRequiredBackfill(tag, {\n table: {...table, metadata},\n columns: {[column.name]: {id: backfill}},\n });\n } else {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n table: {...backfillRequest.table, metadata},\n columns: {\n ...backfillRequest.columns,\n [column.name]: {id: backfill},\n },\n });\n // Note: The running backfill need not be canceled if a\n // new column is added. The new column will be backfilled\n // by its own stream after the current backfill completes.\n }\n }\n break;\n }\n case 'update-column': {\n const {\n table,\n old: {name: oldName},\n new: {name: newName},\n } = change;\n if (oldName !== newName) {\n const backfillRequest = this.#requiredBackfills.get(table);\n if (backfillRequest && oldName in backfillRequest.columns) {\n const {[oldName]: colSpec, ...otherCols} = backfillRequest.columns;\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n columns: {...otherCols, [newName]: colSpec},\n });\n const backfill = this.#backfillRunningFor(table);\n if (backfill && oldName in backfill.request.columns) {\n this.#stopRunningBackfill(`column renamed`);\n }\n }\n }\n break;\n }\n case 'drop-column': {\n const {table, column} = change;\n const backfillRequest = this.#requiredBackfills.get(table);\n if (backfillRequest && column in backfillRequest.columns) {\n const {[column]: _excluded, ...remaining} = backfillRequest.columns;\n if (Object.keys(remaining).length === 0) {\n this.#deleteRequiredBackfill(tag, table);\n } else {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n columns: remaining,\n });\n }\n const backfill = this.#backfillRunningFor(table);\n if (backfill && column in backfill.request.columns) {\n this.#stopRunningBackfill(`column dropped`);\n }\n }\n break;\n }\n case 'update': {\n const {relation, key, new: row} = change;\n const backfill = this.#backfillRunningFor(relation);\n const txWatermark = must(this.#currentTxWatermark, `not in a tx`);\n if (backfill?.request.table.metadata && key !== null) {\n // A corner case that backfill is unable to correctly handle is\n // when a row's key changes; this is decomposed into a delete\n // of the old key and a set of the new key in the replica change\n // log, at which point the backfill algorithm assumes that the\n // (old) row is deleted but does not know to backfill the new row.\n // In these corner cases, the current backfill is canceled and\n // retried if its version precedes this update.\n for (const col of Object.keys(\n backfill.request.table.metadata.rowKey,\n )) {\n if (key[col] !== row[col]) {\n backfill.minWatermark = txWatermark;\n this.#lc.info?.(\n `key for row as changed (col: ${col}). ` +\n `backfill data must not predate ${backfill.minWatermark}`,\n );\n break;\n }\n }\n }\n break;\n }\n case 'backfill-completed': {\n const {relation, columns} = change;\n const backfillRequest = this.#requiredBackfills.get(relation);\n assert(\n backfillRequest,\n () => `No BackfillRequest completed backfill ${stringify(change)}`,\n );\n const remaining = Object.entries(backfillRequest.columns).filter(\n ([col]) =>\n !(columns.includes(col) || relation.rowKey.columns.includes(col)),\n );\n if (remaining.length === 0) {\n this.#deleteRequiredBackfill(tag, relation);\n } else {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n columns: Object.fromEntries(remaining),\n });\n }\n // Technically the backfill is already stopping, but this method\n // cleans up the state that tracks it.\n this.#stopRunningBackfill();\n break;\n }\n }\n }\n\n cancel(): void {\n this.#controller.abort('canceled');\n this.#stopRunningBackfill(`change stream canceled`);\n clearTimeout(this.#backfillRetryTimer);\n this.#backfillRetryTimer = undefined;\n\n // Wake up a backfill that is waiting for the change stream to reach a\n // watermark. The change stream never will, and the backfill must be\n // allowed to unwind (and release its upstream resources) rather than\n // remain suspended forever.\n for (const {reached} of this.#awaitingStatusWatermarks.splice(0)) {\n reached();\n }\n }\n}\n\nabstract class BackfillStreamError extends Error {\n constructor(bf: BackfillRequest, msg: string, cause?: unknown) {\n super(\n `Cannot backfill ${bf.table.schema}.${bf.table.name}` +\n `[${Object.keys(bf.columns).join(',')}]: ${msg}`,\n {cause},\n );\n }\n}\n\n/**\n * Background: The zero-cache supports replication of tables without a\n * PRIMARY KEY to facilitate the onboarding process. These rows can be\n * INSERT'ed, but postgres will rightfully prohibit UPDATEs and DELETEs\n * on such tables because the rows cannot be identified by a key. Supporting\n * this mode of replication allows the user to \"fix\" the setup by adding the\n * primary key, after which the table can be published downstream without\n * requiring a resync of the data.\n *\n * In terms of backfill, however, non-empty tables without a row key **cannot**\n * be backfilled, because backfill retries would result in writing duplicating\n * rows. (Empty tables, on the other hand, are fine because there is no data\n * to be deduped.)\n *\n * The MissingRowKeyError is used to signal that the table cannot be backfilled\n * in its current state. For simplicity, it is handled like runtime errors and\n * retried with backoff, with which it can eventually succeed if (1) a primary\n * key is added or (2) the table is emptied, e.g. via a TRUNCATE.\n */\nclass MissingRowKeyError extends BackfillStreamError {\n readonly name = 'MissingRowKeyError';\n\n constructor(bf: BackfillRequest, cause?: unknown) {\n super(bf, `\"${bf.table.name}\" is missing a PRIMARY KEY`, cause);\n }\n}\n\n/**\n * Error type for backfill stream implementations to throw indicating that\n * the backfill request failed due to a schema incompatibility error. This\n * type of error does not need exponential backoff, as the retry happens\n * naturally once the invalidating schema change is processed and committed.\n */\nexport class SchemaIncompatibilityError extends BackfillStreamError {\n readonly name = 'SchemaIncompatibilityError';\n\n constructor(bf: BackfillRequest, msg: string, cause?: unknown) {\n super(bf, msg, cause);\n }\n}\n"],"mappings":";;;;;;;;;;;;AA4BA,SAAS,SAAS,EAAC,QAAQ,QAAmB;CAC5C,OAAO,GAAG,OAAO,GAAG;AACtB;;;;;;AAsBA,IAAM,yBAAyB,IAAI,OAAO;;;;;;;;AAS1C,IAAM,4BAA4B;;;;;;;;;;;;;;AAelC,IAAM,0BAA0B;;AAGhC,IAAM,iCAAiC;;AAGvC,IAAM,OAAO,OAAO,eAAe;;AAEnC,IAAM,OAAO,OAAO,eAAe;AAmCnC,IAAM,0BAA0B;AAChC,IAAM,0BAA0B;;;;;;;;;;;;;;;;;AAuBhC,IAAa,kBAAb,MAA6D;CAC3D;;;;;CAMA,qBAA8B,IAAI,aAChC,QACF;CACA;CACA;CACA;;;;;;;CAQA,mBAAgD;;CAGhD,uBAAsC;CAEtC,4BAAgE,CAAC;;CAGjE,sBAAqC;CAErC;;;;;;;CAQA,cAAuB,IAAI,gBAAgB;CAE3C,IAAIQ,YAAY;EACd,OAAO,KAAKD,YAAY,OAAO;CACjC;CAEA,YACE,IACA,gBACA,kBACA,aAAA,KACA,eAAe,yBACf,eAAe,yBACf,uBAAuB,wBACvB;EACA,KAAKP,MAAM,GAAG,YAAY,aAAa,kBAAkB;EACzD,KAAKE,kBAAkB;EACvB,KAAKC,oBAAoB;EACzB,KAAKC,cAAc;EACnB,KAAKK,gBAAgB;EACrB,KAAKC,gBAAgB;EACrB,KAAKC,gBAAgB;EACrB,KAAKL,wBAAwB;CAC/B;CAEA,IAAI,eAAuB,iBAAoC;EAC7D,KAAKN,IAAI,OACP,kCAAkC,gBAAgB,OAAO,oBACzD,EAAC,UAAU,gBAAe,CAC5B;EACA,KAAKY,uBAAuB;EAC5B,gBAAgB,SAAQ,QACtB,KAAKC,qBAAqB,mBAAmB,GAAG,CAClD;EACA,KAAKC,uBAAuB;CAC9B;CAEA,wBAAwB,EAAC,aAAiC;EAIxD,KAAK,KAAKF,wBAAwB,MAAM,WAAW;GACjD,KAAKA,uBAAuB;GAC5B,KAAK,IAAI,IAAI,KAAKP,0BAA0B,SAAS,GAAG,KAAK,GAAG,KAAK;IACnE,MAAM,WAAW,KAAKA,0BAA0B;IAChD,IAAI,aAAa,SAAS,WAAW;KACnC,SAAS,QAAQ;KACjB,KAAKA,0BAA0B,OAAO,GAAG,CAAC;IAC5C;GACF;EACF;CACF;CAEA,qBACE,IACA,WACsB;EACtB,KAAK,KAAKO,wBAAwB,MAAM,WAAW;GACjD,MAAM,EAAC,SAAS,SAAS,YAAW,SAAS;GAC7C,KAAKP,0BAA0B,KAAK;IAAC;IAAW;GAAO,CAAC;GACxD,GAAG,OACD,iCAAiC,KAAKO,qBAAqB,aAAa,WAC1E;GACA,OAAO;EACT;EACA,OAAO;CACT;CAEA;CACA;CACA;CACA;CAEA,yBAAyB;EACvB,IACE,CAAC,KAAKJ,aACN,CAAC,KAAKO,uBACN,CAAC,KAAKC,oBACN,KAAKf,mBAAmB,MACxB;GAKA,MAAM,aAAa,CAAC,GAAG,KAAKA,mBAAmB,OAAO,CAAC;GACvD,MAAM,UAAU,WAAW,QAAQ,GAAG,WAAW,SAAS,CAAC;GAC3D,MAAM,QAAQ;IACZ;IACA,cAAc;IACd,SAAS,IAAI,gBAAgB;GAC/B;GACA,MAAM,KAAK,KAAKD,IAAI,YAAY,SAAS,QAAQ,MAAM,IAAI;GAE3D,KAAKgB,mBAAmB;GACxB,KAAUC,aAAa,IAAI,KAAK,EAC7B,WAAW;IACV,KAAKC,qBAAqB,mBAAmB,KAAK;IAClD,KAAKP,gBAAgB,KAAKF;GAC5B,CAAC,EAGA,OAAM,MAAK;IACV,KAAKS,qBAAqB,OAAO,CAAC,GAAG,KAAK;IAC1C,KAAKC,0BAA0B,CAAC;GAClC,CAAC;EACL;CACF;CAEA,0BAA0B,GAAY;EACpC,IAAI,KAAKX,WAAW;GAClB,KAAKR,IAAI,QAAQ,iDAAiD,CAAC;GACnE;EACF;EACA,KAAKA,IAAI,OACP,uCAAuC,KAAKW,cAAc,MAC1D,CACF;EACA,KAAKI,sBAAsB,iBAAiB;GAC1C,KAAKA,sBAAsB,KAAA;GAC3B,KAAKD,uBAAuB;EAC9B,GAAG,KAAKH,aAAa;EAErB,KAAKA,gBAAgB,KAAK,IAAI,KAAKA,gBAAgB,GAAG,KAAKD,aAAa;CAC1E;CAEA,MAAMO,aAAa,IAAgB,OAA6B;EAC9D,MAAM,eAAe,KAAKf;EAI1B,IAAI,aAA4B;EAChC,IAAI,mBAAmB;EAEvB,MAAM,QAA6B;GACjC,OAAO,YAAY,IAAI;GACvB,YAAY,YAAY,IAAI;GAC5B,UAAU;GACV,OAAO;GACP,SAAS;GACT,QAAQ;GACR,WAAW;GACX,QAAQ;GACR,WAAW;GACX,SAAS;GACT,QAAQ;EACV;;;;EAKA,MAAM,aAAa,OACjB,QAC2B;GAC3B,OAAO,eAAe,MAAM,yCAAyC;GACrE,MAAM,gBAAgB,MAAM,aAAa,QAAQ,UAAU;GAI3D,IACE,MAAM,QAAQ,OAAO,WACpB,IAAI,QAAQ,cAAc,IAAI,YAAY,MAAM,cACjD;IACA,IAAI,CAAC,MAAM,QAAQ,OAAO,SAAS;KACjC,OAAO,IAAI,QAAQ,YAAY,+BAA+B;KAC9D,KAAKgB,qBACH,qBAAqB,MAAM,aAAa,mCACH,IAAI,aACzC,KACF;IACF;IACA,aAAa,QAAQ,aAAa;IAClC,OAAO;GACT;GAEA,MAAM,EAAC,OAAO,QAAQ,OAAM,uBAAuB,aAAa;GAChE,IAAI,KAAK,qBAAqB;IAC5B;IACA,OAAO,OAAO,KAAK,IAAI;GACzB,CAAC;GAED,IAAI,KAAK,IAAI,WAOX,KAAK,IAAI;GAGX,aAAkB,KAAK;IACrB;IACA;KAAC,KAAK;KAAS,MAAM,KAAKd;KAAa,SAAS;IAAI;IACpD,EAAC,iBAAiB,GAAE;GACtB,CAAC;GACD,OAAQ,aAAa;EACvB;EAEA,MAAM,iBAAiB;GACrB,IAAI,YAAY;IACd,aAAkB,KAAK;KACrB;KACA,EAAC,KAAK,SAAQ;KACd,EAAC,WAAW,WAAU;IACxB,CAAC;IACD,aAAa,QAAQ,UAAU;IAC/B,MAAM;GACR;GACA,aAAa;GACb,mBAAmB;EACrB;EASA,MAAM,QAAQ,IAAI,MAAY;EAC9B,MAAM,UAAU,IAAI,MAAS;EAC7B,KAAK,IAAI,IAAI,GAAG,IAAI,2BAA2B,KAC7C,QAAQ,QAAQ,CAAC;EAEnB,IAAI,eAAe;EAInB,MAAM,iBACJ,MAAM,iBAAiB,IAAI,WAAW,mBAAmB,CAAC;EAC5D,IAAI,CAAC,KAAKI,WACR,KAAKD,YAAY,OAAO,iBAAiB,SAAS,QAAQ;EAG5D,MAAM,YAAY,YAAY;GAC5B,IAAI;IACF,IAAI,KAAK,YAAY,IAAI;IACzB,WAAW,MAAM,SAAS,KAAKJ,kBAAkB,MAAM,OAAO,GAAG;KAC/D,MAAM,aAAa,YAAY,IAAI,IAAI;KACvC,MAAM,QAAQ,QAAQ;KACtB,IAAI,gBAAgB,KAAKK,WAAW;MAClC,MAAM,iBAAiB,IAAI,WAAW,mBAAmB,CAAC;MAC1D;KACF;KACA,MAAM,QAAQ,KAAK;KACnB,KAAK,YAAY,IAAI;IACvB;IACA,MAAM,QAAQ,IAAI;GACpB,SAAS,GAAG;IACV,MAAM,iBAAiB,CAAC;GAC1B;EACF,GAAG;EAIH,SAAc,YAAY,CAAC,CAAC;EAS5B,MAAM,WAAW,YAAoD;GAKnE,IAAI,eAAe,QAAQ,MAAM,KAAK,IAAI,GAAG;IAC3C,MAAM,IAAI,MAAM,QAAQ;IAExB,OADU,aAAa,UAAU,MAAM,IAAI;GAE7C;GAEA,SAAS;IACP,IAAI,eAAe,QAAQ,aAAa,YAAY,IAAI,GACtD,SAAS;IAEX,MAAM,IACJ,eAAe,OACX,MAAM,QAAQ,MAAM,uBAAuB,IAC3C,MAAM,QAAQ;IACpB,MAAM,KAAK,YAAY,IAAI;IAC3B,MAAM,IAAI,aAAa,UAAU,MAAM,IAAI;IAC3C,IAAI,MAAM,MAAM;KACd,MAAM,WAAW,YAAY,IAAI,IAAI;KACrC;IACF;IACA,IAAI,aAAa,SAAS;KACxB,MAAM,WAAW,YAAY,IAAI,IAAI;KACrC,MAAM;IACR;IACA,OAAO;GACT;EACF;EAEA,IAAI;GACF,SAAS;IACP,MAAM,OAAO,MAAM,SAAS;IAC5B,IAAI,SAAS,MACX;IAIF,QAAQ,QAAQ,CAAC;IAEjB,IAAI,KAAKA,WAAW;KAIlB,GAAG,OAAO,kDAAkD;KAC5D;IACF;IACA,MAAM,EAAC,SAAS,KAAK,aAAY;IAOjC,MAAM,sBAAsB,KAAKY,qBAC/B,IACA,IAAI,SACN;IAKA,IACE,eACC,aAAa,YAAY,IAAI,KAC5B,uBACA,oBAAoB,KAAKd,wBAE3B,SAAS;IAGX,IAAI,qBAAqB;KACvB,MAAM,KAAK,YAAY,IAAI;KAG3B,MAAM,eAAe,qBAAqB,MAAM,QAAQ,MAAM;KAC9D,MAAM,UAAU,YAAY,IAAI,IAAI;KACpC,MAAM,UAAU;KAChB,GAAG,OACD,yBAAyB,IAAI,UAAU,iBACpB,KAAK,MAAM,OAAO,EAAE,IACzC;IACF;IAEA,IACE,IAAI,QAAQ,cACZ,IAAI,UAAU,SAAS,KACvB,IAAI,SAAS,OAAO,QAAQ,WAAW,GAEvC,MAAM,IAAI,mBAAmB,MAAM,OAAO;IAI5C,IAAI,eAAe,MAAM;KACvB,MAAM,KAAK,YAAY,IAAI;KAC3B,aAAa,MAAM,WAAW,GAAG;KACjC,MAAM,aAAa,YAAY,IAAI,IAAI;KACvC,IAAI,eAAe,MAAM;MACvB,GAAG,OACD,6BAA6B,MAAM,QAAQ,OAAO,UAClD,MAAM,OACR;MACA,KAAKQ,uBAAuB;MAC5B;KACF;IACF;IAIA,MAAM,KAAK,YAAY,IAAI;IAC3B,MAAM,aAAa,KAAK,CAAC,QAAQ,GAAG,CAAC;IACrC,MAAM,UAAU,YAAY,IAAI,IAAI;IACpC,oBAAoB;IACpB,MAAM;IACN,MAAM,SAAS;IAEf,KAAKO,uBAAuB,IAAI,KAAK;GACvC;GAGA,IAAI,YACF,SAAS;GAEX,GAAG,QAAQ,wBAAwB;EACrC,UAAU;GACR,eAAe;GACf,QAAQ,QAAQ,CAAC;GAGjB,IAAI,CAAC,KAAKb,WACR,MAAM;GAER,KAAKD,YAAY,OAAO,oBAAoB,SAAS,QAAQ;GAC7D,KAAKe,kBAAkB,IAAI,KAAK;EAClC;CACF;CAEA,uBAAuB,IAAgB,OAA4B;EACjE,MAAM,MAAM,YAAY,IAAI;EAC5B,IAAI,MAAM,MAAM,cAAc,gCAAgC;GAC5D,KAAKA,kBAAkB,IAAI,KAAK;GAChC,MAAM,aAAa;EACrB;CACF;;;;;;;;;;;;CAaA,kBAAkB,IAAgB,OAA4B;EAC5D,MAAM,UAAU,YAAY,IAAI,IAAI,MAAM;EAC1C,GAAG,OAAO,mBAAmB;GAC3B,UAAU,MAAM;GAChB,OAAO,MAAM;GACb,SAAS,MAAM;GACf,QAAQ,MAAM;GACd,WAAW,KAAK,MAAM,OAAO;GAC7B,WAAW,KAAK,MAAM,MAAM,SAAS;GACrC,QAAQ,KAAK,MAAM,MAAM,MAAM;GAC/B,WAAW,KAAK,MAAM,MAAM,SAAS;GACrC,SAAS,KAAK,MAAM,MAAM,OAAO;GACjC,QAAQ,KAAK,MAAM,MAAM,MAAM;GAC/B,gBACE,UAAU,IAAI,KAAK,MAAM,MAAM,QAAQ,QAAQ,UAAU,IAAK,IAAI;EACtE,CAAC;CACH;CAEA,oBAAoB,OAAgD;EAClE,MAAM,QAAQ,KAAKN;EACnB,OAAO,OAAO,QAAQ,MAAM,WAAW,MAAM,UAC3C,MAAM,QAAQ,MAAM,SAAS,MAAM,OACjC,QACA;CACN;;;;;;;CAQA,qBAAqB,QAAiB,UAAiC;EACrE,MAAM,WAAW,KAAKA;EACtB,IAAI,YAAY,cAAc,YAAY,WAAW;GACnD,SAAS,QAAQ,MAAM,MAAM;GAC7B,KAAKA,mBAAmB;GACxB,UAAU,KAAKhB,IAAI,OAAO,uBAAuB,MAAM;EACzD;CACF;CAEA,qBAAqB,QAAgB,KAAsB;EACzD,MAAM,SAAS,KAAKC,mBAAmB,IAAI,IAAI,KAAK,IAAI,YAAY;EACpE,KAAKD,IAAI,OAAO,YAAY,OAAO,IAAI,UAAU,EAAC,UAAU,IAAG,CAAC;EAChE,KAAKC,mBAAmB,IAAI,IAAI,OAAO,GAAG;CAC5C;CAEA,wBAAwB,QAAgB,IAAgB;EACtD,MAAM,MAAM,KAAKA,mBAAmB,IAAI,EAAE;EAC1C,IAAI,KAAK;GACP,MAAM,SAAS,WAAW,uBAAuB,cAAc;GAC/D,KAAKD,IAAI,OAAO,YAAY,OAAO,IAAI,UAAU,EAAC,UAAU,IAAG,CAAC;GAChE,KAAKC,mBAAmB,OAAO,EAAE;EACnC;CACF;;;;;CAMA,SAAS,SAAoC;EAC3C,IAAI,QAAQ,OAAO,SAAS;GAC1B,KAAKsB,sBAAsB,QAAQ,GAAG;GACtC;EACF;EACA,IAAI,QAAQ,OAAO,UAAU;GAC3B,KAAKA,sBAAsB;GAC3B,KAAKC,wBAAwB,QAAQ,EAAE;GAGvC,KAAKV,uBAAuB;GAC5B;EACF;EACA,IAAI,QAAQ,OAAO,UAAU;GAC3B,KAAKU,wBAAwB,QAAQ,EAAE;GACvC;EACF;EACA,IAAI,QAAQ,OAAO,QACjB;EAEF,MAAM,SAAS,QAAQ;EACvB,MAAM,EAAC,QAAO;EACd,QAAQ,KAAR;GACE,KAAK,yBAAyB;IAC5B,MAAM,EAAC,OAAO,KAAK,aAAY;IAC/B,MAAM,kBAAkB,KAAKvB,mBAAmB,IAAI,KAAK;IACzD,IAAI,iBAAiB;KACnB,KAAKY,qBAAqB,KAAK;MAC7B,GAAG;MACH,OAAO;OAAC,GAAG,gBAAgB;OAAO;MAAQ;KAC5C,CAAC;KACD,IAAI,KAAKY,oBAAoB,KAAK,GAChC,KAAKP,qBAAqB,uBAAuB;IAErD;IACA;GACF;GACA,KAAK,gBAAgB;IACnB,MAAM,EACJ,MAAM,EAAC,QAAQ,QACf,WAAW,MACX,aACE;IAEJ,IAAI,UACF,KAAKL,qBAAqB,KAAK;KAC7B,OAAO;MAAC;MAAQ;MAAM;KAAQ;KAC9B,SAAS,OAAO,YACd,OAAO,QAAQ,QAAQ,EAAE,KAAK,CAAC,KAAK,QAAQ,CAAC,KAAK,EAAC,GAAE,CAAC,CAAC,CACzD;IACF,CAAC;IAEH;GACF;GACA,KAAK,gBAAgB;IACnB,MAAM,EAAC,KAAK,KAAK,aAAY;IAC7B,MAAM,kBAAkB,KAAKZ,mBAAmB,IAAI,GAAG;IACvD,IAAI,iBAAiB;KACnB,MAAM,EAAC,QAAQ,SAAQ;KACvB,KAAKyB,wBAAwB,KAAK,GAAG;KACrC,KAAKb,qBAAqB,KAAK;MAC7B,GAAG;MACH,OAAO;OAAC,GAAG,gBAAgB;OAAO;OAAQ;MAAI;KAChD,CAAC;KACD,IAAI,KAAKY,oBAAoB,GAAG,GAC9B,KAAKP,qBAAqB,eAAe;IAE7C;IACA;GACF;GACA,KAAK,cAAc;IACjB,MAAM,EAAC,OAAM;IAEb,IADwB,KAAKjB,mBAAmB,IAAI,EAChD,GAAiB;KACnB,KAAKyB,wBAAwB,KAAK,EAAE;KACpC,IAAI,KAAKD,oBAAoB,EAAE,GAC7B,KAAKP,qBAAqB,eAAe;IAE7C;IACA;GACF;GACA,KAAK,cAAc;IACjB,MAAM,EACJ,OACA,eAAe,WAAW,MAC1B,QACA,aACE;IACJ,IAAI,UAAU;KACZ,MAAM,kBAAkB,KAAKjB,mBAAmB,IAAI,KAAK;KACzD,IAAI,CAAC,iBACH,KAAKY,qBAAqB,KAAK;MAC7B,OAAO;OAAC,GAAG;OAAO;MAAQ;MAC1B,SAAS,GAAE,OAAO,OAAO,EAAC,IAAI,SAAQ,EAAC;KACzC,CAAC;UAED,KAAKA,qBAAqB,KAAK;MAC7B,GAAG;MACH,OAAO;OAAC,GAAG,gBAAgB;OAAO;MAAQ;MAC1C,SAAS;OACP,GAAG,gBAAgB;QAClB,OAAO,OAAO,EAAC,IAAI,SAAQ;MAC9B;KACF,CAAC;IAKL;IACA;GACF;GACA,KAAK,iBAAiB;IACpB,MAAM,EACJ,OACA,KAAK,EAAC,MAAM,WACZ,KAAK,EAAC,MAAM,cACV;IACJ,IAAI,YAAY,SAAS;KACvB,MAAM,kBAAkB,KAAKZ,mBAAmB,IAAI,KAAK;KACzD,IAAI,mBAAmB,WAAW,gBAAgB,SAAS;MACzD,MAAM,GAAE,UAAU,SAAS,GAAG,cAAa,gBAAgB;MAC3D,KAAKY,qBAAqB,KAAK;OAC7B,GAAG;OACH,SAAS;QAAC,GAAG;SAAY,UAAU;OAAO;MAC5C,CAAC;MACD,MAAM,WAAW,KAAKY,oBAAoB,KAAK;MAC/C,IAAI,YAAY,WAAW,SAAS,QAAQ,SAC1C,KAAKP,qBAAqB,gBAAgB;KAE9C;IACF;IACA;GACF;GACA,KAAK,eAAe;IAClB,MAAM,EAAC,OAAO,WAAU;IACxB,MAAM,kBAAkB,KAAKjB,mBAAmB,IAAI,KAAK;IACzD,IAAI,mBAAmB,UAAU,gBAAgB,SAAS;KACxD,MAAM,GAAE,SAAS,WAAW,GAAG,cAAa,gBAAgB;KAC5D,IAAI,OAAO,KAAK,SAAS,EAAE,WAAW,GACpC,KAAKyB,wBAAwB,KAAK,KAAK;UAEvC,KAAKb,qBAAqB,KAAK;MAC7B,GAAG;MACH,SAAS;KACX,CAAC;KAEH,MAAM,WAAW,KAAKY,oBAAoB,KAAK;KAC/C,IAAI,YAAY,UAAU,SAAS,QAAQ,SACzC,KAAKP,qBAAqB,gBAAgB;IAE9C;IACA;GACF;GACA,KAAK,UAAU;IACb,MAAM,EAAC,UAAU,KAAK,KAAK,QAAO;IAClC,MAAM,WAAW,KAAKO,oBAAoB,QAAQ;IAClD,MAAM,cAAc,KAAK,KAAKF,qBAAqB,aAAa;IAChE,IAAI,UAAU,QAAQ,MAAM,YAAY,QAAQ;UAQzC,MAAM,OAAO,OAAO,KACvB,SAAS,QAAQ,MAAM,SAAS,MAClC,GACE,IAAI,IAAI,SAAS,IAAI,MAAM;MACzB,SAAS,eAAe;MACxB,KAAKvB,IAAI,OACP,gCAAgC,IAAI,oCACA,SAAS,cAC/C;MACA;KACF;;IAGJ;GACF;GACA,KAAK,sBAAsB;IACzB,MAAM,EAAC,UAAU,YAAW;IAC5B,MAAM,kBAAkB,KAAKC,mBAAmB,IAAI,QAAQ;IAC5D,OACE,uBACM,yCAAyC,UAAU,MAAM,GACjE;IACA,MAAM,YAAY,OAAO,QAAQ,gBAAgB,OAAO,EAAE,QACvD,CAAC,SACA,EAAE,QAAQ,SAAS,GAAG,KAAK,SAAS,OAAO,QAAQ,SAAS,GAAG,EACnE;IACA,IAAI,UAAU,WAAW,GACvB,KAAKyB,wBAAwB,KAAK,QAAQ;SAE1C,KAAKb,qBAAqB,KAAK;KAC7B,GAAG;KACH,SAAS,OAAO,YAAY,SAAS;IACvC,CAAC;IAIH,KAAKK,qBAAqB;IAC1B;GACF;EACF;CACF;CAEA,SAAe;EACb,KAAKX,YAAY,MAAM,UAAU;EACjC,KAAKW,qBAAqB,wBAAwB;EAClD,aAAa,KAAKH,mBAAmB;EACrC,KAAKA,sBAAsB,KAAA;EAM3B,KAAK,MAAM,EAAC,aAAY,KAAKV,0BAA0B,OAAO,CAAC,GAC7D,QAAQ;CAEZ;AACF;AAEA,IAAe,sBAAf,cAA2C,MAAM;CAC/C,YAAY,IAAqB,KAAa,OAAiB;EAC7D,MACE,mBAAmB,GAAG,MAAM,OAAO,GAAG,GAAG,MAAM,KAAA,GACzC,OAAO,KAAK,GAAG,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,OAC7C,EAAC,MAAK,CACR;CACF;AACF;;;;;;;;;;;;;;;;;;;;AAqBA,IAAM,qBAAN,cAAiC,oBAAoB;CACnD,OAAgB;CAEhB,YAAY,IAAqB,OAAiB;EAChD,MAAM,IAAI,IAAI,GAAG,MAAM,KAAK,6BAA6B,KAAK;CAChE;AACF;;;;;;;AAQA,IAAa,6BAAb,cAAgD,oBAAoB;CAClE,OAAgB;CAEhB,YAAY,IAAqB,KAAa,OAAiB;EAC7D,MAAM,IAAI,KAAK,KAAK;CACtB;AACF"}
|
|
1
|
+
{"version":3,"file":"backfill-manager.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/backfill-manager.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../../../../shared/src/abort-error.ts';\nimport {assert} from '../../../../../shared/src/asserts.ts';\nimport {stringify} from '../../../../../shared/src/bigint-json.ts';\nimport {CustomKeyMap} from '../../../../../shared/src/custom-key-map.ts';\nimport {must} from '../../../../../shared/src/must.ts';\nimport {promiseOrAbort} from '../../../../../shared/src/promise-race.ts';\nimport {Queue} from '../../../../../shared/src/queue.ts';\nimport {randInt} from '../../../../../shared/src/rand.ts';\nimport {resolver} from '../../../../../shared/src/resolver.ts';\nimport {JSON_STRINGIFIED, type JSONFormat} from '../../../types/lite.ts';\nimport {\n stateVersionFromString,\n stateVersionToString,\n} from '../../../types/state-version.ts';\nimport type {\n BackfillCompleted,\n BackfillRequest,\n ChangeStreamMessage,\n Identifier,\n MessageBackfill,\n} from '../protocol/current.ts';\nimport type {\n Cancelable,\n ChangeStreamMultiplexer,\n Listener,\n} from './change-stream-multiplexer.ts';\n\nfunction tableKey({schema, name}: Identifier) {\n return `${schema}.${name}`;\n}\n\n/**\n * A {@link MessageBackfill} or {@link BackfillCompleted} paired with the\n * approximate number of upstream bytes it represents. The BackfillManager uses\n * `byteSize` to bound the size of each replica transaction, committing and\n * reopening once {@link COMMIT_THRESHOLD_BYTES} is reached.\n */\nexport type BackfillMessage = {\n message: MessageBackfill | BackfillCompleted;\n byteSize: number;\n};\n\ntype BackfillStreamer = (\n req: BackfillRequest,\n) => AsyncGenerator<BackfillMessage>;\n\n/**\n * Commit (and reopen) the current backfill transaction once this many bytes of\n * backfill data have accumulated in it. Bounds the size of a single replica\n * COMMIT/checkpoint so it can't monopolize the replica.\n */\nconst COMMIT_THRESHOLD_BYTES = 8 * 1024 * 1024;\n\n/**\n * How many backfill messages the prefetch producer may read ahead of the\n * reservation-holding consumer loop. This bounds the in-memory buffer (~this\n * many {@link BackfillMessage}s, each up to the stream's flush threshold, e.g.\n * 64 KiB) while giving the consumer a supply of ready messages so it never\n * has to wait on the upstream COPY while holding the change-stream reservation.\n */\nconst BACKFILL_PREFETCH_CREDITS = 16;\n\n/**\n * While the backfill holds an open transaction but its prefetch queue is empty\n * (i.e. the upstream is momentarily behind), the consumer polls for the next\n * message at this interval so that a replication transaction that begins\n * waiting mid-fetch can preempt the backfill within this bound, rather than\n * being blocked for the entire (possibly slow) upstream read.\n *\n * If stats indicate that these stalls are highly correlative with replication\n * lag (indicating that replication changes are waiting on these polls), we\n * can address this by adding an API to the change stream multiplexer that\n * would allow backfill to relinquish an in-progress commit on demand (i.e.\n * only if replication asks for a reservation).\n */\nconst BACKFILL_WAITER_POLL_MS = 10;\n\n/** Interval at which in-progress backfill timing stats are logged. */\nconst BACKFILL_STATS_LOG_INTERVAL_MS = 10_000;\n\n/** Sentinel enqueued by the prefetch producer when the backfill stream ends. */\nconst DONE = Symbol('backfill-done');\n/** Sentinel returned by a polled dequeue that timed out (see {@link BACKFILL_WAITER_POLL_MS}). */\nconst POLL = Symbol('backfill-poll');\n\ntype Pull = BackfillMessage | typeof DONE | typeof POLL;\n\n/**\n * Accumulated timing attribution for a single backfill run, logged\n * periodically to reveal where the backfill spends its time (and, in\n * particular, where the change-stream reservation is held). `produceMs`\n * accrues on the prefetch producer task and thus overlaps with the consumer's\n * `pushMs`; the others accrue on the reservation-holding consumer loop.\n */\ntype BackfillTimingStats = {\n start: number;\n lastLogged: number;\n messages: number;\n bytes: number;\n commits: number;\n stalls: number;\n produceMs: number;\n pushMs: number;\n reserveMs: number;\n stallMs: number;\n waitMs: number;\n};\n\ntype RunningBackfillState = {\n request: BackfillRequest;\n minWatermark: string;\n /**\n * Aborted (with the reason, if any) when this backfill is stopped,\n * e.g. canceled.\n */\n stopped: AbortController;\n};\n\nconst MIN_BACKOFF_INTERVAL_MS = 2_000;\nconst MAX_BACKOFF_INTERVAL_MS = 60_000;\n\ntype AwaitingStatusWatermark = {\n watermark: string;\n reached: () => void;\n};\n\n/**\n * The BackfillManager initiates backfills for BackfillRequests from the\n * change-streamer (i.e. unfinished backfills from previous sessions)\n * or for new backfills signaled by `create-table` or `add-column` messages\n * from the change-source.\n *\n * The BackfillManager registers itself as a change stream listener in order\n * to track necessary backfills, and potentially invalidate the in-progress\n * backfill (e.g. due to a schema change) so that it can be retried at a\n * new snapshot.\n *\n * The manager also handles low priority streaming of the backfill messages\n * using the {@link ChangeStreamMultiplexer}, implementing a policy of always\n * releasing its reservation if another producer (i.e. the main change stream)\n * has messages to stream.\n */\nexport class BackfillManager implements Cancelable, Listener {\n readonly #lc: LogContext;\n\n /**\n * Tracks the metadata of required backfills based on schema changes\n * and initial backfill requests.\n */\n readonly #requiredBackfills = new CustomKeyMap<Identifier, BackfillRequest>(\n tableKey,\n );\n readonly #changeStreamer: ChangeStreamMultiplexer;\n readonly #backfillStreamer: BackfillStreamer;\n readonly #jsonFormat: JSONFormat;\n\n /**\n * The current running backfill. The backfill request is always also in\n * `#requiredBackfills` (technically, it can be a subset of what's in\n * `#requiredBackfills`); the request is removed from `#requiredBackfills`\n * upon completion.\n */\n #runningBackfill: RunningBackfillState | null = null;\n\n /** The last seen watermark in the change stream. */\n #lastStatusWatermark: string | null = null;\n\n readonly #awaitingStatusWatermarks: AwaitingStatusWatermark[] = [];\n\n /** The watermark of the current transaction in the change stream. */\n #currentTxWatermark: string | null = null;\n\n readonly #commitThresholdBytes: number;\n\n /**\n * Aborted when the change stream is canceled. No further backfills are run.\n *\n * TODO: Thread this into the backfillStream so that upstream I/O can be\n * aborted.\n */\n readonly #controller = new AbortController();\n\n get #canceled() {\n return this.#controller.signal.aborted;\n }\n\n constructor(\n lc: LogContext,\n changeStreamer: ChangeStreamMultiplexer,\n backfillStreamer: BackfillStreamer,\n jsonFormat: JSONFormat = JSON_STRINGIFIED,\n minBackoffMs = MIN_BACKOFF_INTERVAL_MS,\n maxBackoffMs = MAX_BACKOFF_INTERVAL_MS,\n commitThresholdBytes = COMMIT_THRESHOLD_BYTES,\n ) {\n this.#lc = lc.withContext('component', 'backfill-manager');\n this.#changeStreamer = changeStreamer;\n this.#backfillStreamer = backfillStreamer;\n this.#jsonFormat = jsonFormat;\n this.#minBackoffMs = minBackoffMs;\n this.#maxBackoffMs = maxBackoffMs;\n this.#retryDelayMs = minBackoffMs;\n this.#commitThresholdBytes = commitThresholdBytes;\n }\n\n run(lastWatermark: string, initialRequests: BackfillRequest[]) {\n this.#lc.info?.(\n `starting backfill manager with ${initialRequests.length} initial requests`,\n {requests: initialRequests},\n );\n this.#lastStatusWatermark = lastWatermark;\n initialRequests.forEach(req =>\n this.#setRequiredBackfill('initial-request', req),\n );\n this.#checkAndStartBackfill();\n }\n\n #setLastStatusWatermark({watermark}: {watermark: string}) {\n // Only allow the watermark to move forward. This prevents a backfill\n // transaction (whose watermark is unrelated to change-stream state)\n // from moving the watermark backwards.\n if ((this.#lastStatusWatermark ?? '') < watermark) {\n this.#lastStatusWatermark = watermark;\n for (let i = this.#awaitingStatusWatermarks.length - 1; i >= 0; i--) {\n const awaiting = this.#awaitingStatusWatermarks[i];\n if (watermark >= awaiting.watermark) {\n awaiting.reached();\n this.#awaitingStatusWatermarks.splice(i, 1);\n }\n }\n }\n }\n\n #changeStreamReached(\n lc: LogContext,\n watermark: string,\n ): Promise<void> | null {\n if ((this.#lastStatusWatermark ?? '') < watermark) {\n const {promise, resolve: reached} = resolver();\n this.#awaitingStatusWatermarks.push({watermark, reached});\n lc.info?.(\n `waiting for change stream (at ${this.#lastStatusWatermark}) to reach ${watermark}`,\n );\n return promise;\n }\n return null;\n }\n\n readonly #minBackoffMs: number;\n readonly #maxBackoffMs: number;\n #retryDelayMs: number;\n #backfillRetryTimer: NodeJS.Timeout | undefined;\n\n #checkAndStartBackfill() {\n if (\n !this.#canceled &&\n !this.#backfillRetryTimer &&\n !this.#runningBackfill &&\n this.#requiredBackfills.size\n ) {\n // Pick a random backfill to avoid head-of-line blocking by a\n // problematic backfill (e.g. awaiting a primary key). This is\n // simpler that adding logic to classify (and declassify)\n // problematic backfills.\n const candidates = [...this.#requiredBackfills.values()];\n const request = candidates[randInt(0, candidates.length - 1)];\n const state = {\n request,\n minWatermark: '',\n stopped: new AbortController(),\n };\n const lc = this.#lc.withContext('table', request.table.name);\n\n this.#runningBackfill = state;\n void this.#runBackfill(lc, state)\n .then(() => {\n this.#stopRunningBackfill('backfill exited', state);\n this.#retryDelayMs = this.#minBackoffMs; // reset on success\n })\n // For unexpected errors (e.g. upstream replication slot\n // unavailability), retry with exponential backoff.\n .catch(e => {\n this.#stopRunningBackfill(String(e), state);\n this.#retryBackfillWithBackoff(e);\n });\n }\n }\n\n #retryBackfillWithBackoff(e: unknown) {\n if (this.#canceled) {\n this.#lc.debug?.(`not retrying backfill: change stream canceled`, e);\n return;\n }\n this.#lc.warn?.(\n `Error running backfill. Retrying in ${this.#retryDelayMs} ms`,\n e,\n );\n this.#backfillRetryTimer = setTimeout(() => {\n this.#backfillRetryTimer = undefined;\n this.#checkAndStartBackfill();\n }, this.#retryDelayMs);\n\n this.#retryDelayMs = Math.min(this.#retryDelayMs * 2, this.#maxBackoffMs);\n }\n\n async #runBackfill(lc: LogContext, state: RunningBackfillState) {\n const changeStream = this.#changeStreamer; // Purely for readability\n\n // backfillTx is set if and only if a changeStreamer reservation has been\n // acquired and the backfill stream is inside a transaction.\n let backfillTx: string | null = null;\n let uncommittedBytes = 0;\n\n const stats: BackfillTimingStats = {\n start: performance.now(),\n lastLogged: performance.now(),\n messages: 0,\n bytes: 0,\n commits: 0,\n stalls: 0,\n produceMs: 0,\n pushMs: 0,\n reserveMs: 0,\n stallMs: 0,\n waitMs: 0,\n };\n\n /**\n * @returns the new tx watermark, or null if backfill was cancelled\n */\n const beginTxFor = async (\n msg: MessageBackfill | BackfillCompleted,\n ): Promise<string | null> => {\n assert(backfillTx === null, 'Expected no active backfill transaction');\n const lastWatermark = await changeStream.reserve('backfill');\n\n // After obtaining the changeStream reservation, check if the stream\n // had changes that resulted in invalidating / canceling this backfill.\n if (\n state.stopped.signal.aborted ||\n (msg.tag === 'backfill' && msg.watermark < state.minWatermark)\n ) {\n if (!state.stopped.signal.aborted) {\n assert(msg.tag === 'backfill', 'Expected backfill message tag'); // TypeScript should have figured this out.\n this.#stopRunningBackfill(\n `row key change at ${state.minWatermark} ` +\n `postdates backfill watermark at ${msg.watermark}`,\n state,\n );\n }\n changeStream.release(lastWatermark);\n return null;\n }\n\n const {major, minor = 0n} = stateVersionFromString(lastWatermark);\n let tx = stateVersionToString({\n major,\n minor: BigInt(minor) + 1n,\n });\n\n if (tx < msg.watermark) {\n // At this point it must be the case that the #changeStreamReached()\n // the backfill watermark (possibly via a status message, which does\n // not advance the reservation watermark). Given that guarantee,\n // ensure that the version of the backfill transaction is at least up\n // to the backfill watermark, so that the database state version is\n // never earlier than the version of any backfilled rows.\n tx = msg.watermark;\n }\n\n void changeStream.push([\n 'begin',\n {tag: 'begin', json: this.#jsonFormat, skipAck: true},\n {commitWatermark: tx},\n ]);\n return (backfillTx = tx);\n };\n\n const commitTx = () => {\n if (backfillTx) {\n void changeStream.push([\n 'commit',\n {tag: 'commit'},\n {watermark: backfillTx},\n ]);\n changeStream.release(backfillTx);\n stats.commits++;\n }\n backfillTx = null;\n uncommittedBytes = 0;\n };\n\n // === Prefetch producer ===\n //\n // The backfill stream (an upstream Postgres COPY) is drained on a separate\n // task into a bounded queue, so that the reservation-holding consumer loop\n // below never blocks on the upstream read while it holds the change-stream\n // reservation. `credits` bounds how far the producer runs ahead; the\n // consumer returns a credit for every message it takes.\n const ready = new Queue<Pull>();\n const credits = new Queue<1>();\n for (let i = 0; i < BACKFILL_PREFETCH_CREDITS; i++) {\n credits.enqueue(1);\n }\n let stopProducer = false;\n\n // Wakes a consumer blocked awaiting the next prefetched message so a\n // canceled backfill unwinds promptly.\n const onCancel = () =>\n ready.enqueueRejection(new AbortError('backfill canceled'));\n if (!this.#canceled) {\n this.#controller.signal.addEventListener('abort', onCancel);\n }\n\n const producer = (async () => {\n try {\n let t0 = performance.now();\n for await (const value of this.#backfillStreamer(state.request)) {\n stats.produceMs += performance.now() - t0;\n await credits.dequeue(); // wait for buffer space (flow control)\n if (stopProducer || this.#canceled) {\n ready.enqueueRejection(new AbortError('backfill canceled'));\n return;\n }\n ready.enqueue(value);\n t0 = performance.now();\n }\n ready.enqueue(DONE);\n } catch (e) {\n ready.enqueueRejection(e);\n }\n })();\n // The producer routes errors through `ready` and never rejects; guard\n // anyway so that leaving it un-awaited on the cancellation path (below)\n // cannot surface as an unhandled rejection.\n void producer.catch(() => {});\n\n // === Consumer ===\n\n // Fetches the next item from the prefetch queue. If a transaction is open\n // but the queue is empty (the producer/upstream is momentarily behind),\n // polls so that a replication transaction that begins waiting during the\n // upstream read can preempt the backfill: rather than hold the reservation\n // for the whole read, commit and release, letting replication proceed.\n const nextItem = async (): Promise<BackfillMessage | typeof DONE> => {\n // Fast path: a message is already buffered, or there's no reservation to\n // protect. Take it without altering transaction boundaries. `POLL` is\n // never enqueued (only used as a dequeue timeout value), so the result is\n // always a message or DONE.\n if (backfillTx === null || ready.size() > 0) {\n const n = ready.dequeue();\n const v = n instanceof Promise ? await n : n;\n return v as BackfillMessage | typeof DONE;\n }\n // Slow path: holding a reservation with an empty queue.\n for (;;) {\n if (backfillTx !== null && changeStream.waiterDelay() > 0) {\n commitTx(); // yield the stream to the waiting replication txn\n }\n const n =\n backfillTx !== null\n ? ready.dequeue(POLL, BACKFILL_WAITER_POLL_MS)\n : ready.dequeue(); // released: just wait for the next message\n const t0 = performance.now();\n const v = n instanceof Promise ? await n : n;\n if (v === POLL) {\n stats.stallMs += performance.now() - t0; // timed out; re-check waiter\n continue;\n }\n if (n instanceof Promise) {\n stats.stallMs += performance.now() - t0;\n stats.stalls++;\n }\n return v;\n }\n };\n\n try {\n for (;;) {\n const item = await nextItem();\n if (item === DONE) {\n break;\n }\n // Allow the producer to fetch the next message concurrently with the\n // processing (and downstream push) of this one.\n credits.enqueue(1);\n\n if (this.#canceled) {\n // Returning finalizes the backfill stream (and the upstream resources\n // it holds) via the producer's `finally`. The reservation, if held,\n // does not need to be released since the change stream is gone.\n lc.info?.(`backfill stream canceled: change stream canceled`);\n return;\n }\n const {message: msg, byteSize} = item;\n\n // Before sending any backfill message, the main replication stream\n // must reach the backfill (snapshot) watermark. Otherwise, snapshot\n // rows can constitute \"future\" state (e.g. phantom rows at keys that\n // the stream has yet to move or insert) that the subsequent\n // replication changes conflict with (e.g. on unique indexes).\n const waitForChangeStream = this.#changeStreamReached(\n lc,\n msg.watermark,\n );\n\n // Commit (and later reopen) the transaction if the main stream is\n // waiting on the reservation, if we must wait for the main stream, or\n // if the size of current transaction has reached the commit threshold.\n if (\n backfillTx &&\n (changeStream.waiterDelay() > 0 ||\n waitForChangeStream ||\n uncommittedBytes >= this.#commitThresholdBytes)\n ) {\n commitTx();\n }\n\n if (waitForChangeStream) {\n const t0 = performance.now();\n // Exit promptly (via the error path) if the backfill is canceled\n // while waiting, releasing its upstream resources.\n await promiseOrAbort(waitForChangeStream, state.stopped.signal);\n const elapsed = performance.now() - t0;\n stats.waitMs += elapsed;\n lc.info?.(\n `change stream reached ${msg.watermark} ` +\n `after waiting ${Math.round(elapsed)} ms`,\n );\n }\n\n if (\n msg.tag === 'backfill' &&\n msg.rowValues.length > 0 &&\n msg.relation.rowKey.columns.length === 0\n ) {\n throw new MissingRowKeyError(state.request);\n }\n\n // Reserve the changeStreamer if not in a transaction.\n if (backfillTx === null) {\n const t0 = performance.now();\n backfillTx = await beginTxFor(msg);\n stats.reserveMs += performance.now() - t0;\n if (backfillTx === null) {\n lc.info?.(\n `backfill stream canceled: ${state.stopped.signal.reason}`,\n state.request,\n );\n this.#checkAndStartBackfill(); // start the next backfill if present\n return; // this backfill is canceled\n }\n }\n\n // `await` to allow the change streamer to exert back pressure\n // on backfills.\n const t0 = performance.now();\n await changeStream.push(['data', msg]);\n stats.pushMs += performance.now() - t0;\n uncommittedBytes += byteSize;\n stats.messages++;\n stats.bytes += byteSize;\n\n this.#maybeLogBackfillStats(lc, stats);\n }\n\n // Flush any final tx and release the stream.\n if (backfillTx) {\n commitTx();\n }\n lc.debug?.(`backfill stream exited`);\n } finally {\n stopProducer = true;\n credits.enqueue(1);\n // The producer can potentially be hung on upstream I/O.\n // TODO: Thread AbortSignal logic into the backfillStreamer.\n if (!this.#canceled) {\n await producer;\n }\n this.#controller.signal.removeEventListener('abort', onCancel);\n this.#logBackfillStats(lc, stats);\n }\n }\n\n #maybeLogBackfillStats(lc: LogContext, stats: BackfillTimingStats) {\n const now = performance.now();\n if (now - stats.lastLogged >= BACKFILL_STATS_LOG_INTERVAL_MS) {\n this.#logBackfillStats(lc, stats);\n stats.lastLogged = now;\n }\n }\n\n /**\n * Logs where the backfill spent its time. `produceMs` (upstream read +\n * parse/decode) accrues on the prefetch producer concurrently with the\n * consumer's `pushMs` (downstream backpressure), so the two can overlap and\n * their sum can exceed `elapsedMs`. `reserveMs` is time spent (re)acquiring\n * the change-stream reservation, and `stallMs` is time the consumer waited on\n * an empty prefetch queue (i.e. blocked on the upstream) — a large `stallMs`\n * indicates an upstream-bound backfill. `waitMs` is time spent waiting\n * (without the reservation) for the change stream to reach the backfill\n * watermark, during which the upstream snapshot is held open.\n */\n #logBackfillStats(lc: LogContext, stats: BackfillTimingStats) {\n const elapsed = performance.now() - stats.start;\n lc.info?.(`backfill timing`, {\n messages: stats.messages,\n bytes: stats.bytes,\n commits: stats.commits,\n stalls: stats.stalls,\n elapsedMs: Math.round(elapsed),\n produceMs: Math.round(stats.produceMs),\n pushMs: Math.round(stats.pushMs),\n reserveMs: Math.round(stats.reserveMs),\n stallMs: Math.round(stats.stallMs),\n waitMs: Math.round(stats.waitMs),\n throughputKBps:\n elapsed > 0 ? Math.round(stats.bytes / 1024 / (elapsed / 1000)) : 0,\n });\n }\n\n #backfillRunningFor(table: Identifier): RunningBackfillState | null {\n const state = this.#runningBackfill;\n return state?.request.table.schema === table.schema &&\n state.request.table.name === table.name\n ? state\n : null;\n }\n\n /**\n * Stops the running backfill for the specified `reason`. If `instance` is\n * specified, the running backfill is stopped only if it is that instance.\n * This allows the running backfill itself to clear backfill state without\n * accidentally stopping a different (e.g. subsequent) backfill.\n */\n #stopRunningBackfill(reason?: string, instance?: RunningBackfillState) {\n const backfill = this.#runningBackfill;\n if (backfill && backfill === (instance ?? backfill)) {\n backfill.stopped.abort(reason);\n this.#runningBackfill = null;\n reason && this.#lc.info?.(`canceling backfill:`, reason);\n }\n }\n\n #setRequiredBackfill(source: string, req: BackfillRequest) {\n const action = this.#requiredBackfills.has(req.table) ? 'updated' : 'added';\n this.#lc.info?.(`Backfill ${action}: ${source}`, {backfill: req});\n this.#requiredBackfills.set(req.table, req);\n }\n\n #deleteRequiredBackfill(source: string, id: Identifier) {\n const req = this.#requiredBackfills.get(id);\n if (req) {\n const action = source === 'backfill-completed' ? 'completed' : 'dropped';\n this.#lc.info?.(`Backfill ${action}: ${source}`, {backfill: req});\n this.#requiredBackfills.delete(id);\n }\n }\n\n /**\n * Implements {@link Listener.onChange()}, invoked by the\n * {@link ChangeStreamMultiplexer}.\n */\n onChange(message: ChangeStreamMessage): void {\n if (message[0] === 'begin') {\n this.#currentTxWatermark = message[2].commitWatermark;\n return;\n }\n if (message[0] === 'commit') {\n this.#currentTxWatermark = null;\n this.#setLastStatusWatermark(message[2]);\n // Every commit is a candidate for starting the next backfill\n // (if one is not currently running).\n this.#checkAndStartBackfill();\n return;\n }\n if (message[0] === 'status') {\n this.#setLastStatusWatermark(message[2]);\n return;\n }\n if (message[0] !== 'data') {\n return;\n }\n const change = message[1];\n const {tag} = change;\n switch (tag) {\n case 'update-table-metadata': {\n const {table, new: metadata} = change;\n const backfillRequest = this.#requiredBackfills.get(table);\n if (backfillRequest) {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n table: {...backfillRequest.table, metadata},\n });\n if (this.#backfillRunningFor(table)) {\n this.#stopRunningBackfill(`TableMetadata updated`);\n }\n }\n break;\n }\n case 'create-table': {\n const {\n spec: {schema, name},\n metadata = null,\n backfill,\n } = change;\n\n if (backfill) {\n this.#setRequiredBackfill(tag, {\n table: {schema, name, metadata},\n columns: Object.fromEntries(\n Object.entries(backfill).map(([col, id]) => [col, {id}]),\n ),\n });\n }\n break;\n }\n case 'rename-table': {\n const {old, new: newTable} = change;\n const backfillRequest = this.#requiredBackfills.get(old);\n if (backfillRequest) {\n const {schema, name} = newTable;\n this.#deleteRequiredBackfill(tag, old);\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n table: {...backfillRequest.table, schema, name},\n });\n if (this.#backfillRunningFor(old)) {\n this.#stopRunningBackfill(`table renamed`);\n }\n }\n break;\n }\n case 'drop-table': {\n const {id} = change;\n const backfillRequest = this.#requiredBackfills.get(id);\n if (backfillRequest) {\n this.#deleteRequiredBackfill(tag, id);\n if (this.#backfillRunningFor(id)) {\n this.#stopRunningBackfill(`table dropped`);\n }\n }\n break;\n }\n case 'add-column': {\n const {\n table,\n tableMetadata: metadata = null,\n column,\n backfill,\n } = change;\n if (backfill) {\n const backfillRequest = this.#requiredBackfills.get(table);\n if (!backfillRequest) {\n this.#setRequiredBackfill(tag, {\n table: {...table, metadata},\n columns: {[column.name]: {id: backfill}},\n });\n } else {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n table: {...backfillRequest.table, metadata},\n columns: {\n ...backfillRequest.columns,\n [column.name]: {id: backfill},\n },\n });\n // Note: The running backfill need not be canceled if a\n // new column is added. The new column will be backfilled\n // by its own stream after the current backfill completes.\n }\n }\n break;\n }\n case 'update-column': {\n const {\n table,\n old: {name: oldName},\n new: {name: newName},\n } = change;\n if (oldName !== newName) {\n const backfillRequest = this.#requiredBackfills.get(table);\n if (backfillRequest && oldName in backfillRequest.columns) {\n const {[oldName]: colSpec, ...otherCols} = backfillRequest.columns;\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n columns: {...otherCols, [newName]: colSpec},\n });\n const backfill = this.#backfillRunningFor(table);\n if (backfill && oldName in backfill.request.columns) {\n this.#stopRunningBackfill(`column renamed`);\n }\n }\n }\n break;\n }\n case 'drop-column': {\n const {table, column} = change;\n const backfillRequest = this.#requiredBackfills.get(table);\n if (backfillRequest && column in backfillRequest.columns) {\n const {[column]: _excluded, ...remaining} = backfillRequest.columns;\n if (Object.keys(remaining).length === 0) {\n this.#deleteRequiredBackfill(tag, table);\n } else {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n columns: remaining,\n });\n }\n const backfill = this.#backfillRunningFor(table);\n if (backfill && column in backfill.request.columns) {\n this.#stopRunningBackfill(`column dropped`);\n }\n }\n break;\n }\n case 'update': {\n const {relation, key, new: row} = change;\n const backfill = this.#backfillRunningFor(relation);\n const txWatermark = must(this.#currentTxWatermark, `not in a tx`);\n if (backfill?.request.table.metadata && key !== null) {\n // A corner case that backfill is unable to correctly handle is\n // when a row's key changes; this is decomposed into a delete\n // of the old key and a set of the new key in the replica change\n // log, at which point the backfill algorithm assumes that the\n // (old) row is deleted but does not know to backfill the new row.\n // In these corner cases, the current backfill is canceled and\n // retried if its version precedes this update.\n for (const col of Object.keys(\n backfill.request.table.metadata.rowKey,\n )) {\n if (key[col] !== row[col]) {\n backfill.minWatermark = txWatermark;\n this.#lc.info?.(\n `key for row as changed (col: ${col}). ` +\n `backfill data must not predate ${backfill.minWatermark}`,\n );\n break;\n }\n }\n }\n break;\n }\n case 'backfill-completed': {\n const {relation, columns} = change;\n const backfillRequest = this.#requiredBackfills.get(relation);\n assert(\n backfillRequest,\n () => `No BackfillRequest completed backfill ${stringify(change)}`,\n );\n const remaining = Object.entries(backfillRequest.columns).filter(\n ([col]) =>\n !(columns.includes(col) || relation.rowKey.columns.includes(col)),\n );\n if (remaining.length === 0) {\n this.#deleteRequiredBackfill(tag, relation);\n } else {\n this.#setRequiredBackfill(tag, {\n ...backfillRequest,\n columns: Object.fromEntries(remaining),\n });\n }\n // Technically the backfill is already stopping, but this method\n // cleans up the state that tracks it.\n this.#stopRunningBackfill();\n break;\n }\n }\n }\n\n cancel(): void {\n this.#controller.abort('canceled');\n this.#stopRunningBackfill(`change stream canceled`);\n clearTimeout(this.#backfillRetryTimer);\n this.#backfillRetryTimer = undefined;\n\n // Wake up a backfill that is waiting for the change stream to reach a\n // watermark. The change stream never will, and the backfill must be\n // allowed to unwind (and release its upstream resources) rather than\n // remain suspended forever.\n for (const {reached} of this.#awaitingStatusWatermarks.splice(0)) {\n reached();\n }\n }\n}\n\nabstract class BackfillStreamError extends Error {\n constructor(bf: BackfillRequest, msg: string, cause?: unknown) {\n super(\n `Cannot backfill ${bf.table.schema}.${bf.table.name}` +\n `[${Object.keys(bf.columns).join(',')}]: ${msg}`,\n {cause},\n );\n }\n}\n\n/**\n * Background: The zero-cache supports replication of tables without a\n * PRIMARY KEY to facilitate the onboarding process. These rows can be\n * INSERT'ed, but postgres will rightfully prohibit UPDATEs and DELETEs\n * on such tables because the rows cannot be identified by a key. Supporting\n * this mode of replication allows the user to \"fix\" the setup by adding the\n * primary key, after which the table can be published downstream without\n * requiring a resync of the data.\n *\n * In terms of backfill, however, non-empty tables without a row key **cannot**\n * be backfilled, because backfill retries would result in writing duplicating\n * rows. (Empty tables, on the other hand, are fine because there is no data\n * to be deduped.)\n *\n * The MissingRowKeyError is used to signal that the table cannot be backfilled\n * in its current state. For simplicity, it is handled like runtime errors and\n * retried with backoff, with which it can eventually succeed if (1) a primary\n * key is added or (2) the table is emptied, e.g. via a TRUNCATE.\n */\nclass MissingRowKeyError extends BackfillStreamError {\n readonly name = 'MissingRowKeyError';\n\n constructor(bf: BackfillRequest, cause?: unknown) {\n super(bf, `\"${bf.table.name}\" is missing a PRIMARY KEY`, cause);\n }\n}\n\n/**\n * Error type for backfill stream implementations to throw indicating that\n * the backfill request failed due to a schema incompatibility error. This\n * type of error does not need exponential backoff, as the retry happens\n * naturally once the invalidating schema change is processed and committed.\n */\nexport class SchemaIncompatibilityError extends BackfillStreamError {\n readonly name = 'SchemaIncompatibilityError';\n\n constructor(bf: BackfillRequest, msg: string, cause?: unknown) {\n super(bf, msg, cause);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { assert } from "../../../../../shared/src/asserts.js";
|
|
2
|
+
import { resolver } from "../../../../../shared/src/resolver.js";
|
|
2
3
|
import { AbortError } from "../../../../../shared/src/abort-error.js";
|
|
3
4
|
import { Subscription } from "../../../types/subscription.js";
|
|
4
|
-
import { resolver } from "@rocicorp/resolver";
|
|
5
5
|
//#region ../zero-cache/src/services/change-source/common/change-stream-multiplexer.ts
|
|
6
6
|
/**
|
|
7
7
|
* Facilitates cooperative multiplexing of transactions from
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"change-stream-multiplexer.js","names":[
|
|
1
|
+
{"version":3,"file":"change-stream-multiplexer.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/change-stream-multiplexer.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {AbortError} from '../../../../../shared/src/abort-error.ts';\nimport {assert} from '../../../../../shared/src/asserts.ts';\nimport {resolver} from '../../../../../shared/src/resolver.ts';\nimport type {Source} from '../../../types/streams.ts';\nimport {Subscription} from '../../../types/subscription.ts';\nimport type {\n ChangeStreamMessage,\n DownstreamStatusMessage,\n} from '../protocol/current.ts';\n\nexport type Cancelable = {\n cancel(): void;\n};\n\nexport type Listener = {\n onChange(change: ChangeStreamMessage): void;\n};\n\ntype Waiter = {\n producer: string;\n startTime: number;\n grantReservation: (watermark: string) => void;\n rejectReservation: (err: Error) => void;\n};\n\n/**\n * Facilitates cooperative multiplexing of transactions from\n * multiple producers into a single change stream.\n */\nexport class ChangeStreamMultiplexer {\n readonly #lc: LogContext;\n readonly #sub: Subscription<ChangeStreamMessage>;\n readonly #producers: Cancelable[] = [];\n readonly #listeners: Listener[] = [];\n\n /**\n * The `#lastWatermark` tracks the watermark of the last transaction\n * committed to stream. It is set to null when a producer has reserved\n * the stream, and set to the new watermark when the producer releases\n * the reservation.\n */\n #lastWatermark: string | null;\n\n /**\n * Tracks the queue of producers waiting for a reservation.\n */\n readonly #waiters: Waiter[] = [];\n\n #canceled = false;\n\n constructor(lc: LogContext, lastWatermark: string) {\n this.#lc = lc;\n this.#sub = Subscription.create<ChangeStreamMessage>({\n cleanup: () => this.#cancel(),\n });\n this.#lastWatermark = lastWatermark;\n }\n\n #cancel() {\n this.#canceled = true;\n this.#producers.forEach(p => p.cancel());\n\n // A producer awaiting a reservation would otherwise remain suspended\n // forever, since the reservation held when the stream was canceled is\n // never released. Reject the pending reservations so that the producers\n // unwind and release the resources (e.g. upstream connections and\n // transactions) that they were holding for the stream.\n for (const {producer, rejectReservation} of this.#waiters.splice(0)) {\n this.#lc.info?.(\n `rejecting reservation request from ${producer}: stream canceled`,\n );\n rejectReservation(new AbortError('change stream canceled'));\n }\n }\n\n addProducers(...p: Cancelable[]): this {\n this.#producers.push(...p);\n return this;\n }\n\n addListeners(...l: Listener[]): this {\n this.#listeners.push(...l);\n return this;\n }\n\n /**\n * Called by a producer to \"reserve\" the exclusive right to push data\n * changes to the stream. If the stream is currently reserved,\n * the resulting Promise must be awaited.\n *\n * The producer must then {@link release()} the reservation when it sees\n * fit.\n *\n * @param producer The name of the producer, purely for debugging output\n */\n reserve(producer: string): string | Promise<string> {\n if (this.#canceled) {\n return Promise.reject(new AbortError('change stream canceled'));\n }\n if (this.#lastWatermark !== null) {\n // If the stream is not reserved, reserve it and return the\n // watermark.\n const lastWatermark = this.#lastWatermark;\n this.#lastWatermark = null;\n return lastWatermark;\n }\n\n // Otherwise, wait for the current reservation to be released.\n const startTime = performance.now();\n const {\n promise,\n resolve: grantReservation,\n reject: rejectReservation,\n } = resolver<string>();\n this.#waiters.push({\n producer,\n startTime,\n grantReservation,\n rejectReservation,\n });\n\n return promise;\n }\n\n /**\n * If there are producers currently awaiting a reservation, returns\n * the duration (in milliseconds) of the oldest reservation request.\n * Returns a negative number if there are no waiters.\n */\n waiterDelay(): number {\n if (this.#waiters.length === 0) {\n return -1;\n }\n return performance.now() - this.#waiters[0].startTime;\n }\n\n /**\n * Called by a producer to release its reservation after committing its\n * last transaction.\n */\n release(newWatermark: string) {\n const waiter = this.#waiters.shift();\n if (!waiter) {\n this.#lastWatermark = newWatermark;\n } else {\n const {producer, startTime, grantReservation} = waiter;\n grantReservation(newWatermark);\n const elapsed = performance.now() - startTime;\n this.#lc.info?.(\n `${producer} waited ${elapsed.toFixed(3)} ms for stream reservation`,\n );\n }\n }\n\n /**\n * `pushStatus()` can be called without a reservation, as it\n * does not constitute a data change and can appear anywhere\n * in the stream.\n */\n pushStatus(message: DownstreamStatusMessage) {\n this.#listeners.forEach(l => l.onChange(message));\n this.#sub.push(message);\n }\n\n /**\n * `push()` must only be called by a producer after it has\n * {@link reserve}d the stream.\n */\n push(message: ChangeStreamMessage): Promise<unknown> {\n assert(\n this.#lastWatermark === null,\n `push() called without reserve()-ing the stream`,\n );\n this.#listeners.forEach(l => l.onChange(message));\n return this.#sub.push(message).result;\n }\n\n fail(err: Error) {\n this.#sub.fail(err);\n }\n\n asSource(): Source<ChangeStreamMessage> {\n return this.#sub;\n }\n}\n"],"mappings":";;;;;;;;;AA8BA,IAAa,0BAAb,MAAqC;CACnC;CACA;CACA,aAAoC,CAAC;CACrC,aAAkC,CAAC;;;;;;;CAQnC;;;;CAKA,WAA8B,CAAC;CAE/B,YAAY;CAEZ,YAAY,IAAgB,eAAuB;EACjD,KAAK,MAAM;EACX,KAAK,OAAO,aAAa,OAA4B,EACnD,eAAe,KAAK,QAAQ,EAC9B,CAAC;EACD,KAAK,iBAAiB;CACxB;CAEA,UAAU;EACR,KAAK,YAAY;EACjB,KAAK,WAAW,SAAQ,MAAK,EAAE,OAAO,CAAC;EAOvC,KAAK,MAAM,EAAC,UAAU,uBAAsB,KAAK,SAAS,OAAO,CAAC,GAAG;GACnE,KAAK,IAAI,OACP,sCAAsC,SAAS,kBACjD;GACA,kBAAkB,IAAI,WAAW,wBAAwB,CAAC;EAC5D;CACF;CAEA,aAAa,GAAG,GAAuB;EACrC,KAAK,WAAW,KAAK,GAAG,CAAC;EACzB,OAAO;CACT;CAEA,aAAa,GAAG,GAAqB;EACnC,KAAK,WAAW,KAAK,GAAG,CAAC;EACzB,OAAO;CACT;;;;;;;;;;;CAYA,QAAQ,UAA4C;EAClD,IAAI,KAAK,WACP,OAAO,QAAQ,OAAO,IAAI,WAAW,wBAAwB,CAAC;EAEhE,IAAI,KAAK,mBAAmB,MAAM;GAGhC,MAAM,gBAAgB,KAAK;GAC3B,KAAK,iBAAiB;GACtB,OAAO;EACT;EAGA,MAAM,YAAY,YAAY,IAAI;EAClC,MAAM,EACJ,SACA,SAAS,kBACT,QAAQ,sBACN,SAAiB;EACrB,KAAK,SAAS,KAAK;GACjB;GACA;GACA;GACA;EACF,CAAC;EAED,OAAO;CACT;;;;;;CAOA,cAAsB;EACpB,IAAI,KAAK,SAAS,WAAW,GAC3B,OAAO;EAET,OAAO,YAAY,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;CAC9C;;;;;CAMA,QAAQ,cAAsB;EAC5B,MAAM,SAAS,KAAK,SAAS,MAAM;EACnC,IAAI,CAAC,QACH,KAAK,iBAAiB;OACjB;GACL,MAAM,EAAC,UAAU,WAAW,qBAAoB;GAChD,iBAAiB,YAAY;GAC7B,MAAM,UAAU,YAAY,IAAI,IAAI;GACpC,KAAK,IAAI,OACP,GAAG,SAAS,UAAU,QAAQ,QAAQ,CAAC,EAAE,2BAC3C;EACF;CACF;;;;;;CAOA,WAAW,SAAkC;EAC3C,KAAK,WAAW,SAAQ,MAAK,EAAE,SAAS,OAAO,CAAC;EAChD,KAAK,KAAK,KAAK,OAAO;CACxB;;;;;CAMA,KAAK,SAAgD;EACnD,OACE,KAAK,mBAAmB,MACxB,gDACF;EACA,KAAK,WAAW,SAAQ,MAAK,EAAE,SAAS,OAAO,CAAC;EAChD,OAAO,KAAK,KAAK,KAAK,OAAO,CAAC,CAAC;CACjC;CAEA,KAAK,KAAY;EACf,KAAK,KAAK,KAAK,GAAG;CACpB;CAEA,WAAwC;EACtC,OAAO,KAAK;CACd;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-cleanup.js","names":[
|
|
1
|
+
{"version":3,"file":"init-cleanup.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/init-cleanup.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\n\n/**\n * Releases the resources acquired by an initialization attempt (e.g. a\n * claimed replication slot, or a purge lock on the change-log) if the attempt\n * fails, e.g. before it is retried after an AutoResetSignal, or when a restore\n * is abandoned in favor of an initial sync.\n *\n * On success, the resources are handed over (e.g. the replication slot is\n * taken over by the change source, and the purge lock by the change-streamer)\n * and the cleanup is simply dropped.\n */\nexport class InitCleanup {\n readonly #lc: LogContext;\n #releasers: {name: string; release: () => unknown}[] = [];\n\n constructor(lc: LogContext) {\n this.#lc = lc;\n }\n\n /** Registers a resource to be released if the attempt fails. */\n onFailure(name: string, release: () => unknown) {\n this.#releasers.push({name, release});\n }\n\n /**\n * Releases the registered resources in the reverse order of their\n * registration. Errors are logged rather than thrown so as not to mask the\n * failure of the attempt.\n */\n async release() {\n const releasers = this.#releasers.reverse();\n this.#releasers = [];\n for (const {name, release} of releasers) {\n try {\n await release();\n this.#lc.info?.(`released ${name}`);\n } catch (e) {\n this.#lc.warn?.(`error releasing ${name}`, e);\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;AAYA,IAAa,cAAb,MAAyB;CACvB;CACA,aAAuD,CAAC;CAExD,YAAY,IAAgB;EAC1B,KAAK,MAAM;CACb;;CAGA,UAAU,MAAc,SAAwB;EAC9C,KAAK,WAAW,KAAK;GAAC;GAAM;EAAO,CAAC;CACtC;;;;;;CAOA,MAAM,UAAU;EACd,MAAM,YAAY,KAAK,WAAW,QAAQ;EAC1C,KAAK,aAAa,CAAC;EACnB,KAAK,MAAM,EAAC,MAAM,aAAY,WAC5B,IAAI;GACF,MAAM,QAAQ;GACd,KAAK,IAAI,OAAO,YAAY,MAAM;EACpC,SAAS,GAAG;GACV,KAAK,IAAI,OAAO,mBAAmB,QAAQ,CAAC;EAC9C;CAEJ;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"replica-restore.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-restore.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {sleep} from '../../../../../shared/src/sleep.ts';\nimport type {LitestreamConfig} from '../../../config/normalize.ts';\nimport {\n tryRestore,\n type ReplicaConstraints,\n type RestoreResult,\n} from '../../litestream/commands.ts';\nimport {\n litestreamRestoreDuration,\n litestreamRestoreMetricAttrs,\n litestreamRestoreRuns,\n} from '../../litestream/metrics.ts';\nimport type {SubscriptionState} from '../../replicator/schema/replication-state.ts';\nimport type {ChangeSource} from '../change-source.ts';\nimport type {InitCleanup} from './init-cleanup.ts';\n\nexport interface PurgeLock {\n release(): Promise<void>;\n}\n\n/** A PurgeLock that also constrains the replica that can be restored. */\nexport interface ConstrainingPurgeLock extends PurgeLock, ReplicaConstraints {\n /**\n * The head of the change log when the lock was acquired, from which (or\n * from past which) the change log is resumed.\n */\n readonly headWatermark: string;\n}\n\n/**\n * Acquires a purge lock on the PG change-log (if it is not empty).\n *\n * When resuming the change-log from a replication slot, `slotWatermark` is the\n * slot's position (as a watermark). If the change-log's head is behind it, the\n * change-log may be missing transactions that the slot will not stream, in\n * which case nothing is locked and `'behind-slot'` is returned.\n */\nexport type PgChangeLogPurgeLocker = (\n slotWatermark?: string,\n) => Promise<ConstrainingPurgeLock | null | 'behind-slot'>;\n\nexport type RestoreOptions = {\n litestream?: LitestreamConfig;\n /**\n * With the PG change-log enabled, purge-locks the change-log before the\n * replica is restored, which constrains the replica to one from which the\n * change-log can be resumed. The lock is acquired as late as possible (i.e.\n * after a replication slot is created, if applicable) because, if the\n * change-db is the upstream db, a transaction holding the lock would block\n * the creation of a replication slot.\n */\n acquirePurgeLock?: PgChangeLogPurgeLocker | undefined;\n /**\n * Resources acquired by the initialization (e.g. a claimed replication slot)\n * are registered here to be released if the initialization attempt fails.\n * Note that a purge lock acquired with `acquirePurgeLock` must be registered\n * here by the locker, so that it is released on failure.\n */\n cleanup?: InitCleanup | undefined;\n};\n\nexport type InitializeResult = {\n subscriptionState: SubscriptionState;\n changeSource: ChangeSource;\n destinationBackupURL: string | undefined;\n /**\n * The replica this change stream belongs to, from the upstream `replicas`\n * table. It is part of the identity the SQLite change log records, because a\n * generation (i.e. `replicaVersion`) is shared by every sibling of a forked\n * replica and so cannot distinguish two siblings' logs. `null` when the\n * change source has no upstream table to identify itself from.\n */\n replicaID: string | null;\n\n /**\n * Whether server readiness should be gated on the first litestream backup,\n * in order to ensure that a newly connecting subscriber can restore from\n * this change-streamer's backup.\n *\n * This should be true when the backup destination differs from where the\n * backup was restored from, which is the case for (1) initial-sync and\n * (2) most initialization cases in RMv2, with the exception being when\n * an abandoned replica is resumed.\n */\n waitForBackupBeforeServing: boolean;\n\n /**\n * Whether the PG change-log's head was behind the position of the\n * replication slot from which replication resumes (see\n * {@link PgChangeLogPurgeLocker}), in which case it is re-initialized from\n * the restored replica if it does not contain the replica's changes.\n */\n pgChangeLogBehindSlot?: boolean | undefined;\n\n /**\n * Whether the litestream backup to `destinationBackupURL` starts a new\n * (litestream v5) backup lineage, i.e. one that no local litestream state\n * belongs to. Any such state (e.g. from a previous run of a restarted\n * container, whose restore reused the existing replica) describes a\n * different lineage and must be discarded before replicating, or litestream\n * resolves its position from it and fails (and auto-recovers) on its first\n * sync to the empty lineage.\n *\n * This is false when the backup continues a lineage from the local\n * litestream state (see {@link ResumableBackup}).\n */\n newBackupLineage: boolean;\n};\n\n/**\n * Where the backup goes after a restore, when it can continue from the\n * restored replica's local litestream state instead of starting a new lineage\n * with a full snapshot:\n * - `fork`: a new, unique subfolder of `baseURL`, which the restore seeds with\n * the restored backup files.\n */\nexport type BackupDestination = {type: 'fork'; baseURL: string};\n\n/**\n * A backup lineage at `backupPath` that the litestream backup continues from\n * the local litestream state and the restored replica's WAL.\n */\nexport type ResumableBackup = {\n backupPath: string;\n};\n\n// A short retry is much cheaper than an initial Postgres sync, while keeping a\n// persistent failure from delaying startup appreciably.\nconst MAX_RESTORE_ATTEMPTS = 3;\nconst RESTORE_RETRY_DELAY_MS = 5_000;\n\n/**\n * Restores the replica from `config.backupURL`. With a `destination`, it\n * returns the backup that continues from the restored replica, if the\n * restore prepared one (e.g. it was not skipped because the replica already\n * exists).\n */\nexport async function restoreReplica(\n lc: LogContext,\n config: LitestreamConfig,\n replicaFile: string,\n replicaConstraints: ReplicaConstraints | undefined,\n destination?: BackupDestination | undefined,\n): Promise<ResumableBackup | undefined> {\n const start = performance.now();\n let result: RestoreResult | undefined;\n try {\n // `tryRestore` returns ordinary restore outcomes (no backup or an invalid\n // replica) rather than throwing; preserve their existing immediate\n // initial-sync fallback. Retry every thrown restore error twice before\n // falling back to the initial Postgres sync.\n for (let attemptNum = 1; attemptNum <= MAX_RESTORE_ATTEMPTS; attemptNum++) {\n // Each attempt seeds a new subfolder, as a failed attempt can leave\n // files in its subfolder.\n const backupPath =\n destination?.type === 'fork' ? String(Date.now()) : undefined;\n try {\n const attempt = await tryRestore(\n lc,\n config,\n replicaFile,\n replicaConstraints,\n 'replication_manager',\n undefined,\n backupPath\n ? {url: new URL(backupPath, destination?.baseURL).toString()}\n : undefined,\n );\n result = attempt.result;\n return backupPath && attempt.forked ? {backupPath} : undefined;\n } catch (e) {\n if (attemptNum === MAX_RESTORE_ATTEMPTS) {\n lc.error?.(\n `litestream restore failed after ${attemptNum} attempts; resyncing the replica`,\n e,\n );\n break;\n }\n\n lc.warn?.(\n `litestream restore attempt ${attemptNum} failed; retrying in ${RESTORE_RETRY_DELAY_MS}ms (attempt ${attemptNum + 1} of ${MAX_RESTORE_ATTEMPTS})`,\n e,\n );\n await sleep(RESTORE_RETRY_DELAY_MS);\n }\n }\n return undefined;\n } finally {\n const attrs = litestreamRestoreMetricAttrs(config, 'replication_manager');\n const labels = {...attrs, result: result ?? 'error'};\n litestreamRestoreRuns().add(1, labels);\n litestreamRestoreDuration().recordMs(performance.now() - start, labels);\n }\n}\n"],"mappings":";;;;AAiIA,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;;;;;;;AAQ/B,eAAsB,eACpB,IACA,QACA,aACA,oBACA,aACsC;CACtC,MAAM,QAAQ,YAAY,IAAI;CAC9B,IAAI;CACJ,IAAI;EAKF,KAAK,IAAI,aAAa,GAAG,cAAc,sBAAsB,cAAc;GAGzE,MAAM,aACJ,aAAa,SAAS,SAAS,OAAO,KAAK,IAAI,CAAC,IAAI,KAAA;GACtD,IAAI;IACF,MAAM,UAAU,MAAM,WACpB,IACA,QACA,aACA,oBACA,uBACA,KAAA,GACA,aACI,EAAC,KAAK,IAAI,IAAI,YAAY,aAAa,OAAO,EAAE,SAAS,EAAC,IAC1D,KAAA,CACN;IACA,SAAS,QAAQ;IACjB,OAAO,cAAc,QAAQ,SAAS,EAAC,WAAU,IAAI,KAAA;GACvD,SAAS,GAAG;IACV,IAAI,eAAe,sBAAsB;KACvC,GAAG,QACD,mCAAmC,WAAW,mCAC9C,CACF;KACA;IACF;IAEA,GAAG,OACD,8BAA8B,WAAW,uBAAuB,uBAAuB,cAAc,aAAa,EAAE,MAAM,qBAAqB,IAC/I,CACF;IACA,MAAM,MAAM,sBAAsB;GACpC;EACF;EACA;CACF,UAAU;EAER,MAAM,SAAS;GAAC,GADF,6BAA6B,QAAQ,qBAChC;GAAO,QAAQ,UAAU;EAAO;EACnD,sBAAsB,EAAE,IAAI,GAAG,MAAM;EACrC,0BAA0B,EAAE,SAAS,YAAY,IAAI,IAAI,OAAO,MAAM;CACxE;AACF"}
|
|
1
|
+
{"version":3,"file":"replica-restore.js","names":[],"sources":["../../../../../../../zero-cache/src/services/change-source/common/replica-restore.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {sleep} from '../../../../../shared/src/sleep.ts';\nimport type {LitestreamConfig} from '../../../config/normalize.ts';\nimport {\n tryRestore,\n type ReplicaConstraints,\n type RestoreResult,\n} from '../../litestream/commands.ts';\nimport {\n litestreamRestoreDuration,\n litestreamRestoreMetricAttrs,\n litestreamRestoreRuns,\n} from '../../litestream/metrics.ts';\nimport type {SubscriptionState} from '../../replicator/schema/replication-state.ts';\nimport type {ChangeSource} from '../change-source.ts';\nimport type {InitCleanup} from './init-cleanup.ts';\n\ninterface PurgeLock {\n release(): Promise<void>;\n}\n\n/** A PurgeLock that also constrains the replica that can be restored. */\nexport interface ConstrainingPurgeLock extends PurgeLock, ReplicaConstraints {\n /**\n * The head of the change log when the lock was acquired, from which (or\n * from past which) the change log is resumed.\n */\n readonly headWatermark: string;\n}\n\n/**\n * Acquires a purge lock on the PG change-log (if it is not empty).\n *\n * When resuming the change-log from a replication slot, `slotWatermark` is the\n * slot's position (as a watermark). If the change-log's head is behind it, the\n * change-log may be missing transactions that the slot will not stream, in\n * which case nothing is locked and `'behind-slot'` is returned.\n */\nexport type PgChangeLogPurgeLocker = (\n slotWatermark?: string,\n) => Promise<ConstrainingPurgeLock | null | 'behind-slot'>;\n\nexport type RestoreOptions = {\n litestream?: LitestreamConfig;\n /**\n * With the PG change-log enabled, purge-locks the change-log before the\n * replica is restored, which constrains the replica to one from which the\n * change-log can be resumed. The lock is acquired as late as possible (i.e.\n * after a replication slot is created, if applicable) because, if the\n * change-db is the upstream db, a transaction holding the lock would block\n * the creation of a replication slot.\n */\n acquirePurgeLock?: PgChangeLogPurgeLocker | undefined;\n /**\n * Resources acquired by the initialization (e.g. a claimed replication slot)\n * are registered here to be released if the initialization attempt fails.\n * Note that a purge lock acquired with `acquirePurgeLock` must be registered\n * here by the locker, so that it is released on failure.\n */\n cleanup?: InitCleanup | undefined;\n};\n\nexport type InitializeResult = {\n subscriptionState: SubscriptionState;\n changeSource: ChangeSource;\n destinationBackupURL: string | undefined;\n /**\n * The replica this change stream belongs to, from the upstream `replicas`\n * table. It is part of the identity the SQLite change log records, because a\n * generation (i.e. `replicaVersion`) is shared by every sibling of a forked\n * replica and so cannot distinguish two siblings' logs. `null` when the\n * change source has no upstream table to identify itself from.\n */\n replicaID: string | null;\n\n /**\n * Whether server readiness should be gated on the first litestream backup,\n * in order to ensure that a newly connecting subscriber can restore from\n * this change-streamer's backup.\n *\n * This should be true when the backup destination differs from where the\n * backup was restored from, which is the case for (1) initial-sync and\n * (2) most initialization cases in RMv2, with the exception being when\n * an abandoned replica is resumed.\n */\n waitForBackupBeforeServing: boolean;\n\n /**\n * Whether the PG change-log's head was behind the position of the\n * replication slot from which replication resumes (see\n * {@link PgChangeLogPurgeLocker}), in which case it is re-initialized from\n * the restored replica if it does not contain the replica's changes.\n */\n pgChangeLogBehindSlot?: boolean | undefined;\n\n /**\n * Whether the litestream backup to `destinationBackupURL` starts a new\n * (litestream v5) backup lineage, i.e. one that no local litestream state\n * belongs to. Any such state (e.g. from a previous run of a restarted\n * container, whose restore reused the existing replica) describes a\n * different lineage and must be discarded before replicating, or litestream\n * resolves its position from it and fails (and auto-recovers) on its first\n * sync to the empty lineage.\n *\n * This is false when the backup continues a lineage from the local\n * litestream state (see {@link ResumableBackup}).\n */\n newBackupLineage: boolean;\n\n /**\n * How the replica was initialized, and the durations of its phases, for\n * the replication-manager's start metrics (see `ServerStartMetrics`).\n * Absent for change sources that do not report them.\n */\n startTimings?: InitializeTimings | undefined;\n};\n\n/**\n * How a replica was initialized (see {@link InitializeResult.startTimings}):\n * - `fork`: restored from the backup of a running replica, with a new slot\n * - `resume`: restored from the backup of an orphaned replica, with its slot\n * - `rmv1`: restored from the backup of the replica whose slot it takes over\n * - `initial_sync`: initially synced\n */\nexport type InitializeKind = 'fork' | 'resume' | 'rmv1' | 'initial_sync';\n\nexport type InitializeTimings = {\n kind: InitializeKind;\n /**\n * The time spent creating the new replica and its slot, including retries\n * while slot creation is blocked by upstream transactions (which only the\n * upstream's owner controls). Absent if no slot was created, e.g. when\n * resuming an orphaned replica without first having prepared a fork.\n */\n slotCreateMs?: number | undefined;\n /**\n * The time spent selecting the replica to fork (or resume) and claiming its\n * slot, i.e. before restoring, including any wait for the source replica to\n * pass the new slot's position. It excludes {@link slotCreateMs}.\n */\n forkWaitMs?: number | undefined;\n /** The time spent restoring the replica from its backup. */\n restoreMs?: number | undefined;\n};\n\n/**\n * Where the backup goes after a restore, when it can continue from the\n * restored replica's local litestream state instead of starting a new lineage\n * with a full snapshot:\n * - `fork`: a new, unique subfolder of `baseURL`, which the restore seeds with\n * the restored backup files.\n */\nexport type BackupDestination = {type: 'fork'; baseURL: string};\n\n/**\n * A backup lineage at `backupPath` that the litestream backup continues from\n * the local litestream state and the restored replica's WAL.\n */\nexport type ResumableBackup = {\n backupPath: string;\n};\n\n// A short retry is much cheaper than an initial Postgres sync, while keeping a\n// persistent failure from delaying startup appreciably.\nconst MAX_RESTORE_ATTEMPTS = 3;\nconst RESTORE_RETRY_DELAY_MS = 5_000;\n\n/**\n * Restores the replica from `config.backupURL`. With a `destination`, it\n * returns the backup that continues from the restored replica, if the\n * restore prepared one (e.g. it was not skipped because the replica already\n * exists).\n */\nexport async function restoreReplica(\n lc: LogContext,\n config: LitestreamConfig,\n replicaFile: string,\n replicaConstraints: ReplicaConstraints | undefined,\n destination?: BackupDestination | undefined,\n): Promise<ResumableBackup | undefined> {\n const start = performance.now();\n let result: RestoreResult | undefined;\n try {\n // `tryRestore` returns ordinary restore outcomes (no backup or an invalid\n // replica) rather than throwing; preserve their existing immediate\n // initial-sync fallback. Retry every thrown restore error twice before\n // falling back to the initial Postgres sync.\n for (let attemptNum = 1; attemptNum <= MAX_RESTORE_ATTEMPTS; attemptNum++) {\n // Each attempt seeds a new subfolder, as a failed attempt can leave\n // files in its subfolder.\n const backupPath =\n destination?.type === 'fork' ? String(Date.now()) : undefined;\n try {\n const attempt = await tryRestore(\n lc,\n config,\n replicaFile,\n replicaConstraints,\n 'replication_manager',\n undefined,\n backupPath\n ? {url: new URL(backupPath, destination?.baseURL).toString()}\n : undefined,\n );\n result = attempt.result;\n return backupPath && attempt.forked ? {backupPath} : undefined;\n } catch (e) {\n if (attemptNum === MAX_RESTORE_ATTEMPTS) {\n lc.error?.(\n `litestream restore failed after ${attemptNum} attempts; resyncing the replica`,\n e,\n );\n break;\n }\n\n lc.warn?.(\n `litestream restore attempt ${attemptNum} failed; retrying in ${RESTORE_RETRY_DELAY_MS}ms (attempt ${attemptNum + 1} of ${MAX_RESTORE_ATTEMPTS})`,\n e,\n );\n await sleep(RESTORE_RETRY_DELAY_MS);\n }\n }\n return undefined;\n } finally {\n const attrs = litestreamRestoreMetricAttrs(config, 'replication_manager');\n const labels = {...attrs, result: result ?? 'error'};\n litestreamRestoreRuns().add(1, labels);\n litestreamRestoreDuration().recordMs(performance.now() - start, labels);\n }\n}\n"],"mappings":";;;;AAoKA,IAAM,uBAAuB;AAC7B,IAAM,yBAAyB;;;;;;;AAQ/B,eAAsB,eACpB,IACA,QACA,aACA,oBACA,aACsC;CACtC,MAAM,QAAQ,YAAY,IAAI;CAC9B,IAAI;CACJ,IAAI;EAKF,KAAK,IAAI,aAAa,GAAG,cAAc,sBAAsB,cAAc;GAGzE,MAAM,aACJ,aAAa,SAAS,SAAS,OAAO,KAAK,IAAI,CAAC,IAAI,KAAA;GACtD,IAAI;IACF,MAAM,UAAU,MAAM,WACpB,IACA,QACA,aACA,oBACA,uBACA,KAAA,GACA,aACI,EAAC,KAAK,IAAI,IAAI,YAAY,aAAa,OAAO,CAAC,CAAC,SAAS,EAAC,IAC1D,KAAA,CACN;IACA,SAAS,QAAQ;IACjB,OAAO,cAAc,QAAQ,SAAS,EAAC,WAAU,IAAI,KAAA;GACvD,SAAS,GAAG;IACV,IAAI,eAAe,sBAAsB;KACvC,GAAG,QACD,mCAAmC,WAAW,mCAC9C,CACF;KACA;IACF;IAEA,GAAG,OACD,8BAA8B,WAAW,uBAAuB,uBAAuB,cAAc,aAAa,EAAE,MAAM,qBAAqB,IAC/I,CACF;IACA,MAAM,MAAM,sBAAsB;GACpC;EACF;EACA;CACF,UAAU;EAER,MAAM,SAAS;GAAC,GADF,6BAA6B,QAAQ,qBAChC;GAAO,QAAQ,UAAU;EAAO;EACnD,sBAAsB,CAAC,CAAC,IAAI,GAAG,MAAM;EACrC,0BAA0B,CAAC,CAAC,SAAS,YAAY,IAAI,IAAI,OAAO,MAAM;CACxE;AACF"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { isSQLiteCorruption, logSQLiteCorruptionDiagnostics } from "../../../db/sqlite-corruption.js";
|
|
1
2
|
import { populateFromExistingTables } from "../../replicator/schema/column-metadata.js";
|
|
2
3
|
import { listTables } from "../../../db/lite-tables.js";
|
|
3
4
|
import { BACKFILLING_TABLE, populateBackfillingFromColumnMetadata } from "../../replicator/schema/backfilling.js";
|
|
4
5
|
import { CREATE_RUNTIME_EVENTS_TABLE, recordEvent } from "../../replicator/schema/replication-state.js";
|
|
5
|
-
import { isSQLiteCorruption, logSQLiteCorruptionDiagnostics } from "../../../db/sqlite-corruption.js";
|
|
6
6
|
import { deleteLiteDB } from "../../../db/delete-lite-db.js";
|
|
7
7
|
import { AutoResetSignal } from "../../change-streamer/schema/tables.js";
|
|
8
8
|
import { runSchemaMigrations } from "../../../db/migration-lite.js";
|
|
@@ -81,7 +81,6 @@ var CREATE_V17_BACKFILLING_TABLE = `
|
|
|
81
81
|
`;
|
|
82
82
|
var V14_CHANGE_LOG_STREAM_TABLE = "_zero.changeLogStream";
|
|
83
83
|
var V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX = "_zero.changeLogStream_writeTimeMs";
|
|
84
|
-
`${V14_CHANGE_LOG_STREAM_TABLE}${V14_CHANGE_LOG_STREAM_WRITE_TIME_INDEX}${V14_CHANGE_LOG_STREAM_TABLE}`;
|
|
85
84
|
var schemaVersionMigrationMap = {
|
|
86
85
|
4: {
|
|
87
86
|
migrateSchema: () => {
|
|
@@ -108,7 +107,8 @@ var schemaVersionMigrationMap = {
|
|
|
108
107
|
},
|
|
109
108
|
migrateData: (_, db) => {
|
|
110
109
|
db.exec(`DELETE FROM "_zero.column_metadata"`);
|
|
111
|
-
|
|
110
|
+
const tables = listTables(db, false, false);
|
|
111
|
+
populateFromExistingTables(db, tables);
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
114
|
9: { migrateSchema: (_, db) => {
|
|
@@ -202,6 +202,6 @@ var schemaVersionMigrationMap = {
|
|
|
202
202
|
};
|
|
203
203
|
Object.keys(schemaVersionMigrationMap).reduce((prev, curr) => Math.max(prev, parseInt(curr)), 0);
|
|
204
204
|
//#endregion
|
|
205
|
-
export { initReplica, upgradeReplica };
|
|
205
|
+
export { CREATE_V17_BACKFILLING_TABLE, CREATE_V6_COLUMN_METADATA_TABLE, CREATE_V7_CHANGE_LOG, CREATE_V9_TABLE_METADATA_TABLE, V14_CHANGE_LOG_STREAM_TABLE, initReplica, schemaVersionMigrationMap, upgradeReplica };
|
|
206
206
|
|
|
207
207
|
//# sourceMappingURL=replica-schema.js.map
|