@quereus/quereus 3.1.2 → 3.2.1

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 (142) hide show
  1. package/dist/src/core/database-assertions.js +3 -3
  2. package/dist/src/core/database-assertions.js.map +1 -1
  3. package/dist/src/core/database.js +3 -3
  4. package/dist/src/core/database.js.map +1 -1
  5. package/dist/src/core/statement.js +3 -3
  6. package/dist/src/core/statement.js.map +1 -1
  7. package/dist/src/index.d.ts +2 -1
  8. package/dist/src/index.d.ts.map +1 -1
  9. package/dist/src/index.js +1 -0
  10. package/dist/src/index.js.map +1 -1
  11. package/dist/src/parser/visitor.js +1 -1
  12. package/dist/src/parser/visitor.js.map +1 -1
  13. package/dist/src/planner/analysis/attribute-provenance.d.ts +45 -0
  14. package/dist/src/planner/analysis/attribute-provenance.d.ts.map +1 -0
  15. package/dist/src/planner/analysis/attribute-provenance.js +81 -0
  16. package/dist/src/planner/analysis/attribute-provenance.js.map +1 -0
  17. package/dist/src/planner/analysis/const-evaluator.js +5 -5
  18. package/dist/src/planner/analysis/const-evaluator.js.map +1 -1
  19. package/dist/src/planner/building/select-window.d.ts.map +1 -1
  20. package/dist/src/planner/building/select-window.js +54 -21
  21. package/dist/src/planner/building/select-window.js.map +1 -1
  22. package/dist/src/planner/cache/correlation-detector.d.ts +7 -0
  23. package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -1
  24. package/dist/src/planner/cache/correlation-detector.js +34 -2
  25. package/dist/src/planner/cache/correlation-detector.js.map +1 -1
  26. package/dist/src/planner/nodes/async-gather-node.d.ts +169 -0
  27. package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -0
  28. package/dist/src/planner/nodes/async-gather-node.js +488 -0
  29. package/dist/src/planner/nodes/async-gather-node.js.map +1 -0
  30. package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
  31. package/dist/src/planner/nodes/bloom-join-node.js +8 -7
  32. package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
  33. package/dist/src/planner/nodes/eager-prefetch-node.d.ts +47 -0
  34. package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -0
  35. package/dist/src/planner/nodes/eager-prefetch-node.js +96 -0
  36. package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -0
  37. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +150 -0
  38. package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -0
  39. package/dist/src/planner/nodes/fanout-lookup-join-node.js +265 -0
  40. package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -0
  41. package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
  42. package/dist/src/planner/nodes/merge-join-node.js +8 -7
  43. package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
  44. package/dist/src/planner/nodes/plan-node-type.d.ts +3 -0
  45. package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
  46. package/dist/src/planner/nodes/plan-node-type.js +3 -0
  47. package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
  48. package/dist/src/planner/nodes/plan-node.d.ts +36 -0
  49. package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
  50. package/dist/src/planner/nodes/plan-node.js +26 -0
  51. package/dist/src/planner/nodes/plan-node.js.map +1 -1
  52. package/dist/src/planner/nodes/reference.d.ts.map +1 -1
  53. package/dist/src/planner/nodes/reference.js +13 -0
  54. package/dist/src/planner/nodes/reference.js.map +1 -1
  55. package/dist/src/planner/optimizer-tuning.d.ts +107 -0
  56. package/dist/src/planner/optimizer-tuning.d.ts.map +1 -1
  57. package/dist/src/planner/optimizer-tuning.js +43 -0
  58. package/dist/src/planner/optimizer-tuning.js.map +1 -1
  59. package/dist/src/planner/optimizer.d.ts.map +1 -1
  60. package/dist/src/planner/optimizer.js +91 -0
  61. package/dist/src/planner/optimizer.js.map +1 -1
  62. package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
  63. package/dist/src/planner/rules/access/rule-monotonic-range-access.js +1 -6
  64. package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
  65. package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts +74 -0
  66. package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts.map +1 -0
  67. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +139 -0
  68. package/dist/src/planner/rules/join/rule-fanout-batched-outer.js.map +1 -0
  69. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts +58 -0
  70. package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -0
  71. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +592 -0
  72. package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -0
  73. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts +43 -0
  74. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts.map +1 -0
  75. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js +115 -0
  76. package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js.map +1 -0
  77. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts +102 -0
  78. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts.map +1 -0
  79. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +545 -0
  80. package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -0
  81. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts +45 -0
  82. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts.map +1 -0
  83. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js +78 -0
  84. package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js.map +1 -0
  85. package/dist/src/planner/scopes/param.d.ts.map +1 -1
  86. package/dist/src/planner/scopes/param.js +13 -11
  87. package/dist/src/planner/scopes/param.js.map +1 -1
  88. package/dist/src/planner/type-utils.js +1 -1
  89. package/dist/src/planner/type-utils.js.map +1 -1
  90. package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
  91. package/dist/src/planner/validation/plan-validator.js +17 -19
  92. package/dist/src/planner/validation/plan-validator.js.map +1 -1
  93. package/dist/src/runtime/async-semaphore.d.ts +36 -0
  94. package/dist/src/runtime/async-semaphore.d.ts.map +1 -0
  95. package/dist/src/runtime/async-semaphore.js +72 -0
  96. package/dist/src/runtime/async-semaphore.js.map +1 -0
  97. package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
  98. package/dist/src/runtime/deferred-constraint-queue.js +4 -3
  99. package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
  100. package/dist/src/runtime/emit/async-gather.d.ts +77 -0
  101. package/dist/src/runtime/emit/async-gather.d.ts.map +1 -0
  102. package/dist/src/runtime/emit/async-gather.js +234 -0
  103. package/dist/src/runtime/emit/async-gather.js.map +1 -0
  104. package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
  105. package/dist/src/runtime/emit/bloom-join.js +38 -17
  106. package/dist/src/runtime/emit/bloom-join.js.map +1 -1
  107. package/dist/src/runtime/emit/eager-prefetch.d.ts +77 -0
  108. package/dist/src/runtime/emit/eager-prefetch.d.ts.map +1 -0
  109. package/dist/src/runtime/emit/eager-prefetch.js +223 -0
  110. package/dist/src/runtime/emit/eager-prefetch.js.map +1 -0
  111. package/dist/src/runtime/emit/fanout-lookup-join.d.ts +130 -0
  112. package/dist/src/runtime/emit/fanout-lookup-join.d.ts.map +1 -0
  113. package/dist/src/runtime/emit/fanout-lookup-join.js +521 -0
  114. package/dist/src/runtime/emit/fanout-lookup-join.js.map +1 -0
  115. package/dist/src/runtime/parallel-driver.d.ts +68 -0
  116. package/dist/src/runtime/parallel-driver.d.ts.map +1 -0
  117. package/dist/src/runtime/parallel-driver.js +233 -0
  118. package/dist/src/runtime/parallel-driver.js.map +1 -0
  119. package/dist/src/runtime/register.d.ts.map +1 -1
  120. package/dist/src/runtime/register.js +9 -0
  121. package/dist/src/runtime/register.js.map +1 -1
  122. package/dist/src/runtime/strict-fork.d.ts +36 -0
  123. package/dist/src/runtime/strict-fork.d.ts.map +1 -0
  124. package/dist/src/runtime/strict-fork.js +125 -0
  125. package/dist/src/runtime/strict-fork.js.map +1 -0
  126. package/dist/src/util/comparison.d.ts.map +1 -1
  127. package/dist/src/util/comparison.js +11 -1
  128. package/dist/src/util/comparison.js.map +1 -1
  129. package/dist/src/vtab/concurrency.d.ts +29 -0
  130. package/dist/src/vtab/concurrency.d.ts.map +1 -0
  131. package/dist/src/vtab/concurrency.js +47 -0
  132. package/dist/src/vtab/concurrency.js.map +1 -0
  133. package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
  134. package/dist/src/vtab/memory/layer/scan-layer.js +67 -29
  135. package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
  136. package/dist/src/vtab/memory/module.d.ts +21 -0
  137. package/dist/src/vtab/memory/module.d.ts.map +1 -1
  138. package/dist/src/vtab/memory/module.js +21 -0
  139. package/dist/src/vtab/memory/module.js.map +1 -1
  140. package/dist/src/vtab/module.d.ts +47 -0
  141. package/dist/src/vtab/module.d.ts.map +1 -1
  142. package/package.json +4 -3
@@ -0,0 +1,234 @@
1
+ import { emitCallFromPlan } from '../emitters.js';
2
+ import { ParallelDriver } from '../parallel-driver.js';
3
+ import { BTree } from 'inheritree';
4
+ import { createCollationRowComparator, BINARY_COLLATION } from '../../util/comparison.js';
5
+ /**
6
+ * Yield the N-ary Cartesian product of the given per-branch row buffers, in
7
+ * lexicographic order over branch indices (branch 0 varies slowest). Caller
8
+ * is responsible for confirming every buffer is non-empty; an empty buffer
9
+ * means the product is empty and this helper should not be called.
10
+ *
11
+ * Exported for unit testing.
12
+ */
13
+ export function* cartesianProduct(buffers) {
14
+ const n = buffers.length;
15
+ const indices = new Array(n).fill(0);
16
+ while (true) {
17
+ const row = [];
18
+ for (let i = 0; i < n; i++) {
19
+ const sub = buffers[i][indices[i]];
20
+ for (let j = 0; j < sub.length; j++) {
21
+ row.push(sub[j]);
22
+ }
23
+ }
24
+ yield row;
25
+ let k = n - 1;
26
+ while (k >= 0) {
27
+ indices[k]++;
28
+ if (indices[k] < buffers[k].length)
29
+ break;
30
+ indices[k] = 0;
31
+ k--;
32
+ }
33
+ if (k < 0)
34
+ return;
35
+ }
36
+ }
37
+ /**
38
+ * Async-iterate the `unionAll` shape: fork N child views off `rctx`, drive
39
+ * the factories concurrently via {@link ParallelDriver.drive}, and yield every
40
+ * produced row in arrival order. Yielded order is non-deterministic.
41
+ *
42
+ * Exported for unit testing — production callers go through {@link emitAsyncGather}.
43
+ */
44
+ export async function* runUnionAll(rctx, factories, concurrencyCap, driver = new ParallelDriver()) {
45
+ const forks = driver.fork(rctx, factories.length);
46
+ for await (const { value } of driver.drive(factories, forks, { concurrency: concurrencyCap })) {
47
+ yield value;
48
+ }
49
+ }
50
+ /**
51
+ * Async-iterate the `crossProduct` shape: fork N child views off `rctx`,
52
+ * drive the factories concurrently, buffer every branch's rows in memory,
53
+ * then yield the full N-ary Cartesian product. **Every branch is drained
54
+ * before the first row is yielded.** If any branch is empty, the product
55
+ * is empty.
56
+ *
57
+ * Exported for unit testing — production callers go through {@link emitAsyncGather}.
58
+ */
59
+ export async function* runCrossProduct(rctx, factories, concurrencyCap, driver = new ParallelDriver()) {
60
+ const n = factories.length;
61
+ const forks = driver.fork(rctx, n);
62
+ const buffers = Array.from({ length: n }, () => []);
63
+ for await (const { branch, value } of driver.drive(factories, forks, {
64
+ concurrency: concurrencyCap,
65
+ })) {
66
+ buffers[branch].push(value);
67
+ }
68
+ for (let i = 0; i < n; i++) {
69
+ if (buffers[i].length === 0)
70
+ return;
71
+ }
72
+ yield* cartesianProduct(buffers);
73
+ }
74
+ /**
75
+ * Compose the merged key cells for a group **deterministically**: the
76
+ * lowest-indexed branch that has a row for this key supplies all K key cells.
77
+ *
78
+ * This matches `coalesce(b0.k, b1.k, …)`'s left-to-right first-non-null
79
+ * contract: every branch present for a (non-NULL) key has all its key columns
80
+ * non-null and collation-equal to the group key, so the first present branch
81
+ * wins every key position — independent of concurrent arrival order. Callers
82
+ * guarantee at least one branch is present.
83
+ */
84
+ function composeMergedKeyCells(cells, branchKeyIndices) {
85
+ for (let b = 0; b < cells.length; b++) {
86
+ const cell = cells[b];
87
+ if (cell)
88
+ return branchKeyIndices[b].map(ix => cell[ix]);
89
+ }
90
+ // Unreachable: a group always has at least one present branch.
91
+ return [];
92
+ }
93
+ /**
94
+ * Compose one output row from a key tuple and per-branch row slots:
95
+ * `[ key cells ] ++ for each branch b: (cells[b] ? its non-key cells : NULLs)`.
96
+ */
97
+ function composeZipRow(keyCells, cells, branchNonKeyIndices) {
98
+ const out = [...keyCells];
99
+ for (let b = 0; b < cells.length; b++) {
100
+ const cell = cells[b];
101
+ const nonKeyIx = branchNonKeyIndices[b];
102
+ if (cell) {
103
+ for (const ix of nonKeyIx)
104
+ out.push(cell[ix]);
105
+ }
106
+ else {
107
+ for (let j = 0; j < nonKeyIx.length; j++)
108
+ out.push(null);
109
+ }
110
+ }
111
+ return out;
112
+ }
113
+ /**
114
+ * Async-iterate the `zipByKey` shape: a full N-way outer join on the shared key
115
+ * columns, implemented as an **eager hash-merge**. Forks N child views off
116
+ * `rctx`, drives the factories concurrently, and upserts each row into a `BTree`
117
+ * keyed by its key tuple. **Every branch is drained before the first row is
118
+ * yielded** (memory-bound, like {@link runCrossProduct}).
119
+ *
120
+ * NULL keys never merge (SQL `NULL = NULL` is unknown): each NULL-keyed row is
121
+ * buffered and emitted standalone (only its own branch's columns populated).
122
+ *
123
+ * The merged key cells are **deterministic** regardless of concurrent branch
124
+ * arrival order: at emit time the lowest-indexed present branch supplies them
125
+ * (see {@link composeMergedKeyCells}), matching `coalesce`'s left-to-right pick
126
+ * even under a non-binary collation that makes collation-equal keys byte-distinct
127
+ * (NOCASE `'A'`/`'a'`). The `BTree` is still keyed by whichever key tuple arrived
128
+ * first, but that only drives comparison (collation-equal → identical merges).
129
+ *
130
+ * Within-branch duplicate keys are **unspecified** in v1 — branches are assumed
131
+ * key-unique; a second write for the same key overwrites the first.
132
+ *
133
+ * Exported for unit testing — production callers go through {@link emitAsyncGather}.
134
+ */
135
+ export async function* runZipByKey(rctx, factories, branchKeyIndices, branchNonKeyIndices, keyComparator, concurrencyCap, driver = new ParallelDriver()) {
136
+ const n = factories.length;
137
+ const forks = driver.fork(rctx, n);
138
+ const tree = new BTree(e => e.key, keyComparator);
139
+ const nullKeyed = [];
140
+ for await (const { branch, value } of driver.drive(factories, forks, { concurrency: concurrencyCap })) {
141
+ const keyRow = branchKeyIndices[branch].map(ix => value[ix]);
142
+ if (keyRow.some(v => v === null)) {
143
+ // NULL key: never merges; emit standalone at the end.
144
+ nullKeyed.push({ branch, value });
145
+ continue;
146
+ }
147
+ const path = tree.find(keyRow);
148
+ if (path.on) {
149
+ tree.at(path).cells[branch] = value;
150
+ }
151
+ else {
152
+ const cells = new Array(n).fill(undefined);
153
+ cells[branch] = value;
154
+ tree.insert({ key: keyRow, cells });
155
+ }
156
+ }
157
+ // Walk the tree in key order; the tree is no longer mutated, so a plain
158
+ // first()/moveNext() walk is safe (no safeIterate recovery needed).
159
+ const path = tree.first();
160
+ while (path.on) {
161
+ const entry = tree.at(path);
162
+ const keyCells = composeMergedKeyCells(entry.cells, branchKeyIndices);
163
+ yield composeZipRow(keyCells, entry.cells, branchNonKeyIndices);
164
+ tree.moveNext(path);
165
+ }
166
+ // NULL-keyed rows: each emits standalone with only its branch's columns.
167
+ for (const { branch, value } of nullKeyed) {
168
+ const cells = new Array(n).fill(undefined);
169
+ cells[branch] = value;
170
+ const keyCells = composeMergedKeyCells(cells, branchKeyIndices);
171
+ yield composeZipRow(keyCells, cells, branchNonKeyIndices);
172
+ }
173
+ }
174
+ /**
175
+ * Emit an {@link AsyncGatherNode}.
176
+ *
177
+ * - `unionAll`: drives every branch concurrently and yields each branch's
178
+ * rows in arrival order (multiset union, no dedup). Downstream consumers
179
+ * requiring ordering must wrap the gather in `Sort`.
180
+ *
181
+ * - `crossProduct`: drives every branch concurrently, buffers each branch's
182
+ * rows in memory, then yields the full N-ary Cartesian product. **All
183
+ * branches are materialised before the first row is yielded.**
184
+ *
185
+ * - `zipByKey`: drives every branch concurrently, hash-merges rows by key tuple,
186
+ * then yields one composed row per distinct key (full N-way outer join).
187
+ * **All branches are materialised before the first row is yielded.**
188
+ *
189
+ * All combinators inherit cancellation, error propagation, strict-fork
190
+ * bookkeeping, and consumer-break cleanup from `ParallelDriver.drive`.
191
+ */
192
+ export function emitAsyncGather(plan, ctx) {
193
+ const childInstructions = plan.children.map(c => emitCallFromPlan(c, ctx));
194
+ const concurrencyCap = plan.concurrencyCap;
195
+ const branchCount = plan.children.length;
196
+ if (plan.combinator.kind === 'unionAll') {
197
+ function run(rctx, ...childFactories) {
198
+ return runUnionAll(rctx, childFactories, concurrencyCap);
199
+ }
200
+ return {
201
+ params: childInstructions,
202
+ run: run,
203
+ note: `async_gather(unionAll, N=${branchCount}, cap=${concurrencyCap})`,
204
+ };
205
+ }
206
+ if (plan.combinator.kind === 'zipByKey') {
207
+ const { branchKeyIndices, branchNonKeyIndices } = plan.getZipByKeyIndices();
208
+ // Build the key comparator from children[0]'s key column collations (key
209
+ // columns share affinity across branches per the construction contract).
210
+ const child0Attrs = plan.children[0].getAttributes();
211
+ const keyCollations = branchKeyIndices[0].map((colIx) => {
212
+ const attr = child0Attrs[colIx];
213
+ return attr.type.collationName ? ctx.resolveCollation(attr.type.collationName) : BINARY_COLLATION;
214
+ });
215
+ const keyComparator = createCollationRowComparator(keyCollations);
216
+ function run(rctx, ...childFactories) {
217
+ return runZipByKey(rctx, childFactories, branchKeyIndices, branchNonKeyIndices, keyComparator, concurrencyCap);
218
+ }
219
+ return {
220
+ params: childInstructions,
221
+ run: run,
222
+ note: `async_gather(zipByKey, N=${branchCount}, cap=${concurrencyCap})`,
223
+ };
224
+ }
225
+ function run(rctx, ...childFactories) {
226
+ return runCrossProduct(rctx, childFactories, concurrencyCap);
227
+ }
228
+ return {
229
+ params: childInstructions,
230
+ run: run,
231
+ note: `async_gather(crossProduct, N=${branchCount}, cap=${concurrencyCap})`,
232
+ };
233
+ }
234
+ //# sourceMappingURL=async-gather.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async-gather.js","sourceRoot":"","sources":["../../../../src/runtime/emit/async-gather.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"bloom-join.d.ts","sourceRoot":"","sources":["../../../../src/runtime/emit/bloom-join.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,aAAa,CAAC;AAG/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAS9D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,eAAe,GAAG,WAAW,CA2GpF"}
1
+ {"version":3,"file":"bloom-join.d.ts","sourceRoot":"","sources":["../../../../src/runtime/emit/bloom-join.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,KAAK,EAAE,WAAW,EAAkC,MAAM,aAAa,CAAC;AAG/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAS9D;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,aAAa,EAAE,GAAG,EAAE,eAAe,GAAG,WAAW,CA+HpF"}
@@ -36,27 +36,39 @@ export function emitBloomJoin(plan, ctx) {
36
36
  const rightColCount = rightAttributes.length;
37
37
  async function* run(rctx, leftSource, rightSource, residualCallback) {
38
38
  log('Starting %s hash join: %d equi-pairs, %d left attrs, %d right attrs', plan.joinType.toUpperCase(), plan.equiPairs.length, leftAttributes.length, rightAttributes.length);
39
- // === Build phase: materialize right side into hash map ===
40
- const hashMap = new Map();
41
- for await (const rightRow of rightSource) {
42
- const key = serializeRowKey(rightRow, rightIndices, keyNormalizers);
43
- if (key === null)
44
- continue; // null keys can't match
45
- const bucket = hashMap.get(key);
46
- if (bucket) {
47
- bucket.push(rightRow);
48
- }
49
- else {
50
- hashMap.set(key, [rightRow]);
51
- }
52
- }
53
- log('Build phase complete: %d buckets, right side materialized', hashMap.size);
54
- // === Probe phase: stream left side, probe hash map ===
39
+ // Acquire the left (probe) iterator up front. When `left` is an
40
+ // EagerPrefetchNode its pump is already running (it forks `rctx` and
41
+ // starts on run()), so we MUST guarantee the iterator is closed even if
42
+ // the build phase throws before the probe loop begins — otherwise the
43
+ // eager pump leaks (fills its buffer then blocks forever) and its
44
+ // strict-fork counter stays bumped. The `finally` below covers both
45
+ // phases for exactly that reason.
46
+ const leftIter = leftSource[Symbol.asyncIterator]();
55
47
  const isSemiOrAnti = plan.joinType === 'semi' || plan.joinType === 'anti';
56
48
  const leftSlot = createRowSlot(rctx, leftRowDescriptor);
57
49
  const rightSlot = createRowSlot(rctx, rightRowDescriptor);
58
50
  try {
59
- for await (const leftRow of leftSource) {
51
+ // === Build phase: materialize right side into hash map ===
52
+ const hashMap = new Map();
53
+ for await (const rightRow of rightSource) {
54
+ const key = serializeRowKey(rightRow, rightIndices, keyNormalizers);
55
+ if (key === null)
56
+ continue; // null keys can't match
57
+ const bucket = hashMap.get(key);
58
+ if (bucket) {
59
+ bucket.push(rightRow);
60
+ }
61
+ else {
62
+ hashMap.set(key, [rightRow]);
63
+ }
64
+ }
65
+ log('Build phase complete: %d buckets, right side materialized', hashMap.size);
66
+ // === Probe phase: stream left side, probe hash map ===
67
+ while (true) {
68
+ const next = await leftIter.next();
69
+ if (next.done)
70
+ break;
71
+ const leftRow = next.value;
60
72
  leftSlot.set(leftRow);
61
73
  const key = serializeRowKey(leftRow, leftIndices, keyNormalizers);
62
74
  let matched = false;
@@ -88,6 +100,15 @@ export function emitBloomJoin(plan, ctx) {
88
100
  finally {
89
101
  leftSlot.close();
90
102
  rightSlot.close();
103
+ // Close the probe iterator on every exit path (normal completion,
104
+ // consumer break, throw, or build-phase error) so an eager prefetch
105
+ // pump is always torn down.
106
+ try {
107
+ await leftIter.return?.(undefined);
108
+ }
109
+ catch {
110
+ // Swallow — already in cleanup.
111
+ }
91
112
  }
92
113
  }
93
114
  const leftInstruction = emitPlanNode(plan.left, ctx);
@@ -1 +1 @@
1
- {"version":3,"file":"bloom-join.js","sourceRoot":"","sources":["../../../../src/runtime/emit/bloom-join.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bloom-join.js","sourceRoot":"","sources":["../../../../src/runtime/emit/bloom-join.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ import type { EagerPrefetchNode } from '../../planner/nodes/eager-prefetch-node.js';
2
+ import type { Instruction, RuntimeContext } from '../types.js';
3
+ import type { Row } from '../../common/types.js';
4
+ import type { EmissionContext } from '../emission-context.js';
5
+ import { ParallelDriver } from '../parallel-driver.js';
6
+ /**
7
+ * Bounded promise-based prefetch buffer used by {@link emitEagerPrefetch}.
8
+ *
9
+ * Exactly one producer (the pump) and one consumer (the parent emit's
10
+ * iterator) operate on this at a time, so a single nullable callback for each
11
+ * direction is enough — no waiter queues required.
12
+ *
13
+ * Exported for unit-test access only.
14
+ */
15
+ export declare class BoundedPrefetchBuffer<T> {
16
+ private readonly capacity;
17
+ private readonly queue;
18
+ private done;
19
+ private hasError;
20
+ private error;
21
+ private spaceWaiter;
22
+ private itemWaiter;
23
+ constructor(capacity: number);
24
+ get size(): number;
25
+ /**
26
+ * Push an item, awaiting space when the buffer is full. Returns false if
27
+ * the abort signal fired before space became available; otherwise true.
28
+ */
29
+ push(item: T, signal: AbortSignal): Promise<boolean>;
30
+ /**
31
+ * Wait for an item, end-of-stream marker, or buffered error.
32
+ * Throws the cached error if {@link fail} was called.
33
+ */
34
+ shift(): Promise<{
35
+ done: true;
36
+ } | {
37
+ done: false;
38
+ value: T;
39
+ }>;
40
+ /** Mark end-of-stream; wakes a pending shifter. */
41
+ close(): void;
42
+ /** Record a producer error; wakes a pending shifter to throw it. */
43
+ fail(err: unknown): void;
44
+ }
45
+ /**
46
+ * Core prefetch primitive. Forks `rctx` and **eagerly** — at call time, before
47
+ * the consumer's first `next()` — starts a detached pump that drains the child
48
+ * iterator into a bounded buffer. The returned `AsyncIterable<Row>` hands rows
49
+ * out of that buffer; its iterator owns teardown via `next()`/`return()`/
50
+ * `throw()`.
51
+ *
52
+ * Eager-on-call is the point: when a `BloomJoinNode` wraps its probe (`left`) in
53
+ * this, the scheduler invokes `run()` during arg-assembly — before the join's
54
+ * generator body drains the build (`right`) — so the probe's first fetch is
55
+ * already in flight while the build materializes.
56
+ *
57
+ * Cleanup (abort pump, close buffer, child `return()`, drop strict-fork
58
+ * counters) fires when the iterator reaches done, `return()`, or `throw()`.
59
+ * Because the fork counters are bumped at construction, a returned iterable that
60
+ * is **never iterated** leaks the pump (it fills the buffer then blocks forever)
61
+ * and leaves the counters bumped — every consumer must guarantee iterate-or-
62
+ * close. Today the only inserter is `rule-eager-prefetch-probe`, and
63
+ * `emitBloomJoin` closes the left iterator in a `finally` covering both phases.
64
+ *
65
+ * Exported for unit testing — production callers go through {@link emitEagerPrefetch}.
66
+ */
67
+ export declare function prefetchAsyncIterable(rctx: RuntimeContext, sourceCallback: (innerCtx: RuntimeContext) => AsyncIterable<Row>, bufferSize: number, driver?: ParallelDriver): AsyncIterable<Row>;
68
+ /**
69
+ * Emit an EagerPrefetchNode: forks the runtime context and immediately starts
70
+ * pumping the child sub-tree into a bounded buffer, yielding rows from that
71
+ * buffer to the parent emit.
72
+ *
73
+ * The pump starts on `run()` (emit / scheduler arg-assembly), not on the
74
+ * consumer's first `next()`.
75
+ */
76
+ export declare function emitEagerPrefetch(plan: EagerPrefetchNode, ctx: EmissionContext): Instruction;
77
+ //# sourceMappingURL=eager-prefetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eager-prefetch.d.ts","sourceRoot":"","sources":["../../../../src/runtime/emit/eager-prefetch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,4CAA4C,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAkB,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,OAAO,EAAE,cAAc,EAAgD,MAAM,uBAAuB,CAAC;AAErG;;;;;;;;GAQG;AACH,qBAAa,qBAAqB,CAAC,CAAC;IAQvB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAPrC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAW;IACjC,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,UAAU,CAA6B;gBAElB,QAAQ,EAAE,MAAM;IAM7C,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;OAGG;IACG,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC;IAwB1D;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC;QAAE,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,KAAK,CAAC;QAAC,KAAK,EAAE,CAAC,CAAA;KAAE,CAAC;IAmBlE,mDAAmD;IACnD,KAAK,IAAI,IAAI;IAQb,oEAAoE;IACpE,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI;CAQxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,qBAAqB,CACpC,IAAI,EAAE,cAAc,EACpB,cAAc,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,aAAa,CAAC,GAAG,CAAC,EAChE,UAAU,EAAE,MAAM,EAClB,MAAM,GAAE,cAAqC,GAC3C,aAAa,CAAC,GAAG,CAAC,CA2EpB;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE,eAAe,GAAG,WAAW,CAkB5F"}
@@ -0,0 +1,223 @@
1
+ import { emitCallFromPlan } from '../emitters.js';
2
+ import { ParallelDriver, bumpParentForkCounter, dropParentForkCounter } from '../parallel-driver.js';
3
+ /**
4
+ * Bounded promise-based prefetch buffer used by {@link emitEagerPrefetch}.
5
+ *
6
+ * Exactly one producer (the pump) and one consumer (the parent emit's
7
+ * iterator) operate on this at a time, so a single nullable callback for each
8
+ * direction is enough — no waiter queues required.
9
+ *
10
+ * Exported for unit-test access only.
11
+ */
12
+ export class BoundedPrefetchBuffer {
13
+ capacity;
14
+ queue = [];
15
+ done = false;
16
+ hasError = false;
17
+ error;
18
+ spaceWaiter = null;
19
+ itemWaiter = null;
20
+ constructor(capacity) {
21
+ this.capacity = capacity;
22
+ if (!Number.isInteger(capacity) || capacity < 1) {
23
+ throw new RangeError(`BoundedPrefetchBuffer: capacity must be a positive integer, got ${capacity}`);
24
+ }
25
+ }
26
+ get size() {
27
+ return this.queue.length;
28
+ }
29
+ /**
30
+ * Push an item, awaiting space when the buffer is full. Returns false if
31
+ * the abort signal fired before space became available; otherwise true.
32
+ */
33
+ async push(item, signal) {
34
+ while (this.queue.length >= this.capacity && !this.done && !this.hasError && !signal.aborted) {
35
+ await new Promise(resolve => {
36
+ this.spaceWaiter = resolve;
37
+ const onAbort = () => {
38
+ const r = this.spaceWaiter;
39
+ this.spaceWaiter = null;
40
+ if (r)
41
+ r();
42
+ };
43
+ if (signal.aborted) {
44
+ onAbort();
45
+ return;
46
+ }
47
+ signal.addEventListener('abort', onAbort, { once: true });
48
+ });
49
+ }
50
+ if (signal.aborted || this.done || this.hasError)
51
+ return false;
52
+ this.queue.push(item);
53
+ const w = this.itemWaiter;
54
+ this.itemWaiter = null;
55
+ if (w)
56
+ w();
57
+ return true;
58
+ }
59
+ /**
60
+ * Wait for an item, end-of-stream marker, or buffered error.
61
+ * Throws the cached error if {@link fail} was called.
62
+ */
63
+ async shift() {
64
+ while (this.queue.length === 0 && !this.done && !this.hasError) {
65
+ await new Promise(resolve => {
66
+ this.itemWaiter = resolve;
67
+ });
68
+ }
69
+ if (this.queue.length > 0) {
70
+ const value = this.queue.shift();
71
+ const w = this.spaceWaiter;
72
+ this.spaceWaiter = null;
73
+ if (w)
74
+ w();
75
+ return { done: false, value };
76
+ }
77
+ if (this.hasError) {
78
+ throw this.error;
79
+ }
80
+ return { done: true };
81
+ }
82
+ /** Mark end-of-stream; wakes a pending shifter. */
83
+ close() {
84
+ if (this.done || this.hasError)
85
+ return;
86
+ this.done = true;
87
+ const w = this.itemWaiter;
88
+ this.itemWaiter = null;
89
+ if (w)
90
+ w();
91
+ }
92
+ /** Record a producer error; wakes a pending shifter to throw it. */
93
+ fail(err) {
94
+ if (this.done || this.hasError)
95
+ return;
96
+ this.hasError = true;
97
+ this.error = err;
98
+ const w = this.itemWaiter;
99
+ this.itemWaiter = null;
100
+ if (w)
101
+ w();
102
+ }
103
+ }
104
+ /**
105
+ * Core prefetch primitive. Forks `rctx` and **eagerly** — at call time, before
106
+ * the consumer's first `next()` — starts a detached pump that drains the child
107
+ * iterator into a bounded buffer. The returned `AsyncIterable<Row>` hands rows
108
+ * out of that buffer; its iterator owns teardown via `next()`/`return()`/
109
+ * `throw()`.
110
+ *
111
+ * Eager-on-call is the point: when a `BloomJoinNode` wraps its probe (`left`) in
112
+ * this, the scheduler invokes `run()` during arg-assembly — before the join's
113
+ * generator body drains the build (`right`) — so the probe's first fetch is
114
+ * already in flight while the build materializes.
115
+ *
116
+ * Cleanup (abort pump, close buffer, child `return()`, drop strict-fork
117
+ * counters) fires when the iterator reaches done, `return()`, or `throw()`.
118
+ * Because the fork counters are bumped at construction, a returned iterable that
119
+ * is **never iterated** leaks the pump (it fills the buffer then blocks forever)
120
+ * and leaves the counters bumped — every consumer must guarantee iterate-or-
121
+ * close. Today the only inserter is `rule-eager-prefetch-probe`, and
122
+ * `emitBloomJoin` closes the left iterator in a `finally` covering both phases.
123
+ *
124
+ * Exported for unit testing — production callers go through {@link emitEagerPrefetch}.
125
+ */
126
+ export function prefetchAsyncIterable(rctx, sourceCallback, bufferSize, driver = new ParallelDriver()) {
127
+ const [forkCtx] = driver.fork(rctx, 1);
128
+ // Manually bump strict-fork bookkeeping (ParallelDriver.drive does this
129
+ // internally, but we are using fork() directly). The fork is "live" from
130
+ // construction — that is the intended eager semantics.
131
+ const parentTableState = bumpParentForkCounter(forkCtx.tableContexts);
132
+ const parentRowState = bumpParentForkCounter(forkCtx.context);
133
+ const childIter = sourceCallback(forkCtx)[Symbol.asyncIterator]();
134
+ const buf = new BoundedPrefetchBuffer(bufferSize);
135
+ const abort = new AbortController();
136
+ // EAGER: start the pump now, not on first next().
137
+ const pump = (async () => {
138
+ try {
139
+ while (!abort.signal.aborted) {
140
+ const r = await childIter.next();
141
+ if (r.done) {
142
+ buf.close();
143
+ return;
144
+ }
145
+ const ok = await buf.push(r.value, abort.signal);
146
+ if (!ok)
147
+ return;
148
+ }
149
+ }
150
+ catch (e) {
151
+ buf.fail(e);
152
+ }
153
+ })();
154
+ // Detach; awaited in cleanup for clean shutdown.
155
+ void pump;
156
+ let cleanedUp = false;
157
+ const cleanup = async () => {
158
+ if (cleanedUp)
159
+ return;
160
+ cleanedUp = true;
161
+ abort.abort();
162
+ buf.close();
163
+ try {
164
+ await childIter.return?.(undefined);
165
+ }
166
+ catch {
167
+ // Swallow — already in cleanup.
168
+ }
169
+ await pump.catch(() => undefined);
170
+ dropParentForkCounter(parentTableState);
171
+ dropParentForkCounter(parentRowState);
172
+ };
173
+ return {
174
+ [Symbol.asyncIterator]() {
175
+ return {
176
+ async next() {
177
+ try {
178
+ const item = await buf.shift();
179
+ if (item.done) {
180
+ await cleanup();
181
+ return { done: true, value: undefined };
182
+ }
183
+ return { done: false, value: item.value };
184
+ }
185
+ catch (e) {
186
+ await cleanup();
187
+ throw e;
188
+ }
189
+ },
190
+ async return(value) {
191
+ await cleanup();
192
+ return { done: true, value: value };
193
+ },
194
+ async throw(err) {
195
+ await cleanup();
196
+ throw err;
197
+ },
198
+ };
199
+ },
200
+ };
201
+ }
202
+ /**
203
+ * Emit an EagerPrefetchNode: forks the runtime context and immediately starts
204
+ * pumping the child sub-tree into a bounded buffer, yielding rows from that
205
+ * buffer to the parent emit.
206
+ *
207
+ * The pump starts on `run()` (emit / scheduler arg-assembly), not on the
208
+ * consumer's first `next()`.
209
+ */
210
+ export function emitEagerPrefetch(plan, ctx) {
211
+ const driver = new ParallelDriver();
212
+ const bufferSize = plan.bufferSize;
213
+ function run(rctx, sourceCallback) {
214
+ return prefetchAsyncIterable(rctx, sourceCallback, bufferSize, driver);
215
+ }
216
+ const sourceInstruction = emitCallFromPlan(plan.source, ctx);
217
+ return {
218
+ params: [sourceInstruction],
219
+ run: run,
220
+ note: `eager_prefetch(buffer=${bufferSize})`,
221
+ };
222
+ }
223
+ //# sourceMappingURL=eager-prefetch.js.map