@rocicorp/zero 1.11.0-canary.21 → 1.11.0-canary.23
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/zero/package.js +1 -1
- package/out/zero/package.js.map +1 -1
- package/out/zero-cache/src/config/normalize.d.ts.map +1 -1
- package/out/zero-cache/src/config/normalize.js +1 -2
- package/out/zero-cache/src/config/normalize.js.map +1 -1
- package/out/zero-cache/src/config/zero-config.d.ts +0 -22
- package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
- package/out/zero-cache/src/config/zero-config.js +38 -42
- package/out/zero-cache/src/config/zero-config.js.map +1 -1
- package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
- package/out/zero-cache/src/server/change-streamer.js +90 -73
- package/out/zero-cache/src/server/change-streamer.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 +1 -1
- package/out/zero-cache/src/services/change-source/common/change-stream-multiplexer.js.map +1 -1
- package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts +24 -0
- package/out/zero-cache/src/services/change-source/common/init-cleanup.d.ts.map +1 -0
- package/out/zero-cache/src/services/change-source/common/init-cleanup.js +44 -0
- package/out/zero-cache/src/services/change-source/common/init-cleanup.js.map +1 -0
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts +49 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/common/replica-restore.js.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/custom/change-source.js +7 -3
- package/out/zero-cache/src/services/change-source/custom/change-source.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts +10 -5
- package/out/zero-cache/src/services/change-source/pg/change-source-init.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js +65 -21
- package/out/zero-cache/src/services/change-source/pg/change-source-init.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
- 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 +2 -1
- 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 +3 -1
- package/out/zero-cache/src/services/change-source/pg/initial-sync.js.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts +31 -0
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js +100 -2
- package/out/zero-cache/src/services/change-source/pg/logical-replication/stream.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts +6 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js +8 -0
- package/out/zero-cache/src/services/change-streamer/backfill-state-tracker.js.map +1 -1
- 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 +3 -16
- package/out/zero-cache/src/services/change-streamer/backup-cleanup-monitor-factory.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts +17 -0
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js +44 -1
- package/out/zero-cache/src/services/change-streamer/change-log-initializer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +7 -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 +27 -8
- package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/schema/tables.d.ts +57 -0
- 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 +103 -23
- package/out/zero-cache/src/services/change-streamer/schema/tables.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts +86 -1
- package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
- package/out/zero-cache/src/services/change-streamer/storer.js +272 -77
- package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
- package/out/zero-cache/src/services/change-streamer/upstream-acker.d.ts +7 -5
- 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 +9 -5
- package/out/zero-cache/src/services/change-streamer/upstream-acker.js.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.d.ts +3 -11
- package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
- package/out/zero-cache/src/services/litestream/commands.js +29 -23
- package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
- package/out/zero-cache/src/services/litestream/config-v5.yml +0 -7
- package/out/zero-cache/src/services/profz.d.ts.map +1 -1
- package/out/zero-cache/src/services/profz.js +19 -1
- package/out/zero-cache/src/services/profz.js.map +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js +1 -1
- package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts +26 -0
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.d.ts.map +1 -0
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.js +26 -0
- package/out/zero-cache/src/services/view-syncer/advancement-metrics.js.map +1 -0
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +10 -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 +102 -122
- package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +8 -9
- package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/snapshotter.js +15 -3
- package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
- package/out/zero-cache/src/services/view-syncer/view-syncer.js +50 -28
- package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
- 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 +2 -1
- package/out/zero-client/src/client/zero.js.map +1 -1
- package/out/zero-react/src/use-query.js +12 -3
- package/out/zero-react/src/use-query.js.map +1 -1
- package/out/zql/src/ivm/array-view.d.ts.map +1 -1
- package/out/zql/src/ivm/array-view.js +21 -12
- package/out/zql/src/ivm/array-view.js.map +1 -1
- package/out/zqlite/src/db.d.ts.map +1 -1
- package/out/zqlite/src/db.js +34 -6
- package/out/zqlite/src/db.js.map +1 -1
- package/package.json +1 -1
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts +0 -34
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.d.ts.map +0 -1
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js +0 -184
- package/out/zero-cache/src/services/change-streamer/vfs-watermark-poller.js.map +0 -1
|
@@ -2,6 +2,7 @@ import { assert, unreachable } from "../../../../shared/src/asserts.js";
|
|
|
2
2
|
import { deepEqual } from "../../../../shared/src/json.js";
|
|
3
3
|
import { getOrInsertComputed } from "../../../../shared/src/map.js";
|
|
4
4
|
import { must } from "../../../../shared/src/must.js";
|
|
5
|
+
import { assignProperty } from "../../../../shared/src/objects.js";
|
|
5
6
|
import { skipYields } from "../../../../zql/src/ivm/skip-yields.js";
|
|
6
7
|
import { throwOutput } from "../../../../zql/src/ivm/operator.js";
|
|
7
8
|
import { MeasurePushOperator } from "../../../../zql/src/query/measure-push-operator.js";
|
|
@@ -92,6 +93,8 @@ var PipelineDriver = class {
|
|
|
92
93
|
#planWarningThresholds;
|
|
93
94
|
#yieldThresholdMs;
|
|
94
95
|
#streamer = null;
|
|
96
|
+
/** The row changes of the push in progress, until #push yields them. */
|
|
97
|
+
#pushedRowChanges = null;
|
|
95
98
|
#hydrateContext = null;
|
|
96
99
|
#advanceContext = null;
|
|
97
100
|
#replicaVersion = null;
|
|
@@ -172,6 +175,7 @@ var PipelineDriver = class {
|
|
|
172
175
|
primaryKeys.clear();
|
|
173
176
|
for (const [table, spec] of this.#tableSpecs.entries()) primaryKeys.set(table, spec.tableSpec.primaryKey);
|
|
174
177
|
buildPrimaryKeys(clientSchema, primaryKeys);
|
|
178
|
+
this.#streamer ??= new Streamer(primaryKeys, this.#tableSpecs);
|
|
175
179
|
const { replicaVersion } = getSubscriptionState(db);
|
|
176
180
|
this.#replicaVersion = replicaVersion;
|
|
177
181
|
}
|
|
@@ -446,7 +450,7 @@ var PipelineDriver = class {
|
|
|
446
450
|
}, planWarnings);
|
|
447
451
|
const schema = input.getSchema();
|
|
448
452
|
input.setOutput({ push: (change) => this.#streamPushed(queryID, schema, change) });
|
|
449
|
-
for (const change of
|
|
453
|
+
for (const change of must(this.#streamer).streamNodes(queryID, schema, 0, input.fetch({}))) {
|
|
450
454
|
if (change !== "yield") hydrationRowCount++;
|
|
451
455
|
yield change;
|
|
452
456
|
}
|
|
@@ -675,17 +679,26 @@ var PipelineDriver = class {
|
|
|
675
679
|
const diff = this.#snapshotter.advance(this.#tableSpecs, this.#allTableNames, this.#tables, "divergent");
|
|
676
680
|
const { prev, curr, changes } = diff;
|
|
677
681
|
this.#lc.debug?.(`advance ${prev.version} => ${curr.version}: ${changes} changes`);
|
|
682
|
+
const progress = { changesProcessed: 0 };
|
|
678
683
|
return {
|
|
679
684
|
version: curr.version,
|
|
680
685
|
numChanges: changes,
|
|
681
|
-
changes: this.#trackRowSetSignatures(this.#advance(diff, timer, changes))
|
|
686
|
+
changes: this.#trackRowSetSignatures(this.#advance(diff, timer, changes, progress)),
|
|
687
|
+
progress: () => ({
|
|
688
|
+
changesScanned: diff.changesScanned,
|
|
689
|
+
changesProcessed: progress.changesProcessed,
|
|
690
|
+
changesSkipped: diff.changesSkipped
|
|
691
|
+
})
|
|
682
692
|
};
|
|
683
693
|
}
|
|
684
|
-
*#advance(diff, timer, numChanges) {
|
|
694
|
+
*#advance(diff, timer, numChanges, progress) {
|
|
685
695
|
assert(this.#hydrateContext === null, "Cannot advance while hydration is in progress");
|
|
686
696
|
const totalHydrationTimeMs = this.totalHydrationTimeMs();
|
|
687
697
|
const advanceContext = {
|
|
688
698
|
timer,
|
|
699
|
+
progress,
|
|
700
|
+
diff,
|
|
701
|
+
completedChanges: 0,
|
|
689
702
|
totalHydrationTimeMs,
|
|
690
703
|
numChanges,
|
|
691
704
|
reservedRows: void 0,
|
|
@@ -704,15 +717,20 @@ var PipelineDriver = class {
|
|
|
704
717
|
for (const table of this.#tables.values()) table.setDeferWrites(deferWrites);
|
|
705
718
|
this.#lc.debug?.(`starting pipeline advancement of ${numChanges} changes with an advancement time limited based on total hydration time of ${totalHydrationTimeMs} ms (${deferWrites ? "deferred" : "write-through"}).`);
|
|
706
719
|
for (const { table, prevValues: probedPrevValues, nextValue, rowKey } of diff) {
|
|
720
|
+
advanceContext.completedChanges = diff.changesScanned - 1;
|
|
707
721
|
if (this.#shouldAdvanceYieldMaybeAbortAdvance()) yield "yield";
|
|
708
722
|
const start = timer.totalElapsed();
|
|
709
723
|
advanceContext.currentChangeStartMs = start;
|
|
710
724
|
advanceContext.currentTable = table;
|
|
711
725
|
let holds = "fits";
|
|
726
|
+
let pushCompleted = false;
|
|
712
727
|
try {
|
|
713
728
|
try {
|
|
714
729
|
const tableSource = this.#tables.get(table);
|
|
715
|
-
if (!tableSource)
|
|
730
|
+
if (!tableSource) {
|
|
731
|
+
pushCompleted = true;
|
|
732
|
+
continue;
|
|
733
|
+
}
|
|
716
734
|
const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);
|
|
717
735
|
if (nextValue !== null && !this.#reserveSecondRow(advanceContext, rowKey, primaryKey)) holds = "rows";
|
|
718
736
|
const prevValues = tableSource.reconcilePendingConflicts(probedPrevValues, nextValue, rowKey, this.#tableSpecs.get(table)?.tableSpec.uniqueKeys ?? []);
|
|
@@ -724,8 +742,13 @@ var PipelineDriver = class {
|
|
|
724
742
|
}
|
|
725
743
|
if (nextValue) if (editOldRow) yield* this.#push(tableSource, makeSourceChangeEdit(nextValue, editOldRow));
|
|
726
744
|
else yield* this.#push(tableSource, makeSourceChangeAdd(nextValue));
|
|
745
|
+
pushCompleted = true;
|
|
727
746
|
} finally {
|
|
728
747
|
advanceContext.pos++;
|
|
748
|
+
if (pushCompleted) {
|
|
749
|
+
progress.changesProcessed++;
|
|
750
|
+
advanceContext.completedChanges = diff.changesScanned;
|
|
751
|
+
}
|
|
729
752
|
}
|
|
730
753
|
this.#shouldAdvanceYieldMaybeAbortAdvance(false);
|
|
731
754
|
if (holds === "fits") holds = this.#holdPendingRows(advanceContext);
|
|
@@ -736,6 +759,7 @@ var PipelineDriver = class {
|
|
|
736
759
|
this.#advanceTime.recordMs(elapsed, { table });
|
|
737
760
|
if (holds !== "fits") yield* this.#writeThrough(advanceContext, diff, holds);
|
|
738
761
|
}
|
|
762
|
+
advanceContext.completedChanges = diff.changesScanned;
|
|
739
763
|
const { curr } = diff;
|
|
740
764
|
for (const table of this.#tables.values()) table.setDB(curr.db.db);
|
|
741
765
|
this.#ensureCostModelExistsIfEnabled(curr.db.db);
|
|
@@ -854,13 +878,31 @@ var PipelineDriver = class {
|
|
|
854
878
|
}
|
|
855
879
|
};
|
|
856
880
|
}
|
|
881
|
+
/** Compute once for an admitted log, without clocks or allocations per change. */
|
|
882
|
+
#advancementLogFields({ timer, diff, progress, completedChanges, queryStats, totalHydrationTimeMs }) {
|
|
883
|
+
const advancementTimeMs = timer.totalElapsed();
|
|
884
|
+
let queryPushTimeMs = 0;
|
|
885
|
+
for (const stats of queryStats.values()) queryPushTimeMs += stats.timeMs;
|
|
886
|
+
return {
|
|
887
|
+
advancementTimeMs,
|
|
888
|
+
queryPushTimeMs,
|
|
889
|
+
outsideQueryPushTimeMs: Math.max(0, advancementTimeMs - queryPushTimeMs),
|
|
890
|
+
totalHydrationTimeMs,
|
|
891
|
+
changesScanned: diff.changesScanned,
|
|
892
|
+
changesCompleted: completedChanges,
|
|
893
|
+
changesProcessed: progress.changesProcessed,
|
|
894
|
+
changesSkipped: diff.changesSkipped
|
|
895
|
+
};
|
|
896
|
+
}
|
|
857
897
|
/**
|
|
858
898
|
* Logs each query whose pushes took longer than the slow advance
|
|
859
899
|
* threshold, at most once per query shape per
|
|
860
900
|
* {@link SLOW_ADVANCE_LOG_WINDOW_MS}.
|
|
861
901
|
*/
|
|
862
|
-
#logSlowAdvances(
|
|
902
|
+
#logSlowAdvances(context) {
|
|
863
903
|
if (!this.#lc.warn) return;
|
|
904
|
+
const { queryStats, numChanges } = context;
|
|
905
|
+
let advancementFields;
|
|
864
906
|
for (const [queryID, stats] of queryStats) {
|
|
865
907
|
if (stats.timeMs <= this.#logConfig.slowAdvanceThreshold) continue;
|
|
866
908
|
const query = this.#queryForLog(queryID);
|
|
@@ -873,6 +915,7 @@ var PipelineDriver = class {
|
|
|
873
915
|
advanceTimeMs: stats.timeMs,
|
|
874
916
|
changes: stats.changes,
|
|
875
917
|
advancementChanges: numChanges,
|
|
918
|
+
...advancementFields ??= this.#advancementLogFields(context),
|
|
876
919
|
timeMsByTable: Object.fromEntries(stats.timeMsByTable),
|
|
877
920
|
...suppressed > 0 && { suppressedSinceLastLog: suppressed },
|
|
878
921
|
zql: query.shape.zql
|
|
@@ -882,10 +925,12 @@ var PipelineDriver = class {
|
|
|
882
925
|
/**
|
|
883
926
|
* Logs the queries that took the most time in an advancement that timed
|
|
884
927
|
* out, since the reset that follows would otherwise not say what was slow.
|
|
885
|
-
* Throttled per query shape of the slowest query
|
|
928
|
+
* Throttled per query shape of the slowest query, with a shared fallback
|
|
929
|
+
* when the timeout happens before any query push timings are recorded.
|
|
886
930
|
*/
|
|
887
|
-
#logAdvanceTimeout(
|
|
931
|
+
#logAdvanceTimeout(context, reset) {
|
|
888
932
|
if (!this.#lc.warn) return;
|
|
933
|
+
const { queryStats, numChanges } = context;
|
|
889
934
|
const slowest = [...queryStats].toSorted(([, a], [, b]) => b.timeMs - a.timeMs).slice(0, ADVANCE_TIMEOUT_LOG_MAX_QUERIES).flatMap(([queryID, stats]) => {
|
|
890
935
|
const query = this.#queryForLog(queryID);
|
|
891
936
|
return query ? [{
|
|
@@ -893,14 +938,15 @@ var PipelineDriver = class {
|
|
|
893
938
|
stats
|
|
894
939
|
}] : [];
|
|
895
940
|
});
|
|
896
|
-
|
|
897
|
-
const suppressed = slowAdvanceLogThrottle.admit(`timeout:${
|
|
941
|
+
const leadingQuery = slowest[0]?.query;
|
|
942
|
+
const suppressed = slowAdvanceLogThrottle.admit(leadingQuery ? `timeout:${leadingQuery.queryName ?? ""}:${leadingQuery.shape.hash}` : "timeout:outside-query-push");
|
|
898
943
|
if (suppressed === void 0) return;
|
|
899
944
|
const summary = slowest.map(({ query, stats }) => `${query.queryName ?? query.fields.queryHash} (${Math.round(stats.timeMs)} ms)`).join(", ");
|
|
900
|
-
this.#lc.warn(`Advancement of ${numChanges} changes timed out. The queries that took the most time: ${summary}
|
|
945
|
+
this.#lc.warn(`Advancement of ${numChanges} changes timed out. ` + (summary ? `The queries that took the most time: ${summary}` : "No query push timings were recorded."), {
|
|
901
946
|
zeroEvent: "query-advance-timeout",
|
|
902
947
|
reason: reset.message,
|
|
903
948
|
advancementChanges: numChanges,
|
|
949
|
+
...this.#advancementLogFields(context),
|
|
904
950
|
queries: slowest.map(({ query, stats }) => ({
|
|
905
951
|
...query.fields,
|
|
906
952
|
advanceTimeMs: stats.timeMs,
|
|
@@ -933,14 +979,14 @@ var PipelineDriver = class {
|
|
|
933
979
|
* checks; a single pathological push always resets.
|
|
934
980
|
*/
|
|
935
981
|
#shouldAdvanceYieldMaybeAbortAdvance(checkYield = true) {
|
|
936
|
-
const { currentChangeStartMs,
|
|
982
|
+
const { currentChangeStartMs, completedChanges, numChanges, timer: advanceTimer, totalHydrationTimeMs } = must(this.#advanceContext);
|
|
937
983
|
const elapsed = advanceTimer.totalElapsed();
|
|
938
984
|
const currentChangeElapsedMs = currentChangeStartMs === void 0 ? void 0 : elapsed - currentChangeStartMs;
|
|
939
|
-
if (currentChangeElapsedMs !== void 0 && shouldResetSlowCurrentChange(currentChangeElapsedMs, totalHydrationTimeMs)) this.#throwSlowCurrentChangeReset(
|
|
940
|
-
const projectedTotalTimeMs = projectedAdvancementTimeMs(elapsed,
|
|
941
|
-
const shouldFinish = shouldFinishLateAdvancement(
|
|
942
|
-
if (!shouldFinish && shouldResetProjectedAdvancement(elapsed, projectedTotalTimeMs,
|
|
943
|
-
if (!shouldFinish && elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS && elapsed > totalHydrationTimeMs / 2 && (projectedTotalTimeMs === void 0 || projectedTotalTimeMs - elapsed > totalHydrationTimeMs)) throw new ResetPipelinesSignal(`Advancement exceeded timeout at ${
|
|
985
|
+
if (currentChangeElapsedMs !== void 0 && shouldResetSlowCurrentChange(currentChangeElapsedMs, totalHydrationTimeMs)) this.#throwSlowCurrentChangeReset(completedChanges, numChanges, elapsed, currentChangeElapsedMs, totalHydrationTimeMs);
|
|
986
|
+
const projectedTotalTimeMs = projectedAdvancementTimeMs(elapsed, completedChanges, numChanges);
|
|
987
|
+
const shouldFinish = shouldFinishLateAdvancement(completedChanges, numChanges);
|
|
988
|
+
if (!shouldFinish && shouldResetProjectedAdvancement(elapsed, projectedTotalTimeMs, completedChanges, numChanges, totalHydrationTimeMs)) this.#throwProjectedAdvancementReset(completedChanges, numChanges, elapsed, projectedTotalTimeMs, totalHydrationTimeMs);
|
|
989
|
+
if (!shouldFinish && elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS && elapsed > totalHydrationTimeMs / 2 && (projectedTotalTimeMs === void 0 || projectedTotalTimeMs - elapsed > totalHydrationTimeMs)) throw new ResetPipelinesSignal(`Advancement exceeded timeout at ${completedChanges} of ${numChanges} changes after ${elapsed} ms. Advancement time limited based on total hydration time of ${totalHydrationTimeMs} ms.`, "advancement-timeout");
|
|
944
990
|
return checkYield && advanceTimer.elapsedLap() > this.#yieldThresholdMs();
|
|
945
991
|
}
|
|
946
992
|
/**
|
|
@@ -977,15 +1023,17 @@ var PipelineDriver = class {
|
|
|
977
1023
|
return this.#storage.createStorage();
|
|
978
1024
|
}
|
|
979
1025
|
*#push(source, change) {
|
|
980
|
-
this.#
|
|
1026
|
+
assert(this.#pushedRowChanges === null, "push already in progress");
|
|
981
1027
|
try {
|
|
1028
|
+
this.#pushedRowChanges = [];
|
|
982
1029
|
for (const val of source.genPush(change)) {
|
|
983
1030
|
if (val === "yield") yield "yield";
|
|
984
|
-
|
|
985
|
-
this.#
|
|
1031
|
+
const rowChanges = this.#pushedRowChanges;
|
|
1032
|
+
this.#pushedRowChanges = [];
|
|
1033
|
+
yield* rowChanges;
|
|
986
1034
|
}
|
|
987
1035
|
} finally {
|
|
988
|
-
|
|
1036
|
+
this.#pushedRowChanges = null;
|
|
989
1037
|
}
|
|
990
1038
|
}
|
|
991
1039
|
/**
|
|
@@ -998,106 +1046,54 @@ var PipelineDriver = class {
|
|
|
998
1046
|
* rows that are also pushed separately are counted twice.
|
|
999
1047
|
*/
|
|
1000
1048
|
*#streamPushed(queryID, schema, change) {
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
for (const rowChange of streamer.streamChange(queryID, schema, change)) {
|
|
1049
|
+
assert(this.#pushedRowChanges, "changes are only pushed by #push");
|
|
1050
|
+
for (const rowChange of must(this.#streamer).streamChange(queryID, schema, change)) {
|
|
1004
1051
|
if (rowChange === "yield") {
|
|
1005
1052
|
yield rowChange;
|
|
1006
1053
|
continue;
|
|
1007
1054
|
}
|
|
1008
|
-
must(this.#
|
|
1055
|
+
must(this.#pushedRowChanges).push(rowChange);
|
|
1009
1056
|
}
|
|
1010
1057
|
}
|
|
1011
|
-
#startAccumulating() {
|
|
1012
|
-
assert(this.#streamer === null, "Streamer already started");
|
|
1013
|
-
this.#streamer = new Streamer(must(this.#primaryKeys), this.#tableSpecs, (queryID, error) => this.#logQueryFailure(queryID, "query pipeline failed", error));
|
|
1014
|
-
}
|
|
1015
|
-
#stopAccumulating() {
|
|
1016
|
-
const streamer = this.#streamer;
|
|
1017
|
-
assert(streamer, "Streamer not started");
|
|
1018
|
-
this.#streamer = null;
|
|
1019
|
-
return streamer;
|
|
1020
|
-
}
|
|
1021
|
-
#logQueryFailure(queryID, message, error) {
|
|
1022
|
-
const pipeline = this.#pipelines.get(queryID);
|
|
1023
|
-
const queryInfo = pipeline ? {
|
|
1024
|
-
queryHash: queryID,
|
|
1025
|
-
transformationHash: pipeline.transformationHash,
|
|
1026
|
-
queryName: pipeline.queryName
|
|
1027
|
-
} : void 0;
|
|
1028
|
-
logQueryFailure(this.#lc, queryInfo, message, error);
|
|
1029
|
-
}
|
|
1030
1058
|
};
|
|
1059
|
+
/** Turns the output of query pipelines into the row changes sent to clients. */
|
|
1031
1060
|
var Streamer = class {
|
|
1032
1061
|
#primaryKeys;
|
|
1033
1062
|
#tableSpecs;
|
|
1034
|
-
|
|
1035
|
-
constructor(primaryKeys, tableSpecs, logQueryFailure) {
|
|
1063
|
+
constructor(primaryKeys, tableSpecs) {
|
|
1036
1064
|
this.#primaryKeys = primaryKeys;
|
|
1037
1065
|
this.#tableSpecs = tableSpecs;
|
|
1038
|
-
this.#logQueryFailure = logQueryFailure;
|
|
1039
|
-
}
|
|
1040
|
-
#changes = [];
|
|
1041
|
-
/** Row changes that were already produced by {@link streamChange}. */
|
|
1042
|
-
#rowChanges = [];
|
|
1043
|
-
add(rowChange) {
|
|
1044
|
-
this.#rowChanges.push(rowChange);
|
|
1045
|
-
}
|
|
1046
|
-
streamChange(queryID, schema, change) {
|
|
1047
|
-
return this.#streamChanges(queryID, schema, [change]);
|
|
1048
|
-
}
|
|
1049
|
-
accumulate(queryID, schema, changes) {
|
|
1050
|
-
this.#changes.push([
|
|
1051
|
-
queryID,
|
|
1052
|
-
schema,
|
|
1053
|
-
changes
|
|
1054
|
-
]);
|
|
1055
|
-
return this;
|
|
1056
1066
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
for (const [queryID, schema, changes] of this.#changes) try {
|
|
1060
|
-
yield* this.#streamChanges(queryID, schema, changes);
|
|
1061
|
-
} catch (e) {
|
|
1062
|
-
this.#logQueryFailure?.(queryID, e);
|
|
1063
|
-
throw e;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
*#streamChanges(queryID, schema, changes) {
|
|
1067
|
+
/** The row changes for a change pushed out of the pipeline of `queryID`. */
|
|
1068
|
+
*streamChange(queryID, schema, change) {
|
|
1067
1069
|
if (schema.system === "permissions") return;
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
break;
|
|
1079
|
-
case 3: {
|
|
1080
|
-
const child = change[2];
|
|
1081
|
-
const childSchema = must(schema.relationships[child.relationshipName]);
|
|
1082
|
-
yield* this.#streamChanges(queryID, childSchema, [child.change]);
|
|
1083
|
-
break;
|
|
1084
|
-
}
|
|
1085
|
-
case 2:
|
|
1086
|
-
yield* this.#streamNodes(queryID, schema, type, () => [{
|
|
1087
|
-
row: change[1].row,
|
|
1088
|
-
relationships: {}
|
|
1089
|
-
}]);
|
|
1090
|
-
break;
|
|
1091
|
-
default: unreachable(change[0]);
|
|
1070
|
+
const type = change[0];
|
|
1071
|
+
switch (type) {
|
|
1072
|
+
case 1:
|
|
1073
|
+
case 0:
|
|
1074
|
+
yield* this.streamNodes(queryID, schema, type, [change[1]]);
|
|
1075
|
+
break;
|
|
1076
|
+
case 3: {
|
|
1077
|
+
const child = change[2];
|
|
1078
|
+
yield* this.streamChange(queryID, must(schema.relationships[child.relationshipName]), child.change);
|
|
1079
|
+
break;
|
|
1092
1080
|
}
|
|
1081
|
+
case 2:
|
|
1082
|
+
yield* this.streamNodes(queryID, schema, type, [{
|
|
1083
|
+
row: change[1].row,
|
|
1084
|
+
relationships: {}
|
|
1085
|
+
}]);
|
|
1086
|
+
break;
|
|
1087
|
+
default: unreachable(change[0]);
|
|
1093
1088
|
}
|
|
1094
1089
|
}
|
|
1095
|
-
|
|
1090
|
+
/** A row change of type `op` for each of `nodes` and their descendants. */
|
|
1091
|
+
*streamNodes(queryID, schema, op, nodes) {
|
|
1096
1092
|
const { tableName: table, system } = schema;
|
|
1093
|
+
if (system === "permissions") return;
|
|
1097
1094
|
const primaryKey = must(this.#primaryKeys.get(table));
|
|
1098
1095
|
const spec = must(this.#tableSpecs.get(table)).tableSpec;
|
|
1099
|
-
|
|
1100
|
-
for (const node of nodes()) {
|
|
1096
|
+
for (const node of nodes) {
|
|
1101
1097
|
if (node === "yield") {
|
|
1102
1098
|
yield node;
|
|
1103
1099
|
continue;
|
|
@@ -1119,9 +1115,9 @@ var Streamer = class {
|
|
|
1119
1115
|
rowKey,
|
|
1120
1116
|
row: op === 1 ? void 0 : row
|
|
1121
1117
|
};
|
|
1122
|
-
for (const
|
|
1118
|
+
for (const relationship of Object.keys(relationships)) {
|
|
1123
1119
|
const childSchema = must(schema.relationships[relationship]);
|
|
1124
|
-
yield* this
|
|
1120
|
+
if (childSchema.system !== "permissions") yield* this.streamNodes(queryID, childSchema, op, relationships[relationship]());
|
|
1125
1121
|
}
|
|
1126
1122
|
}
|
|
1127
1123
|
}
|
|
@@ -1187,21 +1183,10 @@ function logQueryFailure(lc, queryInfo, message, error) {
|
|
|
1187
1183
|
}
|
|
1188
1184
|
queryLC.error?.(message, error);
|
|
1189
1185
|
}
|
|
1190
|
-
function* toAdds(nodes) {
|
|
1191
|
-
for (const node of nodes) {
|
|
1192
|
-
if (node === "yield") {
|
|
1193
|
-
yield node;
|
|
1194
|
-
continue;
|
|
1195
|
-
}
|
|
1196
|
-
yield [
|
|
1197
|
-
0,
|
|
1198
|
-
node,
|
|
1199
|
-
null
|
|
1200
|
-
];
|
|
1201
|
-
}
|
|
1202
|
-
}
|
|
1203
1186
|
function getRowKey(cols, row) {
|
|
1204
|
-
|
|
1187
|
+
const rowKey = {};
|
|
1188
|
+
for (const col of cols) assignProperty(rowKey, col, must(row[col]));
|
|
1189
|
+
return rowKey;
|
|
1205
1190
|
}
|
|
1206
1191
|
/** Whether `rowKey` has exactly the columns of `primaryKey`. */
|
|
1207
1192
|
function isKeyedBy(rowKey, primaryKey) {
|
|
@@ -1218,12 +1203,7 @@ function isKeyedBy(rowKey, primaryKey) {
|
|
|
1218
1203
|
* queries the same way the view-syncer does in production.
|
|
1219
1204
|
*/
|
|
1220
1205
|
function hydrate(input, hash, clientSchema, tableSpecs) {
|
|
1221
|
-
|
|
1222
|
-
return new Streamer(buildPrimaryKeys(clientSchema), tableSpecs).accumulate(hash, input.getSchema(), toAdds(res)).stream();
|
|
1223
|
-
}
|
|
1224
|
-
function hydrateInternal(input, hash, primaryKeys, tableSpecs) {
|
|
1225
|
-
const res = input.fetch({});
|
|
1226
|
-
return new Streamer(primaryKeys, tableSpecs).accumulate(hash, input.getSchema(), toAdds(res)).stream();
|
|
1206
|
+
return new Streamer(buildPrimaryKeys(clientSchema), tableSpecs).streamNodes(hash, input.getSchema(), 0, input.fetch({}));
|
|
1227
1207
|
}
|
|
1228
1208
|
function buildPrimaryKeys(clientSchema, primaryKeys = /* @__PURE__ */ new Map()) {
|
|
1229
1209
|
for (const [tableName, { primaryKey }] of Object.entries(clientSchema.tables)) primaryKeys.set(tableName, primaryKey);
|