@rocicorp/zero 0.25.0-canary.10 → 0.25.0-canary.11

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.
Files changed (184) hide show
  1. package/out/analyze-query/src/run-ast.d.ts.map +1 -1
  2. package/out/analyze-query/src/run-ast.js +3 -7
  3. package/out/analyze-query/src/run-ast.js.map +1 -1
  4. package/out/shared/src/iterables.d.ts +0 -1
  5. package/out/shared/src/iterables.d.ts.map +1 -1
  6. package/out/shared/src/iterables.js +0 -34
  7. package/out/shared/src/iterables.js.map +1 -1
  8. package/out/zero/package.json.js +1 -1
  9. package/out/zero-cache/src/config/zero-config.d.ts +0 -4
  10. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  11. package/out/zero-cache/src/config/zero-config.js +5 -15
  12. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  13. package/out/zero-cache/src/db/transaction-pool.d.ts.map +1 -1
  14. package/out/zero-cache/src/db/transaction-pool.js +3 -6
  15. package/out/zero-cache/src/db/transaction-pool.js.map +1 -1
  16. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  17. package/out/zero-cache/src/server/change-streamer.js +2 -8
  18. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  19. package/out/zero-cache/src/services/analyze.d.ts +1 -1
  20. package/out/zero-cache/src/services/analyze.d.ts.map +1 -1
  21. package/out/zero-cache/src/services/analyze.js +50 -37
  22. package/out/zero-cache/src/services/analyze.js.map +1 -1
  23. package/out/zero-cache/src/services/change-source/pg/change-source.d.ts.map +1 -1
  24. package/out/zero-cache/src/services/change-source/pg/change-source.js +62 -42
  25. package/out/zero-cache/src/services/change-source/pg/change-source.js.map +1 -1
  26. package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts +1 -0
  27. package/out/zero-cache/src/services/change-source/protocol/current/control.d.ts.map +1 -1
  28. package/out/zero-cache/src/services/change-source/protocol/current/control.js +5 -1
  29. package/out/zero-cache/src/services/change-source/protocol/current/control.js.map +1 -1
  30. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts +2 -0
  31. package/out/zero-cache/src/services/change-source/protocol/current/downstream.d.ts.map +1 -1
  32. package/out/zero-cache/src/services/change-source/protocol/current/json.d.ts +8 -0
  33. package/out/zero-cache/src/services/change-source/protocol/current/json.d.ts.map +1 -0
  34. package/out/zero-cache/src/services/change-source/protocol/current/json.js +19 -0
  35. package/out/zero-cache/src/services/change-source/protocol/current/json.js.map +1 -0
  36. package/out/zero-cache/src/services/change-source/protocol/current.d.ts +1 -0
  37. package/out/zero-cache/src/services/change-source/protocol/current.d.ts.map +1 -1
  38. package/out/zero-cache/src/services/change-source/protocol/current.js +3 -0
  39. package/out/zero-cache/src/services/change-source/protocol/current.js.map +1 -1
  40. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +0 -2
  41. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  42. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +0 -5
  43. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  44. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  45. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +8 -1
  46. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  47. package/out/zero-cache/src/services/change-streamer/storer.d.ts.map +1 -1
  48. package/out/zero-cache/src/services/change-streamer/storer.js +2 -3
  49. package/out/zero-cache/src/services/change-streamer/storer.js.map +1 -1
  50. package/out/zero-cache/src/services/http-service.d.ts +0 -1
  51. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  52. package/out/zero-cache/src/services/http-service.js +0 -4
  53. package/out/zero-cache/src/services/http-service.js.map +1 -1
  54. package/out/zero-cache/src/services/replicator/replication-status.d.ts +2 -0
  55. package/out/zero-cache/src/services/replicator/replication-status.d.ts.map +1 -1
  56. package/out/zero-cache/src/services/replicator/replication-status.js +14 -1
  57. package/out/zero-cache/src/services/replicator/replication-status.js.map +1 -1
  58. package/out/zero-cache/src/services/run-ast.d.ts +1 -1
  59. package/out/zero-cache/src/services/run-ast.d.ts.map +1 -1
  60. package/out/zero-cache/src/services/run-ast.js +5 -1
  61. package/out/zero-cache/src/services/run-ast.js.map +1 -1
  62. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +6 -4
  63. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  64. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +71 -23
  65. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  66. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +1 -1
  67. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  68. package/out/zero-cache/src/services/view-syncer/view-syncer.js +10 -6
  69. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  70. package/out/zero-client/src/client/version.js +1 -1
  71. package/out/zero-client/src/client/zero.d.ts.map +1 -1
  72. package/out/zero-client/src/client/zero.js +6 -2
  73. package/out/zero-client/src/client/zero.js.map +1 -1
  74. package/out/zero-events/src/status.d.ts +1 -1
  75. package/out/zero-events/src/status.d.ts.map +1 -1
  76. package/out/zero-solid/src/solid-view.d.ts.map +1 -1
  77. package/out/zero-solid/src/solid-view.js +4 -3
  78. package/out/zero-solid/src/solid-view.js.map +1 -1
  79. package/out/zql/src/builder/builder.d.ts.map +1 -1
  80. package/out/zql/src/builder/builder.js +0 -1
  81. package/out/zql/src/builder/builder.js.map +1 -1
  82. package/out/zql/src/ivm/array-view.d.ts +1 -1
  83. package/out/zql/src/ivm/array-view.d.ts.map +1 -1
  84. package/out/zql/src/ivm/array-view.js +2 -1
  85. package/out/zql/src/ivm/array-view.js.map +1 -1
  86. package/out/zql/src/ivm/data.d.ts +7 -2
  87. package/out/zql/src/ivm/data.d.ts.map +1 -1
  88. package/out/zql/src/ivm/data.js +3 -0
  89. package/out/zql/src/ivm/data.js.map +1 -1
  90. package/out/zql/src/ivm/exists.d.ts +3 -2
  91. package/out/zql/src/ivm/exists.d.ts.map +1 -1
  92. package/out/zql/src/ivm/exists.js +29 -76
  93. package/out/zql/src/ivm/exists.js.map +1 -1
  94. package/out/zql/src/ivm/fan-in.d.ts +2 -0
  95. package/out/zql/src/ivm/fan-in.d.ts.map +1 -1
  96. package/out/zql/src/ivm/fan-in.js +4 -0
  97. package/out/zql/src/ivm/fan-in.js.map +1 -1
  98. package/out/zql/src/ivm/fan-out.d.ts +2 -0
  99. package/out/zql/src/ivm/fan-out.d.ts.map +1 -1
  100. package/out/zql/src/ivm/fan-out.js +4 -0
  101. package/out/zql/src/ivm/fan-out.js.map +1 -1
  102. package/out/zql/src/ivm/filter-operators.d.ts +6 -2
  103. package/out/zql/src/ivm/filter-operators.d.ts.map +1 -1
  104. package/out/zql/src/ivm/filter-operators.js +16 -0
  105. package/out/zql/src/ivm/filter-operators.js.map +1 -1
  106. package/out/zql/src/ivm/filter.d.ts +2 -0
  107. package/out/zql/src/ivm/filter.d.ts.map +1 -1
  108. package/out/zql/src/ivm/filter.js +4 -0
  109. package/out/zql/src/ivm/filter.js.map +1 -1
  110. package/out/zql/src/ivm/flipped-join.d.ts +1 -1
  111. package/out/zql/src/ivm/flipped-join.d.ts.map +1 -1
  112. package/out/zql/src/ivm/flipped-join.js +26 -13
  113. package/out/zql/src/ivm/flipped-join.js.map +1 -1
  114. package/out/zql/src/ivm/join-utils.d.ts +2 -1
  115. package/out/zql/src/ivm/join-utils.d.ts.map +1 -1
  116. package/out/zql/src/ivm/join-utils.js +8 -0
  117. package/out/zql/src/ivm/join-utils.js.map +1 -1
  118. package/out/zql/src/ivm/join.d.ts +1 -1
  119. package/out/zql/src/ivm/join.d.ts.map +1 -1
  120. package/out/zql/src/ivm/join.js +32 -13
  121. package/out/zql/src/ivm/join.js.map +1 -1
  122. package/out/zql/src/ivm/memory-source.d.ts +1 -1
  123. package/out/zql/src/ivm/memory-source.d.ts.map +1 -1
  124. package/out/zql/src/ivm/memory-source.js +8 -1
  125. package/out/zql/src/ivm/memory-source.js.map +1 -1
  126. package/out/zql/src/ivm/operator.d.ts +9 -1
  127. package/out/zql/src/ivm/operator.d.ts.map +1 -1
  128. package/out/zql/src/ivm/operator.js +8 -0
  129. package/out/zql/src/ivm/operator.js.map +1 -1
  130. package/out/zql/src/ivm/push-accumulated.d.ts +1 -1
  131. package/out/zql/src/ivm/push-accumulated.d.ts.map +1 -1
  132. package/out/zql/src/ivm/push-accumulated.js.map +1 -1
  133. package/out/zql/src/ivm/skip.d.ts +1 -1
  134. package/out/zql/src/ivm/skip.d.ts.map +1 -1
  135. package/out/zql/src/ivm/skip.js +7 -1
  136. package/out/zql/src/ivm/skip.js.map +1 -1
  137. package/out/zql/src/ivm/take.d.ts +1 -1
  138. package/out/zql/src/ivm/take.d.ts.map +1 -1
  139. package/out/zql/src/ivm/take.js +87 -59
  140. package/out/zql/src/ivm/take.js.map +1 -1
  141. package/out/zql/src/ivm/union-fan-in.d.ts +2 -1
  142. package/out/zql/src/ivm/union-fan-in.d.ts.map +1 -1
  143. package/out/zql/src/ivm/union-fan-in.js +67 -5
  144. package/out/zql/src/ivm/union-fan-in.js.map +1 -1
  145. package/out/zql/src/ivm/union-fan-out.d.ts +1 -1
  146. package/out/zql/src/ivm/union-fan-out.d.ts.map +1 -1
  147. package/out/zql/src/ivm/union-fan-out.js.map +1 -1
  148. package/out/zql/src/ivm/view-apply-change.d.ts.map +1 -1
  149. package/out/zql/src/ivm/view-apply-change.js +3 -2
  150. package/out/zql/src/ivm/view-apply-change.js.map +1 -1
  151. package/out/zql/src/query/abstract-query.d.ts +43 -0
  152. package/out/zql/src/query/abstract-query.d.ts.map +1 -0
  153. package/out/zql/src/query/abstract-query.js +408 -0
  154. package/out/zql/src/query/abstract-query.js.map +1 -0
  155. package/out/zql/src/query/create-builder.d.ts +2 -0
  156. package/out/zql/src/query/create-builder.d.ts.map +1 -1
  157. package/out/zql/src/query/create-builder.js +7 -2
  158. package/out/zql/src/query/create-builder.js.map +1 -1
  159. package/out/zql/src/query/measure-push-operator.d.ts +1 -1
  160. package/out/zql/src/query/measure-push-operator.d.ts.map +1 -1
  161. package/out/zql/src/query/measure-push-operator.js.map +1 -1
  162. package/out/zql/src/query/query-delegate-base.d.ts +7 -1
  163. package/out/zql/src/query/query-delegate-base.d.ts.map +1 -1
  164. package/out/zql/src/query/query-delegate-base.js +132 -2
  165. package/out/zql/src/query/query-delegate-base.js.map +1 -1
  166. package/out/zql/src/query/query-impl.d.ts +5 -39
  167. package/out/zql/src/query/query-impl.d.ts.map +1 -1
  168. package/out/zql/src/query/query-impl.js +3 -521
  169. package/out/zql/src/query/query-impl.js.map +1 -1
  170. package/out/zql/src/query/query.d.ts +21 -0
  171. package/out/zql/src/query/query.d.ts.map +1 -1
  172. package/out/zql/src/query/runnable-query-impl.d.ts +22 -0
  173. package/out/zql/src/query/runnable-query-impl.d.ts.map +1 -0
  174. package/out/zql/src/query/runnable-query-impl.js +60 -0
  175. package/out/zql/src/query/runnable-query-impl.js.map +1 -0
  176. package/out/zql/src/query/static-query.d.ts +1 -1
  177. package/out/zql/src/query/static-query.d.ts.map +1 -1
  178. package/out/zql/src/query/static-query.js +1 -1
  179. package/out/zql/src/query/static-query.js.map +1 -1
  180. package/out/zqlite/src/table-source.d.ts +7 -1
  181. package/out/zqlite/src/table-source.d.ts.map +1 -1
  182. package/out/zqlite/src/table-source.js +34 -14
  183. package/out/zqlite/src/table-source.js.map +1 -1
  184. package/package.json +1 -1
@@ -16,6 +16,7 @@ import { getSubscriptionState } from "../replicator/schema/replication-state.js"
16
16
  import { checkClientSchema } from "./client-schema.js";
17
17
  import { ResetPipelinesSignal } from "./snapshotter.js";
18
18
  const MIN_ADVANCEMENT_TIME_LIMIT_MS = 30;
19
+ const HYDRATE_YIELD_THRESHOLD_MS = 200;
19
20
  class PipelineDriver {
20
21
  #tables = /* @__PURE__ */ new Map();
21
22
  // We probs need the original query hash
@@ -30,6 +31,7 @@ class PipelineDriver {
30
31
  #tableSpecs = /* @__PURE__ */ new Map();
31
32
  #costModels;
32
33
  #streamer = null;
34
+ #hydrateContext = null;
33
35
  #advanceContext = null;
34
36
  #replicaVersion = null;
35
37
  #primaryKeys = null;
@@ -249,11 +251,22 @@ class PipelineDriver {
249
251
  push: (change) => {
250
252
  const streamer = this.#streamer;
251
253
  assert(streamer, "must #startAccumulating() before pushing changes");
252
- this.#checkAdvanceProgress();
253
254
  streamer.accumulate(transformationHash, schema, [change]);
254
255
  }
255
256
  });
256
- yield* hydrateInternal(input, transformationHash, must(this.#primaryKeys));
257
+ assert(this.#advanceContext === null);
258
+ this.#hydrateContext = {
259
+ timer
260
+ };
261
+ try {
262
+ yield* hydrateInternal(
263
+ input,
264
+ transformationHash,
265
+ must(this.#primaryKeys)
266
+ );
267
+ } finally {
268
+ this.#hydrateContext = null;
269
+ }
257
270
  const hydrationTimeMs = timer.totalElapsed();
258
271
  if (runtimeDebugFlags.trackRowCountsVended) {
259
272
  if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {
@@ -327,11 +340,11 @@ class PipelineDriver {
327
340
  };
328
341
  }
329
342
  *#advance(diff, timer, numChanges) {
343
+ assert(this.#hydrateContext === null);
330
344
  this.#advanceContext = {
331
345
  timer,
332
346
  totalHydrationTimeMs: this.totalHydrationTimeMs(),
333
347
  numChanges,
334
- advanceCheckCount: 0,
335
348
  pos: 0
336
349
  };
337
350
  try {
@@ -395,24 +408,6 @@ class PipelineDriver {
395
408
  this.#advanceContext = null;
396
409
  }
397
410
  }
398
- #checkAdvanceProgress() {
399
- assert(this.#advanceContext !== null);
400
- if (this.#advanceContext.advanceCheckCount++ % 10 === 0) {
401
- return;
402
- }
403
- const {
404
- pos,
405
- numChanges,
406
- timer: advanceTimer,
407
- totalHydrationTimeMs
408
- } = this.#advanceContext;
409
- const elapsed = advanceTimer.totalElapsed();
410
- if (elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS && (elapsed > totalHydrationTimeMs || elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2)) {
411
- throw new ResetPipelinesSignal(
412
- `Advancement exceeded timeout at ${pos} of ${numChanges} changes after ${elapsed} ms. Advancement time limited based on total hydration time of ${totalHydrationTimeMs} ms.`
413
- );
414
- }
415
- }
416
411
  /** Implements `BuilderDelegate.getSource()` */
417
412
  #getSource(tableName) {
418
413
  let source = this.#tables.get(tableName);
@@ -428,12 +423,49 @@ class PipelineDriver {
428
423
  db.db,
429
424
  tableName,
430
425
  tableSpec.zqlSpec,
431
- primaryKey
426
+ primaryKey,
427
+ () => this.#shouldYield()
432
428
  );
433
429
  this.#tables.set(tableName, source);
434
430
  this.#lc.debug?.(`created TableSource for ${tableName}`);
435
431
  return source;
436
432
  }
433
+ #shouldYield() {
434
+ if (this.#hydrateContext) {
435
+ return this.#hydrateContext.timer.elapsedLap() > HYDRATE_YIELD_THRESHOLD_MS;
436
+ }
437
+ if (this.#advanceContext) {
438
+ this.#checkAdvanceProgress();
439
+ }
440
+ return false;
441
+ }
442
+ /**
443
+ * Cancel the advancement processing, by throwing a ResetPipelinesSignal, if
444
+ * it has taken longer than half the total hydration time to make it through
445
+ * half of the advancement, or if processing time exceeds total hydration
446
+ * time. This serves as both a circuit breaker for very large transactions,
447
+ * as well as a bound on the amount of time the previous connection locks
448
+ * the inactive WAL file (as the lock prevents WAL2 from switching to the
449
+ * free WAL when the current one is over the size limit, which can make
450
+ * the WAL grow continuously and compound slowness).
451
+ * This is checked:
452
+ * 1. before starting to process each change in an advancement is processed
453
+ * 2. whenever a row is fetched from a TableSource during push processing
454
+ */
455
+ #checkAdvanceProgress() {
456
+ const {
457
+ pos,
458
+ numChanges,
459
+ timer: advanceTimer,
460
+ totalHydrationTimeMs
461
+ } = must(this.#advanceContext);
462
+ const elapsed = advanceTimer.totalElapsed();
463
+ if (elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS && (elapsed > totalHydrationTimeMs || elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2)) {
464
+ throw new ResetPipelinesSignal(
465
+ `Advancement exceeded timeout at ${pos} of ${numChanges} changes after ${elapsed} ms. Advancement time limited based on total hydration time of ${totalHydrationTimeMs} ms.`
466
+ );
467
+ }
468
+ }
437
469
  /** Implements `BuilderDelegate.createStorage()` */
438
470
  #createStorage() {
439
471
  return this.#storage.createStorage();
@@ -442,7 +474,10 @@ class PipelineDriver {
442
474
  this.#startAccumulating();
443
475
  try {
444
476
  for (const _ of source.genPush(change)) {
445
- yield* this.#stopAccumulating().stream();
477
+ for (const change2 of this.#stopAccumulating().stream()) {
478
+ assert(change2 !== "yield");
479
+ yield change2;
480
+ }
446
481
  this.#startAccumulating();
447
482
  }
448
483
  } finally {
@@ -482,6 +517,10 @@ class Streamer {
482
517
  return;
483
518
  }
484
519
  for (const change of changes) {
520
+ if (change === "yield") {
521
+ yield change;
522
+ continue;
523
+ }
485
524
  const { type } = change;
486
525
  switch (type) {
487
526
  case "add":
@@ -516,6 +555,10 @@ class Streamer {
516
555
  return;
517
556
  }
518
557
  for (const node of nodes()) {
558
+ if (node === "yield") {
559
+ yield node;
560
+ continue;
561
+ }
519
562
  const { relationships, row } = node;
520
563
  const rowKey = getRowKey(primaryKey, row);
521
564
  yield {
@@ -534,6 +577,10 @@ class Streamer {
534
577
  }
535
578
  function* toAdds(nodes) {
536
579
  for (const node of nodes) {
580
+ if (node === "yield") {
581
+ yield node;
582
+ continue;
583
+ }
537
584
  yield { type: "add", node };
538
585
  }
539
586
  }
@@ -572,6 +619,7 @@ function mustGetPrimaryKey(primaryKeys, table) {
572
619
  );
573
620
  }
574
621
  export {
622
+ HYDRATE_YIELD_THRESHOLD_MS,
575
623
  PipelineDriver,
576
624
  hydrate,
577
625
  hydrateInternal
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-driver.js","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {deepEqual, type JSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-protocol/src/primary-key.ts';\nimport {buildPipeline} from '../../../../zql/src/builder/builder.ts';\nimport {\n Debug,\n runtimeDebugFlags,\n} from '../../../../zql/src/builder/debug-delegate.ts';\nimport type {Change} from '../../../../zql/src/ivm/change.ts';\nimport type {Node} from '../../../../zql/src/ivm/data.ts';\nimport type {Input, Storage} from '../../../../zql/src/ivm/operator.ts';\nimport type {SourceSchema} from '../../../../zql/src/ivm/schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceInput,\n} from '../../../../zql/src/ivm/source.ts';\nimport type {ConnectionCostModel} from '../../../../zql/src/planner/planner-connection.ts';\nimport {MeasurePushOperator} from '../../../../zql/src/query/measure-push-operator.ts';\nimport type {ClientGroupStorage} from '../../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {createSQLiteCostModel} from '../../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../../zqlite/src/table-source.ts';\nimport {\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from '../../auth/load-permissions.ts';\nimport type {LogConfig} from '../../config/zero-config.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {type RowKey} from '../../types/row-key.ts';\nimport type {SchemaVersions} from '../../types/schema-versions.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {getSubscriptionState} from '../replicator/schema/replication-state.ts';\nimport {checkClientSchema} from './client-schema.ts';\nimport type {Snapshotter} from './snapshotter.ts';\nimport {ResetPipelinesSignal, type SnapshotDiff} from './snapshotter.ts';\n\nexport type RowAdd = {\n readonly type: 'add';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowRemove = {\n readonly type: 'remove';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: undefined;\n};\n\nexport type RowEdit = {\n readonly type: 'edit';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowChange = RowAdd | RowRemove | RowEdit;\n\ntype Pipeline = {\n readonly input: Input;\n readonly hydrationTimeMs: number;\n readonly originalHash: string;\n readonly transformedAst: AST; // Optional, only set after hydration\n readonly transformationHash: string; // The hash of the transformed AST\n};\n\ntype AdvanceContext = {\n readonly timer: {totalElapsed: () => number};\n readonly totalHydrationTimeMs: number;\n readonly numChanges: number;\n advanceCheckCount: number;\n pos: number;\n};\n\n/**\n * No matter how fast hydration is, advancement is given at least this long to\n * complete before doing a pipeline reset.\n */\nconst MIN_ADVANCEMENT_TIME_LIMIT_MS = 30;\n\n/**\n * Manages the state of IVM pipelines for a given ViewSyncer (i.e. client group).\n */\nexport class PipelineDriver {\n readonly #tables = new Map<string, TableSource>();\n // We probs need the original query hash\n // so we can decide not to re-transform a custom query\n // that is already hydrated.\n readonly #pipelines = new Map<string, Pipeline>();\n\n readonly #lc: LogContext;\n readonly #snapshotter: Snapshotter;\n readonly #storage: ClientGroupStorage;\n readonly #shardID: ShardID;\n readonly #logConfig: LogConfig;\n readonly #tableSpecs = new Map<string, LiteAndZqlSpec>();\n readonly #costModels: WeakMap<Database, ConnectionCostModel> | undefined;\n #streamer: Streamer | null = null;\n #advanceContext: AdvanceContext | null = null;\n #replicaVersion: string | null = null;\n #primaryKeys: Map<string, PrimaryKey> | null = null;\n #permissions: LoadedPermissions | null = null;\n\n readonly #advanceTime = getOrCreateHistogram('sync', 'ivm.advance-time', {\n description:\n 'Time to advance all queries for a given client group for in response to a single change.',\n unit: 's',\n });\n\n readonly #conflictRowsDeleted = getOrCreateCounter(\n 'sync',\n 'ivm.conflict-rows-deleted',\n 'Number of rows deleted because they conflicted with added row',\n );\n\n readonly #inspectorDelegate: InspectorDelegate;\n\n constructor(\n lc: LogContext,\n logConfig: LogConfig,\n snapshotter: Snapshotter,\n shardID: ShardID,\n storage: ClientGroupStorage,\n clientGroupID: string,\n inspectorDelegate: InspectorDelegate,\n enablePlanner?: boolean,\n ) {\n this.#lc = lc.withContext('clientGroupID', clientGroupID);\n this.#snapshotter = snapshotter;\n this.#storage = storage;\n this.#shardID = shardID;\n this.#logConfig = logConfig;\n this.#inspectorDelegate = inspectorDelegate;\n this.#costModels = enablePlanner ? new WeakMap() : undefined;\n }\n\n /**\n * Initializes the PipelineDriver to the current head of the database.\n * Queries can then be added (i.e. hydrated) with {@link addQuery()}.\n *\n * Must only be called once.\n */\n init(clientSchema: ClientSchema) {\n assert(!this.#snapshotter.initialized(), 'Already initialized');\n this.#snapshotter.init();\n this.#initAndResetCommon(clientSchema);\n }\n\n /**\n * @returns Whether the PipelineDriver has been initialized.\n */\n initialized(): boolean {\n return this.#snapshotter.initialized();\n }\n\n /**\n * Clears the current pipelines and TableSources, returning the PipelineDriver\n * to its initial state. This should be called in response to a schema change,\n * as TableSources need to be recomputed.\n */\n reset(clientSchema: ClientSchema) {\n for (const {input} of this.#pipelines.values()) {\n input.destroy();\n }\n this.#pipelines.clear();\n this.#tables.clear();\n this.#initAndResetCommon(clientSchema);\n }\n\n #initAndResetCommon(clientSchema: ClientSchema) {\n const {db} = this.#snapshotter.current();\n const fullTables = new Map<string, LiteTableSpec>();\n computeZqlSpecs(this.#lc, db.db, this.#tableSpecs, fullTables);\n checkClientSchema(\n this.#shardID,\n clientSchema,\n this.#tableSpecs,\n fullTables,\n );\n const primaryKeys = this.#primaryKeys ?? new Map<string, PrimaryKey>();\n this.#primaryKeys = primaryKeys;\n primaryKeys.clear();\n for (const [table, spec] of this.#tableSpecs.entries()) {\n if (table.startsWith(upstreamSchema(this.#shardID))) {\n primaryKeys.set(table, spec.tableSpec.primaryKey);\n }\n }\n buildPrimaryKeys(clientSchema, primaryKeys);\n const {replicaVersion} = getSubscriptionState(db);\n this.#replicaVersion = replicaVersion;\n }\n\n /** @returns The replica version. The PipelineDriver must have been initialized. */\n get replicaVersion(): string {\n return must(this.#replicaVersion, 'Not yet initialized');\n }\n\n /**\n * Returns the current version of the database. This will reflect the\n * latest version change when calling {@link advance()} once the\n * iteration has begun.\n */\n currentVersion(): string {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().version;\n }\n\n /**\n * Returns the current supported schema version range of the database. This\n * will reflect changes to supported schema version range when calling\n * {@link advance()} once the iteration has begun.\n */\n currentSchemaVersions(): SchemaVersions {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().schemaVersions;\n }\n\n /**\n * Returns the current upstream {app}.permissions, or `null` if none are defined.\n */\n currentPermissions(): LoadedPermissions | null {\n assert(this.initialized(), 'Not yet initialized');\n const res = reloadPermissionsIfChanged(\n this.#lc,\n this.#snapshotter.current().db,\n this.#shardID.appID,\n this.#permissions,\n );\n if (res.changed) {\n this.#permissions = res.permissions;\n this.#lc.debug?.(\n 'Reloaded permissions',\n JSON.stringify(this.#permissions),\n );\n }\n return this.#permissions;\n }\n\n advanceWithoutDiff(): string {\n const {db, version} = this.#snapshotter.advanceWithoutDiff().curr;\n for (const table of this.#tables.values()) {\n table.setDB(db.db);\n }\n return version;\n }\n\n #ensureCostModelExistsIfEnabled(db: Database) {\n let existing = this.#costModels?.get(db);\n if (existing) {\n return existing;\n }\n if (this.#costModels) {\n const costModel = createSQLiteCostModel(db, this.#tableSpecs);\n this.#costModels.set(db, costModel);\n return costModel;\n }\n return undefined;\n }\n\n /**\n * Clears storage used for the pipelines. Call this when the\n * PipelineDriver will no longer be used.\n */\n destroy() {\n this.#storage.destroy();\n this.#snapshotter.destroy();\n }\n\n /** @return The Set of query hashes for all added queries. */\n addedQueries(): [\n transformationHashes: Set<string>,\n byOriginalHash: Map<\n string,\n {\n transformationHash: string;\n transformedAst: AST;\n }[]\n >,\n ] {\n const byOriginalHash = new Map<\n string,\n {transformationHash: string; transformedAst: AST}[]\n >();\n for (const pipeline of this.#pipelines.values()) {\n const {originalHash, transformedAst, transformationHash} = pipeline;\n\n if (!byOriginalHash.has(originalHash)) {\n byOriginalHash.set(originalHash, []);\n }\n byOriginalHash.get(originalHash)!.push({\n transformationHash,\n transformedAst,\n });\n }\n return [new Set(this.#pipelines.keys()), byOriginalHash];\n }\n\n totalHydrationTimeMs(): number {\n let total = 0;\n for (const pipeline of this.#pipelines.values()) {\n total += pipeline.hydrationTimeMs;\n }\n return total;\n }\n\n /**\n * Adds a pipeline for the query. The method will hydrate the query using the\n * driver's current snapshot of the database and return a stream of results.\n * Henceforth, updates to the query will be returned when the driver is\n * {@link advance}d. The query and its pipeline can be removed with\n * {@link removeQuery()}.\n *\n * If a query with an identical hash has already been added, this method is a\n * no-op and no RowChanges are generated.\n *\n * @param timer The caller-controlled {@link Timer} used to determine the\n * final hydration time. (The caller may pause and resume the timer\n * when yielding the thread for time-slicing).\n * @return The rows from the initial hydration of the query.\n */\n *addQuery(\n transformationHash: string,\n queryID: string,\n query: AST,\n timer: {totalElapsed: () => number},\n ): Iterable<RowChange> {\n assert(this.initialized());\n this.#inspectorDelegate.addQuery(transformationHash, queryID, query);\n if (this.#pipelines.has(transformationHash)) {\n this.#lc.info?.(`query ${transformationHash} already added`, query);\n return;\n }\n const debugDelegate = runtimeDebugFlags.trackRowsVended\n ? new Debug()\n : undefined;\n\n const costModel = this.#ensureCostModelExistsIfEnabled(\n this.#snapshotter.current().db.db,\n );\n\n const input = buildPipeline(\n query,\n {\n debug: debugDelegate,\n enableNotExists: true, // Server-side can handle NOT EXISTS\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput, _queryID: string): Input =>\n new MeasurePushOperator(\n input,\n transformationHash,\n this.#inspectorDelegate,\n 'query-update-server',\n ),\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n queryID,\n costModel,\n );\n const schema = input.getSchema();\n input.setOutput({\n push: change => {\n const streamer = this.#streamer;\n assert(streamer, 'must #startAccumulating() before pushing changes');\n this.#checkAdvanceProgress();\n streamer.accumulate(transformationHash, schema, [change]);\n },\n });\n\n yield* hydrateInternal(input, transformationHash, must(this.#primaryKeys));\n\n const hydrationTimeMs = timer.totalElapsed();\n if (runtimeDebugFlags.trackRowCountsVended) {\n if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {\n let totalRowsConsidered = 0;\n const lc = this.#lc\n .withContext('hash', transformationHash)\n .withContext('hydrationTimeMs', hydrationTimeMs);\n for (const tableName of this.#tables.keys()) {\n const entries = Object.entries(\n debugDelegate?.getVendedRowCounts()[tableName] ?? {},\n );\n totalRowsConsidered += entries.reduce(\n (acc, entry) => acc + entry[1],\n 0,\n );\n lc.info?.(tableName + ' VENDED: ', entries);\n }\n lc.info?.(`Total rows considered: ${totalRowsConsidered}`);\n }\n }\n debugDelegate?.reset();\n\n // Note: This hydrationTime is a wall-clock overestimate, as it does\n // not take time slicing into account. The view-syncer resets this\n // to a more precise processing-time measurement with setHydrationTime().\n this.#pipelines.set(transformationHash, {\n input,\n hydrationTimeMs,\n originalHash: queryID,\n transformedAst: query,\n transformationHash,\n });\n }\n\n /**\n * Removes the pipeline for the query. This is a no-op if the query\n * was not added.\n */\n removeQuery(hash: string) {\n const pipeline = this.#pipelines.get(hash);\n if (pipeline) {\n this.#pipelines.delete(hash);\n pipeline.input.destroy();\n }\n }\n\n /**\n * Returns the value of the row with the given primary key `pk`,\n * or `undefined` if there is no such row. The pipeline must have been\n * initialized.\n */\n getRow(table: string, pk: RowKey): Row | undefined {\n assert(this.initialized(), 'Not yet initialized');\n const source = must(this.#tables.get(table));\n return source.getRow(pk as Row);\n }\n\n /**\n * Advances to the new head of the database.\n *\n * @param timer The caller-controlled {@link Timer} that will be used to\n * measure the progress of the advancement and abort with a\n * {@link ResetPipelinesSignal} if it is estimated to take longer\n * than a hydration.\n * @return The resulting row changes for all added queries. Note that the\n * `changes` must be iterated over in their entirety in order to\n * advance the database snapshot.\n */\n advance(timer: {totalElapsed: () => number}): {\n version: string;\n numChanges: number;\n changes: Iterable<RowChange>;\n } {\n assert(this.initialized());\n const diff = this.#snapshotter.advance(this.#tableSpecs);\n const {prev, curr, changes} = diff;\n this.#lc.debug?.(\n `advance ${prev.version} => ${curr.version}: ${changes} changes`,\n );\n\n return {\n version: curr.version,\n numChanges: changes,\n changes: this.#advance(diff, timer, changes),\n };\n }\n\n *#advance(\n diff: SnapshotDiff,\n timer: {totalElapsed: () => number},\n numChanges: number,\n ): Iterable<RowChange> {\n this.#advanceContext = {\n timer,\n totalHydrationTimeMs: this.totalHydrationTimeMs(),\n numChanges,\n advanceCheckCount: 0,\n pos: 0,\n };\n try {\n for (const {table, prevValues, nextValue} of diff) {\n this.#checkAdvanceProgress();\n const start = performance.now();\n let type;\n try {\n const tableSource = this.#tables.get(table);\n if (!tableSource) {\n // no pipelines read from this table, so no need to process the change\n continue;\n }\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n let editOldRow: Row | undefined = undefined;\n for (const prevValue of prevValues) {\n if (\n nextValue &&\n deepEqual(\n getRowKey(primaryKey, prevValue as Row) as JSONValue,\n getRowKey(primaryKey, nextValue as Row) as JSONValue,\n )\n ) {\n editOldRow = prevValue;\n } else {\n if (nextValue) {\n this.#conflictRowsDeleted.add(1);\n }\n yield* this.#push(tableSource, {\n type: 'remove',\n row: prevValue,\n });\n }\n }\n if (nextValue) {\n if (editOldRow) {\n yield* this.#push(tableSource, {\n type: 'edit',\n row: nextValue,\n oldRow: editOldRow,\n });\n } else {\n yield* this.#push(tableSource, {\n type: 'add',\n row: nextValue,\n });\n }\n }\n } finally {\n this.#advanceContext.pos++;\n }\n\n const elapsed = performance.now() - start;\n this.#advanceTime.record(elapsed / 1000, {\n table,\n type,\n });\n }\n\n // Set the new snapshot on all TableSources.\n const {curr} = diff;\n for (const table of this.#tables.values()) {\n table.setDB(curr.db.db);\n }\n this.#ensureCostModelExistsIfEnabled(curr.db.db);\n this.#lc.debug?.(`Advanced to ${curr.version}`);\n } finally {\n this.#advanceContext = null;\n }\n }\n\n #checkAdvanceProgress() {\n // Cancel the advancement processing if it takes longer than half the\n // total hydration time to make it through half of the advancement, or\n // if processing time exceeds total hydration time.\n // This serves as both a circuit breaker for very large transactions,\n // as well as a bound on the amount of time the previous connection locks\n // the inactive WAL file (as the lock prevents WAL2 from switching to the\n // free WAL when the current one is over the size limit, which can make\n // the WAL grow continuously and compound slowness).\n assert(this.#advanceContext !== null);\n // Reduce the overhead of checking the timer by only\n // actually checking on the first and then every 10th call to\n // checkAdvanceProgress\n if (this.#advanceContext.advanceCheckCount++ % 10 === 0) {\n return;\n }\n const {\n pos,\n numChanges,\n timer: advanceTimer,\n totalHydrationTimeMs,\n } = this.#advanceContext;\n const elapsed = advanceTimer.totalElapsed();\n if (\n elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS &&\n (elapsed > totalHydrationTimeMs ||\n (elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2))\n ) {\n throw new ResetPipelinesSignal(\n `Advancement exceeded timeout at ${pos} of ${numChanges} changes after ${elapsed} ms. Advancement time limited based on total hydration time of ${totalHydrationTimeMs} ms.`,\n );\n }\n }\n\n /** Implements `BuilderDelegate.getSource()` */\n #getSource(tableName: string): Source {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(this.#tableSpecs, tableName);\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, tableName);\n\n const {db} = this.#snapshotter.current();\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n db.db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n );\n this.#tables.set(tableName, source);\n this.#lc.debug?.(`created TableSource for ${tableName}`);\n return source;\n }\n\n /** Implements `BuilderDelegate.createStorage()` */\n #createStorage(): Storage {\n return this.#storage.createStorage();\n }\n\n *#push(source: TableSource, change: SourceChange): Iterable<RowChange> {\n this.#startAccumulating();\n try {\n for (const _ of source.genPush(change)) {\n yield* this.#stopAccumulating().stream();\n this.#startAccumulating();\n }\n } finally {\n if (this.#streamer !== null) {\n this.#stopAccumulating();\n }\n }\n }\n\n #startAccumulating() {\n assert(this.#streamer === null);\n this.#streamer = new Streamer(must(this.#primaryKeys));\n }\n\n #stopAccumulating(): Streamer {\n const streamer = this.#streamer;\n assert(streamer);\n this.#streamer = null;\n return streamer;\n }\n}\n\nclass Streamer {\n readonly #primaryKeys: Map<string, PrimaryKey>;\n\n constructor(primaryKeys: Map<string, PrimaryKey>) {\n this.#primaryKeys = primaryKeys;\n }\n\n readonly #changes: [\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change>,\n ][] = [];\n\n accumulate(\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change>,\n ): this {\n this.#changes.push([hash, schema, changes]);\n return this;\n }\n\n *stream(): Iterable<RowChange> {\n for (const [hash, schema, changes] of this.#changes) {\n yield* this.#streamChanges(hash, schema, changes);\n }\n }\n\n *#streamChanges(\n queryHash: string,\n schema: SourceSchema,\n changes: Iterable<Change>,\n ): Iterable<RowChange> {\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (schema.system === 'permissions') {\n return;\n }\n\n for (const change of changes) {\n const {type} = change;\n\n switch (type) {\n case 'add':\n case 'remove': {\n yield* this.#streamNodes(queryHash, schema, type, () => [\n change.node,\n ]);\n break;\n }\n case 'child': {\n const {child} = change;\n const childSchema = must(\n schema.relationships[child.relationshipName],\n );\n\n yield* this.#streamChanges(queryHash, childSchema, [child.change]);\n break;\n }\n case 'edit':\n yield* this.#streamNodes(queryHash, schema, type, () => [\n {row: change.node.row, relationships: {}},\n ]);\n break;\n default:\n unreachable(type);\n }\n }\n }\n\n *#streamNodes(\n queryHash: string,\n schema: SourceSchema,\n op: 'add' | 'remove' | 'edit',\n nodes: () => Iterable<Node>,\n ): Iterable<RowChange> {\n const {tableName: table, system} = schema;\n\n const primaryKey = must(this.#primaryKeys.get(table));\n\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (system === 'permissions') {\n return;\n }\n\n for (const node of nodes()) {\n const {relationships, row} = node;\n const rowKey = getRowKey(primaryKey, row);\n\n yield {\n type: op,\n queryHash,\n table,\n rowKey,\n row: op === 'remove' ? undefined : row,\n } as RowChange;\n\n for (const [relationship, children] of Object.entries(relationships)) {\n const childSchema = must(schema.relationships[relationship]);\n yield* this.#streamNodes(queryHash, childSchema, op, children);\n }\n }\n }\n}\n\nfunction* toAdds(nodes: Iterable<Node>): Iterable<Change> {\n for (const node of nodes) {\n yield {type: 'add', node};\n }\n}\n\nfunction getRowKey(cols: PrimaryKey, row: Row): RowKey {\n return Object.fromEntries(cols.map(col => [col, must(row[col])]));\n}\n\n/**\n * Core hydration logic used by {@link PipelineDriver#addQuery}, extracted to a\n * function for reuse by bin-analyze so that bin-analyze's hydration logic\n * is as close as possible to zero-cache's real hydration logic.\n */\nexport function* hydrate(\n input: Input,\n hash: string,\n clientSchema: ClientSchema,\n) {\n const res = input.fetch({});\n const streamer = new Streamer(buildPrimaryKeys(clientSchema)).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nexport function* hydrateInternal(\n input: Input,\n hash: string,\n primaryKeys: Map<string, PrimaryKey>,\n) {\n const res = input.fetch({});\n const streamer = new Streamer(primaryKeys).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nfunction buildPrimaryKeys(\n clientSchema: ClientSchema,\n primaryKeys: Map<string, PrimaryKey> = new Map<string, PrimaryKey>(),\n) {\n for (const [tableName, {primaryKey}] of Object.entries(clientSchema.tables)) {\n primaryKeys.set(tableName, primaryKey as unknown as PrimaryKey);\n }\n return primaryKeys;\n}\n\nfunction mustGetPrimaryKey(\n primaryKeys: Map<string, PrimaryKey> | null,\n table: string,\n): PrimaryKey {\n const pKeys = must(primaryKeys, 'primaryKey map must be non-null');\n\n return must(\n pKeys.get(table),\n `table '${table}' is not one of: ${[...pKeys.keys()].sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n}\n"],"names":["input"],"mappings":"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"}
1
+ {"version":3,"file":"pipeline-driver.js","sources":["../../../../../../zero-cache/src/services/view-syncer/pipeline-driver.ts"],"sourcesContent":["import type {LogContext} from '@rocicorp/logger';\nimport {assert, unreachable} from '../../../../shared/src/asserts.ts';\nimport {deepEqual, type JSONValue} from '../../../../shared/src/json.ts';\nimport {must} from '../../../../shared/src/must.ts';\nimport type {AST} from '../../../../zero-protocol/src/ast.ts';\nimport type {ClientSchema} from '../../../../zero-protocol/src/client-schema.ts';\nimport type {Row} from '../../../../zero-protocol/src/data.ts';\nimport type {PrimaryKey} from '../../../../zero-protocol/src/primary-key.ts';\nimport {buildPipeline} from '../../../../zql/src/builder/builder.ts';\nimport {\n Debug,\n runtimeDebugFlags,\n} from '../../../../zql/src/builder/debug-delegate.ts';\nimport type {Change} from '../../../../zql/src/ivm/change.ts';\nimport type {Node} from '../../../../zql/src/ivm/data.ts';\nimport {type Input, type Storage} from '../../../../zql/src/ivm/operator.ts';\nimport type {SourceSchema} from '../../../../zql/src/ivm/schema.ts';\nimport type {\n Source,\n SourceChange,\n SourceInput,\n} from '../../../../zql/src/ivm/source.ts';\nimport type {ConnectionCostModel} from '../../../../zql/src/planner/planner-connection.ts';\nimport {MeasurePushOperator} from '../../../../zql/src/query/measure-push-operator.ts';\nimport type {ClientGroupStorage} from '../../../../zqlite/src/database-storage.ts';\nimport type {Database} from '../../../../zqlite/src/db.ts';\nimport {createSQLiteCostModel} from '../../../../zqlite/src/sqlite-cost-model.ts';\nimport {TableSource} from '../../../../zqlite/src/table-source.ts';\nimport {\n reloadPermissionsIfChanged,\n type LoadedPermissions,\n} from '../../auth/load-permissions.ts';\nimport type {LogConfig} from '../../config/zero-config.ts';\nimport {computeZqlSpecs, mustGetTableSpec} from '../../db/lite-tables.ts';\nimport type {LiteAndZqlSpec, LiteTableSpec} from '../../db/specs.ts';\nimport {\n getOrCreateCounter,\n getOrCreateHistogram,\n} from '../../observability/metrics.ts';\nimport type {InspectorDelegate} from '../../server/inspector-delegate.ts';\nimport {type RowKey} from '../../types/row-key.ts';\nimport type {SchemaVersions} from '../../types/schema-versions.ts';\nimport {upstreamSchema, type ShardID} from '../../types/shards.ts';\nimport {getSubscriptionState} from '../replicator/schema/replication-state.ts';\nimport {checkClientSchema} from './client-schema.ts';\nimport type {Snapshotter} from './snapshotter.ts';\nimport {ResetPipelinesSignal, type SnapshotDiff} from './snapshotter.ts';\n\nexport type RowAdd = {\n readonly type: 'add';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowRemove = {\n readonly type: 'remove';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: undefined;\n};\n\nexport type RowEdit = {\n readonly type: 'edit';\n readonly queryHash: string;\n readonly table: string;\n readonly rowKey: Row;\n readonly row: Row;\n};\n\nexport type RowChange = RowAdd | RowRemove | RowEdit;\n\ntype Pipeline = {\n readonly input: Input;\n readonly hydrationTimeMs: number;\n readonly originalHash: string;\n readonly transformedAst: AST; // Optional, only set after hydration\n readonly transformationHash: string; // The hash of the transformed AST\n};\n\ntype AdvanceContext = {\n readonly timer: {totalElapsed: () => number};\n readonly totalHydrationTimeMs: number;\n readonly numChanges: number;\n pos: number;\n};\n\ntype HydrateContext = {\n readonly timer: {elapsedLap: () => number};\n};\n\n/**\n * No matter how fast hydration is, advancement is given at least this long to\n * complete before doing a pipeline reset.\n */\nconst MIN_ADVANCEMENT_TIME_LIMIT_MS = 30;\nexport const HYDRATE_YIELD_THRESHOLD_MS = 200;\n\n/**\n * Manages the state of IVM pipelines for a given ViewSyncer (i.e. client group).\n */\nexport class PipelineDriver {\n readonly #tables = new Map<string, TableSource>();\n // We probs need the original query hash\n // so we can decide not to re-transform a custom query\n // that is already hydrated.\n readonly #pipelines = new Map<string, Pipeline>();\n\n readonly #lc: LogContext;\n readonly #snapshotter: Snapshotter;\n readonly #storage: ClientGroupStorage;\n readonly #shardID: ShardID;\n readonly #logConfig: LogConfig;\n readonly #tableSpecs = new Map<string, LiteAndZqlSpec>();\n readonly #costModels: WeakMap<Database, ConnectionCostModel> | undefined;\n #streamer: Streamer | null = null;\n #hydrateContext: HydrateContext | null = null;\n #advanceContext: AdvanceContext | null = null;\n #replicaVersion: string | null = null;\n #primaryKeys: Map<string, PrimaryKey> | null = null;\n #permissions: LoadedPermissions | null = null;\n\n readonly #advanceTime = getOrCreateHistogram('sync', 'ivm.advance-time', {\n description:\n 'Time to advance all queries for a given client group for in response to a single change.',\n unit: 's',\n });\n\n readonly #conflictRowsDeleted = getOrCreateCounter(\n 'sync',\n 'ivm.conflict-rows-deleted',\n 'Number of rows deleted because they conflicted with added row',\n );\n\n readonly #inspectorDelegate: InspectorDelegate;\n\n constructor(\n lc: LogContext,\n logConfig: LogConfig,\n snapshotter: Snapshotter,\n shardID: ShardID,\n storage: ClientGroupStorage,\n clientGroupID: string,\n inspectorDelegate: InspectorDelegate,\n enablePlanner?: boolean,\n ) {\n this.#lc = lc.withContext('clientGroupID', clientGroupID);\n this.#snapshotter = snapshotter;\n this.#storage = storage;\n this.#shardID = shardID;\n this.#logConfig = logConfig;\n this.#inspectorDelegate = inspectorDelegate;\n this.#costModels = enablePlanner ? new WeakMap() : undefined;\n }\n\n /**\n * Initializes the PipelineDriver to the current head of the database.\n * Queries can then be added (i.e. hydrated) with {@link addQuery()}.\n *\n * Must only be called once.\n */\n init(clientSchema: ClientSchema) {\n assert(!this.#snapshotter.initialized(), 'Already initialized');\n this.#snapshotter.init();\n this.#initAndResetCommon(clientSchema);\n }\n\n /**\n * @returns Whether the PipelineDriver has been initialized.\n */\n initialized(): boolean {\n return this.#snapshotter.initialized();\n }\n\n /**\n * Clears the current pipelines and TableSources, returning the PipelineDriver\n * to its initial state. This should be called in response to a schema change,\n * as TableSources need to be recomputed.\n */\n reset(clientSchema: ClientSchema) {\n for (const {input} of this.#pipelines.values()) {\n input.destroy();\n }\n this.#pipelines.clear();\n this.#tables.clear();\n this.#initAndResetCommon(clientSchema);\n }\n\n #initAndResetCommon(clientSchema: ClientSchema) {\n const {db} = this.#snapshotter.current();\n const fullTables = new Map<string, LiteTableSpec>();\n computeZqlSpecs(this.#lc, db.db, this.#tableSpecs, fullTables);\n checkClientSchema(\n this.#shardID,\n clientSchema,\n this.#tableSpecs,\n fullTables,\n );\n const primaryKeys = this.#primaryKeys ?? new Map<string, PrimaryKey>();\n this.#primaryKeys = primaryKeys;\n primaryKeys.clear();\n for (const [table, spec] of this.#tableSpecs.entries()) {\n if (table.startsWith(upstreamSchema(this.#shardID))) {\n primaryKeys.set(table, spec.tableSpec.primaryKey);\n }\n }\n buildPrimaryKeys(clientSchema, primaryKeys);\n const {replicaVersion} = getSubscriptionState(db);\n this.#replicaVersion = replicaVersion;\n }\n\n /** @returns The replica version. The PipelineDriver must have been initialized. */\n get replicaVersion(): string {\n return must(this.#replicaVersion, 'Not yet initialized');\n }\n\n /**\n * Returns the current version of the database. This will reflect the\n * latest version change when calling {@link advance()} once the\n * iteration has begun.\n */\n currentVersion(): string {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().version;\n }\n\n /**\n * Returns the current supported schema version range of the database. This\n * will reflect changes to supported schema version range when calling\n * {@link advance()} once the iteration has begun.\n */\n currentSchemaVersions(): SchemaVersions {\n assert(this.initialized(), 'Not yet initialized');\n return this.#snapshotter.current().schemaVersions;\n }\n\n /**\n * Returns the current upstream {app}.permissions, or `null` if none are defined.\n */\n currentPermissions(): LoadedPermissions | null {\n assert(this.initialized(), 'Not yet initialized');\n const res = reloadPermissionsIfChanged(\n this.#lc,\n this.#snapshotter.current().db,\n this.#shardID.appID,\n this.#permissions,\n );\n if (res.changed) {\n this.#permissions = res.permissions;\n this.#lc.debug?.(\n 'Reloaded permissions',\n JSON.stringify(this.#permissions),\n );\n }\n return this.#permissions;\n }\n\n advanceWithoutDiff(): string {\n const {db, version} = this.#snapshotter.advanceWithoutDiff().curr;\n for (const table of this.#tables.values()) {\n table.setDB(db.db);\n }\n return version;\n }\n\n #ensureCostModelExistsIfEnabled(db: Database) {\n let existing = this.#costModels?.get(db);\n if (existing) {\n return existing;\n }\n if (this.#costModels) {\n const costModel = createSQLiteCostModel(db, this.#tableSpecs);\n this.#costModels.set(db, costModel);\n return costModel;\n }\n return undefined;\n }\n\n /**\n * Clears storage used for the pipelines. Call this when the\n * PipelineDriver will no longer be used.\n */\n destroy() {\n this.#storage.destroy();\n this.#snapshotter.destroy();\n }\n\n /** @return The Set of query hashes for all added queries. */\n addedQueries(): [\n transformationHashes: Set<string>,\n byOriginalHash: Map<\n string,\n {\n transformationHash: string;\n transformedAst: AST;\n }[]\n >,\n ] {\n const byOriginalHash = new Map<\n string,\n {transformationHash: string; transformedAst: AST}[]\n >();\n for (const pipeline of this.#pipelines.values()) {\n const {originalHash, transformedAst, transformationHash} = pipeline;\n\n if (!byOriginalHash.has(originalHash)) {\n byOriginalHash.set(originalHash, []);\n }\n byOriginalHash.get(originalHash)!.push({\n transformationHash,\n transformedAst,\n });\n }\n return [new Set(this.#pipelines.keys()), byOriginalHash];\n }\n\n totalHydrationTimeMs(): number {\n let total = 0;\n for (const pipeline of this.#pipelines.values()) {\n total += pipeline.hydrationTimeMs;\n }\n return total;\n }\n\n /**\n * Adds a pipeline for the query. The method will hydrate the query using the\n * driver's current snapshot of the database and return a stream of results.\n * Henceforth, updates to the query will be returned when the driver is\n * {@link advance}d. The query and its pipeline can be removed with\n * {@link removeQuery()}.\n *\n * If a query with an identical hash has already been added, this method is a\n * no-op and no RowChanges are generated.\n *\n * @param timer The caller-controlled {@link Timer} used to determine the\n * final hydration time. (The caller may pause and resume the timer\n * when yielding the thread for time-slicing).\n * @return The rows from the initial hydration of the query.\n */\n *addQuery(\n transformationHash: string,\n queryID: string,\n query: AST,\n timer: {totalElapsed: () => number; elapsedLap: () => number},\n ): Iterable<RowChange | 'yield'> {\n assert(this.initialized());\n this.#inspectorDelegate.addQuery(transformationHash, queryID, query);\n if (this.#pipelines.has(transformationHash)) {\n this.#lc.info?.(`query ${transformationHash} already added`, query);\n return;\n }\n const debugDelegate = runtimeDebugFlags.trackRowsVended\n ? new Debug()\n : undefined;\n\n const costModel = this.#ensureCostModelExistsIfEnabled(\n this.#snapshotter.current().db.db,\n );\n\n const input = buildPipeline(\n query,\n {\n debug: debugDelegate,\n enableNotExists: true, // Server-side can handle NOT EXISTS\n getSource: name => this.#getSource(name),\n createStorage: () => this.#createStorage(),\n decorateSourceInput: (input: SourceInput, _queryID: string): Input =>\n new MeasurePushOperator(\n input,\n transformationHash,\n this.#inspectorDelegate,\n 'query-update-server',\n ),\n decorateInput: input => input,\n addEdge() {},\n decorateFilterInput: input => input,\n },\n queryID,\n costModel,\n );\n const schema = input.getSchema();\n input.setOutput({\n push: change => {\n const streamer = this.#streamer;\n assert(streamer, 'must #startAccumulating() before pushing changes');\n streamer.accumulate(transformationHash, schema, [change]);\n },\n });\n\n assert(this.#advanceContext === null);\n this.#hydrateContext = {\n timer,\n };\n try {\n yield* hydrateInternal(\n input,\n transformationHash,\n must(this.#primaryKeys),\n );\n } finally {\n this.#hydrateContext = null;\n }\n\n const hydrationTimeMs = timer.totalElapsed();\n if (runtimeDebugFlags.trackRowCountsVended) {\n if (hydrationTimeMs > this.#logConfig.slowHydrateThreshold) {\n let totalRowsConsidered = 0;\n const lc = this.#lc\n .withContext('hash', transformationHash)\n .withContext('hydrationTimeMs', hydrationTimeMs);\n for (const tableName of this.#tables.keys()) {\n const entries = Object.entries(\n debugDelegate?.getVendedRowCounts()[tableName] ?? {},\n );\n totalRowsConsidered += entries.reduce(\n (acc, entry) => acc + entry[1],\n 0,\n );\n lc.info?.(tableName + ' VENDED: ', entries);\n }\n lc.info?.(`Total rows considered: ${totalRowsConsidered}`);\n }\n }\n debugDelegate?.reset();\n\n // Note: This hydrationTime is a wall-clock overestimate, as it does\n // not take time slicing into account. The view-syncer resets this\n // to a more precise processing-time measurement with setHydrationTime().\n this.#pipelines.set(transformationHash, {\n input,\n hydrationTimeMs,\n originalHash: queryID,\n transformedAst: query,\n transformationHash,\n });\n }\n\n /**\n * Removes the pipeline for the query. This is a no-op if the query\n * was not added.\n */\n removeQuery(hash: string) {\n const pipeline = this.#pipelines.get(hash);\n if (pipeline) {\n this.#pipelines.delete(hash);\n pipeline.input.destroy();\n }\n }\n\n /**\n * Returns the value of the row with the given primary key `pk`,\n * or `undefined` if there is no such row. The pipeline must have been\n * initialized.\n */\n getRow(table: string, pk: RowKey): Row | undefined {\n assert(this.initialized(), 'Not yet initialized');\n const source = must(this.#tables.get(table));\n return source.getRow(pk as Row);\n }\n\n /**\n * Advances to the new head of the database.\n *\n * @param timer The caller-controlled {@link Timer} that will be used to\n * measure the progress of the advancement and abort with a\n * {@link ResetPipelinesSignal} if it is estimated to take longer\n * than a hydration.\n * @return The resulting row changes for all added queries. Note that the\n * `changes` must be iterated over in their entirety in order to\n * advance the database snapshot.\n */\n advance(timer: {totalElapsed: () => number}): {\n version: string;\n numChanges: number;\n changes: Iterable<RowChange>;\n } {\n assert(this.initialized());\n const diff = this.#snapshotter.advance(this.#tableSpecs);\n const {prev, curr, changes} = diff;\n this.#lc.debug?.(\n `advance ${prev.version} => ${curr.version}: ${changes} changes`,\n );\n\n return {\n version: curr.version,\n numChanges: changes,\n changes: this.#advance(diff, timer, changes),\n };\n }\n\n *#advance(\n diff: SnapshotDiff,\n timer: {totalElapsed: () => number},\n numChanges: number,\n ): Iterable<RowChange> {\n assert(this.#hydrateContext === null);\n this.#advanceContext = {\n timer,\n totalHydrationTimeMs: this.totalHydrationTimeMs(),\n numChanges,\n pos: 0,\n };\n try {\n for (const {table, prevValues, nextValue} of diff) {\n // Advance progress is checked each time a row is fetched\n // from a TableSource during push processing, but some pushes\n // don't read any rows. Check progress here before processing\n // the next change.\n this.#checkAdvanceProgress();\n const start = performance.now();\n let type;\n try {\n const tableSource = this.#tables.get(table);\n if (!tableSource) {\n // no pipelines read from this table, so no need to process the change\n continue;\n }\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, table);\n let editOldRow: Row | undefined = undefined;\n for (const prevValue of prevValues) {\n if (\n nextValue &&\n deepEqual(\n getRowKey(primaryKey, prevValue as Row) as JSONValue,\n getRowKey(primaryKey, nextValue as Row) as JSONValue,\n )\n ) {\n editOldRow = prevValue;\n } else {\n if (nextValue) {\n this.#conflictRowsDeleted.add(1);\n }\n yield* this.#push(tableSource, {\n type: 'remove',\n row: prevValue,\n });\n }\n }\n if (nextValue) {\n if (editOldRow) {\n yield* this.#push(tableSource, {\n type: 'edit',\n row: nextValue,\n oldRow: editOldRow,\n });\n } else {\n yield* this.#push(tableSource, {\n type: 'add',\n row: nextValue,\n });\n }\n }\n } finally {\n this.#advanceContext.pos++;\n }\n\n const elapsed = performance.now() - start;\n this.#advanceTime.record(elapsed / 1000, {\n table,\n type,\n });\n }\n\n // Set the new snapshot on all TableSources.\n const {curr} = diff;\n for (const table of this.#tables.values()) {\n table.setDB(curr.db.db);\n }\n this.#ensureCostModelExistsIfEnabled(curr.db.db);\n this.#lc.debug?.(`Advanced to ${curr.version}`);\n } finally {\n this.#advanceContext = null;\n }\n }\n\n /** Implements `BuilderDelegate.getSource()` */\n #getSource(tableName: string): Source {\n let source = this.#tables.get(tableName);\n if (source) {\n return source;\n }\n\n const tableSpec = mustGetTableSpec(this.#tableSpecs, tableName);\n const primaryKey = mustGetPrimaryKey(this.#primaryKeys, tableName);\n\n const {db} = this.#snapshotter.current();\n source = new TableSource(\n this.#lc,\n this.#logConfig,\n db.db,\n tableName,\n tableSpec.zqlSpec,\n primaryKey,\n () => this.#shouldYield(),\n );\n this.#tables.set(tableName, source);\n this.#lc.debug?.(`created TableSource for ${tableName}`);\n return source;\n }\n\n #shouldYield(): boolean {\n if (this.#hydrateContext) {\n return (\n this.#hydrateContext.timer.elapsedLap() > HYDRATE_YIELD_THRESHOLD_MS\n );\n }\n if (this.#advanceContext) {\n this.#checkAdvanceProgress();\n }\n return false;\n }\n\n /**\n * Cancel the advancement processing, by throwing a ResetPipelinesSignal, if\n * it has taken longer than half the total hydration time to make it through\n * half of the advancement, or if processing time exceeds total hydration\n * time. This serves as both a circuit breaker for very large transactions,\n * as well as a bound on the amount of time the previous connection locks\n * the inactive WAL file (as the lock prevents WAL2 from switching to the\n * free WAL when the current one is over the size limit, which can make\n * the WAL grow continuously and compound slowness).\n * This is checked:\n * 1. before starting to process each change in an advancement is processed\n * 2. whenever a row is fetched from a TableSource during push processing\n */\n #checkAdvanceProgress() {\n const {\n pos,\n numChanges,\n timer: advanceTimer,\n totalHydrationTimeMs,\n } = must(this.#advanceContext);\n const elapsed = advanceTimer.totalElapsed();\n if (\n elapsed > MIN_ADVANCEMENT_TIME_LIMIT_MS &&\n (elapsed > totalHydrationTimeMs ||\n (elapsed > totalHydrationTimeMs / 2 && pos <= numChanges / 2))\n ) {\n throw new ResetPipelinesSignal(\n `Advancement exceeded timeout at ${pos} of ${numChanges} changes ` +\n `after ${elapsed} ms. Advancement time limited based on total ` +\n `hydration time of ${totalHydrationTimeMs} ms.`,\n );\n }\n }\n\n /** Implements `BuilderDelegate.createStorage()` */\n #createStorage(): Storage {\n return this.#storage.createStorage();\n }\n\n *#push(source: TableSource, change: SourceChange): Iterable<RowChange> {\n this.#startAccumulating();\n try {\n for (const _ of source.genPush(change)) {\n for (const change of this.#stopAccumulating().stream()) {\n // PipelineDriver's shouldYield implementation never yields during\n // push processing, so we can assert that we never see a 'yield'\n // here.\n assert(change !== 'yield');\n yield change;\n }\n this.#startAccumulating();\n }\n } finally {\n if (this.#streamer !== null) {\n this.#stopAccumulating();\n }\n }\n }\n\n #startAccumulating() {\n assert(this.#streamer === null);\n this.#streamer = new Streamer(must(this.#primaryKeys));\n }\n\n #stopAccumulating(): Streamer {\n const streamer = this.#streamer;\n assert(streamer);\n this.#streamer = null;\n return streamer;\n }\n}\n\nclass Streamer {\n readonly #primaryKeys: Map<string, PrimaryKey>;\n\n constructor(primaryKeys: Map<string, PrimaryKey>) {\n this.#primaryKeys = primaryKeys;\n }\n\n readonly #changes: [\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ][] = [];\n\n accumulate(\n hash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): this {\n this.#changes.push([hash, schema, changes]);\n return this;\n }\n\n *stream(): Iterable<RowChange | 'yield'> {\n for (const [hash, schema, changes] of this.#changes) {\n yield* this.#streamChanges(hash, schema, changes);\n }\n }\n\n *#streamChanges(\n queryHash: string,\n schema: SourceSchema,\n changes: Iterable<Change | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (schema.system === 'permissions') {\n return;\n }\n\n for (const change of changes) {\n if (change === 'yield') {\n yield change;\n continue;\n }\n const {type} = change;\n\n switch (type) {\n case 'add':\n case 'remove': {\n yield* this.#streamNodes(queryHash, schema, type, () => [\n change.node,\n ]);\n break;\n }\n case 'child': {\n const {child} = change;\n const childSchema = must(\n schema.relationships[child.relationshipName],\n );\n\n yield* this.#streamChanges(queryHash, childSchema, [child.change]);\n break;\n }\n case 'edit':\n yield* this.#streamNodes(queryHash, schema, type, () => [\n {row: change.node.row, relationships: {}},\n ]);\n break;\n default:\n unreachable(type);\n }\n }\n }\n\n *#streamNodes(\n queryHash: string,\n schema: SourceSchema,\n op: 'add' | 'remove' | 'edit',\n nodes: () => Iterable<Node | 'yield'>,\n ): Iterable<RowChange | 'yield'> {\n const {tableName: table, system} = schema;\n\n const primaryKey = must(this.#primaryKeys.get(table));\n\n // We do not sync rows gathered by the permissions\n // system to the client.\n if (system === 'permissions') {\n return;\n }\n\n for (const node of nodes()) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n const {relationships, row} = node;\n const rowKey = getRowKey(primaryKey, row);\n\n yield {\n type: op,\n queryHash,\n table,\n rowKey,\n row: op === 'remove' ? undefined : row,\n } as RowChange;\n\n for (const [relationship, children] of Object.entries(relationships)) {\n const childSchema = must(schema.relationships[relationship]);\n yield* this.#streamNodes(queryHash, childSchema, op, children);\n }\n }\n }\n}\n\nfunction* toAdds(nodes: Iterable<Node | 'yield'>): Iterable<Change | 'yield'> {\n for (const node of nodes) {\n if (node === 'yield') {\n yield node;\n continue;\n }\n yield {type: 'add', node};\n }\n}\n\nfunction getRowKey(cols: PrimaryKey, row: Row): RowKey {\n return Object.fromEntries(cols.map(col => [col, must(row[col])]));\n}\n\n/**\n * Core hydration logic used by {@link PipelineDriver#addQuery}, extracted to a\n * function for reuse by bin-analyze so that bin-analyze's hydration logic\n * is as close as possible to zero-cache's real hydration logic.\n */\nexport function* hydrate(\n input: Input,\n hash: string,\n clientSchema: ClientSchema,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(buildPrimaryKeys(clientSchema)).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nexport function* hydrateInternal(\n input: Input,\n hash: string,\n primaryKeys: Map<string, PrimaryKey>,\n): Iterable<RowChange | 'yield'> {\n const res = input.fetch({});\n const streamer = new Streamer(primaryKeys).accumulate(\n hash,\n input.getSchema(),\n toAdds(res),\n );\n yield* streamer.stream();\n}\n\nfunction buildPrimaryKeys(\n clientSchema: ClientSchema,\n primaryKeys: Map<string, PrimaryKey> = new Map<string, PrimaryKey>(),\n) {\n for (const [tableName, {primaryKey}] of Object.entries(clientSchema.tables)) {\n primaryKeys.set(tableName, primaryKey as unknown as PrimaryKey);\n }\n return primaryKeys;\n}\n\nfunction mustGetPrimaryKey(\n primaryKeys: Map<string, PrimaryKey> | null,\n table: string,\n): PrimaryKey {\n const pKeys = must(primaryKeys, 'primaryKey map must be non-null');\n\n return must(\n pKeys.get(table),\n `table '${table}' is not one of: ${[...pKeys.keys()].sort()}. ` +\n `Check the spelling and ensure that the table has a primary key.`,\n );\n}\n"],"names":["input","change"],"mappings":"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"}
@@ -83,7 +83,7 @@ export declare class TimeSliceTimer {
83
83
  #private;
84
84
  start(): Promise<this>;
85
85
  startWithoutYielding(): this;
86
- yieldProcess(): Promise<void>;
86
+ yieldProcess(_msgForTesting?: string): Promise<void>;
87
87
  elapsedLap(): number;
88
88
  /** @returns the total elapsed time */
89
89
  stop(): number;
@@ -1 +1 @@
1
- {"version":3,"file":"view-syncer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/view-syncer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;AAcrC,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,yDAAyD,CAAC;AACzG,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,iDAAiD,CAAC;AAC1F,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uCAAuC,CAAC;AAOtE,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,6CAA6C,CAAC;AAMrD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAEpE,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yCAAyC,CAAC;AAOpF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oCAAoC,CAAC;AAK1E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAiBxD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAuBzD,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAMF,MAAM,WAAW,UAAU;IACzB,cAAc,CACZ,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,qBAAqB,GACzB,MAAM,CAAC,UAAU,CAAC,CAAC;IAEtB,oBAAoB,CAClB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,2BAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAQD,KAAK,UAAU,GAAG,CAChB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAChC,KAAK,CAAC,EAAE,MAAM,KACX,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAEnC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,qBAAa,iBAAkB,YAAW,UAAU,EAAE,oBAAoB;;IACxE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAUpB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;gBAsHhC,MAAM,EAAE,oBAAoB,EAC5B,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,YAAY,CAAC,YAAY,CAAC,EAC1C,gBAAgB,EAAE,gBAAgB,EAClC,oBAAoB,EAAE,MAAM,EAC5B,iBAAiB,EAAE,iBAAiB,EACpC,sBAAsB,EAAE,sBAAsB,GAAG,SAAS,EAC1D,WAAW,SAAuB,EAClC,YAAY,GAAE,UAAwC;IA2FxD,UAAU,IAAI,OAAO,CAAC,aAAa,GAAG,UAAU,CAAC;IAO3C,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAqH1B;;;;;;;;OAQG;IACH,SAAS,IAAI,OAAO;IAwEpB,cAAc,CACZ,GAAG,EAAE,WAAW,EAChB,qBAAqB,EAAE,qBAAqB,GAC3C,MAAM,CAAC,UAAU,CAAC;IA4Gf,oBAAoB,CACxB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,2BAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC;IAIV,aAAa,CACjB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,IAAI,CAAC;IAuuChB,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBrB;;;OAGG;IACH,eAAe;CAGhB;AA+ED,wBAAgB,SAAS,CACvB,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,SAAS,GAAG,SAAS,EACpC,QAAQ,EAAE,SAAS,GAAG,SAAS,yBAkDhC;AAyCD,qBAAa,cAAc;;IAInB,KAAK;IAOX,oBAAoB;IAMd,YAAY;IAWlB,UAAU;IAWV,sCAAsC;IACtC,IAAI,IAAI,MAAM;IAKd;;;OAGG;IACH,YAAY,IAAI,MAAM;CAKvB"}
1
+ {"version":3,"file":"view-syncer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/view-syncer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAEjD,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,MAAM,CAAC;AAcrC,OAAO,KAAK,EAAC,2BAA2B,EAAC,MAAM,yDAAyD,CAAC;AACzG,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,0CAA0C,CAAC;AAElD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,iDAAiD,CAAC;AAC1F,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,uCAAuC,CAAC;AAOtE,OAAO,KAAK,EAEV,gBAAgB,EACjB,MAAM,6CAA6C,CAAC;AAMrD,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,2BAA2B,CAAC;AAEpE,OAAO,KAAK,EAAC,sBAAsB,EAAC,MAAM,yCAAyC,CAAC;AAOpF,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,oCAAoC,CAAC;AAK1E,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EAAC,OAAO,EAAC,MAAM,uBAAuB,CAAC;AACnD,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AACzD,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,6BAA6B,CAAC;AAE9D,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAiBxD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAuBzD,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,kBAAkB;IAClB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC,CAAC;AAMF,MAAM,WAAW,UAAU;IACzB,cAAc,CACZ,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,qBAAqB,GACzB,MAAM,CAAC,UAAU,CAAC,CAAC;IAEtB,oBAAoB,CAClB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,2BAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1E,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE;AAQD,KAAK,UAAU,GAAG,CAChB,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,EAChC,KAAK,CAAC,EAAE,MAAM,KACX,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;AAEnC;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAS,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC,qBAAa,iBAAkB,YAAW,UAAU,EAAE,oBAAoB;;IACxE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAUpB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;gBAsHhC,MAAM,EAAE,oBAAoB,EAC5B,EAAE,EAAE,UAAU,EACd,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,UAAU,GAAG,SAAS,EAClC,cAAc,EAAE,cAAc,EAC9B,cAAc,EAAE,YAAY,CAAC,YAAY,CAAC,EAC1C,gBAAgB,EAAE,gBAAgB,EAClC,oBAAoB,EAAE,MAAM,EAC5B,iBAAiB,EAAE,iBAAiB,EACpC,sBAAsB,EAAE,sBAAsB,GAAG,SAAS,EAC1D,WAAW,SAAuB,EAClC,YAAY,GAAE,UAAwC;IA2FxD,UAAU,IAAI,OAAO,CAAC,aAAa,GAAG,UAAU,CAAC;IAO3C,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAqH1B;;;;;;;;OAQG;IACH,SAAS,IAAI,OAAO;IAwEpB,cAAc,CACZ,GAAG,EAAE,WAAW,EAChB,qBAAqB,EAAE,qBAAqB,GAC3C,MAAM,CAAC,UAAU,CAAC;IA4Gf,oBAAoB,CACxB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,2BAA2B,GAC/B,OAAO,CAAC,IAAI,CAAC;IAIV,aAAa,CACjB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,oBAAoB,GACxB,OAAO,CAAC,IAAI,CAAC;IA0uChB,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA2BnE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqBrB;;;OAGG;IACH,eAAe;CAGhB;AA+ED,wBAAgB,SAAS,CACvB,EAAE,EAAE,UAAU,EACd,aAAa,EAAE,SAAS,GAAG,SAAS,EACpC,QAAQ,EAAE,SAAS,GAAG,SAAS,yBAkDhC;AAyCD,qBAAa,cAAc;;IAInB,KAAK;IAOX,oBAAoB;IAMd,YAAY,CAAC,cAAc,CAAC,EAAE,MAAM;IAW1C,UAAU;IAWV,sCAAsC;IACtC,IAAI,IAAI,MAAM;IAKd;;;OAGG;IACH,YAAY,IAAI,MAAM;CAKvB"}
@@ -787,16 +787,16 @@ class ViewSyncerService {
787
787
  span.setAttribute("queryHash", queryID);
788
788
  span.setAttribute("transformationHash", transformationHash);
789
789
  span.setAttribute("table", transformedAst.table);
790
- for (const _ of this.#pipelines.addQuery(
790
+ for (const change of this.#pipelines.addQuery(
791
791
  transformationHash,
792
792
  queryID,
793
793
  transformedAst,
794
794
  await timer.start()
795
795
  )) {
796
- if (++count % TIME_SLICE_CHECK_SIZE === 0) {
797
- if (timer.elapsedLap() > TIME_SLICE_MS) {
798
- await timer.yieldProcess();
799
- }
796
+ if (change === "yield") {
797
+ await timer.yieldProcess("yield in hydrateUnchangedQueries");
798
+ } else {
799
+ count++;
800
800
  }
801
801
  }
802
802
  }
@@ -1278,6 +1278,10 @@ class ViewSyncerService {
1278
1278
  });
1279
1279
  await startAsyncSpan(tracer, "loopingChanges", async (span) => {
1280
1280
  for (const change of changes) {
1281
+ if (change === "yield") {
1282
+ await timer.yieldProcess("yield in processChanges");
1283
+ continue;
1284
+ }
1281
1285
  const {
1282
1286
  type,
1283
1287
  queryHash: transformationHash,
@@ -1554,7 +1558,7 @@ class TimeSliceTimer {
1554
1558
  this.#startLap();
1555
1559
  return this;
1556
1560
  }
1557
- async yieldProcess() {
1561
+ async yieldProcess(_msgForTesting) {
1558
1562
  this.#stopLap();
1559
1563
  await yieldProcess();
1560
1564
  this.#startLap();