@rocicorp/zero 1.12.0-canary.12 → 1.12.0-canary.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/replicache/src/btree/diff.d.ts.map +1 -1
- package/out/replicache/src/btree/diff.js +1 -2
- package/out/replicache/src/btree/diff.js.map +1 -1
- package/out/replicache/src/btree/read.d.ts +31 -1
- package/out/replicache/src/btree/read.d.ts.map +1 -1
- package/out/replicache/src/btree/read.js +74 -19
- package/out/replicache/src/btree/read.js.map +1 -1
- package/out/replicache/src/btree/splice.d.ts.map +1 -1
- package/out/replicache/src/btree/splice.js +2 -1
- package/out/replicache/src/btree/splice.js.map +1 -1
- package/out/replicache/src/btree/write.d.ts.map +1 -1
- package/out/replicache/src/btree/write.js +2 -1
- package/out/replicache/src/btree/write.js.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.d.ts +1 -0
- package/out/replicache/src/persist/collect-idb-databases.d.ts.map +1 -1
- package/out/replicache/src/persist/collect-idb-databases.js +13 -5
- package/out/replicache/src/persist/collect-idb-databases.js.map +1 -1
- package/out/replicache/src/scan-iterator.js +1 -1
- package/out/replicache/src/sync/request-id.js +2 -2
- package/out/replicache/src/sync/request-id.js.map +1 -1
- package/out/shared/src/bigint-json.d.ts.map +1 -1
- package/out/shared/src/bigint-json.js +1 -0
- package/out/shared/src/bigint-json.js.map +1 -1
- package/out/shared/src/btree-set.d.ts +21 -0
- package/out/shared/src/btree-set.d.ts.map +1 -1
- package/out/shared/src/btree-set.js +54 -0
- package/out/shared/src/btree-set.js.map +1 -1
- package/out/shared/src/headers.js +20 -0
- package/out/shared/src/headers.js.map +1 -0
- package/out/shared/src/natural-runs.d.ts +191 -0
- package/out/shared/src/natural-runs.d.ts.map +1 -0
- package/out/shared/src/natural-runs.js +337 -0
- package/out/shared/src/natural-runs.js.map +1 -0
- package/out/shared/src/random-uint64.d.ts.map +1 -1
- package/out/shared/src/random-uint64.js +2 -2
- package/out/shared/src/random-uint64.js.map +1 -1
- package/out/shared/src/random-values.d.ts +19 -1
- package/out/shared/src/random-values.d.ts.map +1 -1
- package/out/shared/src/random-values.js +38 -4
- package/out/shared/src/random-values.js.map +1 -1
- package/out/shared/src/tuple-map.d.ts +22 -0
- package/out/shared/src/tuple-map.d.ts.map +1 -0
- package/out/shared/src/tuple-map.js +48 -0
- package/out/shared/src/tuple-map.js.map +1 -0
- package/out/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/auth/auth.d.ts.map +1 -1
- package/out/zero-cache/src/auth/auth.js +5 -0
- package/out/zero-cache/src/auth/auth.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +21 -0
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +47 -9
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/custom-queries/transform-query.js +2 -2
- package/out/zero-cache/src/custom-queries/transform-query.js.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.d.ts.map +1 -1
- package/out/zero-cache/src/db/pg-to-lite.js +3 -2
- package/out/zero-cache/src/db/pg-to-lite.js.map +1 -1
- package/out/zero-cache/src/db/pg-type-parser.js +55 -2
- package/out/zero-cache/src/db/pg-type-parser.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +5 -2
- package/out/zero-cache/src/server/change-streamer.js.map +1 -1
- package/out/zero-cache/src/server/inspector-delegate.js +6 -29
- package/out/zero-cache/src/server/inspector-delegate.js.map +1 -1
- package/out/zero-cache/src/server/main.js +5 -0
- package/out/zero-cache/src/server/main.js.map +1 -1
- package/out/zero-cache/src/server/replicator.js +3 -2
- package/out/zero-cache/src/server/replicator.js.map +1 -1
- package/out/zero-cache/src/server/syncer.js +5 -4
- 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 +2 -1
- package/out/zero-cache/src/server/worker-dispatcher.js.map +1 -1
- package/out/zero-cache/src/services/admin-auth.d.ts +22 -0
- package/out/zero-cache/src/services/admin-auth.d.ts.map +1 -0
- package/out/zero-cache/src/services/admin-auth.js +42 -0
- package/out/zero-cache/src/services/admin-auth.js.map +1 -0
- package/out/zero-cache/src/services/auth-attempt-counter.d.ts +33 -0
- package/out/zero-cache/src/services/auth-attempt-counter.d.ts.map +1 -0
- package/out/zero-cache/src/services/auth-attempt-counter.js +61 -0
- package/out/zero-cache/src/services/auth-attempt-counter.js.map +1 -0
- package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.js +110 -13
- package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +13 -7
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js +38 -5
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/init.js +10 -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/shard.d.ts +4 -0
- 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 +10 -3
- package/out/zero-cache/src/services/change-source/pg/schema/shard.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +23 -2
- package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +2 -2
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer.js +10 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
- package/out/zero-cache/src/services/heapz.d.ts.map +1 -1
- package/out/zero-cache/src/services/heapz.js +4 -5
- package/out/zero-cache/src/services/heapz.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/error.d.ts +5 -0
- package/out/zero-cache/src/services/mutagen/error.d.ts.map +1 -1
- package/out/zero-cache/src/services/mutagen/error.js +7 -1
- package/out/zero-cache/src/services/mutagen/error.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js +1 -1
- package/out/zero-cache/src/services/mutagen/mutagen.js.map +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js +1 -1
- package/out/zero-cache/src/services/mutagen/pusher.js.map +1 -1
- package/out/zero-cache/src/services/plannerz.d.ts.map +1 -1
- package/out/zero-cache/src/services/plannerz.js +3 -7
- package/out/zero-cache/src/services/plannerz.js.map +1 -1
- package/out/zero-cache/src/services/profz.d.ts.map +1 -1
- package/out/zero-cache/src/services/profz.js +4 -13
- package/out/zero-cache/src/services/profz.js.map +1 -1
- package/out/zero-cache/src/services/replicator/change-processor.js +29 -2
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +3 -3
- package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
- package/out/zero-cache/src/services/statz.d.ts.map +1 -1
- package/out/zero-cache/src/services/statz.js +2 -7
- package/out/zero-cache/src/services/statz.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js +22 -1
- package/out/zero-cache/src/services/view-syncer/client-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js +40 -2
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr-store.js +54 -17
- package/out/zero-cache/src/services/view-syncer/cvr-store.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +11 -0
- package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/inspect-auth-limiter.js +107 -0
- package/out/zero-cache/src/services/view-syncer/inspect-auth-limiter.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js +11 -6
- package/out/zero-cache/src/services/view-syncer/inspect-handler.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +2 -1
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js +16 -14
- package/out/zero-cache/src/services/view-syncer/row-record-cache.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js +4 -1
- package/out/zero-cache/src/services/view-syncer/schema/cvr.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/schema/init.js +3 -0
- package/out/zero-cache/src/services/view-syncer/schema/init.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +89 -51
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- package/out/zero-cache/src/types/client-group-log-id.d.ts +9 -0
- package/out/zero-cache/src/types/client-group-log-id.d.ts.map +1 -0
- package/out/zero-cache/src/types/client-group-log-id.js +16 -0
- package/out/zero-cache/src/types/client-group-log-id.js.map +1 -0
- package/out/zero-cache/src/types/lite.d.ts.map +1 -1
- package/out/zero-cache/src/types/lite.js +1 -0
- package/out/zero-cache/src/types/lite.js.map +1 -1
- package/out/zero-cache/src/types/pg.d.ts +13 -2
- package/out/zero-cache/src/types/pg.d.ts.map +1 -1
- package/out/zero-cache/src/types/pg.js +2 -2
- package/out/zero-cache/src/types/pg.js.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.d.ts +25 -4
- package/out/zero-cache/src/types/poke-chunk.d.ts.map +1 -1
- package/out/zero-cache/src/types/poke-chunk.js +46 -5
- package/out/zero-cache/src/types/poke-chunk.js.map +1 -1
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js +10 -3
- package/out/zero-cache/src/workers/connection.js.map +1 -1
- package/out/zero-cache/src/workers/rehome.d.ts +10 -0
- package/out/zero-cache/src/workers/rehome.d.ts.map +1 -1
- package/out/zero-cache/src/workers/rehome.js +4 -2
- package/out/zero-cache/src/workers/rehome.js.map +1 -1
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js +3 -2
- package/out/zero-cache/src/workers/syncer-ws-message-handler.js.map +1 -1
- package/out/zero-cache/src/workers/syncer.js +15 -15
- package/out/zero-cache/src/workers/syncer.js.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.d.ts +4 -0
- package/out/zero-client/src/client/inspector/inspector.d.ts.map +1 -1
- package/out/zero-client/src/client/inspector/inspector.js +4 -0
- package/out/zero-client/src/client/inspector/inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.d.ts +10 -2
- package/out/zero-client/src/client/inspector/lazy-inspector.d.ts.map +1 -1
- package/out/zero-client/src/client/inspector/lazy-inspector.js +38 -31
- package/out/zero-client/src/client/inspector/lazy-inspector.js.map +1 -1
- package/out/zero-client/src/client/inspector/query.d.ts +2 -2
- package/out/zero-client/src/client/inspector/query.d.ts.map +1 -1
- package/out/zero-client/src/client/inspector/query.js +4 -4
- package/out/zero-client/src/client/inspector/query.js.map +1 -1
- package/out/zero-client/src/client/ivm-branch.d.ts +3 -0
- package/out/zero-client/src/client/ivm-branch.d.ts.map +1 -1
- package/out/zero-client/src/client/ivm-branch.js +10 -5
- package/out/zero-client/src/client/ivm-branch.js.map +1 -1
- package/out/zero-client/src/client/reconnect-backoff.d.ts +31 -0
- package/out/zero-client/src/client/reconnect-backoff.d.ts.map +1 -0
- package/out/zero-client/src/client/reconnect-backoff.js +44 -0
- package/out/zero-client/src/client/reconnect-backoff.js.map +1 -0
- package/out/zero-client/src/client/version.js +1 -1
- package/out/zero-client/src/client/zero.d.ts.map +1 -1
- package/out/zero-client/src/client/zero.js +7 -0
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-client/src/util/nanoid.js +2 -2
- package/out/zero-client/src/util/nanoid.js.map +1 -1
- package/out/zero-protocol/src/up.d.ts +42 -42
- package/out/zero-server/src/process-mutations.d.ts +10 -0
- package/out/zero-server/src/process-mutations.d.ts.map +1 -1
- package/out/zero-server/src/process-mutations.js +39 -6
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
- package/out/zql/src/ivm/memory-source.js +89 -6
- package/out/zql/src/ivm/memory-source.js.map +1 -1
- package/out/zql/src/planner/planner-connection.d.ts.map +1 -1
- package/out/zql/src/planner/planner-connection.js +37 -3
- package/out/zql/src/planner/planner-connection.js.map +1 -1
- package/package.json +1 -1
|
@@ -17,6 +17,7 @@ import { ZERO_VERSION_COLUMN_NAME } from "../replicator/schema/constants.js";
|
|
|
17
17
|
import { rowIDString } from "../../types/row-key.js";
|
|
18
18
|
import "../replicator/schema/replication-state.js";
|
|
19
19
|
import { ProtocolErrorWithLevel, getLogLevel, wrapWithProtocolError } from "../../types/error-with-level.js";
|
|
20
|
+
import { clientGroupLogID } from "../../types/client-group-log-id.js";
|
|
20
21
|
import { Subscription } from "../../types/subscription.js";
|
|
21
22
|
import { CustomKeyMap } from "../../../../shared/src/custom-key-map.js";
|
|
22
23
|
import { ttlClockAsNumber, ttlClockFromNumber } from "./ttl-clock.js";
|
|
@@ -30,8 +31,8 @@ import { ResetPipelinesSignal } from "./snapshotter.js";
|
|
|
30
31
|
import { AdvancementMetrics } from "./advancement-metrics.js";
|
|
31
32
|
import { ClientHandler, startPoke } from "./client-handler.js";
|
|
32
33
|
import { tracer } from "./tracer.js";
|
|
33
|
-
import { CVRStore, ClientNotFoundError } from "./cvr-store.js";
|
|
34
|
-
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, classifyQueriesForHydration, nextEvictionTime } from "./cvr.js";
|
|
34
|
+
import { CVRStore, ClientNotFoundError, PinnedUserMismatchError } from "./cvr-store.js";
|
|
35
|
+
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, CVRUpdater, classifyQueriesForHydration, nextEvictionTime } from "./cvr.js";
|
|
35
36
|
import { E2EServingLagTracker } from "./e2e-serving-lag.js";
|
|
36
37
|
import { HydrationBudget } from "./hydration-budget.js";
|
|
37
38
|
import { HydrationCircuitBreaker } from "./hydration-circuit-breaker.js";
|
|
@@ -147,8 +148,8 @@ var ViewSyncerService = class {
|
|
|
147
148
|
* updates are processed via `#syncQueryPipelineSet`.
|
|
148
149
|
*
|
|
149
150
|
* Resets to `false` if `#advancePipelines` returns a `ResetPipelinesSignal`
|
|
150
|
-
* and pipelines must be reset and rehydrated, or if
|
|
151
|
-
*
|
|
151
|
+
* and pipelines must be reset and rehydrated, or if the CVR is reloaded
|
|
152
|
+
* (see `#resetPipelinesForReloadedCVR`).
|
|
152
153
|
*/
|
|
153
154
|
#pipelinesHydrated = false;
|
|
154
155
|
#servedVersion = null;
|
|
@@ -335,7 +336,7 @@ var ViewSyncerService = class {
|
|
|
335
336
|
}, "info");
|
|
336
337
|
}
|
|
337
338
|
if (await this.#checkForShutdownConditionsInLock()) {
|
|
338
|
-
this.#lc.info?.(`closing clientGroupID=${this.id}`);
|
|
339
|
+
this.#lc.info?.(`closing clientGroupID=${clientGroupLogID(this.id)}`);
|
|
339
340
|
this.#initialized.reject(shutdownBeforeInitializationError());
|
|
340
341
|
this.#stateChanges.cancel();
|
|
341
342
|
return;
|
|
@@ -355,13 +356,20 @@ var ViewSyncerService = class {
|
|
|
355
356
|
};
|
|
356
357
|
}
|
|
357
358
|
try {
|
|
358
|
-
if (reloaded && this.#
|
|
359
|
+
if (reloaded && this.#cvr.pinnedUser !== null) try {
|
|
360
|
+
this.connContextManager.restorePinnedUser(this.#cvr.pinnedUser);
|
|
361
|
+
} catch (e) {
|
|
362
|
+
this.#stateChanges.fail(e instanceof Error ? e : new Error(String(e)));
|
|
363
|
+
throw e;
|
|
364
|
+
}
|
|
365
|
+
if (reloaded && this.#resetPipelinesForReloadedCVR(lc, this.#cvr)) {
|
|
359
366
|
const connCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
360
367
|
if (connCtx) await this.#maybeHydratePipelines(lc, this.#cvr, connCtx);
|
|
361
368
|
}
|
|
362
369
|
await fn(lc, this.#cvr);
|
|
363
370
|
} catch (e) {
|
|
364
371
|
this.#cvr = void 0;
|
|
372
|
+
if (e instanceof PinnedUserMismatchError) this.#stateChanges.fail(e);
|
|
365
373
|
throw e;
|
|
366
374
|
} finally {
|
|
367
375
|
this.#scheduleAuthMaintenance(lc);
|
|
@@ -369,26 +377,29 @@ var ViewSyncerService = class {
|
|
|
369
377
|
});
|
|
370
378
|
}
|
|
371
379
|
/**
|
|
372
|
-
* The CVR is reloaded after an error clears the cached copy.
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
380
|
+
* The CVR is reloaded after an error clears the cached copy. The pipelines
|
|
381
|
+
* may no longer correspond to it:
|
|
382
|
+
*
|
|
383
|
+
* - Another view-syncer may have taken over the client group and flushed
|
|
384
|
+
* the CVR, adding or removing queries (e.g. evicting them when its
|
|
385
|
+
* hydration budget ran out), or at a version ahead of the pipelines.
|
|
386
|
+
* - The failed operation may have changed the pipelines before the CVR
|
|
387
|
+
* flush that would have recorded the change, e.g. a hydration that failed
|
|
388
|
+
* after some of its queries were added.
|
|
378
389
|
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
390
|
+
* Rather than reconcile them, reset the pipelines and let
|
|
391
|
+
* `#maybeHydratePipelines` rehydrate them from the reloaded CVR once the
|
|
392
|
+
* replica has caught up to it, as when a view-syncer takes over a client
|
|
393
|
+
* group.
|
|
381
394
|
*
|
|
382
395
|
* Returns whether the pipelines were reset.
|
|
383
396
|
*
|
|
384
397
|
* Must be called from within the #lock.
|
|
385
398
|
*/
|
|
386
|
-
#
|
|
399
|
+
#resetPipelinesForReloadedCVR(lc, cvr) {
|
|
387
400
|
if (!this.#pipelinesHydrated) return false;
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
lc.info?.(`resetting pipelines: pipelines@${pipelineVersion} are behind reloaded cvr@${versionString(cvr.version)}`);
|
|
391
|
-
this.#pipelineResets.add(1, { reason: "behind-cvr" });
|
|
401
|
+
lc.info?.(`resetting pipelines@${this.#pipelines.currentVersion()} for reloaded cvr@${versionString(cvr.version)}`);
|
|
402
|
+
this.#pipelineResets.add(1, { reason: "cvr-reloaded" });
|
|
392
403
|
this.#pipelinesHydrated = false;
|
|
393
404
|
this.connContextManager.setSharedRetransformReady(false);
|
|
394
405
|
this.#pipelines.reset(must(cvr.clientSchema, "cvr.clientSchema missing after initialization"));
|
|
@@ -410,13 +421,13 @@ var ViewSyncerService = class {
|
|
|
410
421
|
try {
|
|
411
422
|
this.#scheduleShutdown(this.#keepaliveMs);
|
|
412
423
|
if (await this.readyState() === "draining") {
|
|
413
|
-
this.#lc.debug?.(`draining view-syncer ${this.id} before running`);
|
|
424
|
+
this.#lc.debug?.(`draining view-syncer ${clientGroupLogID(this.id)} before running`);
|
|
414
425
|
this.stop();
|
|
415
426
|
}
|
|
416
427
|
for await (const replicaState of this.#stateChanges) {
|
|
417
428
|
const { state } = replicaState;
|
|
418
429
|
if (this.#drainCoordinator.shouldDrain()) {
|
|
419
|
-
this.#lc.debug?.(`draining view-syncer ${this.id} (elective)`);
|
|
430
|
+
this.#lc.debug?.(`draining view-syncer ${clientGroupLogID(this.id)} (elective)`);
|
|
420
431
|
break;
|
|
421
432
|
}
|
|
422
433
|
assert(state === "version-ready", "state should be version-ready");
|
|
@@ -460,11 +471,11 @@ var ViewSyncerService = class {
|
|
|
460
471
|
if (this.#drainCoordinator.shouldDrain()) this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
|
|
461
472
|
await this.#cleanup();
|
|
462
473
|
} catch (e) {
|
|
463
|
-
this.#lc[getLogLevel(e)]?.(`stopping view-syncer ${this.id}: ${String(e)}`, e);
|
|
474
|
+
this.#lc[getLogLevel(e)]?.(`stopping view-syncer ${clientGroupLogID(this.id)}: ${String(e)}`, e);
|
|
464
475
|
await this.#cleanup(e);
|
|
465
476
|
} finally {
|
|
466
477
|
await this.#cvrStore.flushed(this.#lc).catch((e) => this.#lc[getLogLevel(e)]?.(e));
|
|
467
|
-
this.#lc.info?.(`view-syncer ${this.id} finished`);
|
|
478
|
+
this.#lc.info?.(`view-syncer ${clientGroupLogID(this.id)} finished`);
|
|
468
479
|
this.#stopped.resolve();
|
|
469
480
|
}
|
|
470
481
|
}
|
|
@@ -740,6 +751,7 @@ var ViewSyncerService = class {
|
|
|
740
751
|
}, "warn");
|
|
741
752
|
const validatedConnCtx = await this.#validateCurrentConnection(connCtx);
|
|
742
753
|
if (!validatedConnCtx) return;
|
|
754
|
+
newClient.markValidated();
|
|
743
755
|
await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all", validatedConnCtx.profileID ?? `cg${this.id}`, validatedConnCtx);
|
|
744
756
|
this.#initialized.resolve("initialized");
|
|
745
757
|
}, newClient)).catch((e) => newClient.fail(e));
|
|
@@ -756,11 +768,9 @@ var ViewSyncerService = class {
|
|
|
756
768
|
return;
|
|
757
769
|
}
|
|
758
770
|
lc.debug?.("Auth changed, re-validating and re-transforming queries");
|
|
759
|
-
const
|
|
760
|
-
if (!
|
|
761
|
-
|
|
762
|
-
}
|
|
763
|
-
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connCtx);
|
|
771
|
+
const validatedConnCtx = await this.#validateCurrentConnection(selector);
|
|
772
|
+
if (!validatedConnCtx) return;
|
|
773
|
+
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, validatedConnCtx);
|
|
764
774
|
});
|
|
765
775
|
}
|
|
766
776
|
async deleteClients(selector, msg) {
|
|
@@ -785,6 +795,8 @@ var ViewSyncerService = class {
|
|
|
785
795
|
*/
|
|
786
796
|
#flushUpdater(lc, updater, patchesPoked = false) {
|
|
787
797
|
return startAsyncSpan(tracer, "vs.#flushUpdater", () => this.#runPriorityOp(lc, "flushing cvr", async () => {
|
|
798
|
+
const { pinnedUser } = this.connContextManager.getGroupState();
|
|
799
|
+
if (pinnedUser !== void 0) updater.setPinnedUser(pinnedUser);
|
|
788
800
|
const now = Date.now();
|
|
789
801
|
const ttlClock = this.#getTTLClock(now);
|
|
790
802
|
const { cvr, flushed } = await updater.flush(lc, this.#lastConnectTime, now, ttlClock, patchesPoked);
|
|
@@ -863,7 +875,7 @@ var ViewSyncerService = class {
|
|
|
863
875
|
const [cmd, body] = msg;
|
|
864
876
|
if (newClient || !this.#clients.has(clientID)) this.#lastConnectTime = Date.now();
|
|
865
877
|
return startAsyncSpan(tracer, `vs.#runInLockForClient(${cmd})`, async (span) => {
|
|
866
|
-
span.setAttribute("clientGroupID", this.id);
|
|
878
|
+
span.setAttribute("clientGroupID", clientGroupLogID(this.id));
|
|
867
879
|
span.setAttribute("clientID", clientID);
|
|
868
880
|
let client;
|
|
869
881
|
let result;
|
|
@@ -885,17 +897,32 @@ var ViewSyncerService = class {
|
|
|
885
897
|
});
|
|
886
898
|
} catch (e) {
|
|
887
899
|
this.#lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd)[getLogLevel(e)]?.(`closing connection with error`, e);
|
|
888
|
-
|
|
900
|
+
const current = connCtx && this.#currentRegistration(connCtx);
|
|
901
|
+
if (current) this.connContextManager.failConnection(selector, current.revision);
|
|
889
902
|
if (client) client.fail(e);
|
|
890
903
|
else throw e;
|
|
891
904
|
}
|
|
892
905
|
return result;
|
|
893
906
|
});
|
|
894
907
|
}
|
|
908
|
+
/**
|
|
909
|
+
* The clients that pokes and catch-up are sent to. A client whose
|
|
910
|
+
* connection has not been validated yet is left out: its `initConnection`
|
|
911
|
+
* validates it and then catches it up from its baseCookie, so lock-held
|
|
912
|
+
* work for other clients that runs in the meantime must not send it data.
|
|
913
|
+
*/
|
|
895
914
|
#getClients(atVersion) {
|
|
896
|
-
const clients = [...this.#clients.values()];
|
|
915
|
+
const clients = [...this.#clients.values()].filter((c) => c.validated());
|
|
897
916
|
return atVersion ? clients.filter((c) => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0) : clients;
|
|
898
917
|
}
|
|
918
|
+
/**
|
|
919
|
+
* The client to send a targeted message (e.g. a query error) to, or
|
|
920
|
+
* `undefined` while its connection is still unvalidated; see #getClients().
|
|
921
|
+
*/
|
|
922
|
+
#getValidatedClient(clientID) {
|
|
923
|
+
const client = this.#clients.get(clientID);
|
|
924
|
+
return client?.validated() ? client : void 0;
|
|
925
|
+
}
|
|
899
926
|
#handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID, connCtx) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
|
|
900
927
|
const deletedClientIDs = [];
|
|
901
928
|
const deletedClientGroupIDs = [];
|
|
@@ -1122,12 +1149,12 @@ var ViewSyncerService = class {
|
|
|
1122
1149
|
return clientIds;
|
|
1123
1150
|
};
|
|
1124
1151
|
if ("queryIDs" in errorOrErrors) {
|
|
1125
|
-
for (const clientId of getAffectedClientIDs(errorOrErrors.queryIDs)) this.#
|
|
1152
|
+
for (const clientId of getAffectedClientIDs(errorOrErrors.queryIDs)) this.#getValidatedClient(clientId)?.sendQueryTransformFailedError(errorOrErrors);
|
|
1126
1153
|
return;
|
|
1127
1154
|
}
|
|
1128
1155
|
const appErrorGroups = /* @__PURE__ */ new Map();
|
|
1129
1156
|
for (const err of errorOrErrors) for (const clientId of getAffectedClientIDs([err.id])) getOrInsertComputed(appErrorGroups, clientId, newArray).push(err);
|
|
1130
|
-
for (const [clientId, errors] of appErrorGroups) this.#
|
|
1157
|
+
for (const [clientId, errors] of appErrorGroups) this.#getValidatedClient(clientId)?.sendQueryTransformApplicationErrors(errors);
|
|
1131
1158
|
}
|
|
1132
1159
|
#addQueryMaterializationServerMetric(queryID, elapsed) {
|
|
1133
1160
|
this.#inspectorDelegate.addMetric("query-materialization-server", elapsed, queryID);
|
|
@@ -1146,7 +1173,7 @@ var ViewSyncerService = class {
|
|
|
1146
1173
|
}
|
|
1147
1174
|
#logQueryCoverageShadowSummary(lc, hydrationPath, totalHydratedQueries, coveredHydratedQueries, firstCoveredQuery) {
|
|
1148
1175
|
if (!this.#config.enableQueryCovering || totalHydratedQueries === 0) return;
|
|
1149
|
-
let coverageLC = lc.withContext("appID", this.#shard.appID).withContext("shardNum", this.#shard.shardNum).withContext("clientGroupID", this.id).withContext("queryCoverageMode", "shadow").withContext("hydrationPath", hydrationPath).withContext("totalHydratedQueries", totalHydratedQueries).withContext("coveredHydratedQueries", coveredHydratedQueries).withContext("uncoveredHydratedQueries", totalHydratedQueries - coveredHydratedQueries);
|
|
1176
|
+
let coverageLC = lc.withContext("appID", this.#shard.appID).withContext("shardNum", this.#shard.shardNum).withContext("clientGroupID", clientGroupLogID(this.id)).withContext("queryCoverageMode", "shadow").withContext("hydrationPath", hydrationPath).withContext("totalHydratedQueries", totalHydratedQueries).withContext("coveredHydratedQueries", coveredHydratedQueries).withContext("uncoveredHydratedQueries", totalHydratedQueries - coveredHydratedQueries);
|
|
1150
1177
|
if (firstCoveredQuery) {
|
|
1151
1178
|
coverageLC = coverageLC.withContext("firstCoveredQueryHash", firstCoveredQuery.coveredQueryHash).withContext("firstCoveredTransformationHash", firstCoveredQuery.coveredTransformationHash).withContext("firstCoveringQueryHash", firstCoveredQuery.coveringQueryHash).withContext("firstCoveringTransformationHash", firstCoveredQuery.coveringTransformationHash);
|
|
1152
1179
|
if (firstCoveredQuery.coveredQueryName !== void 0) coverageLC = coverageLC.withContext("firstCoveredQueryName", firstCoveredQuery.coveredQueryName);
|
|
@@ -1168,7 +1195,7 @@ var ViewSyncerService = class {
|
|
|
1168
1195
|
}, previousQueries) {
|
|
1169
1196
|
return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
|
|
1170
1197
|
const start = performance.now();
|
|
1171
|
-
span.setAttribute("clientGroupID", this.id);
|
|
1198
|
+
span.setAttribute("clientGroupID", clientGroupLogID(this.id));
|
|
1172
1199
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (syncQueryPipelineSet)");
|
|
1173
1200
|
if (this.#ttlClock === void 0) this.#ttlClock = cvr.ttlClock;
|
|
1174
1201
|
const now = Date.now();
|
|
@@ -1338,7 +1365,7 @@ var ViewSyncerService = class {
|
|
|
1338
1365
|
if (!lc.warn) return;
|
|
1339
1366
|
const shape = queryShape(query.ast);
|
|
1340
1367
|
lc.warn("Query hydration aborted for exceeding the hydration timeout", {
|
|
1341
|
-
clientGroupID: this.id,
|
|
1368
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1342
1369
|
queryHash: query.id,
|
|
1343
1370
|
transformationHash: query.transformationHash,
|
|
1344
1371
|
...query.name !== void 0 && { queryName: query.name },
|
|
@@ -1366,7 +1393,7 @@ var ViewSyncerService = class {
|
|
|
1366
1393
|
if (suppressed === void 0) return;
|
|
1367
1394
|
lc.warn("Slow query materialization", {
|
|
1368
1395
|
zeroEvent: "query-slow-hydration",
|
|
1369
|
-
clientGroupID: this.id,
|
|
1396
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1370
1397
|
queryHash: query.id,
|
|
1371
1398
|
transformationHash: query.transformationHash,
|
|
1372
1399
|
...query.name !== void 0 && { queryName: query.name },
|
|
@@ -1385,7 +1412,7 @@ var ViewSyncerService = class {
|
|
|
1385
1412
|
#recordCircuitBreakerRejection(lc, query) {
|
|
1386
1413
|
this.#hydrationCircuitBreakerRejections.add(1);
|
|
1387
1414
|
lc.warn?.("Query rejected by its open hydration circuit breaker", {
|
|
1388
|
-
clientGroupID: this.id,
|
|
1415
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1389
1416
|
queryHash: query.id,
|
|
1390
1417
|
transformationHash: query.transformationHash,
|
|
1391
1418
|
...query.name !== void 0 && { queryName: query.name },
|
|
@@ -1427,7 +1454,7 @@ var ViewSyncerService = class {
|
|
|
1427
1454
|
};
|
|
1428
1455
|
for (const clientID of Object.keys(query.clientState)) getOrInsertComputed(errorsByClient, clientID, newArray).push(error);
|
|
1429
1456
|
}
|
|
1430
|
-
for (const [clientID, errors] of errorsByClient) this.#
|
|
1457
|
+
for (const [clientID, errors] of errorsByClient) this.#getValidatedClient(clientID)?.sendQueryTransformApplicationErrors(errors);
|
|
1431
1458
|
}
|
|
1432
1459
|
#recordHydrationBudgetExhaustion(lc, hydrationBudget, activeHydratedQueries, inactiveHydratedQueries, inactiveEvictedQueryIDs) {
|
|
1433
1460
|
const elapsedMs = hydrationBudget.exhaustedAtMs;
|
|
@@ -1438,7 +1465,7 @@ var ViewSyncerService = class {
|
|
|
1438
1465
|
this.#hydrationBudgetOvershoot.record(Math.max(0, elapsedMs - hydrationBudget.limitMs));
|
|
1439
1466
|
if (inactiveEvictedQueryIDs.length > 0) this.#queryEvictions.add(inactiveEvictedQueryIDs.length, { reason: "hydration-budget" });
|
|
1440
1467
|
lc.info?.("view-syncer hydration budget exhausted", {
|
|
1441
|
-
clientGroupID: this.id,
|
|
1468
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1442
1469
|
hydrationBudgetMs: hydrationBudget.limitMs,
|
|
1443
1470
|
hydrationElapsedMs: elapsedMs,
|
|
1444
1471
|
activeHydratedQueries,
|
|
@@ -1630,7 +1657,8 @@ var ViewSyncerService = class {
|
|
|
1630
1657
|
if (!row.refCounts) patch = {
|
|
1631
1658
|
type: "row",
|
|
1632
1659
|
op: "del",
|
|
1633
|
-
id
|
|
1660
|
+
id,
|
|
1661
|
+
catchup: true
|
|
1634
1662
|
};
|
|
1635
1663
|
else {
|
|
1636
1664
|
const { contents } = contentsAndVersion(must(this.#pipelines.getRow(table, rowKey), `Missing row in ${table} keyed by ${Object.keys(rowKey).join()}`));
|
|
@@ -1728,7 +1756,7 @@ var ViewSyncerService = class {
|
|
|
1728
1756
|
*/
|
|
1729
1757
|
#advancePipelines(lc, cvr) {
|
|
1730
1758
|
return startAsyncSpan(tracer, "vs.#advancePipelines", async (span) => {
|
|
1731
|
-
span.setAttribute("clientGroupID", this.id);
|
|
1759
|
+
span.setAttribute("clientGroupID", clientGroupLogID(this.id));
|
|
1732
1760
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (advancePipelines");
|
|
1733
1761
|
const start = performance.now();
|
|
1734
1762
|
const timer = this.#timer(lc, "batch");
|
|
@@ -1948,7 +1976,7 @@ var ViewSyncerService = class {
|
|
|
1948
1976
|
const now = this.#now();
|
|
1949
1977
|
if (log.hydrationTimeMs < REBUILD_LOG_MIN_MS || now - this.#rebuildsLoggedAt < REBUILD_LOG_INTERVAL_MS) return;
|
|
1950
1978
|
lc.info?.("Client group hydrated queries again in its batches of changes instead of pushing the changes to them", {
|
|
1951
|
-
clientGroupID: this.id,
|
|
1979
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1952
1980
|
...log
|
|
1953
1981
|
});
|
|
1954
1982
|
this.#rebuildsLoggedAt = now;
|
|
@@ -2016,7 +2044,7 @@ var ViewSyncerService = class {
|
|
|
2016
2044
|
const now = this.#now();
|
|
2017
2045
|
if (log.waitedMs < BATCH_WAIT_LOG_MIN_MS || now - log.loggedAt < BATCH_WAIT_LOG_INTERVAL_MS) return;
|
|
2018
2046
|
this.#lc.info?.("Client group is waiting between batches: its sync worker is over its share target", {
|
|
2019
|
-
clientGroupID: this.id,
|
|
2047
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
2020
2048
|
waits: log.waits,
|
|
2021
2049
|
waitedMs: log.waitedMs,
|
|
2022
2050
|
lastWaitMs: waitedMs,
|
|
@@ -2038,7 +2066,7 @@ var ViewSyncerService = class {
|
|
|
2038
2066
|
clientID,
|
|
2039
2067
|
wsID: client.wsID
|
|
2040
2068
|
});
|
|
2041
|
-
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this
|
|
2069
|
+
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, connCtx);
|
|
2042
2070
|
};
|
|
2043
2071
|
async #runBackgroundRetransform(lc) {
|
|
2044
2072
|
const attemptRetransform = async (connCtx) => {
|
|
@@ -2095,7 +2123,8 @@ var ViewSyncerService = class {
|
|
|
2095
2123
|
if (response.kind === "TransformFailed") throw new ProtocolErrorWithLevel(response, "warn");
|
|
2096
2124
|
validation = response.validation;
|
|
2097
2125
|
} else validation = { kind: "client-fallback" };
|
|
2098
|
-
this
|
|
2126
|
+
if (!this.#currentRegistration(connCtx)) return false;
|
|
2127
|
+
if (this.connContextManager.validateConnection(connCtx, connCtx.revision, validation) && this.#cvr?.pinnedUser === null) this.#cvr = await this.#flushUpdater(this.#lc, new CVRUpdater(this.#cvrStore, this.#cvr, this.#cvr.replicaVersion));
|
|
2099
2128
|
return true;
|
|
2100
2129
|
} catch (e) {
|
|
2101
2130
|
if (isProtocolError(e) && isAuthErrorBody(e.errorBody)) {
|
|
@@ -2105,13 +2134,22 @@ var ViewSyncerService = class {
|
|
|
2105
2134
|
revision: connCtx.revision,
|
|
2106
2135
|
message: e.message
|
|
2107
2136
|
});
|
|
2108
|
-
this.#failMaintenanceConnection(connCtx, e);
|
|
2137
|
+
if (this.#currentRegistration(connCtx)) this.#failMaintenanceConnection(connCtx, e);
|
|
2109
2138
|
return false;
|
|
2110
2139
|
}
|
|
2111
2140
|
throw e;
|
|
2112
2141
|
}
|
|
2113
2142
|
}
|
|
2114
2143
|
/**
|
|
2144
|
+
* The live context registered for `connCtx`'s selector, or `undefined` if
|
|
2145
|
+
* that socket is gone or has been replaced by one reusing the selector
|
|
2146
|
+
* (which starts over at revision 0, so revisions alone cannot tell).
|
|
2147
|
+
*/
|
|
2148
|
+
#currentRegistration(connCtx) {
|
|
2149
|
+
const current = this.connContextManager.getConnectionContext(connCtx);
|
|
2150
|
+
return current?.insertionOrder === connCtx.insertionOrder ? current : void 0;
|
|
2151
|
+
}
|
|
2152
|
+
/**
|
|
2115
2153
|
* Validates the connection's credential as it stands once validation ends.
|
|
2116
2154
|
* An `updateAuth` handled while a validation is in flight moves the
|
|
2117
2155
|
* connection to a newer revision, which makes a failure of the older one
|
|
@@ -2122,8 +2160,9 @@ var ViewSyncerService = class {
|
|
|
2122
2160
|
let connCtx = this.connContextManager.getConnectionContext(selector);
|
|
2123
2161
|
while (connCtx) {
|
|
2124
2162
|
const valid = await this.#validateConnection(connCtx);
|
|
2125
|
-
const current = this
|
|
2126
|
-
if (current
|
|
2163
|
+
const current = this.#currentRegistration(connCtx);
|
|
2164
|
+
if (!current) return;
|
|
2165
|
+
if (current.revision === connCtx.revision) return valid ? connCtx : void 0;
|
|
2127
2166
|
connCtx = current;
|
|
2128
2167
|
}
|
|
2129
2168
|
}
|
|
@@ -2150,10 +2189,9 @@ var ViewSyncerService = class {
|
|
|
2150
2189
|
this.#stopShutdownTimer();
|
|
2151
2190
|
this.#customQueryTransformer?.destroy();
|
|
2152
2191
|
for (const client of this.#clients.values()) if (err) client.fail(err);
|
|
2153
|
-
else client.close(`closed clientGroupID=${this.id}`);
|
|
2192
|
+
else client.close(`closed clientGroupID=${clientGroupLogID(this.id)}`);
|
|
2154
2193
|
await this.#lock.withLock(() => {});
|
|
2155
2194
|
this.#pipelines.destroy();
|
|
2156
|
-
this.#inspectorDelegate.clearAuthenticated(this.id, this);
|
|
2157
2195
|
}
|
|
2158
2196
|
/**
|
|
2159
2197
|
* Test helper: Manually mark initialization as complete.
|