@rocicorp/zero 1.11.0-canary.35 → 1.11.0-canary.37

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 (130) hide show
  1. package/out/zero/package.js +1 -1
  2. package/out/zero/package.js.map +1 -1
  3. package/out/zero-cache/src/config/zero-config.d.ts +28 -0
  4. package/out/zero-cache/src/config/zero-config.d.ts.map +1 -1
  5. package/out/zero-cache/src/config/zero-config.js +83 -0
  6. package/out/zero-cache/src/config/zero-config.js.map +1 -1
  7. package/out/zero-cache/src/server/change-streamer.d.ts.map +1 -1
  8. package/out/zero-cache/src/server/change-streamer.js +2 -1
  9. package/out/zero-cache/src/server/change-streamer.js.map +1 -1
  10. package/out/zero-cache/src/server/main.d.ts.map +1 -1
  11. package/out/zero-cache/src/server/main.js +5 -1
  12. package/out/zero-cache/src/server/main.js.map +1 -1
  13. package/out/zero-cache/src/server/replicator.d.ts +4 -0
  14. package/out/zero-cache/src/server/replicator.d.ts.map +1 -1
  15. package/out/zero-cache/src/server/replicator.js +18 -4
  16. package/out/zero-cache/src/server/replicator.js.map +1 -1
  17. package/out/zero-cache/src/server/runner/run-worker.d.ts.map +1 -1
  18. package/out/zero-cache/src/server/runner/run-worker.js +12 -6
  19. package/out/zero-cache/src/server/runner/run-worker.js.map +1 -1
  20. package/out/zero-cache/src/server/syncer.d.ts.map +1 -1
  21. package/out/zero-cache/src/server/syncer.js +17 -1
  22. package/out/zero-cache/src/server/syncer.js.map +1 -1
  23. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js +1 -1
  24. package/out/zero-cache/src/services/change-source/pg/backfill-stream.js.map +1 -1
  25. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts +27 -7
  26. package/out/zero-cache/src/services/change-source/pg/replication-slots.d.ts.map +1 -1
  27. package/out/zero-cache/src/services/change-source/pg/replication-slots.js +124 -62
  28. package/out/zero-cache/src/services/change-source/pg/replication-slots.js.map +1 -1
  29. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts +9 -3
  30. package/out/zero-cache/src/services/change-streamer/change-streamer-http.d.ts.map +1 -1
  31. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js +19 -6
  32. package/out/zero-cache/src/services/change-streamer/change-streamer-http.js.map +1 -1
  33. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts +8 -0
  34. package/out/zero-cache/src/services/change-streamer/change-streamer-service.d.ts.map +1 -1
  35. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js +131 -62
  36. package/out/zero-cache/src/services/change-streamer/change-streamer-service.js.map +1 -1
  37. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts +124 -2
  38. package/out/zero-cache/src/services/change-streamer/change-streamer.d.ts.map +1 -1
  39. package/out/zero-cache/src/services/change-streamer/change-streamer.js +33 -2
  40. package/out/zero-cache/src/services/change-streamer/change-streamer.js.map +1 -1
  41. package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts +24 -0
  42. package/out/zero-cache/src/services/change-streamer/drain-tracker.d.ts.map +1 -0
  43. package/out/zero-cache/src/services/change-streamer/drain-tracker.js +67 -0
  44. package/out/zero-cache/src/services/change-streamer/drain-tracker.js.map +1 -0
  45. package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts +214 -0
  46. package/out/zero-cache/src/services/change-streamer/restore-admission.d.ts.map +1 -0
  47. package/out/zero-cache/src/services/change-streamer/restore-admission.js +294 -0
  48. package/out/zero-cache/src/services/change-streamer/restore-admission.js.map +1 -0
  49. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts +13 -1
  50. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.d.ts.map +1 -1
  51. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js +7 -6
  52. package/out/zero-cache/src/services/change-streamer/snapshot-reservations.js.map +1 -1
  53. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts +2 -2
  54. package/out/zero-cache/src/services/change-streamer/snapshot.d.ts.map +1 -1
  55. package/out/zero-cache/src/services/change-streamer/snapshot.js +2 -2
  56. package/out/zero-cache/src/services/change-streamer/snapshot.js.map +1 -1
  57. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts +39 -0
  58. package/out/zero-cache/src/services/change-streamer/subscribe.d.ts.map +1 -1
  59. package/out/zero-cache/src/services/change-streamer/subscribe.js +19 -2
  60. package/out/zero-cache/src/services/change-streamer/subscribe.js.map +1 -1
  61. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts +22 -1
  62. package/out/zero-cache/src/services/change-streamer/subscriber.d.ts.map +1 -1
  63. package/out/zero-cache/src/services/change-streamer/subscriber.js +41 -15
  64. package/out/zero-cache/src/services/change-streamer/subscriber.js.map +1 -1
  65. package/out/zero-cache/src/services/http-service.d.ts +6 -0
  66. package/out/zero-cache/src/services/http-service.d.ts.map +1 -1
  67. package/out/zero-cache/src/services/http-service.js +14 -2
  68. package/out/zero-cache/src/services/http-service.js.map +1 -1
  69. package/out/zero-cache/src/services/life-cycle.d.ts +33 -0
  70. package/out/zero-cache/src/services/life-cycle.d.ts.map +1 -1
  71. package/out/zero-cache/src/services/life-cycle.js +56 -10
  72. package/out/zero-cache/src/services/life-cycle.js.map +1 -1
  73. package/out/zero-cache/src/services/litestream/commands.d.ts +8 -0
  74. package/out/zero-cache/src/services/litestream/commands.d.ts.map +1 -1
  75. package/out/zero-cache/src/services/litestream/commands.js +22 -1
  76. package/out/zero-cache/src/services/litestream/commands.js.map +1 -1
  77. package/out/zero-cache/src/services/replicator/drain-handler.d.ts +74 -0
  78. package/out/zero-cache/src/services/replicator/drain-handler.d.ts.map +1 -0
  79. package/out/zero-cache/src/services/replicator/drain-handler.js +185 -0
  80. package/out/zero-cache/src/services/replicator/drain-handler.js.map +1 -0
  81. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts +2 -1
  82. package/out/zero-cache/src/services/replicator/incremental-sync.d.ts.map +1 -1
  83. package/out/zero-cache/src/services/replicator/incremental-sync.js +66 -13
  84. package/out/zero-cache/src/services/replicator/incremental-sync.js.map +1 -1
  85. package/out/zero-cache/src/services/replicator/replicator.d.ts +2 -1
  86. package/out/zero-cache/src/services/replicator/replicator.d.ts.map +1 -1
  87. package/out/zero-cache/src/services/replicator/replicator.js +2 -2
  88. package/out/zero-cache/src/services/replicator/replicator.js.map +1 -1
  89. package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts +79 -0
  90. package/out/zero-cache/src/services/view-syncer/batch-pacer.d.ts.map +1 -0
  91. package/out/zero-cache/src/services/view-syncer/batch-pacer.js +249 -0
  92. package/out/zero-cache/src/services/view-syncer/batch-pacer.js.map +1 -0
  93. package/out/zero-cache/src/services/view-syncer/cvr.d.ts +27 -1
  94. package/out/zero-cache/src/services/view-syncer/cvr.d.ts.map +1 -1
  95. package/out/zero-cache/src/services/view-syncer/cvr.js +107 -17
  96. package/out/zero-cache/src/services/view-syncer/cvr.js.map +1 -1
  97. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts +85 -3
  98. package/out/zero-cache/src/services/view-syncer/pipeline-driver.d.ts.map +1 -1
  99. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js +301 -20
  100. package/out/zero-cache/src/services/view-syncer/pipeline-driver.js.map +1 -1
  101. package/out/zero-cache/src/services/view-syncer/push-cost.d.ts +132 -0
  102. package/out/zero-cache/src/services/view-syncer/push-cost.d.ts.map +1 -0
  103. package/out/zero-cache/src/services/view-syncer/push-cost.js +164 -0
  104. package/out/zero-cache/src/services/view-syncer/push-cost.js.map +1 -0
  105. package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts +55 -0
  106. package/out/zero-cache/src/services/view-syncer/push-cutoff.d.ts.map +1 -0
  107. package/out/zero-cache/src/services/view-syncer/push-cutoff.js +56 -0
  108. package/out/zero-cache/src/services/view-syncer/push-cutoff.js.map +1 -0
  109. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts +7 -0
  110. package/out/zero-cache/src/services/view-syncer/query-stats.d.ts.map +1 -1
  111. package/out/zero-cache/src/services/view-syncer/query-stats.js +20 -1
  112. package/out/zero-cache/src/services/view-syncer/query-stats.js.map +1 -1
  113. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts +136 -5
  114. package/out/zero-cache/src/services/view-syncer/snapshotter.d.ts.map +1 -1
  115. package/out/zero-cache/src/services/view-syncer/snapshotter.js +246 -18
  116. package/out/zero-cache/src/services/view-syncer/snapshotter.js.map +1 -1
  117. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts +8 -2
  118. package/out/zero-cache/src/services/view-syncer/view-syncer.d.ts.map +1 -1
  119. package/out/zero-cache/src/services/view-syncer/view-syncer.js +381 -16
  120. package/out/zero-cache/src/services/view-syncer/view-syncer.js.map +1 -1
  121. package/out/zero-cache/src/types/processes.d.ts +8 -0
  122. package/out/zero-cache/src/types/processes.d.ts.map +1 -1
  123. package/out/zero-cache/src/types/processes.js.map +1 -1
  124. package/out/zero-client/src/client/version.js +1 -1
  125. package/out/zero-react/src/use-query.js +1 -1
  126. package/out/zero-react/src/use-query.js.map +1 -1
  127. package/out/zero-server/src/queries/process-queries.d.ts.map +1 -1
  128. package/out/zero-server/src/queries/process-queries.js +1 -1
  129. package/out/zero-server/src/queries/process-queries.js.map +1 -1
  130. package/package.json +1 -1
@@ -0,0 +1,79 @@
1
+ import type { LogContext } from '@rocicorp/logger';
2
+ export type BatchPacerOptions = {
3
+ /**
4
+ * The largest share of the worker's time that it may be busy before its
5
+ * client groups are paced.
6
+ */
7
+ readonly shareTarget: number;
8
+ /** The longest a client group waits between batches. */
9
+ readonly maxIntervalMs: number;
10
+ readonly now?: (() => number) | undefined;
11
+ /**
12
+ * The share of the time since the previous call that the worker was busy.
13
+ * By default, the utilization of the event loop.
14
+ */
15
+ readonly utilization?: (() => number) | undefined;
16
+ /** Where the worker says that it is pacing its client groups. */
17
+ readonly lc?: LogContext | undefined;
18
+ };
19
+ /**
20
+ * Paces the batches (advancements, including the queries they hydrate
21
+ * again) of the client groups of a sync worker, so that the worker is left
22
+ * with time for new hydrations and connections, and gives the hydrations of
23
+ * new queries priority over the batches.
24
+ *
25
+ * **Pacing.** After each batch, a client group waits {@link waitMs} before
26
+ * it starts the next. The wait is a multiple of the batch's processing
27
+ * time, so a client group that always has changes waiting is busy at most
28
+ * `1 / (1 + k)` of the time, where `k` is the {@link multiplier}. Because
29
+ * the wait is in proportion to a client group's own processing time, those
30
+ * that cause the load are slowed the most, and cheap ones barely at all.
31
+ *
32
+ * The multiplier is shared by the client groups of the worker. Once per
33
+ * second, it is scaled by how far the share of its time that the worker was
34
+ * busy, smoothed over a few seconds, is from the target, and by more while
35
+ * the worker has no time to spare. It never goes below 0, where no client
36
+ * group waits. The share is the utilization of the worker's event loop, i.e. all
37
+ * of what the worker does: what a batch costs is spread over the pipelines,
38
+ * the CVR, the pokes and garbage collection, and is not measurable batch by
39
+ * batch.
40
+ *
41
+ * **Priority of new hydrations.** The worker's time slices are handed out
42
+ * by the pacer (see {@link yieldSlice}), and while the hydration of new
43
+ * queries is waiting for one, most of them go to it rather than to batches.
44
+ */
45
+ export declare class BatchPacer {
46
+ #private;
47
+ constructor({ shareTarget, maxIntervalMs, now, utilization, lc, }: BatchPacerOptions);
48
+ /**
49
+ * How long a client group should wait before its next batch, after one
50
+ * that took `processingMs` to process. The multiplier changes while a
51
+ * client group waits, so a long wait should be taken in steps, asking
52
+ * again after each.
53
+ */
54
+ waitMs(processingMs: number): number;
55
+ /** `k`: a client group waits `k` times the processing time of a batch. */
56
+ get multiplier(): number;
57
+ /**
58
+ * The share of its time that the worker was busy, smoothed over the last
59
+ * few seconds, as of the last update of the multiplier.
60
+ */
61
+ get share(): number;
62
+ /**
63
+ * Yields the worker to the other work that is waiting for a time slice,
64
+ * and resolves when it is the caller's turn again. One piece of work runs
65
+ * per turn of the event loop, as when the work of a worker's client groups
66
+ * simply takes turns, except that the hydration of new queries goes first:
67
+ * while both kinds of work are waiting, `HYDRATION_PRIORITY` slices go to
68
+ * hydrations for each one that goes to a batch.
69
+ *
70
+ * Batches are never made to wait for anything but a slice. If no
71
+ * hydration is waiting for one (because none is running, or because those
72
+ * that are running are waiting for I/O), batches get every slice. And
73
+ * however many hydrations there are, batches keep a share of the slices,
74
+ * so they keep moving, and so do the snapshots of the replica that they
75
+ * hold.
76
+ */
77
+ yieldSlice(kind: 'hydration' | 'batch'): Promise<void>;
78
+ }
79
+ //# sourceMappingURL=batch-pacer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-pacer.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/batch-pacer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAyDjD,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wDAAwD;IACxD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,MAAM,CAAC,GAAG,SAAS,CAAC;IAClD,iEAAiE;IACjE,QAAQ,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;CACtC,CAAC;AAYF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,UAAU;;IA8BrB,YAAY,EACV,WAAW,EACX,aAAa,EACb,GAAG,EACH,WAAW,EACX,EAAE,GACH,EAAE,iBAAiB,EAOnB;IAED;;;;;OAKG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CASnC;IAED,0EAA0E;IAC1E,IAAI,UAAU,IAAI,MAAM,CAGvB;IAED;;;OAGG;IACH,IAAI,KAAK,IAAI,MAAM,CAGlB;IA+FD;;;;;;;;;;;;;;OAcG;IACH,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAQrD;CAuBF"}
@@ -0,0 +1,249 @@
1
+ import { performance } from "node:perf_hooks";
2
+ //#region ../zero-cache/src/services/view-syncer/batch-pacer.ts
3
+ /** How often the multiplier is updated. */
4
+ var UPDATE_INTERVAL_MS = 1e3;
5
+ /**
6
+ * The weight of the latest second in the worker's smoothed busy share.
7
+ * Client groups that wait for seconds between batches make the share of
8
+ * any one second jump between idle and saturated, and a worker that keeps
9
+ * up has the odd busy second. Neither says what the load is.
10
+ */
11
+ var SHARE_SMOOTHING = .3;
12
+ /**
13
+ * How much of the difference between the smoothed busy share and the target
14
+ * each update corrects for. The smoothed share only shows part of what the
15
+ * previous updates did, so correcting for all of the difference each time
16
+ * would overshoot and oscillate.
17
+ */
18
+ var CORRECTION_EXPONENT = .3;
19
+ /**
20
+ * The share of its time above which a worker has no time to spare. A share
21
+ * target has to stay well clear of this to be held, which is why
22
+ * `syncUpdateShareTarget` is at most 0.9 (or 1, which no worker is over).
23
+ */
24
+ var SATURATED_SHARE = .95;
25
+ /** The seconds that a worker has to be saturated for to be treated as such. */
26
+ var SATURATED_SECONDS = 2;
27
+ /**
28
+ * How much `1 + k` is scaled by each second that the worker is saturated.
29
+ * A saturated worker does not show how much more its client groups would
30
+ * use, which can be many times what it has, so the multiplier is raised by
31
+ * more than the difference from the target calls for until it does.
32
+ */
33
+ var SATURATED_CORRECTION = 1.3;
34
+ /**
35
+ * How often a worker that is pacing its client groups says so in its log,
36
+ * and how long it has to have stopped for to say that it has.
37
+ */
38
+ var PACING_LOG_INTERVAL_MS = 6e4;
39
+ /**
40
+ * The most updates that are made up for when nothing has asked the pacer
41
+ * for a wait in a while, which is enough for the multiplier to get to 0.
42
+ */
43
+ var MAX_CATCH_UP_UPDATES = 60;
44
+ /**
45
+ * Bounds the multiplier, which otherwise has no limit while a worker stays
46
+ * over the target however long its client groups wait.
47
+ */
48
+ var MAX_MULTIPLIER = 1e6;
49
+ function eventLoopUtilization() {
50
+ let last = performance.eventLoopUtilization();
51
+ return () => {
52
+ const current = performance.eventLoopUtilization();
53
+ const { utilization } = performance.eventLoopUtilization(current, last);
54
+ last = current;
55
+ return utilization;
56
+ };
57
+ }
58
+ /**
59
+ * Paces the batches (advancements, including the queries they hydrate
60
+ * again) of the client groups of a sync worker, so that the worker is left
61
+ * with time for new hydrations and connections, and gives the hydrations of
62
+ * new queries priority over the batches.
63
+ *
64
+ * **Pacing.** After each batch, a client group waits {@link waitMs} before
65
+ * it starts the next. The wait is a multiple of the batch's processing
66
+ * time, so a client group that always has changes waiting is busy at most
67
+ * `1 / (1 + k)` of the time, where `k` is the {@link multiplier}. Because
68
+ * the wait is in proportion to a client group's own processing time, those
69
+ * that cause the load are slowed the most, and cheap ones barely at all.
70
+ *
71
+ * The multiplier is shared by the client groups of the worker. Once per
72
+ * second, it is scaled by how far the share of its time that the worker was
73
+ * busy, smoothed over a few seconds, is from the target, and by more while
74
+ * the worker has no time to spare. It never goes below 0, where no client
75
+ * group waits. The share is the utilization of the worker's event loop, i.e. all
76
+ * of what the worker does: what a batch costs is spread over the pipelines,
77
+ * the CVR, the pokes and garbage collection, and is not measurable batch by
78
+ * batch.
79
+ *
80
+ * **Priority of new hydrations.** The worker's time slices are handed out
81
+ * by the pacer (see {@link yieldSlice}), and while the hydration of new
82
+ * queries is waiting for one, most of them go to it rather than to batches.
83
+ */
84
+ var BatchPacer = class {
85
+ #shareTarget;
86
+ #maxIntervalMs;
87
+ #now;
88
+ #utilization;
89
+ #lc;
90
+ /** When the worker last logged that it is pacing, while it still is. */
91
+ #pacingLoggedAt;
92
+ /** Since when the worker has not been pacing, after it logged that it was. */
93
+ #notPacingSince;
94
+ #intervalStart;
95
+ #multiplier = 0;
96
+ /** The smoothed share of its time that the worker was busy. */
97
+ #share = 0;
98
+ #saturatedSeconds = 0;
99
+ /** The waits handed out since the last update, by whether at the cap. */
100
+ #waitsBelowMax = 0;
101
+ #waitsAtMax = 0;
102
+ /** The work that is waiting for a time slice, in the order it yielded. */
103
+ #waiting = {
104
+ hydration: [],
105
+ batch: []
106
+ };
107
+ #handingOutSlices = false;
108
+ /** The slices that have gone to hydrations since one went to a batch. */
109
+ #hydrationSlices = 0;
110
+ constructor({ shareTarget, maxIntervalMs, now, utilization, lc }) {
111
+ this.#shareTarget = shareTarget;
112
+ this.#maxIntervalMs = maxIntervalMs;
113
+ this.#now = now ?? (() => performance.now());
114
+ this.#utilization = utilization ?? eventLoopUtilization();
115
+ this.#lc = lc;
116
+ this.#intervalStart = this.#now();
117
+ }
118
+ /**
119
+ * How long a client group should wait before its next batch, after one
120
+ * that took `processingMs` to process. The multiplier changes while a
121
+ * client group waits, so a long wait should be taken in steps, asking
122
+ * again after each.
123
+ */
124
+ waitMs(processingMs) {
125
+ this.#update();
126
+ const wait = this.#multiplier * processingMs;
127
+ if (wait < this.#maxIntervalMs) {
128
+ this.#waitsBelowMax++;
129
+ return wait;
130
+ }
131
+ this.#waitsAtMax++;
132
+ return this.#maxIntervalMs;
133
+ }
134
+ /** `k`: a client group waits `k` times the processing time of a batch. */
135
+ get multiplier() {
136
+ this.#update();
137
+ return this.#multiplier;
138
+ }
139
+ /**
140
+ * The share of its time that the worker was busy, smoothed over the last
141
+ * few seconds, as of the last update of the multiplier.
142
+ */
143
+ get share() {
144
+ this.#update();
145
+ return this.#share;
146
+ }
147
+ /** Updates the multiplier for each interval that has ended. */
148
+ #update() {
149
+ const now = this.#now();
150
+ const ended = Math.floor((now - this.#intervalStart) / UPDATE_INTERVAL_MS);
151
+ if (ended <= 0) return;
152
+ this.#intervalStart += ended * UPDATE_INTERVAL_MS;
153
+ const latest = this.#utilization();
154
+ const allAtMax = this.#waitsAtMax > 0 && this.#waitsBelowMax === 0;
155
+ this.#waitsAtMax = 0;
156
+ this.#waitsBelowMax = 0;
157
+ for (let i = Math.min(ended, MAX_CATCH_UP_UPDATES); i > 0; i--) {
158
+ this.#share += SHARE_SMOOTHING * (latest - this.#share);
159
+ this.#saturatedSeconds = latest >= SATURATED_SHARE && latest > this.#shareTarget ? this.#saturatedSeconds + 1 : 0;
160
+ let correction = this.#saturatedSeconds >= SATURATED_SECONDS ? SATURATED_CORRECTION : (this.#share / this.#shareTarget) ** CORRECTION_EXPONENT;
161
+ if (allAtMax && correction > 1) correction = 1;
162
+ this.#multiplier = Math.min(Math.max((1 + this.#multiplier) * correction - 1, 0), MAX_MULTIPLIER);
163
+ }
164
+ this.#logPacing(now, allAtMax);
165
+ }
166
+ /**
167
+ * Says in the worker's log when it starts to pace its client groups, once
168
+ * a minute while it does, and when it has stopped. The pacing of a client
169
+ * group is logged by its view syncer.
170
+ */
171
+ #logPacing(now, allAtMax) {
172
+ const lc = this.#lc;
173
+ if (lc === void 0) return;
174
+ const state = {
175
+ busyShare: this.#share,
176
+ shareTarget: this.#shareTarget,
177
+ waitMultiplier: this.#multiplier,
178
+ maxBatchIntervalMs: this.#maxIntervalMs
179
+ };
180
+ if (this.#multiplier > 0) {
181
+ this.#notPacingSince = void 0;
182
+ if (this.#pacingLoggedAt === void 0) {
183
+ lc.info?.("Sync worker is over its share target: its client groups wait between batches", state);
184
+ this.#pacingLoggedAt = now;
185
+ } else if (now - this.#pacingLoggedAt >= PACING_LOG_INTERVAL_MS) {
186
+ if (allAtMax && this.#share > this.#shareTarget) lc.warn?.("Sync worker is over its share target although every client group waits the longest it may", state);
187
+ else lc.info?.("Sync worker is pacing its client groups", state);
188
+ this.#pacingLoggedAt = now;
189
+ }
190
+ } else if (this.#pacingLoggedAt !== void 0) {
191
+ this.#notPacingSince ??= now;
192
+ if (now - this.#notPacingSince >= PACING_LOG_INTERVAL_MS) {
193
+ lc.info?.("Sync worker is under its share target: its client groups no longer wait", state);
194
+ this.#pacingLoggedAt = void 0;
195
+ this.#notPacingSince = void 0;
196
+ }
197
+ }
198
+ }
199
+ /**
200
+ * Yields the worker to the other work that is waiting for a time slice,
201
+ * and resolves when it is the caller's turn again. One piece of work runs
202
+ * per turn of the event loop, as when the work of a worker's client groups
203
+ * simply takes turns, except that the hydration of new queries goes first:
204
+ * while both kinds of work are waiting, `HYDRATION_PRIORITY` slices go to
205
+ * hydrations for each one that goes to a batch.
206
+ *
207
+ * Batches are never made to wait for anything but a slice. If no
208
+ * hydration is waiting for one (because none is running, or because those
209
+ * that are running are waiting for I/O), batches get every slice. And
210
+ * however many hydrations there are, batches keep a share of the slices,
211
+ * so they keep moving, and so do the snapshots of the replica that they
212
+ * hold.
213
+ */
214
+ yieldSlice(kind) {
215
+ return new Promise((resolve) => {
216
+ this.#waiting[kind].push(resolve);
217
+ if (!this.#handingOutSlices) {
218
+ this.#handingOutSlices = true;
219
+ setImmediate(this.#nextSlice);
220
+ }
221
+ });
222
+ }
223
+ #nextSlice = () => {
224
+ const { hydration, batch } = this.#waiting;
225
+ let next;
226
+ if (hydration.length > 0 && (batch.length === 0 || this.#hydrationSlices < HYDRATION_PRIORITY)) {
227
+ next = hydration.shift();
228
+ this.#hydrationSlices++;
229
+ } else if (batch.length > 0) {
230
+ next = batch.shift();
231
+ this.#hydrationSlices = 0;
232
+ }
233
+ if (next === void 0) {
234
+ this.#handingOutSlices = false;
235
+ return;
236
+ }
237
+ next();
238
+ setImmediate(this.#nextSlice);
239
+ };
240
+ };
241
+ /**
242
+ * How many time slices go to the hydration of new queries for each one that
243
+ * goes to a batch, while both are waiting for one.
244
+ */
245
+ var HYDRATION_PRIORITY = 9;
246
+ //#endregion
247
+ export { BatchPacer };
248
+
249
+ //# sourceMappingURL=batch-pacer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-pacer.js","names":["#shareTarget","#maxIntervalMs","#now","#utilization","#lc","#waiting","#intervalStart","#update","#multiplier","#waitsBelowMax","#waitsAtMax","#share","#saturatedSeconds","#logPacing","#notPacingSince","#pacingLoggedAt","#handingOutSlices","#nextSlice","#hydrationSlices"],"sources":["../../../../../../zero-cache/src/services/view-syncer/batch-pacer.ts"],"sourcesContent":["import {performance} from 'node:perf_hooks';\nimport type {LogContext} from '@rocicorp/logger';\n\n/** How often the multiplier is updated. */\nconst UPDATE_INTERVAL_MS = 1000;\n\n/**\n * The weight of the latest second in the worker's smoothed busy share.\n * Client groups that wait for seconds between batches make the share of\n * any one second jump between idle and saturated, and a worker that keeps\n * up has the odd busy second. Neither says what the load is.\n */\nconst SHARE_SMOOTHING = 0.3;\n\n/**\n * How much of the difference between the smoothed busy share and the target\n * each update corrects for. The smoothed share only shows part of what the\n * previous updates did, so correcting for all of the difference each time\n * would overshoot and oscillate.\n */\nconst CORRECTION_EXPONENT = 0.3;\n\n/**\n * The share of its time above which a worker has no time to spare. A share\n * target has to stay well clear of this to be held, which is why\n * `syncUpdateShareTarget` is at most 0.9 (or 1, which no worker is over).\n */\nconst SATURATED_SHARE = 0.95;\n\n/** The seconds that a worker has to be saturated for to be treated as such. */\nconst SATURATED_SECONDS = 2;\n\n/**\n * How much `1 + k` is scaled by each second that the worker is saturated.\n * A saturated worker does not show how much more its client groups would\n * use, which can be many times what it has, so the multiplier is raised by\n * more than the difference from the target calls for until it does.\n */\nconst SATURATED_CORRECTION = 1.3;\n\n/**\n * How often a worker that is pacing its client groups says so in its log,\n * and how long it has to have stopped for to say that it has.\n */\nconst PACING_LOG_INTERVAL_MS = 60_000;\n\n/**\n * The most updates that are made up for when nothing has asked the pacer\n * for a wait in a while, which is enough for the multiplier to get to 0.\n */\nconst MAX_CATCH_UP_UPDATES = 60;\n\n/**\n * Bounds the multiplier, which otherwise has no limit while a worker stays\n * over the target however long its client groups wait.\n */\nconst MAX_MULTIPLIER = 1_000_000;\n\nexport type BatchPacerOptions = {\n /**\n * The largest share of the worker's time that it may be busy before its\n * client groups are paced.\n */\n readonly shareTarget: number;\n /** The longest a client group waits between batches. */\n readonly maxIntervalMs: number;\n readonly now?: (() => number) | undefined;\n /**\n * The share of the time since the previous call that the worker was busy.\n * By default, the utilization of the event loop.\n */\n readonly utilization?: (() => number) | undefined;\n /** Where the worker says that it is pacing its client groups. */\n readonly lc?: LogContext | undefined;\n};\n\nfunction eventLoopUtilization(): () => number {\n let last = performance.eventLoopUtilization();\n return () => {\n const current = performance.eventLoopUtilization();\n const {utilization} = performance.eventLoopUtilization(current, last);\n last = current;\n return utilization;\n };\n}\n\n/**\n * Paces the batches (advancements, including the queries they hydrate\n * again) of the client groups of a sync worker, so that the worker is left\n * with time for new hydrations and connections, and gives the hydrations of\n * new queries priority over the batches.\n *\n * **Pacing.** After each batch, a client group waits {@link waitMs} before\n * it starts the next. The wait is a multiple of the batch's processing\n * time, so a client group that always has changes waiting is busy at most\n * `1 / (1 + k)` of the time, where `k` is the {@link multiplier}. Because\n * the wait is in proportion to a client group's own processing time, those\n * that cause the load are slowed the most, and cheap ones barely at all.\n *\n * The multiplier is shared by the client groups of the worker. Once per\n * second, it is scaled by how far the share of its time that the worker was\n * busy, smoothed over a few seconds, is from the target, and by more while\n * the worker has no time to spare. It never goes below 0, where no client\n * group waits. The share is the utilization of the worker's event loop, i.e. all\n * of what the worker does: what a batch costs is spread over the pipelines,\n * the CVR, the pokes and garbage collection, and is not measurable batch by\n * batch.\n *\n * **Priority of new hydrations.** The worker's time slices are handed out\n * by the pacer (see {@link yieldSlice}), and while the hydration of new\n * queries is waiting for one, most of them go to it rather than to batches.\n */\nexport class BatchPacer {\n readonly #shareTarget: number;\n readonly #maxIntervalMs: number;\n readonly #now: () => number;\n readonly #utilization: () => number;\n readonly #lc: LogContext | undefined;\n\n /** When the worker last logged that it is pacing, while it still is. */\n #pacingLoggedAt: number | undefined;\n /** Since when the worker has not been pacing, after it logged that it was. */\n #notPacingSince: number | undefined;\n\n #intervalStart: number;\n #multiplier = 0;\n /** The smoothed share of its time that the worker was busy. */\n #share = 0;\n #saturatedSeconds = 0;\n /** The waits handed out since the last update, by whether at the cap. */\n #waitsBelowMax = 0;\n #waitsAtMax = 0;\n\n /** The work that is waiting for a time slice, in the order it yielded. */\n readonly #waiting = {\n hydration: [] as (() => void)[],\n batch: [] as (() => void)[],\n };\n #handingOutSlices = false;\n /** The slices that have gone to hydrations since one went to a batch. */\n #hydrationSlices = 0;\n\n constructor({\n shareTarget,\n maxIntervalMs,\n now,\n utilization,\n lc,\n }: BatchPacerOptions) {\n this.#shareTarget = shareTarget;\n this.#maxIntervalMs = maxIntervalMs;\n this.#now = now ?? (() => performance.now());\n this.#utilization = utilization ?? eventLoopUtilization();\n this.#lc = lc;\n this.#intervalStart = this.#now();\n }\n\n /**\n * How long a client group should wait before its next batch, after one\n * that took `processingMs` to process. The multiplier changes while a\n * client group waits, so a long wait should be taken in steps, asking\n * again after each.\n */\n waitMs(processingMs: number): number {\n this.#update();\n const wait = this.#multiplier * processingMs;\n if (wait < this.#maxIntervalMs) {\n this.#waitsBelowMax++;\n return wait;\n }\n this.#waitsAtMax++;\n return this.#maxIntervalMs;\n }\n\n /** `k`: a client group waits `k` times the processing time of a batch. */\n get multiplier(): number {\n this.#update();\n return this.#multiplier;\n }\n\n /**\n * The share of its time that the worker was busy, smoothed over the last\n * few seconds, as of the last update of the multiplier.\n */\n get share(): number {\n this.#update();\n return this.#share;\n }\n\n /** Updates the multiplier for each interval that has ended. */\n #update(): void {\n const now = this.#now();\n const ended = Math.floor((now - this.#intervalStart) / UPDATE_INTERVAL_MS);\n if (ended <= 0) {\n return;\n }\n this.#intervalStart += ended * UPDATE_INTERVAL_MS;\n // If more than one interval has ended, nothing asked the pacer for a\n // wait in the meantime, and the utilization since then is that of each.\n const latest = this.#utilization();\n // Once every client group is told to wait the longest it can, raising\n // the multiplier changes nothing, and only makes it take longer to come\n // back down. A worker that is still over its target then is busy with\n // something that making its client groups wait does not relieve.\n const allAtMax = this.#waitsAtMax > 0 && this.#waitsBelowMax === 0;\n this.#waitsAtMax = 0;\n this.#waitsBelowMax = 0;\n for (let i = Math.min(ended, MAX_CATCH_UP_UPDATES); i > 0; i--) {\n this.#share += SHARE_SMOOTHING * (latest - this.#share);\n // A worker that is allowed to be this busy is only raised the\n // multiplier for what it is over its target by.\n this.#saturatedSeconds =\n latest >= SATURATED_SHARE && latest > this.#shareTarget\n ? this.#saturatedSeconds + 1\n : 0;\n let correction =\n this.#saturatedSeconds >= SATURATED_SECONDS\n ? SATURATED_CORRECTION\n : (this.#share / this.#shareTarget) ** CORRECTION_EXPONENT;\n if (allAtMax && correction > 1) {\n correction = 1;\n }\n this.#multiplier = Math.min(\n Math.max((1 + this.#multiplier) * correction - 1, 0),\n MAX_MULTIPLIER,\n );\n }\n this.#logPacing(now, allAtMax);\n }\n\n /**\n * Says in the worker's log when it starts to pace its client groups, once\n * a minute while it does, and when it has stopped. The pacing of a client\n * group is logged by its view syncer.\n */\n #logPacing(now: number, allAtMax: boolean): void {\n const lc = this.#lc;\n if (lc === undefined) {\n return;\n }\n const state = {\n busyShare: this.#share,\n shareTarget: this.#shareTarget,\n waitMultiplier: this.#multiplier,\n maxBatchIntervalMs: this.#maxIntervalMs,\n };\n if (this.#multiplier > 0) {\n this.#notPacingSince = undefined;\n if (this.#pacingLoggedAt === undefined) {\n lc.info?.(\n 'Sync worker is over its share target: its client groups wait between batches',\n state,\n );\n this.#pacingLoggedAt = now;\n } else if (now - this.#pacingLoggedAt >= PACING_LOG_INTERVAL_MS) {\n if (allAtMax && this.#share > this.#shareTarget) {\n // Waiting longer is not an option, so pacing cannot bring the\n // worker to its target: it has more to do than it has time for.\n lc.warn?.(\n 'Sync worker is over its share target although every client group waits the longest it may',\n state,\n );\n } else {\n lc.info?.('Sync worker is pacing its client groups', state);\n }\n this.#pacingLoggedAt = now;\n }\n } else if (this.#pacingLoggedAt !== undefined) {\n // A worker around its target goes in and out of pacing. It only says\n // that it has stopped once it has stayed out.\n this.#notPacingSince ??= now;\n if (now - this.#notPacingSince >= PACING_LOG_INTERVAL_MS) {\n lc.info?.(\n 'Sync worker is under its share target: its client groups no longer wait',\n state,\n );\n this.#pacingLoggedAt = undefined;\n this.#notPacingSince = undefined;\n }\n }\n }\n\n /**\n * Yields the worker to the other work that is waiting for a time slice,\n * and resolves when it is the caller's turn again. One piece of work runs\n * per turn of the event loop, as when the work of a worker's client groups\n * simply takes turns, except that the hydration of new queries goes first:\n * while both kinds of work are waiting, `HYDRATION_PRIORITY` slices go to\n * hydrations for each one that goes to a batch.\n *\n * Batches are never made to wait for anything but a slice. If no\n * hydration is waiting for one (because none is running, or because those\n * that are running are waiting for I/O), batches get every slice. And\n * however many hydrations there are, batches keep a share of the slices,\n * so they keep moving, and so do the snapshots of the replica that they\n * hold.\n */\n yieldSlice(kind: 'hydration' | 'batch'): Promise<void> {\n return new Promise(resolve => {\n this.#waiting[kind].push(resolve);\n if (!this.#handingOutSlices) {\n this.#handingOutSlices = true;\n setImmediate(this.#nextSlice);\n }\n });\n }\n\n readonly #nextSlice = () => {\n const {hydration, batch} = this.#waiting;\n let next: (() => void) | undefined;\n if (\n hydration.length > 0 &&\n (batch.length === 0 || this.#hydrationSlices < HYDRATION_PRIORITY)\n ) {\n next = hydration.shift();\n this.#hydrationSlices++;\n } else if (batch.length > 0) {\n next = batch.shift();\n this.#hydrationSlices = 0;\n }\n if (next === undefined) {\n this.#handingOutSlices = false;\n return;\n }\n next();\n // After the work that was just resumed has run its slice.\n setImmediate(this.#nextSlice);\n };\n}\n\n/**\n * How many time slices go to the hydration of new queries for each one that\n * goes to a batch, while both are waiting for one.\n */\nconst HYDRATION_PRIORITY = 9;\n"],"mappings":"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"}
@@ -204,6 +204,32 @@ export declare class CVRQueryDrivenUpdater extends CVRUpdater {
204
204
  * rows of the aborted queries have been {@link received}.
205
205
  */
206
206
  abortExecutedQueries(lc: LogContext, queryIDs: readonly string[]): Promise<PatchToVersion[]>;
207
+ /**
208
+ * Retracts what queries have contributed to this update, so that they can
209
+ * be executed again from scratch in the same update. This is for a query
210
+ * whose changes were being received incrementally (see
211
+ * `PipelineDriver.advance()`) until its pipeline was abandoned in favor of
212
+ * hydrating it again.
213
+ *
214
+ * Rows received so far in this update have the queries' references
215
+ * stripped, as in {@link abortExecutedQueries}, except that a row left
216
+ * with no references is only deleted by {@link deleteUnreferencedRows}, if
217
+ * it is still unreferenced by then. Until then the clients keep the row
218
+ * and the patches they received for it in this update, so a row that is
219
+ * received again unchanged needs no patch at all. The queries are then
220
+ * tracked as executed, without changing them in the CVR: the references
221
+ * they held before this update are replaced, rather than adjusted, by the
222
+ * rows subsequently {@link received} for them, and
223
+ * {@link deleteUnreferencedRows} drops the references of rows that are not
224
+ * received again.
225
+ *
226
+ * Unlike {@link trackQueries}, this can be called on an updater that has
227
+ * not tracked any queries, and after rows have been received. All rows
228
+ * that the queries' pipelines have output must have been {@link received}
229
+ * first, and {@link deleteUnreferencedRows} must be called once the
230
+ * queries' rows have been received again.
231
+ */
232
+ retractQueries(lc: LogContext, queryIDs: readonly string[]): Promise<PatchToVersion[]>;
207
233
  updatedVersion(): CVRVersion;
208
234
  /**
209
235
  * Public alias for {@link _ensureNewVersion}. Forces a `configVersion` bump
@@ -221,7 +247,7 @@ export declare class CVRQueryDrivenUpdater extends CVRUpdater {
221
247
  * returns (put) patches to be returned to update their state, versioned by
222
248
  * patchVersion so that only the patches new to the clients are sent.
223
249
  */
224
- received(_lc: LogContext, rows: Map<RowID, RowUpdate>): Promise<PatchToVersion[]>;
250
+ received(lc: LogContext, rows: Map<RowID, RowUpdate>): Promise<PatchToVersion[]>;
225
251
  /**
226
252
  * Computes and updates the row records based on:
227
253
  * * The {@link #executed} queries
@@ -1 +1 @@
1
- {"version":3,"file":"cvr.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,UAAU,EAAC,MAAM,kBAAkB,CAAC;AAGjD,OAAO,EAAC,KAAK,UAAU,EAAC,MAAM,uCAAuC,CAAC;AAGtE,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,gCAAgC,CAAC;AAQxC,OAAO,KAAK,EAAC,GAAG,EAAC,MAAM,sCAAsC,CAAC;AAC9D,OAAO,KAAK,EAAC,YAAY,EAAC,MAAM,gDAAgD,CAAC;AASjF,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAiB,KAAK,OAAO,EAAC,MAAM,uBAAuB,CAAC;AACnE,OAAO,KAAK,EAAQ,cAAc,EAAC,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAC,KAAK,aAAa,EAAE,KAAK,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAML,KAAK,YAAY,EAEjB,KAAK,UAAU,EACf,KAAK,mBAAmB,EACxB,KAAK,WAAW,EAChB,KAAK,KAAK,EAEX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAmB,KAAK,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAE/D,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,SAAS,EAAE;QAAC,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAC,CAAC;CACrC,CAAC;AAEF,wCAAwC;AACxC,MAAM,MAAM,GAAG,GAAG;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,UAAU,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACtC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,mCAAmC;AAEnC,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACzD,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IACxD,QAAQ,CAAC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC,CAAC;AAcF,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,MAAM,EACtB,aAAa,EAAE,MAAM,GACpB,mBAAmB,CA+BrB;AAED;;;;;;;;GAQG;AACH,qBAAa,UAAU;IACrB,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IACtC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IAE7B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;IAEvC;;;OAGG;IACH,YACE,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,WAAW,EAChB,cAAc,EAAE,MAAM,GAAG,IAAI,EAQ9B;IAED,SAAS,CAAC,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAKxD;IAED,SAAS,CAAC,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAYjD;IAED,SAAS,CAAC,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAKvD;IAED,SAAS,CAAC,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,WAAW,CAc/C;IAED,SAAS,CAAC,WAAW,CAAC,OAAO,EAAE,UAAU;;;MAOxC;IAED;;;;OAIG;IACH,SAAS,CAAC,iBAAiB,IAAI,UAAU,CAKxC;IAED;;;OAGG;IACG,KAAK,CACT,EAAE,EAAE,UAAU,EACd,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,QAAQ,EAClB,UAAU,UAAQ,GACjB,OAAO,CAAC;QACT,GAAG,EAAE,WAAW,CAAC;QACjB,OAAO,EAAE,aAAa,GAAG,KAAK,CAAC;KAChC,CAAC,CAcD;CACF;AAED;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,UAAU;;IAGpD,YAAY,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,OAAO,EAG/D;IAED,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,CAmDrC;IAED,eAAe,CAAC,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,QAwBzD;IAED,YAAY,CAAC,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAgB7C;IAED,iBAAiB,CACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,QAAQ,CAAC;QAChB,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,GAAG,GAAG,SAAS,CAAC;QACtB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC1B,IAAI,CAAC,EAAE,SAAS,iBAAiB,EAAE,GAAG,SAAS,CAAC;QAChD,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KAC1B,CAAC,EAAE,GACH,cAAc,EAAE,CA4FlB;IAED,4BAA4B,CAC1B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,EAAE,QAAQ,GACjB,cAAc,EAAE,CAElB;IAED,oBAAoB,CAClB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EAAE,GACpB,cAAc,EAAE,CAElB;IAuED,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,EAAE,CAGtD;IAED,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,cAAc,EAAE,CAwBnE;CACF;AAED,KAAK,IAAI,GAAG,MAAM,CAAC;AACnB,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAC5B,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAO7C;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,uBAAuB,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;IAE5C;;;OAGG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IAErD,6DAA6D;IAC7D,4BAA4B,IAAI,IAAI,CAAC;CACtC;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,qBAAsB,SAAQ,UAAU;;IAWnD;;;;;OAKG;IACH,YACE,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,WAAW,EAChB,YAAY,EAAE,WAAW,EACzB,cAAc,EAAE,MAAM,EACtB,eAAe,CAAC,EAAE,uBAAuB,EAoB1C;IAED;;;;;;;;;;;;OAYG;IACH,YAAY,CACV,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,kBAAkB,EAAE,MAAM,CAAA;KAAC,EAAE,EACpD,OAAO,EAAE;QAAC,EAAE,EAAE,MAAM,CAAA;KAAC,EAAE,GACtB;QAAC,UAAU,EAAE,UAAU,CAAC;QAAC,YAAY,EAAE,cAAc,EAAE,CAAA;KAAC,CA6B1D;IAuFD;;;;;;;;;;;OAWG;IACH,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,cAAc,EAAE,CAgCjE;IAED;;;;;;;;;;;;;;;OAeG;IACG,oBAAoB,CACxB,EAAE,EAAE,UAAU,EACd,QAAQ,EAAE,SAAS,MAAM,EAAE,GAC1B,OAAO,CAAC,cAAc,EAAE,CAAC,CAqD3B;IA2DD,cAAc,IAAI,UAAU,CAE3B;IAED;;;;OAIG;IACH,gBAAgB,IAAI,UAAU,CAE7B;IAEc,KAAK,CAClB,EAAE,EAAE,UAAU,EACd,eAAe,EAAE,MAAM,EACvB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,QAAQ,EAClB,UAAU,UAAQ,GACjB,OAAO,CAAC;QAAC,GAAG,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,aAAa,GAAG,KAAK,CAAA;KAAC,CAAC,CAsC7D;IAED;;;;;OAKG;IACH,QAAQ,CACN,GAAG,EAAE,UAAU,EACf,IAAI,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,CAAC,GAC1B,OAAO,CAAC,cAAc,EAAE,CAAC,CA0G3B;IAED;;;;;;;;;;;OAWG;IACH,sBAAsB,CAAC,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CA2CjE;CA8CF;AAgCD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,GAAG,GAAG;IAC5C,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,QAAQ,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;CACb,EAAE,CA+DF;AAED,MAAM,MAAM,oBAAoB,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI;IACtE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACd;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC,CAAC,EAAE,mBAAmB,CAAC,EAAE,CAAC;CAC7C,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,CAAC,SAAS,WAAW,EAC/D,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,GACnB,oBAAoB,CAAC,CAAC,CAAC,CA2CzB;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,GAAG,GAAG,QAAQ,GAAG,SAAS,CAS/D"}
1
+ {"version":3,"file":"cvr.d.ts","sourceRoot":"","sources":["../../../../../../zero-cache/src/services/view-syncer/cvr.ts"],"names":[],"mappings":"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"}
@@ -365,6 +365,13 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
365
365
  #executedQueryIDs = /* @__PURE__ */ new Set();
366
366
  #receivedRows = new CustomKeyMap(rowIDString);
367
367
  #lastPatches = new CustomKeyMap(rowIDString);
368
+ /**
369
+ * Rows that {@link retractQueries} left without references, and the patch
370
+ * version of their deletion. The 'del' patches are held back until
371
+ * {@link deleteUnreferencedRows}, because the retracted queries are
372
+ * executed again and usually reference most of these rows again.
373
+ */
374
+ #retractedRows = new CustomKeyMap(rowIDString);
368
375
  #rowSetSignature;
369
376
  #existingRows = void 0;
370
377
  /**
@@ -398,7 +405,7 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
398
405
  assert(this.#existingRows === void 0, `trackQueries already called`);
399
406
  const queryPatches = [executed.map((q) => this.#trackExecuted(q.id, q.transformationHash)), removed.map((q) => this.#trackRemoved(q.id))].flat(2);
400
407
  this.#existingRows = this.#lookupRowsForExecutedAndRemovedQueries(lc);
401
- this.#existingRows.then(() => {});
408
+ this.#existingRows.catch(() => {});
402
409
  const versionBumped = cmpVersions(this._orig.version, this._cvr.version) < 0;
403
410
  lc.info?.(`trackQueries: ${executed.length} executed, ${removed.length} removed, version ${versionBumped ? "bumped" : "unchanged"}`);
404
411
  return {
@@ -518,12 +525,37 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
518
525
  assert(this.#executedQueryIDs.has(queryID), `Query ${queryID} was not tracked as executed`);
519
526
  assertNotInternal(must(this._cvr.queries[queryID]));
520
527
  }
528
+ const patches = await this.#unrefReceivedRows(lc, aborted);
529
+ for (const queryID of aborted) {
530
+ delete this._mutableQueries()[queryID];
531
+ const patch = {
532
+ type: "query",
533
+ op: "del",
534
+ id: queryID
535
+ };
536
+ this._cvrStore.markQueryAsDeleted(this._cvr.version, patch);
537
+ patches.push({
538
+ patch,
539
+ toVersion: this._cvr.version
540
+ });
541
+ }
542
+ return patches;
543
+ }
544
+ /**
545
+ * Strips the references of `queryIDs` from every row received so far in
546
+ * this update. A row left with no references is deleted, and the 'del'
547
+ * patch cancels the 'put' the client has already received in this poke. The
548
+ * version of each unref is the version the row currently has in this
549
+ * update, so a row that stays referenced does not get a spurious patch
550
+ * version bump.
551
+ */
552
+ async #unrefReceivedRows(lc, queryIDs, holdDeletes = false) {
521
553
  const existingRows = await this._cvrStore.getRowRecords();
522
554
  const unrefs = new CustomKeyMap(rowIDString);
523
555
  for (const [id, refCounts] of this.#receivedRows) {
524
556
  if (refCounts === null) continue;
525
557
  let unref;
526
- for (const queryID of aborted) {
558
+ for (const queryID of queryIDs) {
527
559
  const count = refCounts[queryID];
528
560
  if (!count) continue;
529
561
  if (!unref) {
@@ -537,19 +569,50 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
537
569
  unref.refCounts[queryID] = -count;
538
570
  }
539
571
  }
540
- const patches = unrefs.size > 0 ? await this.received(lc, unrefs) : [];
541
- for (const queryID of aborted) {
542
- delete this._mutableQueries()[queryID];
543
- const patch = {
544
- type: "query",
545
- op: "del",
546
- id: queryID
547
- };
548
- this._cvrStore.markQueryAsDeleted(this._cvr.version, patch);
549
- patches.push({
550
- patch,
551
- toVersion: this._cvr.version
552
- });
572
+ return unrefs.size > 0 ? this.#receive(lc, unrefs, holdDeletes) : [];
573
+ }
574
+ /**
575
+ * Retracts what queries have contributed to this update, so that they can
576
+ * be executed again from scratch in the same update. This is for a query
577
+ * whose changes were being received incrementally (see
578
+ * `PipelineDriver.advance()`) until its pipeline was abandoned in favor of
579
+ * hydrating it again.
580
+ *
581
+ * Rows received so far in this update have the queries' references
582
+ * stripped, as in {@link abortExecutedQueries}, except that a row left
583
+ * with no references is only deleted by {@link deleteUnreferencedRows}, if
584
+ * it is still unreferenced by then. Until then the clients keep the row
585
+ * and the patches they received for it in this update, so a row that is
586
+ * received again unchanged needs no patch at all. The queries are then
587
+ * tracked as executed, without changing them in the CVR: the references
588
+ * they held before this update are replaced, rather than adjusted, by the
589
+ * rows subsequently {@link received} for them, and
590
+ * {@link deleteUnreferencedRows} drops the references of rows that are not
591
+ * received again.
592
+ *
593
+ * Unlike {@link trackQueries}, this can be called on an updater that has
594
+ * not tracked any queries, and after rows have been received. All rows
595
+ * that the queries' pipelines have output must have been {@link received}
596
+ * first, and {@link deleteUnreferencedRows} must be called once the
597
+ * queries' rows have been received again.
598
+ */
599
+ async retractQueries(lc, queryIDs) {
600
+ assert(cmpVersions(this._orig.version, this._cvr.version) < 0, "A final CVR version must be set before retracting queries");
601
+ const retracted = new Set(queryIDs);
602
+ for (const queryID of retracted) {
603
+ assert(this._cvr.queries[queryID] !== void 0, () => `Query ${queryID} is not in the CVR`);
604
+ assert(this.#executedQueryIDs.has(queryID) || !this.#removedOrExecutedQueryIDs.has(queryID), () => `Query ${queryID} was tracked as removed`);
605
+ }
606
+ const patches = await this.#unrefReceivedRows(lc, retracted, true);
607
+ let tracked = false;
608
+ for (const queryID of retracted) if (!this.#executedQueryIDs.has(queryID)) {
609
+ this.#removedOrExecutedQueryIDs.add(queryID);
610
+ this.#executedQueryIDs.add(queryID);
611
+ tracked = true;
612
+ }
613
+ if (tracked) {
614
+ this.#existingRows = this.#lookupRowsForExecutedAndRemovedQueries(lc);
615
+ this.#existingRows.then(() => {});
553
616
  }
554
617
  return patches;
555
618
  }
@@ -622,7 +685,14 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
622
685
  * returns (put) patches to be returned to update their state, versioned by
623
686
  * patchVersion so that only the patches new to the clients are sent.
624
687
  */
625
- received(_lc, rows) {
688
+ received(lc, rows) {
689
+ return this.#receive(lc, rows, false);
690
+ }
691
+ /**
692
+ * @param holdDeletes Whether to hold back the 'del' patches of rows that
693
+ * are left without references until {@link deleteUnreferencedRows}.
694
+ */
695
+ #receive(_lc, rows, holdDeletes) {
626
696
  return startAsyncSpan(tracer, "CVRQueryDrivenUpdater.received", async () => {
627
697
  const patches = [];
628
698
  const existingRows = await this._cvrStore.getRowRecords();
@@ -632,6 +702,7 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
632
702
  const previouslyReceived = this.#receivedRows.get(id);
633
703
  const merged = previouslyReceived !== void 0 ? mergeRefCounts(previouslyReceived, refCounts) : mergeRefCounts(existing?.refCounts, refCounts, this.#removedOrExecutedQueryIDs);
634
704
  this.#receivedRows.set(id, merged);
705
+ if (merged !== null) this.#retractedRows.delete(id);
635
706
  const newRowVersion = merged === null ? void 0 : version;
636
707
  const patchVersion = existing && existing.rowVersion === newRowVersion ? existing.patchVersion : this.#assertNewVersion(id, existing?.rowVersion, newRowVersion, refCounts);
637
708
  const rowVersion = version ?? existing?.rowVersion;
@@ -646,7 +717,8 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
646
717
  const toVersion = maxVersion(patchVersion, lastPatch?.toVersion);
647
718
  if (merged === null) {
648
719
  if (existing || previouslyReceived) {
649
- if (lastPatch?.rowVersion !== null) {
720
+ if (holdDeletes) this.#retractedRows.set(id, toVersion);
721
+ else if (lastPatch?.rowVersion !== null) {
650
722
  patches.push({
651
723
  patch: {
652
724
  type: "row",
@@ -704,6 +776,24 @@ var CVRQueryDrivenUpdater = class extends CVRUpdater {
704
776
  const patches = [];
705
777
  const start = Date.now();
706
778
  assert(this.#existingRows, `trackQueries() was not called`);
779
+ for (const [id, deletedVersion] of this.#retractedRows) {
780
+ const lastPatch = this.#lastPatches.get(id);
781
+ if (lastPatch?.rowVersion === null) continue;
782
+ const toVersion = maxVersion(deletedVersion, lastPatch?.toVersion);
783
+ patches.push({
784
+ toVersion,
785
+ patch: {
786
+ type: "row",
787
+ op: "del",
788
+ id
789
+ }
790
+ });
791
+ this.#lastPatches.set(id, {
792
+ rowVersion: null,
793
+ toVersion
794
+ });
795
+ }
796
+ this.#retractedRows.clear();
707
797
  for (const existing of await this.#existingRows) {
708
798
  const deletedID = this.#deleteUnreferencedRow(existing);
709
799
  if (deletedID === null) continue;