@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.
- package/dist/src/core/database-assertions.js +3 -3
- package/dist/src/core/database-assertions.js.map +1 -1
- package/dist/src/core/database.js +3 -3
- package/dist/src/core/database.js.map +1 -1
- package/dist/src/core/statement.js +3 -3
- package/dist/src/core/statement.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/parser/visitor.js +1 -1
- package/dist/src/parser/visitor.js.map +1 -1
- package/dist/src/planner/analysis/attribute-provenance.d.ts +45 -0
- package/dist/src/planner/analysis/attribute-provenance.d.ts.map +1 -0
- package/dist/src/planner/analysis/attribute-provenance.js +81 -0
- package/dist/src/planner/analysis/attribute-provenance.js.map +1 -0
- package/dist/src/planner/analysis/const-evaluator.js +5 -5
- package/dist/src/planner/analysis/const-evaluator.js.map +1 -1
- package/dist/src/planner/building/select-window.d.ts.map +1 -1
- package/dist/src/planner/building/select-window.js +54 -21
- package/dist/src/planner/building/select-window.js.map +1 -1
- package/dist/src/planner/cache/correlation-detector.d.ts +7 -0
- package/dist/src/planner/cache/correlation-detector.d.ts.map +1 -1
- package/dist/src/planner/cache/correlation-detector.js +34 -2
- package/dist/src/planner/cache/correlation-detector.js.map +1 -1
- package/dist/src/planner/nodes/async-gather-node.d.ts +169 -0
- package/dist/src/planner/nodes/async-gather-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/async-gather-node.js +488 -0
- package/dist/src/planner/nodes/async-gather-node.js.map +1 -0
- package/dist/src/planner/nodes/bloom-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/bloom-join-node.js +8 -7
- package/dist/src/planner/nodes/bloom-join-node.js.map +1 -1
- package/dist/src/planner/nodes/eager-prefetch-node.d.ts +47 -0
- package/dist/src/planner/nodes/eager-prefetch-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/eager-prefetch-node.js +96 -0
- package/dist/src/planner/nodes/eager-prefetch-node.js.map +1 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts +150 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.d.ts.map +1 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.js +265 -0
- package/dist/src/planner/nodes/fanout-lookup-join-node.js.map +1 -0
- package/dist/src/planner/nodes/merge-join-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/merge-join-node.js +8 -7
- package/dist/src/planner/nodes/merge-join-node.js.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.d.ts +3 -0
- package/dist/src/planner/nodes/plan-node-type.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node-type.js +3 -0
- package/dist/src/planner/nodes/plan-node-type.js.map +1 -1
- package/dist/src/planner/nodes/plan-node.d.ts +36 -0
- package/dist/src/planner/nodes/plan-node.d.ts.map +1 -1
- package/dist/src/planner/nodes/plan-node.js +26 -0
- package/dist/src/planner/nodes/plan-node.js.map +1 -1
- package/dist/src/planner/nodes/reference.d.ts.map +1 -1
- package/dist/src/planner/nodes/reference.js +13 -0
- package/dist/src/planner/nodes/reference.js.map +1 -1
- package/dist/src/planner/optimizer-tuning.d.ts +107 -0
- package/dist/src/planner/optimizer-tuning.d.ts.map +1 -1
- package/dist/src/planner/optimizer-tuning.js +43 -0
- package/dist/src/planner/optimizer-tuning.js.map +1 -1
- package/dist/src/planner/optimizer.d.ts.map +1 -1
- package/dist/src/planner/optimizer.js +91 -0
- package/dist/src/planner/optimizer.js.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.d.ts.map +1 -1
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js +1 -6
- package/dist/src/planner/rules/access/rule-monotonic-range-access.js.map +1 -1
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts +74 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js +139 -0
- package/dist/src/planner/rules/join/rule-fanout-batched-outer.js.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts +58 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.d.ts.map +1 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js +592 -0
- package/dist/src/planner/rules/join/rule-fanout-lookup-join.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts +43 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.d.ts.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js +115 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-union-all.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts +102 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.d.ts.map +1 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js +545 -0
- package/dist/src/planner/rules/parallel/rule-async-gather-zip-by-key.js.map +1 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts +45 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.d.ts.map +1 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js +78 -0
- package/dist/src/planner/rules/parallel/rule-eager-prefetch-probe.js.map +1 -0
- package/dist/src/planner/scopes/param.d.ts.map +1 -1
- package/dist/src/planner/scopes/param.js +13 -11
- package/dist/src/planner/scopes/param.js.map +1 -1
- package/dist/src/planner/type-utils.js +1 -1
- package/dist/src/planner/type-utils.js.map +1 -1
- package/dist/src/planner/validation/plan-validator.d.ts.map +1 -1
- package/dist/src/planner/validation/plan-validator.js +17 -19
- package/dist/src/planner/validation/plan-validator.js.map +1 -1
- package/dist/src/runtime/async-semaphore.d.ts +36 -0
- package/dist/src/runtime/async-semaphore.d.ts.map +1 -0
- package/dist/src/runtime/async-semaphore.js +72 -0
- package/dist/src/runtime/async-semaphore.js.map +1 -0
- package/dist/src/runtime/deferred-constraint-queue.d.ts.map +1 -1
- package/dist/src/runtime/deferred-constraint-queue.js +4 -3
- package/dist/src/runtime/deferred-constraint-queue.js.map +1 -1
- package/dist/src/runtime/emit/async-gather.d.ts +77 -0
- package/dist/src/runtime/emit/async-gather.d.ts.map +1 -0
- package/dist/src/runtime/emit/async-gather.js +234 -0
- package/dist/src/runtime/emit/async-gather.js.map +1 -0
- package/dist/src/runtime/emit/bloom-join.d.ts.map +1 -1
- package/dist/src/runtime/emit/bloom-join.js +38 -17
- package/dist/src/runtime/emit/bloom-join.js.map +1 -1
- package/dist/src/runtime/emit/eager-prefetch.d.ts +77 -0
- package/dist/src/runtime/emit/eager-prefetch.d.ts.map +1 -0
- package/dist/src/runtime/emit/eager-prefetch.js +223 -0
- package/dist/src/runtime/emit/eager-prefetch.js.map +1 -0
- package/dist/src/runtime/emit/fanout-lookup-join.d.ts +130 -0
- package/dist/src/runtime/emit/fanout-lookup-join.d.ts.map +1 -0
- package/dist/src/runtime/emit/fanout-lookup-join.js +521 -0
- package/dist/src/runtime/emit/fanout-lookup-join.js.map +1 -0
- package/dist/src/runtime/parallel-driver.d.ts +68 -0
- package/dist/src/runtime/parallel-driver.d.ts.map +1 -0
- package/dist/src/runtime/parallel-driver.js +233 -0
- package/dist/src/runtime/parallel-driver.js.map +1 -0
- package/dist/src/runtime/register.d.ts.map +1 -1
- package/dist/src/runtime/register.js +9 -0
- package/dist/src/runtime/register.js.map +1 -1
- package/dist/src/runtime/strict-fork.d.ts +36 -0
- package/dist/src/runtime/strict-fork.d.ts.map +1 -0
- package/dist/src/runtime/strict-fork.js +125 -0
- package/dist/src/runtime/strict-fork.js.map +1 -0
- package/dist/src/util/comparison.d.ts.map +1 -1
- package/dist/src/util/comparison.js +11 -1
- package/dist/src/util/comparison.js.map +1 -1
- package/dist/src/vtab/concurrency.d.ts +29 -0
- package/dist/src/vtab/concurrency.d.ts.map +1 -0
- package/dist/src/vtab/concurrency.js +47 -0
- package/dist/src/vtab/concurrency.js.map +1 -0
- package/dist/src/vtab/memory/layer/scan-layer.d.ts.map +1 -1
- package/dist/src/vtab/memory/layer/scan-layer.js +67 -29
- package/dist/src/vtab/memory/layer/scan-layer.js.map +1 -1
- package/dist/src/vtab/memory/module.d.ts +21 -0
- package/dist/src/vtab/memory/module.d.ts.map +1 -1
- package/dist/src/vtab/memory/module.js +21 -0
- package/dist/src/vtab/memory/module.js.map +1 -1
- package/dist/src/vtab/module.d.ts +47 -0
- package/dist/src/vtab/module.d.ts.map +1 -1
- 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,
|
|
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
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
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":"AAEA,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGhE,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,MAAM,GAAG,GAAG,YAAY,CAAC,yBAAyB,CAAC,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,IAAmB,EAAE,GAAoB;IACtE,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IACjD,MAAM,eAAe,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;IAEnD,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAC7D,MAAM,kBAAkB,GAAG,kBAAkB,CAAC,eAAe,CAAC,CAAC;IAE/D,oFAAoF;IACpF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,cAAc,GAA8B,EAAE,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC;QACnE,MAAM,EAAE,GAAG,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,WAAW,CAAC,CAAC;QACrE,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,mDAAmD,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3G,CAAC;QACD,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrB,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtB,iFAAiF;QACjF,MAAM,aAAa,GAAG,cAAc,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,IAAI,eAAe,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;QACtG,cAAc,CAAC,IAAI,CAAC,oBAAoB,CAAC,aAAa,CAAC,CAAC,CAAC;IAC1D,CAAC;IAED,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC;IAE7C,KAAK,SAAS,CAAC,CAAC,GAAG,CAClB,IAAoB,EACpB,UAA8B,EAC9B,WAA+B,EAC/B,gBAAuD;QAEvD,GAAG,CAAC,qEAAqE,EACxE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,cAAc,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;QAEpG,4DAA4D;
|
|
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
|