@rocicorp/zero 1.11.3 → 1.11.5
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/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/headers.d.ts +12 -0
- package/out/shared/src/headers.d.ts.map +1 -0
- package/out/shared/src/headers.js +20 -0
- package/out/shared/src/headers.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 +14 -1
- package/out/shared/src/random-values.d.ts.map +1 -1
- package/out/shared/src/random-values.js +24 -4
- package/out/shared/src/random-values.js.map +1 -1
- 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.d.ts +13 -0
- package/out/zero-cache/src/db/pg-type-parser.d.ts.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.d.ts.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.d.ts +2 -25
- package/out/zero-cache/src/server/inspector-delegate.d.ts.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.d.ts.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.d.ts.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.d.ts.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.d.ts +7 -1
- 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 +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/initial-sync.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +1 -1
- package/out/zero-cache/src/services/change-source/pg/schema/ddl.d.ts +15 -8
- 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.d.ts.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.d.ts +7 -1
- 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 +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.d.ts +30 -9
- 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 +10 -3
- package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +1 -0
- package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +1 -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.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/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 +1 -2
- package/out/zero-cache/src/services/replicator/change-processor.js.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
- package/out/zero-cache/src/services/replicator/incremental-sync.js +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.d.ts +16 -0
- 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 +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.d.ts +29 -4
- package/out/zero-cache/src/services/view-syncer/connection-context-manager.d.ts.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.d.ts +10 -2
- 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 +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.d.ts +8 -0
- package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/cvr.js +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.d.ts +35 -0
- package/out/zero-cache/src/services/view-syncer/inspect-auth-limiter.d.ts.map +1 -0
- 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.d.ts +2 -2
- 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 +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.d.ts.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/schema/cvr.d.ts +9 -0
- package/out/zero-cache/src/services/view-syncer/schema/cvr.d.ts.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.d.ts.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/snapshotter.js +1 -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 +96 -44
- 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/workers/connection.d.ts +1 -0
- package/out/zero-cache/src/workers/connection.d.ts.map +1 -1
- package/out/zero-cache/src/workers/connection.js +5 -1
- package/out/zero-cache/src/workers/connection.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 +12 -3
- 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 +15 -14
- 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/version.js +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-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 +38 -5
- package/out/zero-server/src/process-mutations.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,6 +14,7 @@ import { transformAndHashQuery } from "../../auth/read-authorizer.js";
|
|
|
14
14
|
import { randInt } from "../../../../shared/src/rand.js";
|
|
15
15
|
import { LogThrottle } from "../../observability/log-throttle.js";
|
|
16
16
|
import { getOrCreateCounter, getOrCreateLatencyHistogram, getOrCreateNativeHistogram, getOrCreateUpDownCounter, getOrCreateValueHistogram } from "../../observability/metrics.js";
|
|
17
|
+
import { clientGroupLogID } from "../../types/client-group-log-id.js";
|
|
17
18
|
import { rowIDString } from "../../types/row-key.js";
|
|
18
19
|
import "../replicator/schema/replication-state.js";
|
|
19
20
|
import { planWarningMessage } from "./plan-warnings.js";
|
|
@@ -29,8 +30,8 @@ import { isAuthErrorBody } from "../../auth/auth.js";
|
|
|
29
30
|
import { AdvancementMetrics } from "./advancement-metrics.js";
|
|
30
31
|
import { ClientHandler, startPoke } from "./client-handler.js";
|
|
31
32
|
import { tracer } from "./tracer.js";
|
|
32
|
-
import { CVRStore, ClientNotFoundError } from "./cvr-store.js";
|
|
33
|
-
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, classifyQueriesForHydration, nextEvictionTime } from "./cvr.js";
|
|
33
|
+
import { CVRStore, ClientNotFoundError, PinnedUserMismatchError } from "./cvr-store.js";
|
|
34
|
+
import { CVRConfigDrivenUpdater, CVRQueryDrivenUpdater, CVRUpdater, classifyQueriesForHydration, nextEvictionTime } from "./cvr.js";
|
|
34
35
|
import { E2EServingLagTracker } from "./e2e-serving-lag.js";
|
|
35
36
|
import { HydrationBudget } from "./hydration-budget.js";
|
|
36
37
|
import { HydrationCircuitBreaker } from "./hydration-circuit-breaker.js";
|
|
@@ -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,6 +356,12 @@ var ViewSyncerService = class {
|
|
|
355
356
|
};
|
|
356
357
|
}
|
|
357
358
|
try {
|
|
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
|
+
}
|
|
358
365
|
if (reloaded && this.#resetPipelinesIfBehindCVR(lc, this.#cvr)) {
|
|
359
366
|
const connCtx = this.connContextManager.getBackgroundConnectionContext();
|
|
360
367
|
if (connCtx) await this.#maybeHydratePipelines(lc, this.#cvr, connCtx);
|
|
@@ -362,6 +369,7 @@ var ViewSyncerService = class {
|
|
|
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);
|
|
@@ -410,13 +418,13 @@ var ViewSyncerService = class {
|
|
|
410
418
|
try {
|
|
411
419
|
this.#scheduleShutdown(this.#keepaliveMs);
|
|
412
420
|
if (await this.readyState() === "draining") {
|
|
413
|
-
this.#lc.debug?.(`draining view-syncer ${this.id} before running`);
|
|
421
|
+
this.#lc.debug?.(`draining view-syncer ${clientGroupLogID(this.id)} before running`);
|
|
414
422
|
this.stop();
|
|
415
423
|
}
|
|
416
424
|
for await (const replicaState of this.#stateChanges) {
|
|
417
425
|
const { state } = replicaState;
|
|
418
426
|
if (this.#drainCoordinator.shouldDrain()) {
|
|
419
|
-
this.#lc.debug?.(`draining view-syncer ${this.id} (elective)`);
|
|
427
|
+
this.#lc.debug?.(`draining view-syncer ${clientGroupLogID(this.id)} (elective)`);
|
|
420
428
|
break;
|
|
421
429
|
}
|
|
422
430
|
assert(state === "version-ready", "state should be version-ready");
|
|
@@ -460,11 +468,11 @@ var ViewSyncerService = class {
|
|
|
460
468
|
if (this.#drainCoordinator.shouldDrain()) this.#drainCoordinator.drainNextIn(this.#totalHydrationTimeMs());
|
|
461
469
|
await this.#cleanup();
|
|
462
470
|
} catch (e) {
|
|
463
|
-
this.#lc[getLogLevel(e)]?.(`stopping view-syncer ${this.id}: ${String(e)}`, e);
|
|
471
|
+
this.#lc[getLogLevel(e)]?.(`stopping view-syncer ${clientGroupLogID(this.id)}: ${String(e)}`, e);
|
|
464
472
|
await this.#cleanup(e);
|
|
465
473
|
} finally {
|
|
466
474
|
await this.#cvrStore.flushed(this.#lc).catch((e) => this.#lc[getLogLevel(e)]?.(e));
|
|
467
|
-
this.#lc.info?.(`view-syncer ${this.id} finished`);
|
|
475
|
+
this.#lc.info?.(`view-syncer ${clientGroupLogID(this.id)} finished`);
|
|
468
476
|
this.#stopped.resolve();
|
|
469
477
|
}
|
|
470
478
|
}
|
|
@@ -632,11 +640,12 @@ var ViewSyncerService = class {
|
|
|
632
640
|
return this.#clients.size === 0;
|
|
633
641
|
}
|
|
634
642
|
#deleteClientDueToDisconnect(clientID, client) {
|
|
635
|
-
this.
|
|
643
|
+
const c = this.#clients.get(clientID);
|
|
644
|
+
if (c === client || c?.wsID !== client.wsID) this.connContextManager.closeConnection({
|
|
636
645
|
clientID,
|
|
637
646
|
wsID: client.wsID
|
|
638
647
|
});
|
|
639
|
-
if (
|
|
648
|
+
if (c === client) {
|
|
640
649
|
this.#clients.delete(clientID);
|
|
641
650
|
if (this.#clients.size === 0) {
|
|
642
651
|
if (this.#ttlClock !== void 0) this.#updateTTLClockInCVRWithoutLock(this.#lc);
|
|
@@ -725,16 +734,19 @@ var ViewSyncerService = class {
|
|
|
725
734
|
this.#ttlClockBase = now;
|
|
726
735
|
}
|
|
727
736
|
const newClient = new ClientHandler(lc, this.id, connCtx.clientID, connCtx.wsID, this.#shard, connCtx.baseCookie, downstream);
|
|
728
|
-
this.#clients.get(connCtx.clientID)
|
|
737
|
+
const replaced = this.#clients.get(connCtx.clientID);
|
|
729
738
|
this.#clients.set(connCtx.clientID, newClient);
|
|
739
|
+
replaced?.close(`replaced by wsID: ${connCtx.wsID}`);
|
|
730
740
|
startAsyncSpan(tracer, "vs.initConnection.async", () => this.#runInLockForClient(connCtx, initConnectionMessage, async (lc, clientID, msg, cvr) => {
|
|
731
741
|
if (cvr.clientSchema === null && !msg.clientSchema) throw new ProtocolErrorWithLevel({
|
|
732
742
|
kind: InvalidConnectionRequest,
|
|
733
743
|
message: "The initConnection message for a new client group must include client schema.",
|
|
734
744
|
origin: ZeroCache
|
|
735
745
|
}, "warn");
|
|
736
|
-
|
|
737
|
-
|
|
746
|
+
const validatedConnCtx = await this.#validateCurrentConnection(connCtx);
|
|
747
|
+
if (!validatedConnCtx) return;
|
|
748
|
+
newClient.markValidated();
|
|
749
|
+
await this.#handleConfigUpdate(lc, clientID, msg, cvr, "all", validatedConnCtx.profileID ?? `cg${this.id}`, validatedConnCtx);
|
|
738
750
|
this.#initialized.resolve("initialized");
|
|
739
751
|
}, newClient)).catch((e) => newClient.fail(e));
|
|
740
752
|
return downstream;
|
|
@@ -750,11 +762,9 @@ var ViewSyncerService = class {
|
|
|
750
762
|
return;
|
|
751
763
|
}
|
|
752
764
|
lc.debug?.("Auth changed, re-validating and re-transforming queries");
|
|
753
|
-
const
|
|
754
|
-
if (!
|
|
755
|
-
|
|
756
|
-
}
|
|
757
|
-
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, connCtx);
|
|
765
|
+
const validatedConnCtx = await this.#validateCurrentConnection(selector);
|
|
766
|
+
if (!validatedConnCtx) return;
|
|
767
|
+
return await this.#handleConfigUpdate(lc, clientID, {}, cvr, "all", void 0, validatedConnCtx);
|
|
758
768
|
});
|
|
759
769
|
}
|
|
760
770
|
async deleteClients(selector, msg) {
|
|
@@ -779,6 +789,8 @@ var ViewSyncerService = class {
|
|
|
779
789
|
*/
|
|
780
790
|
#flushUpdater(lc, updater, patchesPoked = false) {
|
|
781
791
|
return startAsyncSpan(tracer, "vs.#flushUpdater", () => this.#runPriorityOp(lc, "flushing cvr", async () => {
|
|
792
|
+
const { pinnedUser } = this.connContextManager.getGroupState();
|
|
793
|
+
if (pinnedUser !== void 0) updater.setPinnedUser(pinnedUser);
|
|
782
794
|
const now = Date.now();
|
|
783
795
|
const ttlClock = this.#getTTLClock(now);
|
|
784
796
|
const { cvr, flushed } = await updater.flush(lc, this.#lastConnectTime, now, ttlClock, patchesPoked);
|
|
@@ -851,7 +863,7 @@ var ViewSyncerService = class {
|
|
|
851
863
|
const [cmd, body] = msg;
|
|
852
864
|
if (newClient || !this.#clients.has(clientID)) this.#lastConnectTime = Date.now();
|
|
853
865
|
return startAsyncSpan(tracer, `vs.#runInLockForClient(${cmd})`, async (span) => {
|
|
854
|
-
span.setAttribute("clientGroupID", this.id);
|
|
866
|
+
span.setAttribute("clientGroupID", clientGroupLogID(this.id));
|
|
855
867
|
span.setAttribute("clientID", clientID);
|
|
856
868
|
let client;
|
|
857
869
|
let result;
|
|
@@ -861,31 +873,44 @@ var ViewSyncerService = class {
|
|
|
861
873
|
lc = lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd);
|
|
862
874
|
lc.debug?.("acquired lock for cvr");
|
|
863
875
|
client = this.#clients.get(clientID);
|
|
864
|
-
if (client?.wsID !== wsID) {
|
|
865
|
-
lc.debug?.("mismatched
|
|
876
|
+
if (client?.wsID !== wsID || newClient && client !== newClient) {
|
|
877
|
+
lc.debug?.("mismatched or superseded client", client?.wsID, wsID);
|
|
866
878
|
return;
|
|
867
879
|
}
|
|
868
880
|
connCtx = this.connContextManager.getConnectionContext(selector);
|
|
869
|
-
if (newClient)
|
|
870
|
-
|
|
871
|
-
checkClientAndCVRVersions(client.version(), cvr.version);
|
|
872
|
-
} else if (!this.#clients.has(clientID)) lc.warn?.(`Processing ${cmd} before initConnection was received`);
|
|
881
|
+
if (newClient) checkClientAndCVRVersions(client.version(), cvr.version);
|
|
882
|
+
else if (!this.#clients.has(clientID)) lc.warn?.(`Processing ${cmd} before initConnection was received`);
|
|
873
883
|
lc.debug?.(cmd, body);
|
|
874
884
|
result = await fn(lc, clientID, body, cvr);
|
|
875
885
|
});
|
|
876
886
|
} catch (e) {
|
|
877
887
|
this.#lc.withContext("clientID", clientID).withContext("wsID", wsID).withContext("cmd", cmd)[getLogLevel(e)]?.(`closing connection with error`, e);
|
|
878
|
-
|
|
888
|
+
const current = connCtx && this.#currentRegistration(connCtx);
|
|
889
|
+
if (current) this.connContextManager.failConnection(selector, current.revision);
|
|
879
890
|
if (client) client.fail(e);
|
|
880
891
|
else throw e;
|
|
881
892
|
}
|
|
882
893
|
return result;
|
|
883
894
|
});
|
|
884
895
|
}
|
|
896
|
+
/**
|
|
897
|
+
* The clients that pokes and catch-up are sent to. A client whose
|
|
898
|
+
* connection has not been validated yet is left out: its `initConnection`
|
|
899
|
+
* validates it and then catches it up from its baseCookie, so lock-held
|
|
900
|
+
* work for other clients that runs in the meantime must not send it data.
|
|
901
|
+
*/
|
|
885
902
|
#getClients(atVersion) {
|
|
886
|
-
const clients = [...this.#clients.values()];
|
|
903
|
+
const clients = [...this.#clients.values()].filter((c) => c.validated());
|
|
887
904
|
return atVersion ? clients.filter((c) => cmpVersions(c.version() ?? EMPTY_CVR_VERSION, atVersion) === 0) : clients;
|
|
888
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* The client to send a targeted message (e.g. a query error) to, or
|
|
908
|
+
* `undefined` while its connection is still unvalidated; see #getClients().
|
|
909
|
+
*/
|
|
910
|
+
#getValidatedClient(clientID) {
|
|
911
|
+
const client = this.#clients.get(clientID);
|
|
912
|
+
return client?.validated() ? client : void 0;
|
|
913
|
+
}
|
|
889
914
|
#handleConfigUpdate = (lc, clientID, { clientSchema, deleted, desiredQueriesPatch, activeClients }, cvr, customQueryTransformMode, profileID, connCtx) => startAsyncSpan(tracer, "vs.#handleConfigUpdate", async () => {
|
|
890
915
|
const deletedClientIDs = [];
|
|
891
916
|
const deletedClientGroupIDs = [];
|
|
@@ -1112,12 +1137,12 @@ var ViewSyncerService = class {
|
|
|
1112
1137
|
return clientIds;
|
|
1113
1138
|
};
|
|
1114
1139
|
if ("queryIDs" in errorOrErrors) {
|
|
1115
|
-
for (const clientId of getAffectedClientIDs(errorOrErrors.queryIDs)) this.#
|
|
1140
|
+
for (const clientId of getAffectedClientIDs(errorOrErrors.queryIDs)) this.#getValidatedClient(clientId)?.sendQueryTransformFailedError(errorOrErrors);
|
|
1116
1141
|
return;
|
|
1117
1142
|
}
|
|
1118
1143
|
const appErrorGroups = /* @__PURE__ */ new Map();
|
|
1119
1144
|
for (const err of errorOrErrors) for (const clientId of getAffectedClientIDs([err.id])) getOrInsertComputed(appErrorGroups, clientId, newArray).push(err);
|
|
1120
|
-
for (const [clientId, errors] of appErrorGroups) this.#
|
|
1145
|
+
for (const [clientId, errors] of appErrorGroups) this.#getValidatedClient(clientId)?.sendQueryTransformApplicationErrors(errors);
|
|
1121
1146
|
}
|
|
1122
1147
|
#addQueryMaterializationServerMetric(queryID, elapsed) {
|
|
1123
1148
|
this.#inspectorDelegate.addMetric("query-materialization-server", elapsed, queryID);
|
|
@@ -1136,7 +1161,7 @@ var ViewSyncerService = class {
|
|
|
1136
1161
|
}
|
|
1137
1162
|
#logQueryCoverageShadowSummary(lc, hydrationPath, totalHydratedQueries, coveredHydratedQueries, firstCoveredQuery) {
|
|
1138
1163
|
if (!this.#config.enableQueryCovering || totalHydratedQueries === 0) return;
|
|
1139
|
-
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);
|
|
1164
|
+
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);
|
|
1140
1165
|
if (firstCoveredQuery) {
|
|
1141
1166
|
coverageLC = coverageLC.withContext("firstCoveredQueryHash", firstCoveredQuery.coveredQueryHash).withContext("firstCoveredTransformationHash", firstCoveredQuery.coveredTransformationHash).withContext("firstCoveringQueryHash", firstCoveredQuery.coveringQueryHash).withContext("firstCoveringTransformationHash", firstCoveredQuery.coveringTransformationHash);
|
|
1142
1167
|
if (firstCoveredQuery.coveredQueryName !== void 0) coverageLC = coverageLC.withContext("firstCoveredQueryName", firstCoveredQuery.coveredQueryName);
|
|
@@ -1158,7 +1183,7 @@ var ViewSyncerService = class {
|
|
|
1158
1183
|
}, previousQueries) {
|
|
1159
1184
|
return startAsyncSpan(tracer, "vs.#syncQueryPipelineSet", async (span) => {
|
|
1160
1185
|
const start = performance.now();
|
|
1161
|
-
span.setAttribute("clientGroupID", this.id);
|
|
1186
|
+
span.setAttribute("clientGroupID", clientGroupLogID(this.id));
|
|
1162
1187
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (syncQueryPipelineSet)");
|
|
1163
1188
|
if (this.#ttlClock === void 0) this.#ttlClock = cvr.ttlClock;
|
|
1164
1189
|
const now = Date.now();
|
|
@@ -1328,7 +1353,7 @@ var ViewSyncerService = class {
|
|
|
1328
1353
|
if (!lc.warn) return;
|
|
1329
1354
|
const shape = queryShape(query.ast);
|
|
1330
1355
|
lc.warn("Query hydration aborted for exceeding the hydration timeout", {
|
|
1331
|
-
clientGroupID: this.id,
|
|
1356
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1332
1357
|
queryHash: query.id,
|
|
1333
1358
|
transformationHash: query.transformationHash,
|
|
1334
1359
|
...query.name !== void 0 && { queryName: query.name },
|
|
@@ -1356,7 +1381,7 @@ var ViewSyncerService = class {
|
|
|
1356
1381
|
if (suppressed === void 0) return;
|
|
1357
1382
|
lc.warn("Slow query materialization", {
|
|
1358
1383
|
zeroEvent: "query-slow-hydration",
|
|
1359
|
-
clientGroupID: this.id,
|
|
1384
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1360
1385
|
queryHash: query.id,
|
|
1361
1386
|
transformationHash: query.transformationHash,
|
|
1362
1387
|
...query.name !== void 0 && { queryName: query.name },
|
|
@@ -1375,7 +1400,7 @@ var ViewSyncerService = class {
|
|
|
1375
1400
|
#recordCircuitBreakerRejection(lc, query) {
|
|
1376
1401
|
this.#hydrationCircuitBreakerRejections.add(1);
|
|
1377
1402
|
lc.warn?.("Query rejected by its open hydration circuit breaker", {
|
|
1378
|
-
clientGroupID: this.id,
|
|
1403
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1379
1404
|
queryHash: query.id,
|
|
1380
1405
|
transformationHash: query.transformationHash,
|
|
1381
1406
|
...query.name !== void 0 && { queryName: query.name },
|
|
@@ -1417,7 +1442,7 @@ var ViewSyncerService = class {
|
|
|
1417
1442
|
};
|
|
1418
1443
|
for (const clientID of Object.keys(query.clientState)) getOrInsertComputed(errorsByClient, clientID, newArray).push(error);
|
|
1419
1444
|
}
|
|
1420
|
-
for (const [clientID, errors] of errorsByClient) this.#
|
|
1445
|
+
for (const [clientID, errors] of errorsByClient) this.#getValidatedClient(clientID)?.sendQueryTransformApplicationErrors(errors);
|
|
1421
1446
|
}
|
|
1422
1447
|
#recordHydrationBudgetExhaustion(lc, hydrationBudget, activeHydratedQueries, inactiveHydratedQueries, inactiveEvictedQueryIDs) {
|
|
1423
1448
|
const elapsedMs = hydrationBudget.exhaustedAtMs;
|
|
@@ -1428,7 +1453,7 @@ var ViewSyncerService = class {
|
|
|
1428
1453
|
this.#hydrationBudgetOvershoot.record(Math.max(0, elapsedMs - hydrationBudget.limitMs));
|
|
1429
1454
|
if (inactiveEvictedQueryIDs.length > 0) this.#queryEvictions.add(inactiveEvictedQueryIDs.length, { reason: "hydration-budget" });
|
|
1430
1455
|
lc.info?.("view-syncer hydration budget exhausted", {
|
|
1431
|
-
clientGroupID: this.id,
|
|
1456
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1432
1457
|
hydrationBudgetMs: hydrationBudget.limitMs,
|
|
1433
1458
|
hydrationElapsedMs: elapsedMs,
|
|
1434
1459
|
activeHydratedQueries,
|
|
@@ -1620,7 +1645,8 @@ var ViewSyncerService = class {
|
|
|
1620
1645
|
if (!row.refCounts) patch = {
|
|
1621
1646
|
type: "row",
|
|
1622
1647
|
op: "del",
|
|
1623
|
-
id
|
|
1648
|
+
id,
|
|
1649
|
+
catchup: true
|
|
1624
1650
|
};
|
|
1625
1651
|
else {
|
|
1626
1652
|
const { contents } = contentsAndVersion(must(this.#pipelines.getRow(table, rowKey), `Missing row in ${table} keyed by ${Object.keys(rowKey).join()}`));
|
|
@@ -1718,7 +1744,7 @@ var ViewSyncerService = class {
|
|
|
1718
1744
|
*/
|
|
1719
1745
|
#advancePipelines(lc, cvr) {
|
|
1720
1746
|
return startAsyncSpan(tracer, "vs.#advancePipelines", async (span) => {
|
|
1721
|
-
span.setAttribute("clientGroupID", this.id);
|
|
1747
|
+
span.setAttribute("clientGroupID", clientGroupLogID(this.id));
|
|
1722
1748
|
assert(this.#pipelines.initialized(), "pipelines must be initialized (advancePipelines");
|
|
1723
1749
|
const start = performance.now();
|
|
1724
1750
|
const timer = this.#timer(lc, "batch");
|
|
@@ -1938,7 +1964,7 @@ var ViewSyncerService = class {
|
|
|
1938
1964
|
const now = this.#now();
|
|
1939
1965
|
if (log.hydrationTimeMs < REBUILD_LOG_MIN_MS || now - this.#rebuildsLoggedAt < REBUILD_LOG_INTERVAL_MS) return;
|
|
1940
1966
|
lc.info?.("Client group hydrated queries again in its batches of changes instead of pushing the changes to them", {
|
|
1941
|
-
clientGroupID: this.id,
|
|
1967
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
1942
1968
|
...log
|
|
1943
1969
|
});
|
|
1944
1970
|
this.#rebuildsLoggedAt = now;
|
|
@@ -2006,7 +2032,7 @@ var ViewSyncerService = class {
|
|
|
2006
2032
|
const now = this.#now();
|
|
2007
2033
|
if (log.waitedMs < BATCH_WAIT_LOG_MIN_MS || now - log.loggedAt < BATCH_WAIT_LOG_INTERVAL_MS) return;
|
|
2008
2034
|
this.#lc.info?.("Client group is waiting between batches: its sync worker is over its share target", {
|
|
2009
|
-
clientGroupID: this.id,
|
|
2035
|
+
clientGroupID: clientGroupLogID(this.id),
|
|
2010
2036
|
waits: log.waits,
|
|
2011
2037
|
waitedMs: log.waitedMs,
|
|
2012
2038
|
lastWaitMs: waitedMs,
|
|
@@ -2028,7 +2054,7 @@ var ViewSyncerService = class {
|
|
|
2028
2054
|
clientID,
|
|
2029
2055
|
wsID: client.wsID
|
|
2030
2056
|
});
|
|
2031
|
-
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this
|
|
2057
|
+
return handleInspect(lc, body, cvr, client, this.#inspectorDelegate, this.id, this.#cvrStore, this.#config, connCtx);
|
|
2032
2058
|
};
|
|
2033
2059
|
async #runBackgroundRetransform(lc) {
|
|
2034
2060
|
const attemptRetransform = async (connCtx) => {
|
|
@@ -2085,7 +2111,8 @@ var ViewSyncerService = class {
|
|
|
2085
2111
|
if (response.kind === "TransformFailed") throw new ProtocolErrorWithLevel(response, "warn");
|
|
2086
2112
|
validation = response.validation;
|
|
2087
2113
|
} else validation = { kind: "client-fallback" };
|
|
2088
|
-
this
|
|
2114
|
+
if (!this.#currentRegistration(connCtx)) return false;
|
|
2115
|
+
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));
|
|
2089
2116
|
return true;
|
|
2090
2117
|
} catch (e) {
|
|
2091
2118
|
if (isProtocolError(e) && isAuthErrorBody(e.errorBody)) {
|
|
@@ -2095,12 +2122,38 @@ var ViewSyncerService = class {
|
|
|
2095
2122
|
revision: connCtx.revision,
|
|
2096
2123
|
message: e.message
|
|
2097
2124
|
});
|
|
2098
|
-
this.#failMaintenanceConnection(connCtx, e);
|
|
2125
|
+
if (this.#currentRegistration(connCtx)) this.#failMaintenanceConnection(connCtx, e);
|
|
2099
2126
|
return false;
|
|
2100
2127
|
}
|
|
2101
2128
|
throw e;
|
|
2102
2129
|
}
|
|
2103
2130
|
}
|
|
2131
|
+
/**
|
|
2132
|
+
* The live context registered for `connCtx`'s selector, or `undefined` if
|
|
2133
|
+
* that socket is gone or has been replaced by one reusing the selector
|
|
2134
|
+
* (which starts over at revision 0, so revisions alone cannot tell).
|
|
2135
|
+
*/
|
|
2136
|
+
#currentRegistration(connCtx) {
|
|
2137
|
+
const current = this.connContextManager.getConnectionContext(connCtx);
|
|
2138
|
+
return current?.insertionOrder === connCtx.insertionOrder ? current : void 0;
|
|
2139
|
+
}
|
|
2140
|
+
/**
|
|
2141
|
+
* Validates the connection's credential as it stands once validation ends.
|
|
2142
|
+
* An `updateAuth` handled while a validation is in flight moves the
|
|
2143
|
+
* connection to a newer revision, which makes a failure of the older one
|
|
2144
|
+
* stale, as is its success; the newer credential is then validated in its
|
|
2145
|
+
* place, so the `initConnection` waiting on it is not dropped.
|
|
2146
|
+
*/
|
|
2147
|
+
async #validateCurrentConnection(selector) {
|
|
2148
|
+
let connCtx = this.connContextManager.getConnectionContext(selector);
|
|
2149
|
+
while (connCtx) {
|
|
2150
|
+
const valid = await this.#validateConnection(connCtx);
|
|
2151
|
+
const current = this.#currentRegistration(connCtx);
|
|
2152
|
+
if (!current) return;
|
|
2153
|
+
if (current.revision === connCtx.revision) return valid ? connCtx : void 0;
|
|
2154
|
+
connCtx = current;
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2104
2157
|
#failMaintenanceConnection(connCtx, error) {
|
|
2105
2158
|
if (!this.connContextManager.failConnection(connCtx, connCtx.revision)) return;
|
|
2106
2159
|
const wrapped = wrapWithProtocolError(error);
|
|
@@ -2124,10 +2177,9 @@ var ViewSyncerService = class {
|
|
|
2124
2177
|
this.#stopShutdownTimer();
|
|
2125
2178
|
this.#customQueryTransformer?.destroy();
|
|
2126
2179
|
for (const client of this.#clients.values()) if (err) client.fail(err);
|
|
2127
|
-
else client.close(`closed clientGroupID=${this.id}`);
|
|
2180
|
+
else client.close(`closed clientGroupID=${clientGroupLogID(this.id)}`);
|
|
2128
2181
|
await this.#lock.withLock(() => {});
|
|
2129
2182
|
this.#pipelines.destroy();
|
|
2130
|
-
this.#inspectorDelegate.clearAuthenticated(this.id, this);
|
|
2131
2183
|
}
|
|
2132
2184
|
/**
|
|
2133
2185
|
* Test helper: Manually mark initialization as complete.
|