@rocicorp/zero 1.11.0-canary.2 → 1.11.0-canary.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/analyze-query/src/bin-analyze.js +9 -8
- package/out/analyze-query/src/bin-analyze.js.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.d.ts +8 -1
- package/out/ast-to-zql/src/ast-to-zql.d.ts.map +1 -1
- package/out/ast-to-zql/src/ast-to-zql.js +25 -25
- package/out/ast-to-zql/src/ast-to-zql.js.map +1 -1
- package/out/otel/src/log-options.d.ts +16 -0
- package/out/otel/src/log-options.d.ts.map +1 -1
- package/out/otel/src/log-options.js +54 -1
- package/out/otel/src/log-options.js.map +1 -1
- package/out/replicache/src/bg-interval.d.ts +2 -1
- package/out/replicache/src/bg-interval.d.ts.map +1 -1
- package/out/replicache/src/bg-interval.js +13 -4
- package/out/replicache/src/bg-interval.js.map +1 -1
- package/out/replicache/src/btree/node.d.ts.map +1 -1
- package/out/replicache/src/btree/node.js +3 -6
- package/out/replicache/src/btree/node.js.map +1 -1
- package/out/replicache/src/dag/gc.d.ts.map +1 -1
- package/out/replicache/src/dag/gc.js +8 -11
- package/out/replicache/src/dag/gc.js.map +1 -1
- package/out/replicache/src/dag/invalid-ref-count-error.d.ts +12 -0
- package/out/replicache/src/dag/invalid-ref-count-error.d.ts.map +1 -0
- package/out/replicache/src/dag/invalid-ref-count-error.js +19 -0
- package/out/replicache/src/dag/invalid-ref-count-error.js.map +1 -0
- package/out/replicache/src/dag/lazy-store.d.ts +17 -4
- package/out/replicache/src/dag/lazy-store.d.ts.map +1 -1
- package/out/replicache/src/dag/lazy-store.js +35 -9
- package/out/replicache/src/dag/lazy-store.js.map +1 -1
- package/out/replicache/src/dag/store-impl.d.ts +12 -2
- package/out/replicache/src/dag/store-impl.d.ts.map +1 -1
- package/out/replicache/src/dag/store-impl.js +29 -9
- package/out/replicache/src/dag/store-impl.js.map +1 -1
- package/out/replicache/src/db/rebase.d.ts +14 -2
- package/out/replicache/src/db/rebase.d.ts.map +1 -1
- package/out/replicache/src/db/rebase.js +27 -5
- package/out/replicache/src/db/rebase.js.map +1 -1
- package/out/replicache/src/get-kv-store-provider.d.ts +1 -1
- package/out/replicache/src/get-kv-store-provider.d.ts.map +1 -1
- package/out/replicache/src/get-kv-store-provider.js +4 -4
- package/out/replicache/src/get-kv-store-provider.js.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/expo-sqlite/store.js +28 -5
- package/out/replicache/src/kv/expo-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/idb-store.d.ts +18 -0
- package/out/replicache/src/kv/idb-store.d.ts.map +1 -1
- package/out/replicache/src/kv/idb-store.js +30 -2
- package/out/replicache/src/kv/idb-store.js.map +1 -1
- package/out/replicache/src/kv/mem-fallback-store.d.ts +54 -0
- package/out/replicache/src/kv/mem-fallback-store.d.ts.map +1 -0
- package/out/replicache/src/kv/mem-fallback-store.js +177 -0
- package/out/replicache/src/kv/mem-fallback-store.js.map +1 -0
- package/out/replicache/src/kv/mem-store.d.ts +1 -0
- package/out/replicache/src/kv/mem-store.d.ts.map +1 -1
- package/out/replicache/src/kv/mem-store.js +3 -0
- package/out/replicache/src/kv/mem-store.js.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.d.ts.map +1 -1
- package/out/replicache/src/kv/op-sqlite/store.js +4 -4
- package/out/replicache/src/kv/op-sqlite/store.js.map +1 -1
- package/out/replicache/src/kv/sqlite-store.d.ts +22 -1
- package/out/replicache/src/kv/sqlite-store.d.ts.map +1 -1
- package/out/replicache/src/kv/sqlite-store.js +159 -14
- package/out/replicache/src/kv/sqlite-store.js.map +1 -1
- package/out/replicache/src/kv/store.d.ts +6 -0
- package/out/replicache/src/kv/store.d.ts.map +1 -1
- package/out/replicache/src/new-client-channel.js.map +1 -1
- package/out/replicache/src/persist/client-gc.d.ts +2 -1
- package/out/replicache/src/persist/client-gc.d.ts.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 +2 -1
- package/out/replicache/src/persist/client-group-gc.d.ts.map +1 -1
- package/out/replicache/src/persist/client-group-gc.js +2 -2
- package/out/replicache/src/persist/client-group-gc.js.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +28 -8
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +97 -20
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/persist/heartbeat.d.ts +2 -1
- package/out/replicache/src/persist/heartbeat.d.ts.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-db-name.js +1 -1
- package/out/replicache/src/persist/idb-databases-store-db-name.js.map +1 -1
- package/out/replicache/src/persist/persist.d.ts.map +1 -1
- package/out/replicache/src/persist/persist.js +18 -8
- package/out/replicache/src/persist/persist.js.map +1 -1
- package/out/replicache/src/persist/refresh.js +6 -2
- package/out/replicache/src/persist/refresh.js.map +1 -1
- package/out/replicache/src/replicache-impl.d.ts +85 -3
- package/out/replicache/src/replicache-impl.d.ts.map +1 -1
- package/out/replicache/src/replicache-impl.js +321 -29
- package/out/replicache/src/replicache-impl.js.map +1 -1
- package/out/replicache/src/replicache-options.d.ts +9 -0
- package/out/replicache/src/replicache-options.d.ts.map +1 -1
- package/out/replicache/src/storage-failure.d.ts +37 -0
- package/out/replicache/src/storage-failure.d.ts.map +1 -0
- package/out/replicache/src/storage-failure.js +31 -0
- package/out/replicache/src/storage-failure.js.map +1 -0
- package/out/shared/src/arrays.d.ts +5 -0
- package/out/shared/src/arrays.d.ts.map +1 -1
- package/out/shared/src/arrays.js +8 -10
- package/out/shared/src/arrays.js.map +1 -1
- package/out/shared/src/error.d.ts +11 -0
- package/out/shared/src/error.d.ts.map +1 -1
- package/out/shared/src/error.js +35 -1
- package/out/shared/src/error.js.map +1 -1
- package/out/shared/src/iterables.d.ts +2 -0
- package/out/shared/src/iterables.d.ts.map +1 -1
- package/out/shared/src/iterables.js +18 -1
- package/out/shared/src/iterables.js.map +1 -1
- package/out/shared/src/map.d.ts +24 -2
- package/out/shared/src/map.d.ts.map +1 -1
- package/out/shared/src/map.js +18 -4
- package/out/shared/src/map.js.map +1 -1
- package/out/shared/src/random-values.js +12 -1
- package/out/shared/src/random-values.js.map +1 -1
- package/out/shared/src/ring-buffer.d.ts +10 -0
- package/out/shared/src/ring-buffer.d.ts.map +1 -1
- package/out/shared/src/ring-buffer.js +26 -1
- package/out/shared/src/ring-buffer.js.map +1 -1
- package/out/z2s/src/compiler.js +1 -1
- package/out/z2s/src/sql.d.ts.map +1 -1
- package/out/z2s/src/sql.js +2 -2
- package/out/z2s/src/sql.js.map +1 -1
- package/out/zero/package.js +3 -4
- package/out/zero/package.js.map +1 -1
- package/out/zero/src/zero.js +2 -1
- package/out/zero-cache/src/auth/write-authorizer.d.ts.map +1 -1
- package/out/zero-cache/src/auth/write-authorizer.js +1 -0
- package/out/zero-cache/src/auth/write-authorizer.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js +26 -2
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +102 -6
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +254 -57
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/db/lite-tables.d.ts.map +1 -1
- package/out/zero-cache/src/db/lite-tables.js +3 -4
- package/out/zero-cache/src/db/lite-tables.js.map +1 -1
- package/out/zero-cache/src/observability/events.js +4 -1
- package/out/zero-cache/src/observability/events.js.map +1 -1
- package/out/zero-cache/src/observability/log-throttle.d.ts +44 -0
- package/out/zero-cache/src/observability/log-throttle.d.ts.map +1 -0
- package/out/zero-cache/src/observability/log-throttle.js +76 -0
- package/out/zero-cache/src/observability/log-throttle.js.map +1 -0
- package/out/zero-cache/src/observability/metrics.d.ts.map +1 -1
- package/out/zero-cache/src/observability/metrics.js +2 -7
- package/out/zero-cache/src/observability/metrics.js.map +1 -1
- package/out/zero-cache/src/scripts/permissions.d.ts +16 -0
- package/out/zero-cache/src/scripts/permissions.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +27 -10
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.d.ts +28 -2
- package/out/zero-cache/src/server/inspector-delegate.d.ts.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +37 -17
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.d.ts.map +1 -1
- package/out/zero-cache/src/server/main.js +8 -1
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/mutator.js +2 -0
- package/out/zero-cache/src/server/mutator.js.map +1 -1
- package/out/zero-cache/src/server/reaper.d.ts.map +1 -1
- package/out/zero-cache/src/server/reaper.js +2 -0
- package/out/zero-cache/src/server/reaper.js.map +1 -1
- package/out/zero-cache/src/server/replicator.d.ts +3 -0
- package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/server/replicator.js +79 -15
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/runner/zero-dispatcher.js +5 -0
- package/out/zero-cache/src/server/runner/zero-dispatcher.js.map +1 -1
- package/out/zero-cache/src/server/syncer-assigner.d.ts +14 -0
- package/out/zero-cache/src/server/syncer-assigner.d.ts.map +1 -0
- package/out/zero-cache/src/server/syncer-assigner.js +72 -0
- package/out/zero-cache/src/server/syncer-assigner.js.map +1 -0
- package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/server/syncer.js +24 -2
- package/out/zero-cache/src/server/syncer.js.map +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.d.ts.map +1 -1
- package/out/zero-cache/src/server/worker-dispatcher.js +21 -4
- package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
- package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
- package/out/zero-cache/src/services/analyze.js +11 -9
- package/out/zero-cache/src/services/analyze.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js +198 -24
- package/out/zero-cache/src/services/change-source/common/backfill-manager.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js +15 -3
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts +1 -0
- package/out/zero-cache/src/services/change-source/common/replica-schema.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-schema.js +15 -3
- package/out/zero-cache/src/services/change-source/common/replica-schema.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts +9 -0
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +204 -18
- 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.d.ts +25 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +202 -0
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts +14 -16
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +64 -143
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts +37 -2
- package/out/zero-cache/src/services/change-source/pg/initial-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js +53 -21
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts +16 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js +113 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slot-cleanup-monitor.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +21 -15
- package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js +86 -23
- package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js +68 -8
- package/out/zero-cache/src/services/change-source/pg/schema/index-predicate.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +32 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts +10 -0
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js +6 -0
- package/out/zero-cache/src/services/change-source/pg/schema/replica-stage-enum.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts +50 -27
- package/out/zero-cache/src/services/change-source/pg/schema/shard.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js +100 -34
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts +68 -0
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js +141 -0
- package/out/zero-cache/src/services/change-source/protocol/backfill-progress.js.map +1 -0
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts +43 -0
- package/out/zero-cache/src/services/change-source/protocol/current/data.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/protocol/current/data.js +10 -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 +57 -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/upstream.d.ts +20 -6
- 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 +17 -7
- 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 +2 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +66 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +154 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts +50 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.js +268 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js +2 -0
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js +58 -7
- package/out/zero-cache/src/services/change-streamer/backup-monitor.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts +8 -2
- package/out/zero-cache/src/services/change-streamer/broadcast.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/broadcast.js +24 -4
- package/out/zero-cache/src/services/change-streamer/broadcast.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts +19 -4
- package/out/zero-cache/src/services/change-streamer/change-log-codec.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js +28 -8
- package/out/zero-cache/src/services/change-streamer/change-log-codec.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +48 -6
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +130 -34
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +11 -0
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +118 -68
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +37 -15
- package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts +3 -3
- package/out/zero-cache/src/services/change-streamer/forwarder.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/forwarder.js +36 -5
- package/out/zero-cache/src/services/change-streamer/forwarder.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts +51 -0
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js +132 -0
- package/out/zero-cache/src/services/change-streamer/litestream-sync-requester.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.js +19 -8
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts +92 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-message.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js +42 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-message.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +16 -4
- package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +7 -69
- package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/snapshot.js +21 -53
- package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts +6 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js +27 -9
- package/out/zero-cache/src/services/change-streamer/sqlite-change-log-writer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +2 -2
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +9 -6
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +446 -0
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-streamer/subscribe.js +76 -0
- package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -0
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +33 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js +76 -0
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +17 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js +19 -3
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +5 -0
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +35 -5
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +1 -1
- package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
- package/out/zero-cache/src/services/life-cycle.js +3 -1
- package/out/zero-cache/src/services/life-cycle.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +15 -3
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +24 -7
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config-v5.yml +11 -4
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js +51 -24
- package/out/zero-cache/src/services/litestream/litestream-checkpointer.js.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts +10 -2
- package/out/zero-cache/src/services/litestream/litestream-controller.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/litestream-controller.js +3 -2
- package/out/zero-cache/src/services/litestream/litestream-controller.js.map +1 -1
- package/out/zero-cache/src/services/litestream/restore-progress.d.ts +24 -0
- package/out/zero-cache/src/services/litestream/restore-progress.d.ts.map +1 -0
- package/out/zero-cache/src/services/litestream/restore-progress.js +91 -0
- package/out/zero-cache/src/services/litestream/restore-progress.js.map +1 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts +5 -0
- package/out/zero-cache/src/services/mutagen/mutagen.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +7 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +5 -6
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.d.ts +163 -0
- package/out/zero-cache/src/services/plannerz.d.ts.map +1 -0
- package/out/zero-cache/src/services/plannerz.js +267 -0
- package/out/zero-cache/src/services/plannerz.js.map +1 -0
- package/out/zero-cache/src/services/profz.d.ts +30 -0
- package/out/zero-cache/src/services/profz.d.ts.map +1 -0
- package/out/zero-cache/src/services/profz.js +145 -0
- package/out/zero-cache/src/services/profz.js.map +1 -0
- package/out/zero-cache/src/services/replicator/change-log-cookies.js +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-stream-writer.d.ts +5 -4
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js +20 -22
- package/out/zero-cache/src/services/replicator/change-log-stream-writer.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +49 -5
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +3 -2
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +50 -20
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts +35 -1
- package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +96 -6
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts +2 -1
- package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/replicator.js +2 -2
- package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts +23 -2
- package/out/zero-cache/src/services/replicator/schema/backfilling.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/schema/backfilling.js +54 -2
- package/out/zero-cache/src/services/replicator/schema/backfilling.js.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts +6 -6
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js +19 -14
- package/out/zero-cache/src/services/replicator/sqlite-change-log-observability.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts +11 -3
- package/out/zero-cache/src/services/replicator/write-worker-client.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker-client.js.map +1 -1
- package/out/zero-cache/src/services/replicator/write-worker.js +5 -1
- package/out/zero-cache/src/services/replicator/write-worker.js.map +1 -1
- package/out/zero-cache/src/services/run-ast.d.ts +12 -0
- package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
- package/out/zero-cache/src/services/run-ast.js +26 -14
- package/out/zero-cache/src/services/run-ast.js.map +1 -1
- package/out/zero-cache/src/services/runner.d.ts +2 -1
- package/out/zero-cache/src/services/runner.d.ts.map +1 -1
- package/out/zero-cache/src/services/runner.js +10 -2
- package/out/zero-cache/src/services/runner.js.map +1 -1
- package/out/zero-cache/src/services/statz.d.ts +4 -0
- package/out/zero-cache/src/services/statz.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +22 -5
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts +19 -2
- package/out/zero-cache/src/services/view-syncer/client-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +42 -30
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts +19 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +34 -11
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts +51 -2
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +142 -6
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts +81 -0
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js +128 -0
- package/out/zero-cache/src/services/view-syncer/deferred-writes-budget.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts +14 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js +30 -4
- package/out/zero-cache/src/services/view-syncer/drain-coordinator.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts +33 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js +62 -0
- package/out/zero-cache/src/services/view-syncer/hydration-budget.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts +51 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js +78 -0
- package/out/zero-cache/src/services/view-syncer/hydration-circuit-breaker.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +3 -3
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +50 -2
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +466 -62
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts +7 -0
- package/out/zero-cache/src/services/view-syncer/plan-warnings.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js +35 -0
- package/out/zero-cache/src/services/view-syncer/plan-warnings.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-covering.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-covering.js +2 -6
- package/out/zero-cache/src/services/view-syncer/query-covering.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts +25 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.js +28 -0
- package/out/zero-cache/src/services/view-syncer/query-shape.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +77 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.js +206 -0
- package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts +95 -0
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js +155 -0
- package/out/zero-cache/src/services/view-syncer/snapshot-row-cache.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +78 -4
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +158 -28
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +11 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +587 -103
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/processes.d.ts +39 -0
- package/out/zero-cache/src/types/processes.d.ts.map +1 -1
- package/out/zero-cache/src/types/processes.js +43 -4
- package/out/zero-cache/src/types/processes.js.map +1 -1
- package/out/zero-cache/src/types/profiler.d.ts +12 -0
- package/out/zero-cache/src/types/profiler.d.ts.map +1 -1
- package/out/zero-cache/src/types/profiler.js +46 -1
- package/out/zero-cache/src/types/profiler.js.map +1 -1
- package/out/zero-cache/src/types/row-key.d.ts.map +1 -1
- package/out/zero-cache/src/types/row-key.js +5 -5
- package/out/zero-cache/src/types/row-key.js.map +1 -1
- package/out/zero-cache/src/types/streams.d.ts +49 -7
- package/out/zero-cache/src/types/streams.d.ts.map +1 -1
- package/out/zero-cache/src/types/streams.js +190 -58
- package/out/zero-cache/src/types/streams.js.map +1 -1
- package/out/zero-cache/src/types/subscription.d.ts +15 -0
- package/out/zero-cache/src/types/subscription.d.ts.map +1 -1
- package/out/zero-cache/src/types/subscription.js +123 -31
- package/out/zero-cache/src/types/subscription.js.map +1 -1
- package/out/zero-cache/src/types/websocket-handoff.d.ts +1 -1
- package/out/zero-cache/src/types/websocket-handoff.d.ts.map +1 -1
- package/out/zero-cache/src/types/websocket-handoff.js +18 -9
- package/out/zero-cache/src/types/websocket-handoff.js.map +1 -1
- package/out/zero-cache/src/types/ws.d.ts.map +1 -1
- package/out/zero-cache/src/types/ws.js +1 -16
- package/out/zero-cache/src/types/ws.js.map +1 -1
- package/out/zero-cache/src/workers/connect-params.d.ts +1 -0
- package/out/zero-cache/src/workers/connect-params.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connect-params.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +21 -16
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.d.ts.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +55 -4
- 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 +4 -1
- package/out/zero-client/src/client/active-clients-manager.js.map +1 -1
- package/out/zero-client/src/client/connection-manager.d.ts +20 -0
- package/out/zero-client/src/client/connection-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-manager.js +77 -13
- package/out/zero-client/src/client/connection-manager.js.map +1 -1
- package/out/zero-client/src/client/connection-status-enum.d.ts +2 -0
- package/out/zero-client/src/client/connection-status-enum.d.ts.map +1 -1
- package/out/zero-client/src/client/connection-status-enum.js +3 -1
- package/out/zero-client/src/client/connection-status-enum.js.map +1 -1
- package/out/zero-client/src/client/connection.d.ts +6 -0
- package/out/zero-client/src/client/connection.d.ts.map +1 -1
- package/out/zero-client/src/client/connection.js +2 -1
- package/out/zero-client/src/client/connection.js.map +1 -1
- package/out/zero-client/src/client/context.d.ts +22 -12
- package/out/zero-client/src/client/context.d.ts.map +1 -1
- package/out/zero-client/src/client/context.js +92 -25
- package/out/zero-client/src/client/context.js.map +1 -1
- package/out/zero-client/src/client/custom.js +2 -2
- package/out/zero-client/src/client/custom.js.map +1 -1
- package/out/zero-client/src/client/error.js +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +20 -3
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.d.ts.map +1 -1
- package/out/zero-client/src/client/mutator-proxy.js +5 -2
- package/out/zero-client/src/client/mutator-proxy.js.map +1 -1
- package/out/zero-client/src/client/options.d.ts +33 -0
- package/out/zero-client/src/client/options.d.ts.map +1 -1
- package/out/zero-client/src/client/options.js.map +1 -1
- package/out/zero-client/src/client/query-manager.d.ts.map +1 -1
- package/out/zero-client/src/client/query-manager.js +44 -11
- package/out/zero-client/src/client/query-manager.js.map +1 -1
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero-rep.d.ts +1 -0
- package/out/zero-client/src/client/zero-rep.d.ts.map +1 -1
- package/out/zero-client/src/client/zero-rep.js +8 -6
- package/out/zero-client/src/client/zero-rep.js.map +1 -1
- package/out/zero-client/src/client/zero.d.ts +18 -3
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +84 -47
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/mod.d.ts +1 -0
- package/out/zero-client/src/mod.d.ts.map +1 -1
- package/out/zero-client/src/mod.js +1 -0
- package/out/zero-client/src/types/query-result.d.ts +2 -0
- package/out/zero-client/src/types/query-result.d.ts.map +1 -1
- package/out/zero-events/src/status.d.ts +58 -0
- package/out/zero-events/src/status.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.d.ts.map +1 -1
- package/out/zero-protocol/src/ast.js +13 -14
- package/out/zero-protocol/src/ast.js.map +1 -1
- package/out/zero-protocol/src/down.d.ts +29 -29
- package/out/zero-protocol/src/query-hash.d.ts.map +1 -1
- package/out/zero-protocol/src/query-hash.js +2 -5
- package/out/zero-protocol/src/query-hash.js.map +1 -1
- package/out/zero-react/src/use-query.d.ts +5 -4
- package/out/zero-react/src/use-query.d.ts.map +1 -1
- package/out/zero-react/src/use-query.js +62 -4
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zero-react/src/zero.js +1 -0
- package/out/zero-server/src/adapters/drizzle.d.ts +2 -1
- package/out/zero-server/src/adapters/drizzle.d.ts.map +1 -1
- package/out/zero-server/src/adapters/drizzle.js +12 -7
- package/out/zero-server/src/adapters/drizzle.js.map +1 -1
- package/out/zero-server/src/adapters/kysely.d.ts +2 -1
- package/out/zero-server/src/adapters/kysely.d.ts.map +1 -1
- package/out/zero-server/src/adapters/kysely.js +8 -2
- package/out/zero-server/src/adapters/kysely.js.map +1 -1
- package/out/zero-server/src/adapters/pg.d.ts +1 -0
- package/out/zero-server/src/adapters/pg.d.ts.map +1 -1
- package/out/zero-server/src/adapters/pg.js +8 -2
- package/out/zero-server/src/adapters/pg.js.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.d.ts +1 -0
- package/out/zero-server/src/adapters/postgresjs.d.ts.map +1 -1
- package/out/zero-server/src/adapters/postgresjs.js +7 -1
- package/out/zero-server/src/adapters/postgresjs.js.map +1 -1
- package/out/zero-server/src/adapters/prisma.d.ts +3 -2
- package/out/zero-server/src/adapters/prisma.d.ts.map +1 -1
- package/out/zero-server/src/adapters/prisma.js +8 -2
- package/out/zero-server/src/adapters/prisma.js.map +1 -1
- package/out/zero-server/src/custom.d.ts +5 -1
- package/out/zero-server/src/custom.d.ts.map +1 -1
- package/out/zero-server/src/custom.js +6 -3
- package/out/zero-server/src/custom.js.map +1 -1
- package/out/zero-server/src/logging.d.ts +2 -2
- package/out/zero-server/src/logging.d.ts.map +1 -1
- package/out/zero-server/src/logging.js +2 -2
- package/out/zero-server/src/logging.js.map +1 -1
- package/out/zero-server/src/mod.d.ts +1 -1
- package/out/zero-server/src/mod.d.ts.map +1 -1
- package/out/zero-server/src/pg-query-executor.d.ts +2 -2
- package/out/zero-server/src/pg-query-executor.d.ts.map +1 -1
- package/out/zero-server/src/pg-query-executor.js +2 -2
- package/out/zero-server/src/pg-query-executor.js.map +1 -1
- package/out/zero-server/src/process-mutations.d.ts +12 -3
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +13 -8
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zero-server/src/push-processor.d.ts +8 -2
- package/out/zero-server/src/push-processor.d.ts.map +1 -1
- package/out/zero-server/src/push-processor.js +12 -4
- package/out/zero-server/src/push-processor.js.map +1 -1
- package/out/zero-server/src/schema.d.ts +2 -2
- package/out/zero-server/src/schema.d.ts.map +1 -1
- package/out/zero-server/src/schema.js +2 -2
- package/out/zero-server/src/schema.js.map +1 -1
- package/out/zero-server/src/zql-database.d.ts +21 -1
- package/out/zero-server/src/zql-database.d.ts.map +1 -1
- package/out/zero-server/src/zql-database.js +33 -2
- package/out/zero-server/src/zql-database.js.map +1 -1
- package/out/zero-solid/src/solid-view.d.ts +17 -0
- package/out/zero-solid/src/solid-view.d.ts.map +1 -1
- package/out/zero-solid/src/solid-view.js +39 -1
- package/out/zero-solid/src/solid-view.js.map +1 -1
- package/out/zero-solid/src/use-query.js +1 -2
- package/out/zero-solid/src/use-query.js.map +1 -1
- package/out/zero-solid/src/zero.js +1 -0
- package/out/zql/src/builder/builder.d.ts +25 -0
- package/out/zql/src/builder/builder.d.ts.map +1 -1
- package/out/zql/src/builder/builder.js +69 -19
- package/out/zql/src/builder/builder.js.map +1 -1
- package/out/zql/src/builder/correlated-predicate-pushdown.d.ts +43 -0
- package/out/zql/src/builder/correlated-predicate-pushdown.d.ts.map +1 -0
- package/out/zql/src/builder/correlated-predicate-pushdown.js +161 -0
- package/out/zql/src/builder/correlated-predicate-pushdown.js.map +1 -0
- package/out/zql/src/builder/debug-delegate.d.ts +6 -1
- package/out/zql/src/builder/debug-delegate.d.ts.map +1 -1
- package/out/zql/src/builder/debug-delegate.js +14 -2
- package/out/zql/src/builder/debug-delegate.js.map +1 -1
- package/out/zql/src/ivm/array-view.d.ts +29 -0
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +58 -9
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zql/src/ivm/cap.d.ts +2 -1
- package/out/zql/src/ivm/cap.d.ts.map +1 -1
- package/out/zql/src/ivm/cap.js +14 -4
- package/out/zql/src/ivm/cap.js.map +1 -1
- package/out/zql/src/ivm/connection-index.d.ts +68 -0
- package/out/zql/src/ivm/connection-index.d.ts.map +1 -0
- package/out/zql/src/ivm/connection-index.js +149 -0
- package/out/zql/src/ivm/connection-index.js.map +1 -0
- package/out/zql/src/ivm/data.d.ts.map +1 -1
- package/out/zql/src/ivm/data.js +8 -3
- package/out/zql/src/ivm/data.js.map +1 -1
- package/out/zql/src/ivm/deferred-input.d.ts.map +1 -1
- package/out/zql/src/ivm/deferred-input.js +3 -2
- package/out/zql/src/ivm/deferred-input.js.map +1 -1
- package/out/zql/src/ivm/exists.d.ts +3 -1
- package/out/zql/src/ivm/exists.d.ts.map +1 -1
- package/out/zql/src/ivm/exists.js +4 -1
- package/out/zql/src/ivm/exists.js.map +1 -1
- package/out/zql/src/ivm/fan-in.d.ts +6 -2
- package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-in.js +13 -5
- package/out/zql/src/ivm/fan-in.js.map +1 -1
- package/out/zql/src/ivm/fan-out.d.ts +5 -2
- package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/fan-out.js +4 -0
- package/out/zql/src/ivm/fan-out.js.map +1 -1
- package/out/zql/src/ivm/filter-operators.d.ts +8 -6
- package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
- package/out/zql/src/ivm/filter-operators.js +19 -8
- package/out/zql/src/ivm/filter-operators.js.map +1 -1
- package/out/zql/src/ivm/filter.d.ts +5 -2
- package/out/zql/src/ivm/filter.d.ts.map +1 -1
- package/out/zql/src/ivm/filter.js +10 -4
- package/out/zql/src/ivm/filter.js.map +1 -1
- package/out/zql/src/ivm/flipped-join.d.ts +9 -4
- package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
- package/out/zql/src/ivm/flipped-join.js +97 -46
- package/out/zql/src/ivm/flipped-join.js.map +1 -1
- package/out/zql/src/ivm/join-index-tap.d.ts +33 -0
- package/out/zql/src/ivm/join-index-tap.d.ts.map +1 -0
- package/out/zql/src/ivm/join-index-tap.js +70 -0
- package/out/zql/src/ivm/join-index-tap.js.map +1 -0
- package/out/zql/src/ivm/join-index.d.ts +35 -0
- package/out/zql/src/ivm/join-index.d.ts.map +1 -0
- package/out/zql/src/ivm/join-index.js +141 -0
- package/out/zql/src/ivm/join-index.js.map +1 -0
- package/out/zql/src/ivm/join-utils.d.ts +6 -0
- package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
- package/out/zql/src/ivm/join-utils.js +22 -1
- package/out/zql/src/ivm/join-utils.js.map +1 -1
- package/out/zql/src/ivm/join.d.ts +19 -1
- package/out/zql/src/ivm/join.d.ts.map +1 -1
- package/out/zql/src/ivm/join.js +107 -15
- package/out/zql/src/ivm/join.js.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.d.ts.map +1 -1
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js +6 -4
- package/out/zql/src/ivm/maybe-split-and-push-edit-change.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts +28 -3
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +69 -33
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/ivm/memory-storage.d.ts +1 -0
- package/out/zql/src/ivm/memory-storage.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-storage.js +1 -0
- package/out/zql/src/ivm/memory-storage.js.map +1 -1
- package/out/zql/src/ivm/operator.d.ts +45 -10
- package/out/zql/src/ivm/operator.d.ts.map +1 -1
- package/out/zql/src/ivm/operator.js +9 -4
- package/out/zql/src/ivm/operator.js.map +1 -1
- package/out/zql/src/ivm/push-accumulated.d.ts +6 -1
- package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
- package/out/zql/src/ivm/push-accumulated.js +47 -2
- package/out/zql/src/ivm/push-accumulated.js.map +1 -1
- package/out/zql/src/ivm/skip.d.ts +2 -1
- package/out/zql/src/ivm/skip.d.ts.map +1 -1
- package/out/zql/src/ivm/skip.js +3 -0
- package/out/zql/src/ivm/skip.js.map +1 -1
- package/out/zql/src/ivm/take-gate.d.ts +57 -0
- package/out/zql/src/ivm/take-gate.d.ts.map +1 -0
- package/out/zql/src/ivm/take-gate.js +106 -0
- package/out/zql/src/ivm/take-gate.js.map +1 -0
- package/out/zql/src/ivm/take.d.ts +8 -2
- package/out/zql/src/ivm/take.d.ts.map +1 -1
- package/out/zql/src/ivm/take.js +139 -103
- package/out/zql/src/ivm/take.js.map +1 -1
- package/out/zql/src/ivm/union-fan-in.d.ts +3 -0
- package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-in.js +63 -10
- package/out/zql/src/ivm/union-fan-in.js.map +1 -1
- package/out/zql/src/ivm/union-fan-out.d.ts +2 -1
- package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
- package/out/zql/src/ivm/union-fan-out.js +5 -0
- package/out/zql/src/ivm/union-fan-out.js.map +1 -1
- package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
- package/out/zql/src/ivm/view-apply-change.js +9 -4
- package/out/zql/src/ivm/view-apply-change.js.map +1 -1
- package/out/zql/src/ivm/view.d.ts +15 -0
- package/out/zql/src/ivm/view.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.d.ts +24 -1
- package/out/zql/src/mutate/custom.d.ts.map +1 -1
- package/out/zql/src/mutate/custom.js.map +1 -1
- package/out/zql/src/mutate/mutator-registry.d.ts.map +1 -1
- package/out/zql/src/mutate/mutator-registry.js +2 -2
- package/out/zql/src/mutate/mutator-registry.js.map +1 -1
- package/out/zql/src/planner/planner-builder.d.ts +23 -3
- package/out/zql/src/planner/planner-builder.d.ts.map +1 -1
- package/out/zql/src/planner/planner-builder.js +34 -17
- package/out/zql/src/planner/planner-builder.js.map +1 -1
- package/out/zql/src/planner/planner-connection.d.ts +58 -2
- package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
- package/out/zql/src/planner/planner-connection.js +103 -11
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/out/zql/src/planner/planner-debug.d.ts.map +1 -1
- package/out/zql/src/planner/planner-debug.js +3 -8
- package/out/zql/src/planner/planner-debug.js.map +1 -1
- package/out/zql/src/planner/planner-graph.d.ts +10 -0
- package/out/zql/src/planner/planner-graph.d.ts.map +1 -1
- package/out/zql/src/planner/planner-graph.js +14 -0
- package/out/zql/src/planner/planner-graph.js.map +1 -1
- package/out/zql/src/planner/planner-source.d.ts +2 -2
- package/out/zql/src/planner/planner-source.d.ts.map +1 -1
- package/out/zql/src/planner/planner-source.js +2 -2
- package/out/zql/src/planner/planner-source.js.map +1 -1
- package/out/zql/src/planner/planner-warnings.d.ts +83 -0
- package/out/zql/src/planner/planner-warnings.d.ts.map +1 -0
- package/out/zql/src/planner/planner-warnings.js +78 -0
- package/out/zql/src/planner/planner-warnings.js.map +1 -0
- package/out/zql/src/query/measure-push-operator.d.ts +2 -1
- package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
- package/out/zql/src/query/measure-push-operator.js +33 -4
- package/out/zql/src/query/measure-push-operator.js.map +1 -1
- package/out/zql/src/query/query-delegate-base.d.ts +4 -2
- package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
- package/out/zql/src/query/query-delegate-base.js +66 -33
- package/out/zql/src/query/query-delegate-base.js.map +1 -1
- package/out/zql/src/query/query-delegate.d.ts +33 -6
- package/out/zql/src/query/query-delegate.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.d.ts +1 -0
- package/out/zql/src/query/query-impl.d.ts.map +1 -1
- package/out/zql/src/query/query-impl.js +6 -23
- package/out/zql/src/query/query-impl.js.map +1 -1
- package/out/zql/src/query/query-transitions.d.ts.map +1 -1
- package/out/zql/src/query/query-transitions.js +2 -5
- package/out/zql/src/query/query-transitions.js.map +1 -1
- package/out/zql/src/query/query.d.ts +11 -2
- package/out/zql/src/query/query.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.d.ts +1 -0
- package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -1
- package/out/zql/src/query/runnable-query-impl.js +2 -10
- package/out/zql/src/query/runnable-query-impl.js.map +1 -1
- package/out/zql/src/query/typed-view.d.ts +1 -1
- package/out/zql/src/query/typed-view.d.ts.map +1 -1
- package/out/zqlite/src/database-storage.d.ts.map +1 -1
- package/out/zqlite/src/database-storage.js +9 -1
- package/out/zqlite/src/database-storage.js.map +1 -1
- package/out/zqlite/src/db.d.ts +9 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +31 -27
- package/out/zqlite/src/db.js.map +1 -1
- package/out/zqlite/src/pending-delta.d.ts +110 -0
- package/out/zqlite/src/pending-delta.d.ts.map +1 -0
- package/out/zqlite/src/pending-delta.js +278 -0
- package/out/zqlite/src/pending-delta.js.map +1 -0
- package/out/zqlite/src/query-builder.d.ts +17 -1
- package/out/zqlite/src/query-builder.d.ts.map +1 -1
- package/out/zqlite/src/query-builder.js +111 -20
- package/out/zqlite/src/query-builder.js.map +1 -1
- package/out/zqlite/src/query-delegate.d.ts.map +1 -1
- package/out/zqlite/src/query-delegate.js +10 -7
- package/out/zqlite/src/query-delegate.js.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-cost-model.js +52 -1
- package/out/zqlite/src/sqlite-cost-model.js.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.d.ts.map +1 -1
- package/out/zqlite/src/sqlite-stat-fanout.js +5 -31
- package/out/zqlite/src/sqlite-stat-fanout.js.map +1 -1
- package/out/zqlite/src/sqlite-stat4-sample.d.ts +37 -0
- package/out/zqlite/src/sqlite-stat4-sample.d.ts.map +1 -0
- package/out/zqlite/src/sqlite-stat4-sample.js +61 -0
- package/out/zqlite/src/sqlite-stat4-sample.js.map +1 -0
- package/out/zqlite/src/table-source.d.ts +82 -2
- package/out/zqlite/src/table-source.d.ts.map +1 -1
- package/out/zqlite/src/table-source.js +261 -38
- package/out/zqlite/src/table-source.js.map +1 -1
- package/package.json +3 -4
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts +0 -25
- package/out/replicache/src/kv/idb-store-with-mem-fallback.d.ts.map +0 -1
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js +0 -83
- package/out/replicache/src/kv/idb-store-with-mem-fallback.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collect-idb-databases.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/persist/collect-idb-databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAC,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"collect-idb-databases.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/persist/collect-idb-databases.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAC,MAAM,kBAAkB,CAAC;AAMpE,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAgB3C,OAAO,KAAK,EAAC,WAAW,EAAE,SAAS,EAAE,aAAa,EAAC,MAAM,gBAAgB,CAAC;AAE1E,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAM/D,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,cAAc,CAAC;AAGnD,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAC,iBAAiB,EAAC,MAAM,0BAA0B,CAAC;AAE3D;;GAEG;AACH,eAAO,MAAM,oBAAoB,QAAsB,CAAC;AAExD;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAgB,CAAC;AAEvD,wBAAgB,uBAAuB,CACrC,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,aAAa,EAC9B,eAAe,EAAE,MAAM,EACvB,mBAAmB,EAAE,MAAM,EAC3B,MAAM,EAAE,MAAM,EACd,sBAAsB,EAAE,OAAO,EAC/B,gBAAgB,EAAE,gBAAgB,EAClC,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,EACnB,WAAW,GAAE,WAAgC,EAC7C,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,SAAS,GACtE,IAAI,CA0BN;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,iBAAiB,EAAE,iBAAiB,EACpC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,eAAe,EAAE,aAAa,EAC9B,sBAAsB,EAAE,OAAO,EAC/B,gBAAgB,EAAE,gBAAgB,EAClC,WAAW,GAAE,WAAgC,GAC5C,OAAO,CAAC,IAAI,CAAC,CAyEf;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,iBAAiB,EAAE,iBAAiB,EACpC,WAAW,EAAE,SAAS,iBAIvB;AA6BD;;;;GAIG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,WAAW,KAAK,KAAK,CAAC;AA0C9E;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAChC;;;OAGG;IACH,OAAO,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,aAAa,GAAG,SAAS,CAAC;IACpD;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAChC;;;;;;;;;;;;;;OAcG;IACH,QAAQ,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAC;CAClC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,mBAAmB,iBAe5E;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC;IACpE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC,CAED;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,SAAS,EAAE,CAAC,EAAE,EAAE,iBAAiB,KAAK,OAAO,EAC7C,IAAI,CAAC,EAAE,mBAAmB,GACzB,OAAO,CAAC;IACT,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,OAAO,EAAE,CAAC;CACnB,CAAC,CAqBD;AA0CD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,CAAC,EAAE,mBAAmB;aAvFvD,MAAM,EAAE;YACT,OAAO,EAAE;GAwFlB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { assert } from "../../../shared/src/asserts.js";
|
|
2
2
|
import { initBgIntervalProcess } from "../bg-interval.js";
|
|
3
|
+
import { InvalidRefCountError } from "../dag/invalid-ref-count-error.js";
|
|
3
4
|
import { assertHash, newRandomHash } from "../hash.js";
|
|
4
5
|
import { StoreImpl } from "../dag/store-impl.js";
|
|
5
6
|
import { withRead, withWrite } from "../with-transactions.js";
|
|
@@ -7,7 +8,9 @@ import { clientGroupHasPendingMutations, getClientGroups } from "./client-groups
|
|
|
7
8
|
import { getClients } from "./clients.js";
|
|
8
9
|
import { addDeletedClients, getDeletedClients, mergeDeletedClients, normalizeDeletedClients } from "../deleted-clients.js";
|
|
9
10
|
import { getKVStoreProvider } from "../get-kv-store-provider.js";
|
|
11
|
+
import { fallbackStoreProvider, isFallbackStore } from "../kv/mem-fallback-store.js";
|
|
10
12
|
import { createLogContext } from "../log-options.js";
|
|
13
|
+
import { getIDBDatabasesDBName } from "./idb-databases-store-db-name.js";
|
|
11
14
|
import { IDBDatabasesStore } from "./idb-databases-store.js";
|
|
12
15
|
//#region ../replicache/src/persist/collect-idb-databases.ts
|
|
13
16
|
/**
|
|
@@ -18,17 +21,17 @@ var COLLECT_IDB_INTERVAL = 720 * 60 * 1e3;
|
|
|
18
21
|
* We delay the initial collection to prevent doing it at startup.
|
|
19
22
|
*/
|
|
20
23
|
var INITIAL_COLLECT_IDB_DELAY = 300 * 1e3;
|
|
21
|
-
function initCollectIDBDatabases(idbDatabasesStore, kvStoreProvider, collectInterval, initialCollectDelay, maxAge, enableMutationRecovery, onClientsDeleted, lc, signal) {
|
|
24
|
+
function initCollectIDBDatabases(idbDatabasesStore, kvStoreProvider, collectInterval, initialCollectDelay, maxAge, enableMutationRecovery, onClientsDeleted, lc, signal, newDagStore = defaultNewDagStore, onStorageFailure) {
|
|
22
25
|
let initial = true;
|
|
23
26
|
initBgIntervalProcess("CollectIDBDatabases", async () => {
|
|
24
|
-
await collectIDBDatabases(idbDatabasesStore, Date.now(), maxAge, kvStoreProvider, enableMutationRecovery, onClientsDeleted);
|
|
27
|
+
await collectIDBDatabases(idbDatabasesStore, Date.now(), maxAge, kvStoreProvider, enableMutationRecovery, onClientsDeleted, newDagStore);
|
|
25
28
|
}, () => {
|
|
26
29
|
if (initial) {
|
|
27
30
|
initial = false;
|
|
28
31
|
return initialCollectDelay;
|
|
29
32
|
}
|
|
30
33
|
return collectInterval;
|
|
31
|
-
}, lc, signal);
|
|
34
|
+
}, lc, signal, onStorageFailure);
|
|
32
35
|
}
|
|
33
36
|
/**
|
|
34
37
|
* Collects IDB databases that are no longer needed.
|
|
@@ -47,12 +50,18 @@ async function collectIDBDatabases(idbDatabasesStore, now, maxAge, kvStoreProvid
|
|
|
47
50
|
const { errors } = await dropDatabases(idbDatabasesStore, dbNamesToRemove, kvStoreProvider.drop);
|
|
48
51
|
if (errors.length) throw errors[0];
|
|
49
52
|
if (deletedClientsToRemove.length > 0) {
|
|
50
|
-
let
|
|
51
|
-
for (const name of dbNamesToKeep)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
let newDeletedClients = deletedClientsToRemove;
|
|
54
|
+
for (const name of dbNamesToKeep) {
|
|
55
|
+
let dbDeletedClients;
|
|
56
|
+
try {
|
|
57
|
+
dbDeletedClients = await withWrite(newDagStore(name, kvStoreProvider.create), (dagWrite) => addDeletedClients(dagWrite, deletedClientsToRemove));
|
|
58
|
+
} catch (e) {
|
|
59
|
+
if (!(e instanceof InvalidRefCountError)) throw e;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
newDeletedClients = mergeDeletedClients(newDeletedClients, dbDeletedClients);
|
|
63
|
+
}
|
|
64
|
+
await onClientsDeleted(normalizeDeletedClients(newDeletedClients));
|
|
56
65
|
}
|
|
57
66
|
}
|
|
58
67
|
async function dropDatabaseInternal(name, idbDatabasesStore, kvDropStore) {
|
|
@@ -86,25 +95,93 @@ function gatherDatabaseInfoForCollect(db, now, maxAge, enableMutationRecovery, k
|
|
|
86
95
|
return canDatabaseBeCollectedAndGetDeletedClientIDs(enableMutationRecovery, newDagStore(db.name, kvCreateStore), now, maxAge);
|
|
87
96
|
}
|
|
88
97
|
/**
|
|
89
|
-
* Drops the specified database
|
|
98
|
+
* Drops the specified database, from memory as well as from the configured
|
|
99
|
+
* store (see `onStorageFailure`). Rejects if the configured store cannot be
|
|
100
|
+
* opened or dropped.
|
|
90
101
|
* @param dbName The name of the database to drop.
|
|
91
102
|
* @param opts Options for dropping the database.
|
|
92
103
|
*/
|
|
93
104
|
async function dropDatabase(dbName, opts) {
|
|
94
|
-
const
|
|
95
|
-
|
|
105
|
+
const logContext = createLogContext(opts?.logLevel, opts?.logSinks, { dropDatabase: void 0 });
|
|
106
|
+
for (const { provider, drops } of dropTargets(logContext, opts)) {
|
|
107
|
+
if (!drops(dbName)) continue;
|
|
108
|
+
const store = new IDBDatabasesStore(provider.create);
|
|
109
|
+
try {
|
|
110
|
+
await dropDatabaseInternal(dbName, store, provider.drop);
|
|
111
|
+
} finally {
|
|
112
|
+
await closeIgnoringErrors(store);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
96
115
|
}
|
|
97
116
|
/**
|
|
98
|
-
* Deletes all IndexedDB data associated with Replicache
|
|
117
|
+
* Deletes all IndexedDB data associated with Replicache, and the in-memory
|
|
118
|
+
* databases instances ran on after a storage failure (see
|
|
119
|
+
* `onStorageFailure`).
|
|
99
120
|
*
|
|
100
121
|
* Returns an object with the names of the successfully dropped databases
|
|
101
|
-
* and any errors encountered while dropping.
|
|
122
|
+
* and any errors encountered while dropping. Rejects if the configured store
|
|
123
|
+
* cannot be opened.
|
|
124
|
+
*/
|
|
125
|
+
function dropAllDatabases(opts) {
|
|
126
|
+
return dropMatchingDatabases(() => true, opts);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Like {@link dropAllDatabases}, for the databases whose registry record
|
|
130
|
+
* matches `predicate`.
|
|
131
|
+
*/
|
|
132
|
+
async function dropMatchingDatabases(predicate, opts) {
|
|
133
|
+
const logContext = createLogContext(opts?.logLevel, opts?.logSinks, { dropDatabases: void 0 });
|
|
134
|
+
const dropped = /* @__PURE__ */ new Set();
|
|
135
|
+
const errors = [];
|
|
136
|
+
for (const { provider, drops } of dropTargets(logContext, opts)) {
|
|
137
|
+
const store = new IDBDatabasesStore(provider.create);
|
|
138
|
+
try {
|
|
139
|
+
const databases = await store.getDatabases();
|
|
140
|
+
const result = await dropDatabases(store, Object.values(databases).filter((db) => predicate(db) && drops(db.name)).map((db) => db.name), provider.drop);
|
|
141
|
+
result.dropped.forEach((name) => dropped.add(name));
|
|
142
|
+
errors.push(...result.errors);
|
|
143
|
+
} finally {
|
|
144
|
+
await closeIgnoringErrors(store);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
dropped: [...dropped],
|
|
149
|
+
errors
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The memory stores instances fell back to first, then the configured store.
|
|
154
|
+
* An instance whose store failed to open runs on memory stores of the same
|
|
155
|
+
* names (see `onStorageFailure`), and memory stores outlive the instance for
|
|
156
|
+
* the life of the process, so a drop clears them whatever the configured
|
|
157
|
+
* store is. Only those: the memory stores of `kvStore: 'mem'` instances are
|
|
158
|
+
* left alone unless `'mem'` is the store being dropped from. The configured
|
|
159
|
+
* store is still dropped, and its failure is reported: it may hold data on
|
|
160
|
+
* disk.
|
|
161
|
+
*/
|
|
162
|
+
function dropTargets(lc, opts) {
|
|
163
|
+
const all = () => true;
|
|
164
|
+
if (opts?.kvStore === "mem") return [{
|
|
165
|
+
provider: getKVStoreProvider(lc, "mem"),
|
|
166
|
+
drops: all
|
|
167
|
+
}];
|
|
168
|
+
const targets = [];
|
|
169
|
+
if (isFallbackStore(getIDBDatabasesDBName())) targets.push({
|
|
170
|
+
provider: fallbackStoreProvider,
|
|
171
|
+
drops: isFallbackStore
|
|
172
|
+
});
|
|
173
|
+
targets.push({
|
|
174
|
+
provider: getKVStoreProvider(lc, opts?.kvStore),
|
|
175
|
+
drops: all
|
|
176
|
+
});
|
|
177
|
+
return targets;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* A store that failed to open may also fail to close; the drop's own result
|
|
181
|
+
* is what the caller needs.
|
|
102
182
|
*/
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const store = new IDBDatabasesStore(kvStoreProvider.create);
|
|
106
|
-
const databases = await store.getDatabases();
|
|
107
|
-
return dropDatabases(store, Object.values(databases).map((db) => db.name), kvStoreProvider.drop);
|
|
183
|
+
function closeIgnoringErrors(store) {
|
|
184
|
+
return store.close().catch(() => void 0);
|
|
108
185
|
}
|
|
109
186
|
/**
|
|
110
187
|
* If there are pending mutations in any of the clients in this db we return
|
|
@@ -128,6 +205,6 @@ function canDatabaseBeCollectedAndGetDeletedClientIDs(enableMutationRecovery, pe
|
|
|
128
205
|
});
|
|
129
206
|
}
|
|
130
207
|
//#endregion
|
|
131
|
-
export { COLLECT_IDB_INTERVAL, INITIAL_COLLECT_IDB_DELAY, dropAllDatabases, dropDatabase, initCollectIDBDatabases };
|
|
208
|
+
export { COLLECT_IDB_INTERVAL, INITIAL_COLLECT_IDB_DELAY, dropAllDatabases, dropDatabase, dropDatabaseInternal, dropMatchingDatabases, initCollectIDBDatabases };
|
|
132
209
|
|
|
133
210
|
//# sourceMappingURL=collect-idb-databases.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collect-idb-databases.js","names":[],"sources":["../../../../../replicache/src/persist/collect-idb-databases.ts"],"sourcesContent":["import type {LogContext, LogLevel, LogSink} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {MaybePromise} from '../../../shared/src/types.ts';\nimport {initBgIntervalProcess} from '../bg-interval.ts';\nimport {StoreImpl} from '../dag/store-impl.ts';\nimport type {Store} from '../dag/store.ts';\nimport {\n addDeletedClients,\n getDeletedClients,\n mergeDeletedClients,\n normalizeDeletedClients,\n type DeletedClients,\n type WritableDeletedClients,\n} from '../deleted-clients.ts';\nimport * as FormatVersion from '../format-version-enum.ts';\nimport {getKVStoreProvider} from '../get-kv-store-provider.ts';\nimport {assertHash, newRandomHash} from '../hash.ts';\nimport type {CreateStore, DropStore, StoreProvider} from '../kv/store.ts';\nimport {createLogContext} from '../log-options.ts';\nimport {withRead, withWrite} from '../with-transactions.ts';\nimport {\n clientGroupHasPendingMutations,\n getClientGroups,\n} from './client-groups.ts';\nimport type {OnClientsDeleted} from './clients.ts';\nimport {getClients} from './clients.ts';\nimport type {IndexedDBDatabase} from './idb-databases-store.ts';\nimport {IDBDatabasesStore} from './idb-databases-store.ts';\n\n/**\n * How frequently to try to collect\n */\nexport const COLLECT_IDB_INTERVAL = 12 * 60 * 60 * 1000; // 12 hours\n\n/**\n * We delay the initial collection to prevent doing it at startup.\n */\nexport const INITIAL_COLLECT_IDB_DELAY = 5 * 60 * 1000; // 5 minutes\n\nexport function initCollectIDBDatabases(\n idbDatabasesStore: IDBDatabasesStore,\n kvStoreProvider: StoreProvider,\n collectInterval: number,\n initialCollectDelay: number,\n maxAge: number,\n enableMutationRecovery: boolean,\n onClientsDeleted: OnClientsDeleted,\n lc: LogContext,\n signal: AbortSignal,\n): void {\n let initial = true;\n initBgIntervalProcess(\n 'CollectIDBDatabases',\n async () => {\n await collectIDBDatabases(\n idbDatabasesStore,\n Date.now(),\n maxAge,\n kvStoreProvider,\n enableMutationRecovery,\n onClientsDeleted,\n );\n },\n () => {\n if (initial) {\n initial = false;\n return initialCollectDelay;\n }\n return collectInterval;\n },\n lc,\n signal,\n );\n}\n\n/**\n * Collects IDB databases that are no longer needed.\n */\nexport async function collectIDBDatabases(\n idbDatabasesStore: IDBDatabasesStore,\n now: number,\n maxAge: number,\n kvStoreProvider: StoreProvider,\n enableMutationRecovery: boolean,\n onClientsDeleted: OnClientsDeleted,\n newDagStore = defaultNewDagStore,\n): Promise<void> {\n const databases = await idbDatabasesStore.getDatabases();\n\n const dbs = Object.values(databases);\n const collectResults = await Promise.all(\n dbs.map(\n async db =>\n [\n db.name,\n await gatherDatabaseInfoForCollect(\n db,\n now,\n maxAge,\n enableMutationRecovery,\n kvStoreProvider.create,\n newDagStore,\n ),\n ] as const,\n ),\n );\n\n const dbNamesToRemove: string[] = [];\n const dbNamesToKeep: string[] = [];\n const deletedClientsToRemove: WritableDeletedClients = [];\n for (const [dbName, [canCollect, deletedClients]] of collectResults) {\n if (canCollect) {\n dbNamesToRemove.push(dbName);\n deletedClientsToRemove.push(...deletedClients);\n } else {\n dbNamesToKeep.push(dbName);\n }\n }\n\n const {errors} = await dropDatabases(\n idbDatabasesStore,\n dbNamesToRemove,\n kvStoreProvider.drop,\n );\n if (errors.length) {\n throw errors[0];\n }\n\n if (deletedClientsToRemove.length > 0) {\n // Add the deleted clients to all the dbs that survived the collection.\n let allDeletedClients: DeletedClients = deletedClientsToRemove;\n for (const name of dbNamesToKeep) {\n await withWrite(\n newDagStore(name, kvStoreProvider.create),\n async dagWrite => {\n const newDeletedClients = await addDeletedClients(\n dagWrite,\n deletedClientsToRemove,\n );\n\n allDeletedClients = mergeDeletedClients(\n allDeletedClients,\n newDeletedClients,\n );\n },\n );\n }\n // normalize and dedupe\n const normalizedDeletedClients = normalizeDeletedClients(allDeletedClients);\n\n // Call the callback with the normalized deleted clients\n await onClientsDeleted(normalizedDeletedClients);\n }\n}\n\nasync function dropDatabaseInternal(\n name: string,\n idbDatabasesStore: IDBDatabasesStore,\n kvDropStore: DropStore,\n) {\n await kvDropStore(name);\n await idbDatabasesStore.deleteDatabases([name]);\n}\n\nasync function dropDatabases(\n idbDatabasesStore: IDBDatabasesStore,\n namesToRemove: string[],\n kvDropStore: DropStore,\n): Promise<{dropped: string[]; errors: unknown[]}> {\n // Try to remove the databases in parallel. Don't let a single reject fail the\n // other ones. We will check for failures afterwards.\n const dropStoreResults = await Promise.allSettled(\n namesToRemove.map(async name => {\n await dropDatabaseInternal(name, idbDatabasesStore, kvDropStore);\n return name;\n }),\n );\n\n const dropped: string[] = [];\n const errors: unknown[] = [];\n for (const result of dropStoreResults) {\n if (result.status === 'fulfilled') {\n dropped.push(result.value);\n } else {\n errors.push(result.reason);\n }\n }\n\n return {dropped, errors};\n}\n\nfunction defaultNewDagStore(name: string, kvCreateStore: CreateStore): Store {\n const perKvStore = kvCreateStore(name);\n return new StoreImpl(perKvStore, newRandomHash, assertHash);\n}\n\n/**\n * If any client has a recent heartbeat or there are pending mutations we\n * return `[false]`. Otherwise we return `[true, deletedClients]`.\n */\nfunction gatherDatabaseInfoForCollect(\n db: IndexedDBDatabase,\n now: number,\n maxAge: number,\n enableMutationRecovery: boolean,\n kvCreateStore: CreateStore,\n newDagStore: typeof defaultNewDagStore,\n): MaybePromise<\n [canCollect: false] | [canCollect: true, deletedClients: DeletedClients]\n> {\n if (db.replicacheFormatVersion > FormatVersion.Latest) {\n return [false];\n }\n\n // If increase the format version we need to decide how to deal with this\n // logic.\n assert(\n db.replicacheFormatVersion === FormatVersion.DD31 ||\n db.replicacheFormatVersion === FormatVersion.V6 ||\n db.replicacheFormatVersion === FormatVersion.V7,\n () =>\n `Expected replicacheFormatVersion to be DD31, V6, or V7, got ${db.replicacheFormatVersion}`,\n );\n return canDatabaseBeCollectedAndGetDeletedClientIDs(\n enableMutationRecovery,\n newDagStore(db.name, kvCreateStore),\n now,\n maxAge,\n );\n}\n\n/**\n * Options for `dropDatabase` and `dropAllDatabases`.\n */\nexport type DropDatabaseOptions = {\n /**\n * Allows providing a custom implementation of the underlying storage layer.\n * Default is `'idb'`.\n */\n kvStore?: 'idb' | 'mem' | StoreProvider | undefined;\n /**\n * Determines how much logging to do. When this is set to `'debug'`,\n * Replicache will also log `'info'` and `'error'` messages. When set to\n * `'info'` we log `'info'` and `'error'` but not `'debug'`. When set to\n * `'error'` we only log `'error'` messages.\n * Default is `'info'`.\n */\n logLevel?: LogLevel | undefined;\n /**\n * Enables custom handling of logs.\n *\n * By default logs are logged to the console. If you would like logs to be\n * sent elsewhere (e.g. to a cloud logging service like DataDog) you can\n * provide an array of {@link LogSink}s. Logs at or above\n * {@link DropDatabaseOptions.logLevel} are sent to each of these {@link LogSink}s.\n * If you would still like logs to go to the console, include\n * `consoleLogSink` in the array.\n *\n * ```ts\n * logSinks: [consoleLogSink, myCloudLogSink],\n * ```\n * Default is `[consoleLogSink]`.\n */\n logSinks?: LogSink[] | undefined;\n};\n\n/**\n * Drops the specified database.\n * @param dbName The name of the database to drop.\n * @param opts Options for dropping the database.\n */\nexport async function dropDatabase(dbName: string, opts?: DropDatabaseOptions) {\n const logContext = createLogContext(opts?.logLevel, opts?.logSinks, {\n dropDatabase: undefined,\n });\n const kvStoreProvider = getKVStoreProvider(logContext, opts?.kvStore);\n await dropDatabaseInternal(\n dbName,\n new IDBDatabasesStore(kvStoreProvider.create),\n kvStoreProvider.drop,\n );\n}\n\n/**\n * Deletes all IndexedDB data associated with Replicache.\n *\n * Returns an object with the names of the successfully dropped databases\n * and any errors encountered while dropping.\n */\nexport async function dropAllDatabases(opts?: DropDatabaseOptions): Promise<{\n dropped: string[];\n errors: unknown[];\n}> {\n const logContext = createLogContext(opts?.logLevel, opts?.logSinks, {\n dropAllDatabases: undefined,\n });\n const kvStoreProvider = getKVStoreProvider(logContext, opts?.kvStore);\n const store = new IDBDatabasesStore(kvStoreProvider.create);\n const databases = await store.getDatabases();\n const dbNames = Object.values(databases).map(db => db.name);\n return dropDatabases(store, dbNames, kvStoreProvider.drop);\n}\n\n/**\n * Deletes all IndexedDB data associated with Replicache.\n *\n * Returns an object with the names of the successfully dropped databases\n * and any errors encountered while dropping.\n *\n * @deprecated Use `dropAllDatabases` instead.\n */\nexport function deleteAllReplicacheData(opts?: DropDatabaseOptions) {\n return dropAllDatabases(opts);\n}\n\n/**\n * If there are pending mutations in any of the clients in this db we return\n * `[false]`. If any client has a recent heartbeat we also return `[false]`.\n * Otherwise we return `[true, deletedClients]`.\n */\nfunction canDatabaseBeCollectedAndGetDeletedClientIDs(\n enableMutationRecovery: boolean,\n perdag: Store,\n now: number,\n maxAge: number,\n): Promise<\n [canCollect: false] | [canCollect: true, deletedClients: DeletedClients]\n> {\n return withRead(perdag, async read => {\n // If mutation recovery is disabled we do not care if there are pending\n // mutations when we decide if we can collect the database.\n if (enableMutationRecovery) {\n const clientGroups = await getClientGroups(read);\n for (const clientGroup of clientGroups.values()) {\n if (clientGroupHasPendingMutations(clientGroup)) {\n return [false];\n }\n }\n }\n\n const clients = await getClients(read);\n\n // Don't collect if any client has a recent heartbeat (is still active).\n // This is defense in depth - normally lastOpenedTimestampMS is kept fresh\n // by the heartbeat, but this check protects against edge cases.\n for (const [, client] of clients) {\n if (now - client.heartbeatTimestampMs < maxAge) {\n return [false];\n }\n }\n\n const existingDeletedClients = await getDeletedClients(read);\n const deletedClients: WritableDeletedClients = [...existingDeletedClients];\n\n // Add all current clients to the deleted clients list\n for (const [clientID, client] of clients) {\n deletedClients.push({\n clientID,\n clientGroupID: client.clientGroupID,\n });\n }\n\n // The normalization (deduping and sorting) will be done when storing\n return [true, deletedClients];\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collect-idb-databases.js","names":[],"sources":["../../../../../replicache/src/persist/collect-idb-databases.ts"],"sourcesContent":["import type {LogContext, LogLevel, LogSink} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {MaybePromise} from '../../../shared/src/types.ts';\nimport {initBgIntervalProcess} from '../bg-interval.ts';\nimport {InvalidRefCountError} from '../dag/invalid-ref-count-error.ts';\nimport {StoreImpl} from '../dag/store-impl.ts';\nimport type {Store} from '../dag/store.ts';\nimport {\n addDeletedClients,\n getDeletedClients,\n mergeDeletedClients,\n normalizeDeletedClients,\n type DeletedClients,\n type WritableDeletedClients,\n} from '../deleted-clients.ts';\nimport * as FormatVersion from '../format-version-enum.ts';\nimport {getKVStoreProvider} from '../get-kv-store-provider.ts';\nimport {assertHash, newRandomHash} from '../hash.ts';\nimport {\n fallbackStoreProvider,\n isFallbackStore,\n} from '../kv/mem-fallback-store.ts';\nimport type {CreateStore, DropStore, StoreProvider} from '../kv/store.ts';\nimport {createLogContext} from '../log-options.ts';\nimport type {StorageFailureError} from '../storage-failure.ts';\nimport {withRead, withWrite} from '../with-transactions.ts';\nimport {\n clientGroupHasPendingMutations,\n getClientGroups,\n} from './client-groups.ts';\nimport type {OnClientsDeleted} from './clients.ts';\nimport {getClients} from './clients.ts';\nimport {getIDBDatabasesDBName} from './idb-databases-store-db-name.ts';\nimport type {IndexedDBDatabase} from './idb-databases-store.ts';\nimport {IDBDatabasesStore} from './idb-databases-store.ts';\n\n/**\n * How frequently to try to collect\n */\nexport const COLLECT_IDB_INTERVAL = 12 * 60 * 60 * 1000; // 12 hours\n\n/**\n * We delay the initial collection to prevent doing it at startup.\n */\nexport const INITIAL_COLLECT_IDB_DELAY = 5 * 60 * 1000; // 5 minutes\n\nexport function initCollectIDBDatabases(\n idbDatabasesStore: IDBDatabasesStore,\n kvStoreProvider: StoreProvider,\n collectInterval: number,\n initialCollectDelay: number,\n maxAge: number,\n enableMutationRecovery: boolean,\n onClientsDeleted: OnClientsDeleted,\n lc: LogContext,\n signal: AbortSignal,\n newDagStore: NewDagStore = defaultNewDagStore,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n): void {\n let initial = true;\n initBgIntervalProcess(\n 'CollectIDBDatabases',\n async () => {\n await collectIDBDatabases(\n idbDatabasesStore,\n Date.now(),\n maxAge,\n kvStoreProvider,\n enableMutationRecovery,\n onClientsDeleted,\n newDagStore,\n );\n },\n () => {\n if (initial) {\n initial = false;\n return initialCollectDelay;\n }\n return collectInterval;\n },\n lc,\n signal,\n onStorageFailure,\n );\n}\n\n/**\n * Collects IDB databases that are no longer needed.\n */\nexport async function collectIDBDatabases(\n idbDatabasesStore: IDBDatabasesStore,\n now: number,\n maxAge: number,\n kvStoreProvider: StoreProvider,\n enableMutationRecovery: boolean,\n onClientsDeleted: OnClientsDeleted,\n newDagStore: NewDagStore = defaultNewDagStore,\n): Promise<void> {\n const databases = await idbDatabasesStore.getDatabases();\n\n const dbs = Object.values(databases);\n const collectResults = await Promise.all(\n dbs.map(\n async db =>\n [\n db.name,\n await gatherDatabaseInfoForCollect(\n db,\n now,\n maxAge,\n enableMutationRecovery,\n kvStoreProvider.create,\n newDagStore,\n ),\n ] as const,\n ),\n );\n\n const dbNamesToRemove: string[] = [];\n const dbNamesToKeep: string[] = [];\n const deletedClientsToRemove: WritableDeletedClients = [];\n for (const [dbName, [canCollect, deletedClients]] of collectResults) {\n if (canCollect) {\n dbNamesToRemove.push(dbName);\n deletedClientsToRemove.push(...deletedClients);\n } else {\n dbNamesToKeep.push(dbName);\n }\n }\n\n const {errors} = await dropDatabases(\n idbDatabasesStore,\n dbNamesToRemove,\n kvStoreProvider.drop,\n );\n if (errors.length) {\n throw errors[0];\n }\n\n if (deletedClientsToRemove.length > 0) {\n // Add the deleted clients to all the dbs that survived the collection.\n let newDeletedClients: DeletedClients = deletedClientsToRemove;\n for (const name of dbNamesToKeep) {\n let dbDeletedClients: DeletedClients;\n try {\n dbDeletedClients = await withWrite(\n newDagStore(name, kvStoreProvider.create),\n dagWrite => addDeletedClients(dagWrite, deletedClientsToRemove),\n );\n } catch (e) {\n if (!(e instanceof InvalidRefCountError)) {\n throw e;\n }\n // This database is corrupt. Its own instance will find out and\n // recover the next time it writes to it; here, just skip it and keep\n // collecting into the others, instead of letting one corrupt\n // database break every collection run forever.\n continue;\n }\n newDeletedClients = mergeDeletedClients(\n newDeletedClients,\n dbDeletedClients,\n );\n }\n // normalize and dedupe\n const normalizedDeletedClients = normalizeDeletedClients(newDeletedClients);\n\n // Call the callback with the normalized deleted clients\n await onClientsDeleted(normalizedDeletedClients);\n }\n}\n\nexport async function dropDatabaseInternal(\n name: string,\n idbDatabasesStore: IDBDatabasesStore,\n kvDropStore: DropStore,\n) {\n await kvDropStore(name);\n await idbDatabasesStore.deleteDatabases([name]);\n}\n\nasync function dropDatabases(\n idbDatabasesStore: IDBDatabasesStore,\n namesToRemove: string[],\n kvDropStore: DropStore,\n): Promise<{dropped: string[]; errors: unknown[]}> {\n // Try to remove the databases in parallel. Don't let a single reject fail the\n // other ones. We will check for failures afterwards.\n const dropStoreResults = await Promise.allSettled(\n namesToRemove.map(async name => {\n await dropDatabaseInternal(name, idbDatabasesStore, kvDropStore);\n return name;\n }),\n );\n\n const dropped: string[] = [];\n const errors: unknown[] = [];\n for (const result of dropStoreResults) {\n if (result.status === 'fulfilled') {\n dropped.push(result.value);\n } else {\n errors.push(result.reason);\n }\n }\n\n return {dropped, errors};\n}\n\n/**\n * Creates the dag store used to inspect and update a database during\n * collection. Callers can override it to install store hooks, for example so\n * a corrupt ref count found while writing deleted clients is recovered from.\n */\nexport type NewDagStore = (name: string, kvCreateStore: CreateStore) => Store;\n\nfunction defaultNewDagStore(name: string, kvCreateStore: CreateStore): Store {\n const perKvStore = kvCreateStore(name);\n return new StoreImpl(perKvStore, newRandomHash, assertHash);\n}\n\n/**\n * If any client has a recent heartbeat or there are pending mutations we\n * return `[false]`. Otherwise we return `[true, deletedClients]`.\n */\nfunction gatherDatabaseInfoForCollect(\n db: IndexedDBDatabase,\n now: number,\n maxAge: number,\n enableMutationRecovery: boolean,\n kvCreateStore: CreateStore,\n newDagStore: NewDagStore,\n): MaybePromise<\n [canCollect: false] | [canCollect: true, deletedClients: DeletedClients]\n> {\n if (db.replicacheFormatVersion > FormatVersion.Latest) {\n return [false];\n }\n\n // If increase the format version we need to decide how to deal with this\n // logic.\n assert(\n db.replicacheFormatVersion === FormatVersion.DD31 ||\n db.replicacheFormatVersion === FormatVersion.V6 ||\n db.replicacheFormatVersion === FormatVersion.V7,\n () =>\n `Expected replicacheFormatVersion to be DD31, V6, or V7, got ${db.replicacheFormatVersion}`,\n );\n return canDatabaseBeCollectedAndGetDeletedClientIDs(\n enableMutationRecovery,\n newDagStore(db.name, kvCreateStore),\n now,\n maxAge,\n );\n}\n\n/**\n * Options for `dropDatabase` and `dropAllDatabases`.\n */\nexport type DropDatabaseOptions = {\n /**\n * Allows providing a custom implementation of the underlying storage layer.\n * Default is `'idb'`.\n */\n kvStore?: 'idb' | 'mem' | StoreProvider | undefined;\n /**\n * Determines how much logging to do. When this is set to `'debug'`,\n * Replicache will also log `'info'` and `'error'` messages. When set to\n * `'info'` we log `'info'` and `'error'` but not `'debug'`. When set to\n * `'error'` we only log `'error'` messages.\n * Default is `'info'`.\n */\n logLevel?: LogLevel | undefined;\n /**\n * Enables custom handling of logs.\n *\n * By default logs are logged to the console. If you would like logs to be\n * sent elsewhere (e.g. to a cloud logging service like DataDog) you can\n * provide an array of {@link LogSink}s. Logs at or above\n * {@link DropDatabaseOptions.logLevel} are sent to each of these {@link LogSink}s.\n * If you would still like logs to go to the console, include\n * `consoleLogSink` in the array.\n *\n * ```ts\n * logSinks: [consoleLogSink, myCloudLogSink],\n * ```\n * Default is `[consoleLogSink]`.\n */\n logSinks?: LogSink[] | undefined;\n};\n\n/**\n * Drops the specified database, from memory as well as from the configured\n * store (see `onStorageFailure`). Rejects if the configured store cannot be\n * opened or dropped.\n * @param dbName The name of the database to drop.\n * @param opts Options for dropping the database.\n */\nexport async function dropDatabase(dbName: string, opts?: DropDatabaseOptions) {\n const logContext = createLogContext(opts?.logLevel, opts?.logSinks, {\n dropDatabase: undefined,\n });\n for (const {provider, drops} of dropTargets(logContext, opts)) {\n if (!drops(dbName)) {\n continue;\n }\n const store = new IDBDatabasesStore(provider.create);\n try {\n await dropDatabaseInternal(dbName, store, provider.drop);\n } finally {\n await closeIgnoringErrors(store);\n }\n }\n}\n\n/**\n * Deletes all IndexedDB data associated with Replicache, and the in-memory\n * databases instances ran on after a storage failure (see\n * `onStorageFailure`).\n *\n * Returns an object with the names of the successfully dropped databases\n * and any errors encountered while dropping. Rejects if the configured store\n * cannot be opened.\n */\nexport function dropAllDatabases(opts?: DropDatabaseOptions): Promise<{\n dropped: string[];\n errors: unknown[];\n}> {\n return dropMatchingDatabases(() => true, opts);\n}\n\n/**\n * Like {@link dropAllDatabases}, for the databases whose registry record\n * matches `predicate`.\n */\nexport async function dropMatchingDatabases(\n predicate: (db: IndexedDBDatabase) => boolean,\n opts?: DropDatabaseOptions,\n): Promise<{\n dropped: string[];\n errors: unknown[];\n}> {\n const logContext = createLogContext(opts?.logLevel, opts?.logSinks, {\n dropDatabases: undefined,\n });\n const dropped = new Set<string>();\n const errors: unknown[] = [];\n for (const {provider, drops} of dropTargets(logContext, opts)) {\n const store = new IDBDatabasesStore(provider.create);\n try {\n const databases = await store.getDatabases();\n const dbNames = Object.values(databases)\n .filter(db => predicate(db) && drops(db.name))\n .map(db => db.name);\n const result = await dropDatabases(store, dbNames, provider.drop);\n result.dropped.forEach(name => dropped.add(name));\n errors.push(...result.errors);\n } finally {\n await closeIgnoringErrors(store);\n }\n }\n return {dropped: [...dropped], errors};\n}\n\ntype DropTarget = {\n provider: StoreProvider;\n /** Whether a database of this name is dropped from `provider`. */\n drops: (name: string) => boolean;\n};\n\n/**\n * The memory stores instances fell back to first, then the configured store.\n * An instance whose store failed to open runs on memory stores of the same\n * names (see `onStorageFailure`), and memory stores outlive the instance for\n * the life of the process, so a drop clears them whatever the configured\n * store is. Only those: the memory stores of `kvStore: 'mem'` instances are\n * left alone unless `'mem'` is the store being dropped from. The configured\n * store is still dropped, and its failure is reported: it may hold data on\n * disk.\n */\nfunction dropTargets(\n lc: LogContext,\n opts: DropDatabaseOptions | undefined,\n): DropTarget[] {\n const all = () => true;\n if (opts?.kvStore === 'mem') {\n return [{provider: getKVStoreProvider(lc, 'mem'), drops: all}];\n }\n const targets: DropTarget[] = [];\n if (isFallbackStore(getIDBDatabasesDBName())) {\n targets.push({provider: fallbackStoreProvider, drops: isFallbackStore});\n }\n targets.push({provider: getKVStoreProvider(lc, opts?.kvStore), drops: all});\n return targets;\n}\n\n/**\n * A store that failed to open may also fail to close; the drop's own result\n * is what the caller needs.\n */\nfunction closeIgnoringErrors(store: IDBDatabasesStore): Promise<void> {\n return store.close().catch(() => undefined);\n}\n\n/**\n * Deletes all IndexedDB data associated with Replicache.\n *\n * Returns an object with the names of the successfully dropped databases\n * and any errors encountered while dropping.\n *\n * @deprecated Use `dropAllDatabases` instead.\n */\nexport function deleteAllReplicacheData(opts?: DropDatabaseOptions) {\n return dropAllDatabases(opts);\n}\n\n/**\n * If there are pending mutations in any of the clients in this db we return\n * `[false]`. If any client has a recent heartbeat we also return `[false]`.\n * Otherwise we return `[true, deletedClients]`.\n */\nfunction canDatabaseBeCollectedAndGetDeletedClientIDs(\n enableMutationRecovery: boolean,\n perdag: Store,\n now: number,\n maxAge: number,\n): Promise<\n [canCollect: false] | [canCollect: true, deletedClients: DeletedClients]\n> {\n return withRead(perdag, async read => {\n // If mutation recovery is disabled we do not care if there are pending\n // mutations when we decide if we can collect the database.\n if (enableMutationRecovery) {\n const clientGroups = await getClientGroups(read);\n for (const clientGroup of clientGroups.values()) {\n if (clientGroupHasPendingMutations(clientGroup)) {\n return [false];\n }\n }\n }\n\n const clients = await getClients(read);\n\n // Don't collect if any client has a recent heartbeat (is still active).\n // This is defense in depth - normally lastOpenedTimestampMS is kept fresh\n // by the heartbeat, but this check protects against edge cases.\n for (const [, client] of clients) {\n if (now - client.heartbeatTimestampMs < maxAge) {\n return [false];\n }\n }\n\n const existingDeletedClients = await getDeletedClients(read);\n const deletedClients: WritableDeletedClients = [...existingDeletedClients];\n\n // Add all current clients to the deleted clients list\n for (const [clientID, client] of clients) {\n deletedClients.push({\n clientID,\n clientGroupID: client.clientGroupID,\n });\n }\n\n // The normalization (deduping and sorting) will be done when storing\n return [true, deletedClients];\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { LogContext } from '@rocicorp/logger';
|
|
2
2
|
import type { Store } from '../dag/store.ts';
|
|
3
|
+
import type { StorageFailureError } from '../storage-failure.ts';
|
|
3
4
|
import type { ClientID } from '../sync/ids.ts';
|
|
4
5
|
import { type ClientMap } from './clients.ts';
|
|
5
6
|
export declare const HEARTBEAT_INTERVAL: number;
|
|
6
7
|
export declare let latestHeartbeatUpdate: Promise<ClientMap> | undefined;
|
|
7
|
-
export declare function startHeartbeats(clientID: ClientID, dagStore: Store, onClientStateNotFound: () => void, heartbeatIntervalMs: number, lc: LogContext, signal: AbortSignal): void;
|
|
8
|
+
export declare function startHeartbeats(clientID: ClientID, dagStore: Store, onClientStateNotFound: () => void, heartbeatIntervalMs: number, lc: LogContext, signal: AbortSignal, onStorageFailure?: ((failure: StorageFailureError) => void) | undefined): void;
|
|
8
9
|
export declare function writeHeartbeat(clientID: ClientID, dagStore: Store): Promise<ClientMap>;
|
|
9
10
|
//# sourceMappingURL=heartbeat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/persist/heartbeat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAE5C,eAAO,IAAI,qBAAqB,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;AAEjE,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,KAAK,EACf,qBAAqB,EAAE,MAAM,IAAI,EACjC,mBAAmB,EAAE,MAAM,EAC3B,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"heartbeat.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/persist/heartbeat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,KAAK,EAAC,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAC,mBAAmB,EAAC,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EACL,KAAK,SAAS,EAIf,MAAM,cAAc,CAAC;AAEtB,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAE5C,eAAO,IAAI,qBAAqB,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;AAEjE,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,KAAK,EACf,qBAAqB,EAAE,MAAM,IAAI,EACjC,mBAAmB,EAAE,MAAM,EAC3B,EAAE,EAAE,UAAU,EACd,MAAM,EAAE,WAAW,EACnB,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC,GAAG,SAAS,GACtE,IAAI,CAoBN;AAED,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,KAAK,GACd,OAAO,CAAC,SAAS,CAAC,CAiBpB"}
|
|
@@ -4,7 +4,7 @@ import { ClientStateNotFoundError, getClients, setClients } from "./clients.js";
|
|
|
4
4
|
//#region ../replicache/src/persist/heartbeat.ts
|
|
5
5
|
var HEARTBEAT_INTERVAL = 60 * 1e3;
|
|
6
6
|
var latestHeartbeatUpdate;
|
|
7
|
-
function startHeartbeats(clientID, dagStore, onClientStateNotFound, heartbeatIntervalMs, lc, signal) {
|
|
7
|
+
function startHeartbeats(clientID, dagStore, onClientStateNotFound, heartbeatIntervalMs, lc, signal, onStorageFailure) {
|
|
8
8
|
initBgIntervalProcess("Heartbeat", async () => {
|
|
9
9
|
latestHeartbeatUpdate = writeHeartbeat(clientID, dagStore);
|
|
10
10
|
try {
|
|
@@ -16,7 +16,7 @@ function startHeartbeats(clientID, dagStore, onClientStateNotFound, heartbeatInt
|
|
|
16
16
|
}
|
|
17
17
|
throw e;
|
|
18
18
|
}
|
|
19
|
-
}, () => heartbeatIntervalMs, lc, signal);
|
|
19
|
+
}, () => heartbeatIntervalMs, lc, signal, onStorageFailure);
|
|
20
20
|
}
|
|
21
21
|
function writeHeartbeat(clientID, dagStore) {
|
|
22
22
|
return withWrite(dagStore, async (dagWrite) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"heartbeat.js","names":[],"sources":["../../../../../replicache/src/persist/heartbeat.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {initBgIntervalProcess} from '../bg-interval.ts';\nimport type {Store} from '../dag/store.ts';\nimport type {ClientID} from '../sync/ids.ts';\nimport {withWrite} from '../with-transactions.ts';\nimport {\n type ClientMap,\n ClientStateNotFoundError,\n getClients,\n setClients,\n} from './clients.ts';\n\nexport const HEARTBEAT_INTERVAL = 60 * 1000;\n\nexport let latestHeartbeatUpdate: Promise<ClientMap> | undefined;\n\nexport function startHeartbeats(\n clientID: ClientID,\n dagStore: Store,\n onClientStateNotFound: () => void,\n heartbeatIntervalMs: number,\n lc: LogContext,\n signal: AbortSignal,\n): void {\n initBgIntervalProcess(\n 'Heartbeat',\n async () => {\n latestHeartbeatUpdate = writeHeartbeat(clientID, dagStore);\n try {\n return await latestHeartbeatUpdate;\n } catch (e) {\n if (e instanceof ClientStateNotFoundError) {\n onClientStateNotFound();\n return;\n }\n throw e;\n }\n },\n () => heartbeatIntervalMs,\n lc,\n signal,\n );\n}\n\nexport function writeHeartbeat(\n clientID: ClientID,\n dagStore: Store,\n): Promise<ClientMap> {\n return withWrite(dagStore, async dagWrite => {\n const clients = await getClients(dagWrite);\n const client = clients.get(clientID);\n if (!client) {\n throw new ClientStateNotFoundError(clientID);\n }\n\n const newClient = {\n ...client,\n heartbeatTimestampMs: Date.now(),\n };\n const newClients = new Map(clients).set(clientID, newClient);\n\n await setClients(newClients, dagWrite);\n return newClients;\n });\n}\n"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"heartbeat.js","names":[],"sources":["../../../../../replicache/src/persist/heartbeat.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {initBgIntervalProcess} from '../bg-interval.ts';\nimport type {Store} from '../dag/store.ts';\nimport type {StorageFailureError} from '../storage-failure.ts';\nimport type {ClientID} from '../sync/ids.ts';\nimport {withWrite} from '../with-transactions.ts';\nimport {\n type ClientMap,\n ClientStateNotFoundError,\n getClients,\n setClients,\n} from './clients.ts';\n\nexport const HEARTBEAT_INTERVAL = 60 * 1000;\n\nexport let latestHeartbeatUpdate: Promise<ClientMap> | undefined;\n\nexport function startHeartbeats(\n clientID: ClientID,\n dagStore: Store,\n onClientStateNotFound: () => void,\n heartbeatIntervalMs: number,\n lc: LogContext,\n signal: AbortSignal,\n onStorageFailure?: ((failure: StorageFailureError) => void) | undefined,\n): void {\n initBgIntervalProcess(\n 'Heartbeat',\n async () => {\n latestHeartbeatUpdate = writeHeartbeat(clientID, dagStore);\n try {\n return await latestHeartbeatUpdate;\n } catch (e) {\n if (e instanceof ClientStateNotFoundError) {\n onClientStateNotFound();\n return;\n }\n throw e;\n }\n },\n () => heartbeatIntervalMs,\n lc,\n signal,\n onStorageFailure,\n );\n}\n\nexport function writeHeartbeat(\n clientID: ClientID,\n dagStore: Store,\n): Promise<ClientMap> {\n return withWrite(dagStore, async dagWrite => {\n const clients = await getClients(dagWrite);\n const client = clients.get(clientID);\n if (!client) {\n throw new ClientStateNotFoundError(clientID);\n }\n\n const newClient = {\n ...client,\n heartbeatTimestampMs: Date.now(),\n };\n const newClients = new Map(clients).set(clientID, newClient);\n\n await setClients(newClients, dagWrite);\n return newClients;\n });\n}\n"],"mappings":";;;;AAaA,IAAa,qBAAqB,KAAK;AAEvC,IAAW;AAEX,SAAgB,gBACd,UACA,UACA,uBACA,qBACA,IACA,QACA,kBACM;CACN,sBACE,aACA,YAAY;EACV,wBAAwB,eAAe,UAAU,QAAQ;EACzD,IAAI;GACF,OAAO,MAAM;EACf,SAAS,GAAG;GACV,IAAI,aAAa,0BAA0B;IACzC,sBAAsB;IACtB;GACF;GACA,MAAM;EACR;CACF,SACM,qBACN,IACA,QACA,gBACF;AACF;AAEA,SAAgB,eACd,UACA,UACoB;CACpB,OAAO,UAAU,UAAU,OAAM,aAAY;EAC3C,MAAM,UAAU,MAAM,WAAW,QAAQ;EACzC,MAAM,SAAS,QAAQ,IAAI,QAAQ;EACnC,IAAI,CAAC,QACH,MAAM,IAAI,yBAAyB,QAAQ;EAG7C,MAAM,YAAY;GAChB,GAAG;GACH,sBAAsB,KAAK,IAAI;EACjC;EACA,MAAM,aAAa,IAAI,IAAI,OAAO,EAAE,IAAI,UAAU,SAAS;EAE3D,MAAM,WAAW,YAAY,QAAQ;EACrC,OAAO;CACT,CAAC;AACH"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idb-databases-store-db-name.js","names":[],"sources":["../../../../../replicache/src/persist/idb-databases-store-db-name.ts"],"sourcesContent":["import {randomUint64} from '../../../shared/src/random-uint64.ts';\nimport {
|
|
1
|
+
{"version":3,"file":"idb-databases-store-db-name.js","names":[],"sources":["../../../../../replicache/src/persist/idb-databases-store-db-name.ts"],"sourcesContent":["import {randomUint64} from '../../../shared/src/random-uint64.ts';\nimport {dropIDBStore} from '../kv/idb-store.ts';\n\nconst IDB_DATABASES_VERSION = 0;\nconst IDB_DATABASES_DB_NAME = 'replicache-dbs-v' + IDB_DATABASES_VERSION;\n\nlet testNamespace = '';\n\n/** Namespace db name in test to isolate tests' indexeddb state. */\nexport function setupForTest(): void {\n testNamespace = randomUint64().toString(36);\n}\n\nexport function teardownForTest(): Promise<void> {\n const idbDatabasesDBName = getIDBDatabasesDBName();\n testNamespace = '';\n return dropIDBStore(idbDatabasesDBName);\n}\n\nexport function getIDBDatabasesDBName(): string {\n return testNamespace + IDB_DATABASES_DB_NAME;\n}\n"],"mappings":";;AAIA,IAAM,wBAAwB;AAE9B,IAAI,gBAAgB;AAapB,SAAgB,wBAAgC;CAC9C,OAAO,gBAAgB;AACzB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/persist/persist.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,6BAA6B,CAAC;AAGtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAO,KAAK,EAAQ,MAAM,iBAAiB,CAAC;AAexD,OAAO,KAAK,KAAK,aAAa,MAAM,2BAA2B,CAAC;AAEhE,OAAO,KAAK,EAAC,UAAU,EAAa,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAgB,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAC5D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAgB7C,KAAK,aAAa,GAAG,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,KAAK,EACb,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,OAAO,EACrB,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,EAChD,4BAA4B,sBAA0B,GACrD,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../../../../../replicache/src/persist/persist.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,IAAI,EAAC,MAAM,6BAA6B,CAAC;AAGtD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,sBAAsB,CAAC;AACpD,OAAO,KAAK,EAAO,KAAK,EAAQ,MAAM,iBAAiB,CAAC;AAexD,OAAO,KAAK,KAAK,aAAa,MAAM,2BAA2B,CAAC;AAEhE,OAAO,KAAK,EAAC,UAAU,EAAa,MAAM,0BAA0B,CAAC;AACrE,OAAO,KAAK,EAAgB,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAC5D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,aAAa,CAAC;AAgB7C,KAAK,aAAa,GAAG,IAAI,CAAC,OAAO,aAAa,CAAC,CAAC;AAEhD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,KAAK,EACb,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,MAAM,OAAO,EACrB,aAAa,EAAE,aAAa,EAC5B,WAAW,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,SAAS,EAChD,4BAA4B,sBAA0B,GACrD,OAAO,CAAC,IAAI,CAAC,CAwNf"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { assert } from "../../../shared/src/asserts.js";
|
|
2
|
+
import { getOrInsert, getOrInsertComputed } from "../../../shared/src/map.js";
|
|
2
3
|
import { DEFAULT_HEAD_NAME, assertSnapshotCommitDD31, baseSnapshotFromCommit, commitFromHash, commitFromHead, compareCookiesForSnapshots, localMutationsDD31, localMutationsGreaterThan } from "../db/commit.js";
|
|
3
4
|
import { withRead, withWrite } from "../with-transactions.js";
|
|
4
5
|
import { getClientGroup, setClientGroup } from "./client-groups.js";
|
|
5
6
|
import { assertClientV6, assertHasClientState, getClientGroupIDForClient, mustGetClient, setClient } from "./clients.js";
|
|
6
7
|
import { rebaseMutationAndPutCommit } from "../db/rebase.js";
|
|
7
|
-
import { getOrInsert, getOrInsertComputed } from "../../../shared/src/map.js";
|
|
8
8
|
import { GatherMemoryOnlyVisitor } from "./gather-mem-only-visitor.js";
|
|
9
9
|
//#region ../replicache/src/persist/persist.ts
|
|
10
10
|
/**
|
|
@@ -42,28 +42,31 @@ async function persistDD31(lc, clientID, memdag, perdag, mutators, closed, forma
|
|
|
42
42
|
];
|
|
43
43
|
});
|
|
44
44
|
if (closed()) return;
|
|
45
|
-
const [newMemdagMutations, memdagBaseSnapshot, gatheredChunks] = await withRead(memdag, async (memdagRead) => {
|
|
45
|
+
const [newMemdagMutations, memdagBaseSnapshot, gatheredChunks, zeroDataForBaseSnapshot] = await withRead(memdag, async (memdagRead) => {
|
|
46
46
|
const memdagHeadCommit = await commitFromHead(DEFAULT_HEAD_NAME, memdagRead);
|
|
47
47
|
const newMutations = await localMutationsGreaterThan(memdagHeadCommit, { [clientID]: perdagLMID || 0 }, memdagRead);
|
|
48
48
|
const memdagBaseSnapshot = await baseSnapshotFromCommit(memdagHeadCommit, memdagRead);
|
|
49
49
|
assertSnapshotCommitDD31(memdagBaseSnapshot);
|
|
50
50
|
let gatheredChunks;
|
|
51
|
+
let zeroData;
|
|
51
52
|
if (compareCookiesForSnapshots(memdagBaseSnapshot, perdagBaseSnapshot) > 0) {
|
|
52
53
|
await onGatherMemOnlyChunksForTest();
|
|
53
54
|
const memdagBaseSnapshotHash = memdagBaseSnapshot.chunk.hash;
|
|
54
55
|
const visitor = new GatherMemoryOnlyVisitor(memdagRead);
|
|
55
56
|
await visitor.visit(memdagBaseSnapshotHash);
|
|
56
57
|
gatheredChunks = visitor.gatheredChunks;
|
|
58
|
+
zeroData = getZeroData && await getZeroData(memdagBaseSnapshotHash, { openLazyRead: memdagRead });
|
|
57
59
|
}
|
|
58
60
|
return [
|
|
59
61
|
newMutations,
|
|
60
62
|
memdagBaseSnapshot,
|
|
61
|
-
gatheredChunks
|
|
63
|
+
gatheredChunks,
|
|
64
|
+
zeroData
|
|
62
65
|
];
|
|
63
66
|
});
|
|
64
67
|
if (closed()) return;
|
|
65
68
|
let memdagBaseSnapshotPersisted = false;
|
|
66
|
-
|
|
69
|
+
let zeroDataForRebase = zeroDataForBaseSnapshot;
|
|
67
70
|
await withWrite(perdag, async (perdagWrite) => {
|
|
68
71
|
const [mainClientGroup, latestPerdagMainClientGroupHeadCommit] = await getClientGroupInfo(perdagWrite, mainClientGroupID);
|
|
69
72
|
let newMainClientGroupHeadHash = latestPerdagMainClientGroupHeadCommit.chunk.hash;
|
|
@@ -85,12 +88,14 @@ async function persistDD31(lc, clientID, memdag, perdag, mutators, closed, forma
|
|
|
85
88
|
const mainClientGroupLocalMutations = await localMutationsDD31(mainClientGroup.headHash, perdagWrite);
|
|
86
89
|
lastServerAckdMutationIDs = memdagBaseSnapshot.meta.lastMutationIDs;
|
|
87
90
|
mutationIDs = { ...lastServerAckdMutationIDs };
|
|
88
|
-
|
|
91
|
+
const rebased = await rebase(mainClientGroupLocalMutations, newMainClientGroupHeadHash, perdagWrite, mutators, mutationIDs, lc, formatVersion, zeroDataForRebase);
|
|
92
|
+
newMainClientGroupHeadHash = rebased.hash;
|
|
93
|
+
zeroDataForRebase = rebased.zeroData;
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
let zeroDataForPerdagHeadCommit;
|
|
92
97
|
if (!memdagBaseSnapshotPersisted) zeroDataForPerdagHeadCommit = getZeroData && await getZeroData(newMainClientGroupHeadHash, { openLazySourceRead: perdagWrite });
|
|
93
|
-
newMainClientGroupHeadHash = await rebase(newMemdagMutations, newMainClientGroupHeadHash, perdagWrite, mutators, mutationIDs, lc, formatVersion, zeroDataForPerdagHeadCommit ??
|
|
98
|
+
newMainClientGroupHeadHash = (await rebase(newMemdagMutations, newMainClientGroupHeadHash, perdagWrite, mutators, mutationIDs, lc, formatVersion, zeroDataForPerdagHeadCommit ?? zeroDataForRebase)).hash;
|
|
94
99
|
await setClientGroup(mainClientGroupID, {
|
|
95
100
|
...mainClientGroup,
|
|
96
101
|
headHash: newMainClientGroupHeadHash,
|
|
@@ -113,10 +118,15 @@ async function rebase(mutations, basis, write, mutators, mutationIDs, lc, format
|
|
|
113
118
|
const { meta } = mutationCommit;
|
|
114
119
|
if (meta.mutationID > await getBasisMutationID(basis, meta.clientID)) {
|
|
115
120
|
mutationIDs[meta.clientID] = meta.mutationID;
|
|
116
|
-
|
|
121
|
+
const { result, zeroData: next } = await rebaseMutationAndPutCommit(mutationCommit, write, basis, mutators, lc, meta.clientID, formatVersion, zeroData);
|
|
122
|
+
basis = result.chunk.hash;
|
|
123
|
+
zeroData = next;
|
|
117
124
|
}
|
|
118
125
|
}
|
|
119
|
-
return
|
|
126
|
+
return {
|
|
127
|
+
hash: basis,
|
|
128
|
+
zeroData
|
|
129
|
+
};
|
|
120
130
|
}
|
|
121
131
|
//#endregion
|
|
122
132
|
export { persistDD31 };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persist.js","names":[],"sources":["../../../../../replicache/src/persist/persist.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {Enum} from '../../../shared/src/enum.ts';\nimport {getOrInsert, getOrInsertComputed} from '../../../shared/src/map.ts';\nimport type {Chunk} from '../dag/chunk.ts';\nimport type {LazyStore} from '../dag/lazy-store.ts';\nimport type {Read, Store, Write} from '../dag/store.ts';\nimport type {Commit} from '../db/commit.ts';\nimport {\n DEFAULT_HEAD_NAME,\n type LocalMetaDD31,\n type Meta,\n assertSnapshotCommitDD31,\n baseSnapshotFromCommit,\n commitFromHash,\n commitFromHead,\n compareCookiesForSnapshots,\n localMutationsDD31,\n localMutationsGreaterThan,\n} from '../db/commit.ts';\nimport {rebaseMutationAndPutCommit} from '../db/rebase.ts';\nimport type * as FormatVersion from '../format-version-enum.ts';\nimport type {Hash} from '../hash.ts';\nimport type {ZeroOption, ZeroTxData} from '../replicache-options.ts';\nimport type {ClientGroupID, ClientID} from '../sync/ids.ts';\nimport type {MutatorDefs} from '../types.ts';\nimport {withRead, withWrite} from '../with-transactions.ts';\nimport {\n type ClientGroup,\n getClientGroup,\n setClientGroup,\n} from './client-groups.ts';\nimport {\n assertClientV6,\n assertHasClientState,\n getClientGroupIDForClient,\n mustGetClient,\n setClient,\n} from './clients.ts';\nimport {GatherMemoryOnlyVisitor} from './gather-mem-only-visitor.ts';\n\ntype FormatVersion = Enum<typeof FormatVersion>;\n\n/**\n * Persists the client's memdag state to the client's perdag client group.\n *\n * Persists the base snapshot from memdag to the client's perdag client group,\n * but only if it’s newer than the client's perdag client group’s base snapshot.\n * The base snapshot is persisted by gathering all memory-only chunks in the dag\n * subgraph rooted at the base snapshot's commit and writing them to the perdag.\n * Once the base snapshot is persisted, rebases onto this new base snapshot all\n * local commits from the client's perdag client group that are not already\n * reflected in the base snapshot.\n *\n * Whether or not the base snapshot is persisted, rebases onto the client's\n * perdag client group all memdag local commits not already in the client's\n * perdag client group's history.\n *\n * Also updates the `lastMutationIDs` and `lastServerAckdMutationIDs` properties\n * of the client's client group's entry in the `ClientGroupMap`.\n */\nexport async function persistDD31(\n lc: LogContext,\n clientID: ClientID,\n memdag: LazyStore,\n perdag: Store,\n mutators: MutatorDefs,\n closed: () => boolean,\n formatVersion: FormatVersion,\n getZeroData: ZeroOption['getTxData'] | undefined,\n onGatherMemOnlyChunksForTest = () => Promise.resolve(),\n): Promise<void> {\n if (closed()) {\n return;\n }\n\n const [perdagLMID, perdagBaseSnapshot, mainClientGroupID] = await withRead(\n perdag,\n async perdagRead => {\n await assertHasClientState(clientID, perdagRead);\n const mainClientGroupID = await getClientGroupIDForClient(\n clientID,\n perdagRead,\n );\n assert(\n mainClientGroupID,\n `No main client group for clientID: ${clientID}`,\n );\n const [, perdagMainClientGroupHeadCommit] = await getClientGroupInfo(\n perdagRead,\n mainClientGroupID,\n );\n const perdagLMID = await perdagMainClientGroupHeadCommit.getMutationID(\n clientID,\n perdagRead,\n );\n const perdagBaseSnapshot = await baseSnapshotFromCommit(\n perdagMainClientGroupHeadCommit,\n perdagRead,\n );\n assertSnapshotCommitDD31(perdagBaseSnapshot);\n return [perdagLMID, perdagBaseSnapshot, mainClientGroupID];\n },\n );\n\n if (closed()) {\n return;\n }\n const [newMemdagMutations, memdagBaseSnapshot, gatheredChunks] =\n await withRead(memdag, async memdagRead => {\n const memdagHeadCommit = await commitFromHead(\n DEFAULT_HEAD_NAME,\n memdagRead,\n );\n const newMutations = await localMutationsGreaterThan(\n memdagHeadCommit,\n {[clientID]: perdagLMID || 0},\n memdagRead,\n );\n const memdagBaseSnapshot = await baseSnapshotFromCommit(\n memdagHeadCommit,\n memdagRead,\n );\n assertSnapshotCommitDD31(memdagBaseSnapshot);\n\n let gatheredChunks: ReadonlyMap<Hash, Chunk> | undefined;\n if (\n compareCookiesForSnapshots(memdagBaseSnapshot, perdagBaseSnapshot) > 0\n ) {\n await onGatherMemOnlyChunksForTest();\n // Might need to persist snapshot, we will have to double check\n // after gathering the snapshot chunks from memdag\n const memdagBaseSnapshotHash = memdagBaseSnapshot.chunk.hash;\n // Gather all memory only chunks from base snapshot on the memdag.\n const visitor = new GatherMemoryOnlyVisitor(memdagRead);\n await visitor.visit(memdagBaseSnapshotHash);\n gatheredChunks = visitor.gatheredChunks;\n }\n\n return [newMutations, memdagBaseSnapshot, gatheredChunks];\n });\n\n if (closed()) {\n return;\n }\n\n let memdagBaseSnapshotPersisted = false;\n const zeroDataForMemdagBaseSnapshot =\n getZeroData && (await getZeroData(memdagBaseSnapshot.chunk.hash));\n\n await withWrite(perdag, async perdagWrite => {\n const [mainClientGroup, latestPerdagMainClientGroupHeadCommit] =\n await getClientGroupInfo(perdagWrite, mainClientGroupID);\n\n // These initial values for newMainClientGroupHeadHash, mutationIDs,\n // lastServerAckdMutationIDs are correct for the case where the memdag\n // snapshot is *not* persisted. If the memdag snapshot is persisted\n // these values are overwritten appropriately.\n let newMainClientGroupHeadHash: Hash =\n latestPerdagMainClientGroupHeadCommit.chunk.hash;\n let mutationIDs: Record<ClientID, number> = {\n ...mainClientGroup.mutationIDs,\n };\n let {lastServerAckdMutationIDs} = mainClientGroup;\n\n if (gatheredChunks) {\n // check if memdag snapshot still newer than perdag snapshot\n\n const client = await mustGetClient(clientID, perdagWrite);\n assertClientV6(client);\n\n const latestPerdagBaseSnapshot = await baseSnapshotFromCommit(\n latestPerdagMainClientGroupHeadCommit,\n perdagWrite,\n );\n assertSnapshotCommitDD31(latestPerdagBaseSnapshot);\n\n // check if memdag snapshot still newer than perdag snapshot\n if (\n compareCookiesForSnapshots(\n memdagBaseSnapshot,\n latestPerdagBaseSnapshot,\n ) > 0\n ) {\n // still newer, persist memdag snapshot by writing chunks\n memdagBaseSnapshotPersisted = true;\n await Promise.all(\n Array.from(gatheredChunks.values(), c => perdagWrite.putChunk(c)),\n );\n\n await setClient(\n clientID,\n {\n ...client,\n persistHash: memdagBaseSnapshot.chunk.hash,\n },\n perdagWrite,\n );\n // Rebase local mutations from perdag main client group onto new\n // snapshot\n newMainClientGroupHeadHash = memdagBaseSnapshot.chunk.hash;\n const mainClientGroupLocalMutations = await localMutationsDD31(\n mainClientGroup.headHash,\n perdagWrite,\n );\n\n lastServerAckdMutationIDs = memdagBaseSnapshot.meta.lastMutationIDs;\n mutationIDs = {...lastServerAckdMutationIDs};\n\n newMainClientGroupHeadHash = await rebase(\n mainClientGroupLocalMutations,\n newMainClientGroupHeadHash,\n perdagWrite,\n mutators,\n mutationIDs,\n lc,\n formatVersion,\n zeroDataForMemdagBaseSnapshot,\n );\n }\n }\n\n let zeroDataForPerdagHeadCommit: ZeroTxData | undefined;\n if (!memdagBaseSnapshotPersisted) {\n zeroDataForPerdagHeadCommit =\n getZeroData &&\n (await getZeroData(newMainClientGroupHeadHash, {\n openLazySourceRead: perdagWrite,\n }));\n }\n\n // rebase new memdag mutations onto perdag\n newMainClientGroupHeadHash = await rebase(\n newMemdagMutations,\n newMainClientGroupHeadHash,\n perdagWrite,\n mutators,\n mutationIDs,\n lc,\n formatVersion,\n zeroDataForPerdagHeadCommit ?? zeroDataForMemdagBaseSnapshot,\n );\n\n const newMainClientGroup = {\n ...mainClientGroup,\n headHash: newMainClientGroupHeadHash,\n mutationIDs,\n lastServerAckdMutationIDs,\n };\n\n await setClientGroup(mainClientGroupID, newMainClientGroup, perdagWrite);\n });\n\n if (gatheredChunks && memdagBaseSnapshotPersisted) {\n await withWrite(memdag, memdagWrite =>\n memdagWrite.chunksPersisted([...gatheredChunks.keys()]),\n );\n }\n}\n\nasync function getClientGroupInfo(\n perdagRead: Read,\n clientGroupID: ClientGroupID,\n): Promise<[ClientGroup, Commit<Meta>]> {\n const clientGroup = await getClientGroup(clientGroupID, perdagRead);\n assert(clientGroup, `No client group for clientGroupID: ${clientGroupID}`);\n return [clientGroup, await commitFromHash(clientGroup.headHash, perdagRead)];\n}\n\nasync function rebase(\n mutations: Commit<LocalMetaDD31>[],\n basis: Hash,\n write: Write,\n mutators: MutatorDefs,\n mutationIDs: Record<ClientID, number>,\n lc: LogContext,\n formatVersion: FormatVersion,\n zeroData: ZeroTxData | undefined,\n): Promise<Hash> {\n const basisMutationIDs = new Map<Hash, Map<ClientID, Promise<number>>>();\n const getBasisMutationID = (\n basisHash: Hash,\n clientID: ClientID,\n ): Promise<number> =>\n getOrInsertComputed(\n getOrInsert(basisMutationIDs, basisHash, new Map()),\n clientID,\n () =>\n commitFromHash(basisHash, write).then(commit =>\n commit.getMutationID(clientID, write),\n ),\n );\n for (let i = mutations.length - 1; i >= 0; i--) {\n const mutationCommit = mutations[i];\n const {meta} = mutationCommit;\n if (meta.mutationID > (await getBasisMutationID(basis, meta.clientID))) {\n mutationIDs[meta.clientID] = meta.mutationID;\n basis = (\n await rebaseMutationAndPutCommit(\n mutationCommit,\n write,\n basis,\n mutators,\n lc,\n meta.clientID,\n formatVersion,\n zeroData,\n )\n ).chunk.hash;\n }\n }\n return basis;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persist.js","names":[],"sources":["../../../../../replicache/src/persist/persist.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert} from '../../../shared/src/asserts.ts';\nimport type {Enum} from '../../../shared/src/enum.ts';\nimport {getOrInsert, getOrInsertComputed} from '../../../shared/src/map.ts';\nimport type {Chunk} from '../dag/chunk.ts';\nimport type {LazyStore} from '../dag/lazy-store.ts';\nimport type {Read, Store, Write} from '../dag/store.ts';\nimport type {Commit} from '../db/commit.ts';\nimport {\n DEFAULT_HEAD_NAME,\n type LocalMetaDD31,\n type Meta,\n assertSnapshotCommitDD31,\n baseSnapshotFromCommit,\n commitFromHash,\n commitFromHead,\n compareCookiesForSnapshots,\n localMutationsDD31,\n localMutationsGreaterThan,\n} from '../db/commit.ts';\nimport {rebaseMutationAndPutCommit} from '../db/rebase.ts';\nimport type * as FormatVersion from '../format-version-enum.ts';\nimport type {Hash} from '../hash.ts';\nimport type {ZeroOption, ZeroTxData} from '../replicache-options.ts';\nimport type {ClientGroupID, ClientID} from '../sync/ids.ts';\nimport type {MutatorDefs} from '../types.ts';\nimport {withRead, withWrite} from '../with-transactions.ts';\nimport {\n type ClientGroup,\n getClientGroup,\n setClientGroup,\n} from './client-groups.ts';\nimport {\n assertClientV6,\n assertHasClientState,\n getClientGroupIDForClient,\n mustGetClient,\n setClient,\n} from './clients.ts';\nimport {GatherMemoryOnlyVisitor} from './gather-mem-only-visitor.ts';\n\ntype FormatVersion = Enum<typeof FormatVersion>;\n\n/**\n * Persists the client's memdag state to the client's perdag client group.\n *\n * Persists the base snapshot from memdag to the client's perdag client group,\n * but only if it’s newer than the client's perdag client group’s base snapshot.\n * The base snapshot is persisted by gathering all memory-only chunks in the dag\n * subgraph rooted at the base snapshot's commit and writing them to the perdag.\n * Once the base snapshot is persisted, rebases onto this new base snapshot all\n * local commits from the client's perdag client group that are not already\n * reflected in the base snapshot.\n *\n * Whether or not the base snapshot is persisted, rebases onto the client's\n * perdag client group all memdag local commits not already in the client's\n * perdag client group's history.\n *\n * Also updates the `lastMutationIDs` and `lastServerAckdMutationIDs` properties\n * of the client's client group's entry in the `ClientGroupMap`.\n */\nexport async function persistDD31(\n lc: LogContext,\n clientID: ClientID,\n memdag: LazyStore,\n perdag: Store,\n mutators: MutatorDefs,\n closed: () => boolean,\n formatVersion: FormatVersion,\n getZeroData: ZeroOption['getTxData'] | undefined,\n onGatherMemOnlyChunksForTest = () => Promise.resolve(),\n): Promise<void> {\n if (closed()) {\n return;\n }\n\n const [perdagLMID, perdagBaseSnapshot, mainClientGroupID] = await withRead(\n perdag,\n async perdagRead => {\n await assertHasClientState(clientID, perdagRead);\n const mainClientGroupID = await getClientGroupIDForClient(\n clientID,\n perdagRead,\n );\n assert(\n mainClientGroupID,\n `No main client group for clientID: ${clientID}`,\n );\n const [, perdagMainClientGroupHeadCommit] = await getClientGroupInfo(\n perdagRead,\n mainClientGroupID,\n );\n const perdagLMID = await perdagMainClientGroupHeadCommit.getMutationID(\n clientID,\n perdagRead,\n );\n const perdagBaseSnapshot = await baseSnapshotFromCommit(\n perdagMainClientGroupHeadCommit,\n perdagRead,\n );\n assertSnapshotCommitDD31(perdagBaseSnapshot);\n return [perdagLMID, perdagBaseSnapshot, mainClientGroupID];\n },\n );\n\n if (closed()) {\n return;\n }\n const [\n newMemdagMutations,\n memdagBaseSnapshot,\n gatheredChunks,\n zeroDataForBaseSnapshot,\n ] = await withRead(memdag, async memdagRead => {\n const memdagHeadCommit = await commitFromHead(\n DEFAULT_HEAD_NAME,\n memdagRead,\n );\n const newMutations = await localMutationsGreaterThan(\n memdagHeadCommit,\n {[clientID]: perdagLMID || 0},\n memdagRead,\n );\n const memdagBaseSnapshot = await baseSnapshotFromCommit(\n memdagHeadCommit,\n memdagRead,\n );\n assertSnapshotCommitDD31(memdagBaseSnapshot);\n\n let gatheredChunks: ReadonlyMap<Hash, Chunk> | undefined;\n let zeroData: ZeroTxData | undefined;\n if (\n compareCookiesForSnapshots(memdagBaseSnapshot, perdagBaseSnapshot) > 0\n ) {\n await onGatherMemOnlyChunksForTest();\n // Might need to persist snapshot, we will have to double check\n // after gathering the snapshot chunks from memdag\n const memdagBaseSnapshotHash = memdagBaseSnapshot.chunk.hash;\n // Gather all memory only chunks from base snapshot on the memdag.\n const visitor = new GatherMemoryOnlyVisitor(memdagRead);\n await visitor.visit(memdagBaseSnapshotHash);\n gatheredChunks = visitor.gatheredChunks;\n\n // Fork Zero's IVM state to the base snapshot while this read is still\n // held. The fork is a diff from the IVM's current head (the memdag main\n // head) to the base snapshot, and both are memdag chunks that a\n // concurrent poke is free to collect the moment this read is released:\n // moving the main head drops the superseded local commits, and a\n // snapshot commit carries no ref to its basis. Taking the fork under\n // the same lock that fixed `memdagBaseSnapshot` is what keeps the\n // diff's endpoints alive; taken afterwards it raced every poke, and\n // lost as `ChunkNotFoundError` out of persist. It is only needed when\n // the snapshot may be persisted; otherwise the perdag rebase below\n // forks to the perdag head instead.\n zeroData =\n getZeroData &&\n (await getZeroData(memdagBaseSnapshotHash, {\n openLazyRead: memdagRead,\n }));\n }\n\n return [newMutations, memdagBaseSnapshot, gatheredChunks, zeroData];\n });\n\n if (closed()) {\n return;\n }\n\n let memdagBaseSnapshotPersisted = false;\n // Carried across both rebase batches below: each batch continues from the\n // branch the previous one ended on.\n let zeroDataForRebase = zeroDataForBaseSnapshot;\n\n await withWrite(perdag, async perdagWrite => {\n const [mainClientGroup, latestPerdagMainClientGroupHeadCommit] =\n await getClientGroupInfo(perdagWrite, mainClientGroupID);\n\n // These initial values for newMainClientGroupHeadHash, mutationIDs,\n // lastServerAckdMutationIDs are correct for the case where the memdag\n // snapshot is *not* persisted. If the memdag snapshot is persisted\n // these values are overwritten appropriately.\n let newMainClientGroupHeadHash: Hash =\n latestPerdagMainClientGroupHeadCommit.chunk.hash;\n let mutationIDs: Record<ClientID, number> = {\n ...mainClientGroup.mutationIDs,\n };\n let {lastServerAckdMutationIDs} = mainClientGroup;\n\n if (gatheredChunks) {\n // check if memdag snapshot still newer than perdag snapshot\n\n const client = await mustGetClient(clientID, perdagWrite);\n assertClientV6(client);\n\n const latestPerdagBaseSnapshot = await baseSnapshotFromCommit(\n latestPerdagMainClientGroupHeadCommit,\n perdagWrite,\n );\n assertSnapshotCommitDD31(latestPerdagBaseSnapshot);\n\n // check if memdag snapshot still newer than perdag snapshot\n if (\n compareCookiesForSnapshots(\n memdagBaseSnapshot,\n latestPerdagBaseSnapshot,\n ) > 0\n ) {\n // still newer, persist memdag snapshot by writing chunks\n memdagBaseSnapshotPersisted = true;\n await Promise.all(\n Array.from(gatheredChunks.values(), c => perdagWrite.putChunk(c)),\n );\n\n await setClient(\n clientID,\n {\n ...client,\n persistHash: memdagBaseSnapshot.chunk.hash,\n },\n perdagWrite,\n );\n // Rebase local mutations from perdag main client group onto new\n // snapshot\n newMainClientGroupHeadHash = memdagBaseSnapshot.chunk.hash;\n const mainClientGroupLocalMutations = await localMutationsDD31(\n mainClientGroup.headHash,\n perdagWrite,\n );\n\n lastServerAckdMutationIDs = memdagBaseSnapshot.meta.lastMutationIDs;\n mutationIDs = {...lastServerAckdMutationIDs};\n\n const rebased = await rebase(\n mainClientGroupLocalMutations,\n newMainClientGroupHeadHash,\n perdagWrite,\n mutators,\n mutationIDs,\n lc,\n formatVersion,\n zeroDataForRebase,\n );\n newMainClientGroupHeadHash = rebased.hash;\n // The mutations rebased below run after these, so they have to see\n // what these wrote.\n zeroDataForRebase = rebased.zeroData;\n }\n }\n\n let zeroDataForPerdagHeadCommit: ZeroTxData | undefined;\n if (!memdagBaseSnapshotPersisted) {\n zeroDataForPerdagHeadCommit =\n getZeroData &&\n (await getZeroData(newMainClientGroupHeadHash, {\n openLazySourceRead: perdagWrite,\n }));\n }\n\n // rebase new memdag mutations onto perdag\n newMainClientGroupHeadHash = (\n await rebase(\n newMemdagMutations,\n newMainClientGroupHeadHash,\n perdagWrite,\n mutators,\n mutationIDs,\n lc,\n formatVersion,\n zeroDataForPerdagHeadCommit ?? zeroDataForRebase,\n )\n ).hash;\n\n const newMainClientGroup = {\n ...mainClientGroup,\n headHash: newMainClientGroupHeadHash,\n mutationIDs,\n lastServerAckdMutationIDs,\n };\n\n await setClientGroup(mainClientGroupID, newMainClientGroup, perdagWrite);\n });\n\n if (gatheredChunks && memdagBaseSnapshotPersisted) {\n await withWrite(memdag, memdagWrite =>\n memdagWrite.chunksPersisted([...gatheredChunks.keys()]),\n );\n }\n}\n\nasync function getClientGroupInfo(\n perdagRead: Read,\n clientGroupID: ClientGroupID,\n): Promise<[ClientGroup, Commit<Meta>]> {\n const clientGroup = await getClientGroup(clientGroupID, perdagRead);\n assert(clientGroup, `No client group for clientGroupID: ${clientGroupID}`);\n return [clientGroup, await commitFromHash(clientGroup.headHash, perdagRead)];\n}\n\ntype RebasedBatch = {\n hash: Hash;\n zeroData: ZeroTxData | undefined;\n};\n\nasync function rebase(\n mutations: Commit<LocalMetaDD31>[],\n basis: Hash,\n write: Write,\n mutators: MutatorDefs,\n mutationIDs: Record<ClientID, number>,\n lc: LogContext,\n formatVersion: FormatVersion,\n zeroData: ZeroTxData | undefined,\n): Promise<RebasedBatch> {\n const basisMutationIDs = new Map<Hash, Map<ClientID, Promise<number>>>();\n const getBasisMutationID = (\n basisHash: Hash,\n clientID: ClientID,\n ): Promise<number> =>\n getOrInsertComputed(\n getOrInsert(basisMutationIDs, basisHash, new Map()),\n clientID,\n () =>\n commitFromHash(basisHash, write).then(commit =>\n commit.getMutationID(clientID, write),\n ),\n );\n for (let i = mutations.length - 1; i >= 0; i--) {\n const mutationCommit = mutations[i];\n const {meta} = mutationCommit;\n if (meta.mutationID > (await getBasisMutationID(basis, meta.clientID))) {\n mutationIDs[meta.clientID] = meta.mutationID;\n const {result, zeroData: next} = await rebaseMutationAndPutCommit(\n mutationCommit,\n write,\n basis,\n mutators,\n lc,\n meta.clientID,\n formatVersion,\n zeroData,\n );\n basis = result.chunk.hash;\n zeroData = next;\n }\n }\n return {hash: basis, zeroData};\n}\n"],"mappings":"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"}
|
|
@@ -58,8 +58,12 @@ async function refresh(lc, memdag, perdag, clientID, mutators, diffConfig, close
|
|
|
58
58
|
await Promise.all(ps);
|
|
59
59
|
let newMemdagHeadHash = perdagClientGroupHeadHash;
|
|
60
60
|
if (newMemdagMutations.length > 0) {
|
|
61
|
-
|
|
62
|
-
for (let i = newMemdagMutations.length - 1; i >= 0; i--)
|
|
61
|
+
let zeroData = await zero?.getTxData?.(newMemdagHeadHash, { openLazyRead: memdagWrite });
|
|
62
|
+
for (let i = newMemdagMutations.length - 1; i >= 0; i--) {
|
|
63
|
+
const { result, zeroData: next } = await rebaseMutationAndPutCommit(newMemdagMutations[i], memdagWrite, newMemdagHeadHash, mutators, lc, newMemdagMutations[i].meta.clientID, formatVersion, zeroData);
|
|
64
|
+
newMemdagHeadHash = result.chunk.hash;
|
|
65
|
+
zeroData = next;
|
|
66
|
+
}
|
|
63
67
|
}
|
|
64
68
|
const diffs = await diffCommits(memdagHeadCommit, await commitFromHash(newMemdagHeadHash, memdagWrite), memdagWrite, diffConfig, formatVersion);
|
|
65
69
|
await memdagWrite.setHead(DEFAULT_HEAD_NAME, newMemdagHeadHash);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refresh.js","names":[],"sources":["../../../../../replicache/src/persist/refresh.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {Enum} from '../../../shared/src/enum.ts';\nimport type {LazyStore} from '../dag/lazy-store.ts';\nimport type {Store} from '../dag/store.ts';\nimport type {Commit} from '../db/commit.ts';\nimport {\n DEFAULT_HEAD_NAME,\n type SnapshotMetaDD31,\n assertSnapshotCommitDD31,\n baseSnapshotFromCommit,\n baseSnapshotFromHash,\n baseSnapshotFromHead,\n commitFromHash,\n commitFromHead,\n compareCookiesForSnapshots,\n localMutationsGreaterThan,\n} from '../db/commit.ts';\nimport {rebaseMutationAndPutCommit} from '../db/rebase.ts';\nimport type * as FormatVersion from '../format-version-enum.ts';\nimport type {Hash} from '../hash.ts';\nimport type {ZeroOption} from '../replicache-options.ts';\nimport type {DiffsMap} from '../sync/diff.ts';\nimport {type DiffComputationConfig, diffCommits} from '../sync/diff.ts';\nimport type {ClientID} from '../sync/ids.ts';\nimport type {MutatorDefs} from '../types.ts';\nimport {withRead, withWrite} from '../with-transactions.ts';\nimport {\n ClientStateNotFoundError,\n type ClientV6,\n assertClientV6,\n getClientGroupForClient,\n mustGetClient,\n setClient,\n} from './clients.ts';\nimport {\n type ChunkWithSize,\n GatherNotCachedVisitor,\n} from './gather-not-cached-visitor.ts';\n\ntype FormatVersion = Enum<typeof FormatVersion>;\n\nconst GATHER_SIZE_LIMIT = 5 * 2 ** 20; // 5 MB\n\ntype RefreshResult =\n | {\n type: 'aborted';\n refreshHashesForRevert?: readonly Hash[] | undefined;\n }\n | {\n type: 'complete';\n diffs: DiffsMap;\n newPerdagClientHeadHash: Hash;\n oldHead: Hash;\n newHead: Hash;\n };\n\n/**\n * This returns the diff between the state of the btree before and after\n * refresh. It returns `undefined` if the refresh was aborted.\n */\nexport async function refresh(\n lc: LogContext,\n memdag: LazyStore,\n perdag: Store,\n clientID: ClientID,\n mutators: MutatorDefs,\n diffConfig: DiffComputationConfig,\n closed: () => boolean,\n formatVersion: FormatVersion,\n zero: ZeroOption | undefined,\n): Promise<{oldHead: Hash; newHead: Hash; diffs: DiffsMap} | undefined> {\n if (closed()) {\n return;\n }\n const memdagBaseSnapshot = await withRead(memdag, memdagRead =>\n baseSnapshotFromHead(DEFAULT_HEAD_NAME, memdagRead),\n );\n assertSnapshotCommitDD31(memdagBaseSnapshot);\n\n type PerdagWriteResult = [\n perdagClientGroupHeadHash: Hash,\n perdagClientGroupBaseSnapshot: Commit<SnapshotMetaDD31>,\n perdagLmid: number,\n gatheredChunks: ReadonlyMap<Hash, ChunkWithSize>,\n refreshHashesForRevert: readonly Hash[],\n ];\n\n // Suspend eviction and deletion of chunks cached by the lazy store\n // to prevent cache misses. If eviction and deletion are not suspended\n // some chunks that are not gathered due to already being cached, may be\n // evicted or deleted by the time the write lock is acquired on the memdag,\n // which can lead to cache misses when performing the rebase and diff.\n // It is important to avoid these cache misses because they often create jank\n // because they block local mutations, pulls and queries on reading from idb.\n // Cache misses can still happen during the rebase and diff, but only\n // if the gather step hits its size limit.\n const result: RefreshResult =\n await memdag.withSuspendedSourceCacheEvictsAndDeletes(async () => {\n const perdagWriteResult: PerdagWriteResult | undefined = await withWrite(\n perdag,\n async perdagWrite => {\n const clientGroup = await getClientGroupForClient(\n clientID,\n perdagWrite,\n );\n if (!clientGroup) {\n throw new ClientStateNotFoundError(clientID);\n }\n\n const perdagClientGroupHeadHash = clientGroup.headHash;\n const perdagClientGroupHeadCommit = await commitFromHash(\n perdagClientGroupHeadHash,\n perdagWrite,\n );\n const perdagLmid = await perdagClientGroupHeadCommit.getMutationID(\n clientID,\n perdagWrite,\n );\n\n // Need to pull this head into memdag, but can't have it disappear if\n // perdag moves forward while we're rebasing in memdag. Can't change\n // client headHash until our rebase in memdag is complete, because if\n // rebase fails, then nothing is keeping client's chunks alive in\n // perdag.\n const client = await mustGetClient(clientID, perdagWrite);\n assertClientV6(client);\n const perdagClientGroupBaseSnapshot = await baseSnapshotFromHash(\n perdagClientGroupHeadHash,\n perdagWrite,\n );\n assertSnapshotCommitDD31(perdagClientGroupBaseSnapshot);\n if (\n shouldAbortRefresh(\n memdagBaseSnapshot,\n perdagClientGroupBaseSnapshot,\n perdagClientGroupHeadHash,\n )\n ) {\n return undefined;\n }\n\n // To avoid pulling the entire perdag graph into the memdag\n // the amount of chunk data gathered is limited by size.\n const visitor = new GatherNotCachedVisitor(\n perdagWrite,\n memdag,\n GATHER_SIZE_LIMIT,\n );\n await visitor.visit(perdagClientGroupHeadHash);\n const {gatheredChunks} = visitor;\n\n const refreshHashesSet = new Set(client.refreshHashes);\n refreshHashesSet.add(perdagClientGroupHeadHash);\n\n const newClient: ClientV6 = {\n ...client,\n refreshHashes: [...refreshHashesSet],\n };\n\n await setClient(clientID, newClient, perdagWrite);\n return [\n perdagClientGroupHeadHash,\n perdagClientGroupBaseSnapshot,\n perdagLmid,\n gatheredChunks,\n client.refreshHashes,\n ];\n },\n );\n\n if (closed() || !perdagWriteResult) {\n return {\n type: 'aborted',\n } as const;\n }\n\n const [\n perdagClientGroupHeadHash,\n perdagClientGroupBaseSnapshot,\n perdagLmid,\n gatheredChunks,\n refreshHashesForRevert,\n ] = perdagWriteResult;\n return withWrite(memdag, async memdagWrite => {\n const memdagHeadCommit = await commitFromHead(\n DEFAULT_HEAD_NAME,\n memdagWrite,\n );\n const memdagBaseSnapshot = await baseSnapshotFromCommit(\n memdagHeadCommit,\n memdagWrite,\n );\n assertSnapshotCommitDD31(memdagBaseSnapshot);\n if (\n shouldAbortRefresh(\n memdagBaseSnapshot,\n perdagClientGroupBaseSnapshot,\n perdagClientGroupHeadHash,\n )\n ) {\n return {\n type: 'aborted',\n refreshHashesForRevert,\n };\n }\n\n const newMemdagMutations = await localMutationsGreaterThan(\n memdagHeadCommit,\n {[clientID]: perdagLmid},\n memdagWrite,\n );\n const ps = [];\n for (const {chunk, size} of gatheredChunks.values()) {\n ps.push(memdagWrite.putChunk(chunk, size));\n }\n await Promise.all(ps);\n\n let newMemdagHeadHash = perdagClientGroupHeadHash;\n if (newMemdagMutations.length > 0) {\n const zeroData = await zero?.getTxData?.(newMemdagHeadHash, {\n openLazyRead: memdagWrite,\n });\n for (let i = newMemdagMutations.length - 1; i >= 0; i--) {\n newMemdagHeadHash = (\n await rebaseMutationAndPutCommit(\n newMemdagMutations[i],\n memdagWrite,\n newMemdagHeadHash,\n mutators,\n lc,\n newMemdagMutations[i].meta.clientID,\n formatVersion,\n zeroData,\n )\n ).chunk.hash;\n }\n }\n\n const newMemdagHeadCommit = await commitFromHash(\n newMemdagHeadHash,\n memdagWrite,\n );\n const diffs = await diffCommits(\n memdagHeadCommit,\n newMemdagHeadCommit,\n memdagWrite,\n diffConfig,\n formatVersion,\n );\n\n await memdagWrite.setHead(DEFAULT_HEAD_NAME, newMemdagHeadHash);\n return {\n type: 'complete',\n diffs,\n oldHead: memdagHeadCommit.chunk.hash,\n newHead: newMemdagHeadHash,\n newPerdagClientHeadHash: perdagClientGroupHeadHash,\n } as const;\n });\n });\n\n if (closed()) {\n return;\n }\n\n const setRefreshHashes = (refreshHashes: readonly Hash[]) =>\n withWrite(perdag, async perdagWrite => {\n const client = await mustGetClient(clientID, perdagWrite);\n const newClient = {\n ...client,\n refreshHashes,\n };\n\n // If this cleanup never happens, it's no big deal, some data will stay\n // alive longer but next refresh will fix it.\n await setClient(clientID, newClient, perdagWrite);\n });\n\n if (result.type === 'aborted') {\n if (result.refreshHashesForRevert) {\n await setRefreshHashes(result.refreshHashesForRevert);\n }\n return undefined;\n }\n\n // Advance zero here before setting refresh hashes\n // since we must advance before delegating control of the microtask\n // loop.\n zero?.advance(result.oldHead, result.newHead, result.diffs.get('') ?? []);\n await setRefreshHashes([result.newPerdagClientHeadHash]);\n return {\n oldHead: result.oldHead,\n newHead: result.newHead,\n diffs: result.diffs,\n };\n}\n\nfunction shouldAbortRefresh(\n memdagBaseSnapshot: Commit<SnapshotMetaDD31>,\n perdagClientGroupBaseSnapshot: Commit<SnapshotMetaDD31>,\n perdagClientGroupHeadHash: Hash,\n): boolean {\n const baseSnapshotCookieCompareResult = compareCookiesForSnapshots(\n memdagBaseSnapshot,\n perdagClientGroupBaseSnapshot,\n );\n return (\n baseSnapshotCookieCompareResult > 0 ||\n (baseSnapshotCookieCompareResult === 0 &&\n perdagClientGroupHeadHash === perdagClientGroupBaseSnapshot.chunk.hash)\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"refresh.js","names":[],"sources":["../../../../../replicache/src/persist/refresh.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport type {Enum} from '../../../shared/src/enum.ts';\nimport type {LazyStore} from '../dag/lazy-store.ts';\nimport type {Store} from '../dag/store.ts';\nimport type {Commit} from '../db/commit.ts';\nimport {\n DEFAULT_HEAD_NAME,\n type SnapshotMetaDD31,\n assertSnapshotCommitDD31,\n baseSnapshotFromCommit,\n baseSnapshotFromHash,\n baseSnapshotFromHead,\n commitFromHash,\n commitFromHead,\n compareCookiesForSnapshots,\n localMutationsGreaterThan,\n} from '../db/commit.ts';\nimport {rebaseMutationAndPutCommit} from '../db/rebase.ts';\nimport type * as FormatVersion from '../format-version-enum.ts';\nimport type {Hash} from '../hash.ts';\nimport type {ZeroOption} from '../replicache-options.ts';\nimport type {DiffsMap} from '../sync/diff.ts';\nimport {type DiffComputationConfig, diffCommits} from '../sync/diff.ts';\nimport type {ClientID} from '../sync/ids.ts';\nimport type {MutatorDefs} from '../types.ts';\nimport {withRead, withWrite} from '../with-transactions.ts';\nimport {\n ClientStateNotFoundError,\n type ClientV6,\n assertClientV6,\n getClientGroupForClient,\n mustGetClient,\n setClient,\n} from './clients.ts';\nimport {\n type ChunkWithSize,\n GatherNotCachedVisitor,\n} from './gather-not-cached-visitor.ts';\n\ntype FormatVersion = Enum<typeof FormatVersion>;\n\nconst GATHER_SIZE_LIMIT = 5 * 2 ** 20; // 5 MB\n\ntype RefreshResult =\n | {\n type: 'aborted';\n refreshHashesForRevert?: readonly Hash[] | undefined;\n }\n | {\n type: 'complete';\n diffs: DiffsMap;\n newPerdagClientHeadHash: Hash;\n oldHead: Hash;\n newHead: Hash;\n };\n\n/**\n * This returns the diff between the state of the btree before and after\n * refresh. It returns `undefined` if the refresh was aborted.\n */\nexport async function refresh(\n lc: LogContext,\n memdag: LazyStore,\n perdag: Store,\n clientID: ClientID,\n mutators: MutatorDefs,\n diffConfig: DiffComputationConfig,\n closed: () => boolean,\n formatVersion: FormatVersion,\n zero: ZeroOption | undefined,\n): Promise<{oldHead: Hash; newHead: Hash; diffs: DiffsMap} | undefined> {\n if (closed()) {\n return;\n }\n const memdagBaseSnapshot = await withRead(memdag, memdagRead =>\n baseSnapshotFromHead(DEFAULT_HEAD_NAME, memdagRead),\n );\n assertSnapshotCommitDD31(memdagBaseSnapshot);\n\n type PerdagWriteResult = [\n perdagClientGroupHeadHash: Hash,\n perdagClientGroupBaseSnapshot: Commit<SnapshotMetaDD31>,\n perdagLmid: number,\n gatheredChunks: ReadonlyMap<Hash, ChunkWithSize>,\n refreshHashesForRevert: readonly Hash[],\n ];\n\n // Suspend eviction and deletion of chunks cached by the lazy store\n // to prevent cache misses. If eviction and deletion are not suspended\n // some chunks that are not gathered due to already being cached, may be\n // evicted or deleted by the time the write lock is acquired on the memdag,\n // which can lead to cache misses when performing the rebase and diff.\n // It is important to avoid these cache misses because they often create jank\n // because they block local mutations, pulls and queries on reading from idb.\n // Cache misses can still happen during the rebase and diff, but only\n // if the gather step hits its size limit.\n const result: RefreshResult =\n await memdag.withSuspendedSourceCacheEvictsAndDeletes(async () => {\n const perdagWriteResult: PerdagWriteResult | undefined = await withWrite(\n perdag,\n async perdagWrite => {\n const clientGroup = await getClientGroupForClient(\n clientID,\n perdagWrite,\n );\n if (!clientGroup) {\n throw new ClientStateNotFoundError(clientID);\n }\n\n const perdagClientGroupHeadHash = clientGroup.headHash;\n const perdagClientGroupHeadCommit = await commitFromHash(\n perdagClientGroupHeadHash,\n perdagWrite,\n );\n const perdagLmid = await perdagClientGroupHeadCommit.getMutationID(\n clientID,\n perdagWrite,\n );\n\n // Need to pull this head into memdag, but can't have it disappear if\n // perdag moves forward while we're rebasing in memdag. Can't change\n // client headHash until our rebase in memdag is complete, because if\n // rebase fails, then nothing is keeping client's chunks alive in\n // perdag.\n const client = await mustGetClient(clientID, perdagWrite);\n assertClientV6(client);\n const perdagClientGroupBaseSnapshot = await baseSnapshotFromHash(\n perdagClientGroupHeadHash,\n perdagWrite,\n );\n assertSnapshotCommitDD31(perdagClientGroupBaseSnapshot);\n if (\n shouldAbortRefresh(\n memdagBaseSnapshot,\n perdagClientGroupBaseSnapshot,\n perdagClientGroupHeadHash,\n )\n ) {\n return undefined;\n }\n\n // To avoid pulling the entire perdag graph into the memdag\n // the amount of chunk data gathered is limited by size.\n const visitor = new GatherNotCachedVisitor(\n perdagWrite,\n memdag,\n GATHER_SIZE_LIMIT,\n );\n await visitor.visit(perdagClientGroupHeadHash);\n const {gatheredChunks} = visitor;\n\n const refreshHashesSet = new Set(client.refreshHashes);\n refreshHashesSet.add(perdagClientGroupHeadHash);\n\n const newClient: ClientV6 = {\n ...client,\n refreshHashes: [...refreshHashesSet],\n };\n\n await setClient(clientID, newClient, perdagWrite);\n return [\n perdagClientGroupHeadHash,\n perdagClientGroupBaseSnapshot,\n perdagLmid,\n gatheredChunks,\n client.refreshHashes,\n ];\n },\n );\n\n if (closed() || !perdagWriteResult) {\n return {\n type: 'aborted',\n } as const;\n }\n\n const [\n perdagClientGroupHeadHash,\n perdagClientGroupBaseSnapshot,\n perdagLmid,\n gatheredChunks,\n refreshHashesForRevert,\n ] = perdagWriteResult;\n return withWrite(memdag, async memdagWrite => {\n const memdagHeadCommit = await commitFromHead(\n DEFAULT_HEAD_NAME,\n memdagWrite,\n );\n const memdagBaseSnapshot = await baseSnapshotFromCommit(\n memdagHeadCommit,\n memdagWrite,\n );\n assertSnapshotCommitDD31(memdagBaseSnapshot);\n if (\n shouldAbortRefresh(\n memdagBaseSnapshot,\n perdagClientGroupBaseSnapshot,\n perdagClientGroupHeadHash,\n )\n ) {\n return {\n type: 'aborted',\n refreshHashesForRevert,\n };\n }\n\n const newMemdagMutations = await localMutationsGreaterThan(\n memdagHeadCommit,\n {[clientID]: perdagLmid},\n memdagWrite,\n );\n const ps = [];\n for (const {chunk, size} of gatheredChunks.values()) {\n ps.push(memdagWrite.putChunk(chunk, size));\n }\n await Promise.all(ps);\n\n let newMemdagHeadHash = perdagClientGroupHeadHash;\n if (newMemdagMutations.length > 0) {\n let zeroData = await zero?.getTxData?.(newMemdagHeadHash, {\n openLazyRead: memdagWrite,\n });\n for (let i = newMemdagMutations.length - 1; i >= 0; i--) {\n const {result, zeroData: next} = await rebaseMutationAndPutCommit(\n newMemdagMutations[i],\n memdagWrite,\n newMemdagHeadHash,\n mutators,\n lc,\n newMemdagMutations[i].meta.clientID,\n formatVersion,\n zeroData,\n );\n newMemdagHeadHash = result.chunk.hash;\n zeroData = next;\n }\n }\n\n const newMemdagHeadCommit = await commitFromHash(\n newMemdagHeadHash,\n memdagWrite,\n );\n const diffs = await diffCommits(\n memdagHeadCommit,\n newMemdagHeadCommit,\n memdagWrite,\n diffConfig,\n formatVersion,\n );\n\n await memdagWrite.setHead(DEFAULT_HEAD_NAME, newMemdagHeadHash);\n return {\n type: 'complete',\n diffs,\n oldHead: memdagHeadCommit.chunk.hash,\n newHead: newMemdagHeadHash,\n newPerdagClientHeadHash: perdagClientGroupHeadHash,\n } as const;\n });\n });\n\n if (closed()) {\n return;\n }\n\n const setRefreshHashes = (refreshHashes: readonly Hash[]) =>\n withWrite(perdag, async perdagWrite => {\n const client = await mustGetClient(clientID, perdagWrite);\n const newClient = {\n ...client,\n refreshHashes,\n };\n\n // If this cleanup never happens, it's no big deal, some data will stay\n // alive longer but next refresh will fix it.\n await setClient(clientID, newClient, perdagWrite);\n });\n\n if (result.type === 'aborted') {\n if (result.refreshHashesForRevert) {\n await setRefreshHashes(result.refreshHashesForRevert);\n }\n return undefined;\n }\n\n // Advance zero here before setting refresh hashes\n // since we must advance before delegating control of the microtask\n // loop.\n zero?.advance(result.oldHead, result.newHead, result.diffs.get('') ?? []);\n await setRefreshHashes([result.newPerdagClientHeadHash]);\n return {\n oldHead: result.oldHead,\n newHead: result.newHead,\n diffs: result.diffs,\n };\n}\n\nfunction shouldAbortRefresh(\n memdagBaseSnapshot: Commit<SnapshotMetaDD31>,\n perdagClientGroupBaseSnapshot: Commit<SnapshotMetaDD31>,\n perdagClientGroupHeadHash: Hash,\n): boolean {\n const baseSnapshotCookieCompareResult = compareCookiesForSnapshots(\n memdagBaseSnapshot,\n perdagClientGroupBaseSnapshot,\n );\n return (\n baseSnapshotCookieCompareResult > 0 ||\n (baseSnapshotCookieCompareResult === 0 &&\n perdagClientGroupHeadHash === perdagClientGroupBaseSnapshot.chunk.hash)\n );\n}\n"],"mappings":"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"}
|