Expand description
Primitive #1: the operator graph as an arena + NodeId, NOT
Rc<RefCell<dyn Operator>>.
Why this is the make-or-break decision (verified against join.ts):
#pushChildChange sets in-progress state then re-enters parent.fetch()
while a push is in flight, and self-joins put the same source in the graph
twice. The “obvious” Rc<RefCell<dyn Operator>> translation would hit a
runtime BorrowMutError on exactly that pattern. The arena fixes it: the
whole pipeline is one Vec<Operator> addressed by NodeId, every
fetch/push takes &self (a shared borrow of the graph), and per-operator
mutable state lives behind Cell/RefCell scoped to a single statement —
never held across a vend. Reentrant fetch-during-push is then just another
shared borrow. No cycles-of-owners, no borrow conflict.
The leaf MemorySource (the connection/read/COW machinery) lives in
memory_source.rs; this module hosts the operator graph that wires it up
(SourceConn, Join, View, Collector) and drives the eager push fan-out
(Graph::source_push), which is inherently graph-level (it must reach
downstream operators by NodeId).
Structs§
- ConnId
- A connection handle into a source’s connection table. Generational
{idx, gen}(likeNodeId/StorageId) so a source can RECYCLE a torn-down connection’s slot — theConnTablebumps the generation on free and checks it on every access, so a stale handle to a recycled slot fail-fasts. Distinct fromNodeId. Same role as05’sConnId. - Counting
Source - A
Sourcedecorator that counts the rows crossing the connection boundary — the one new measurement theanalyze querydiagnostic needs (designs-implemented/ANALYZE-QUERY-DESIGN.md§3.4). It wraps any object-safeSourceand delegates every method toinnerunchanged, exceptfetch, whose returnedRowFlowis wrapped in a lazy.inspectthat bumpsemittedonce per row as the row is pulled. Because it countsinner.fetch()’s final stream — after the backend’s overlay/start/constraint/filter chain and across both the ordered and unordered fetch paths — it sees exactly what the pipeline sees, on either backend (SQLite or memory), and a downstreamTakethat abandons the stream early counts only what it consumed (the correct “emitted into the pipeline” semantics). - Graph
- Join
Precheck Bounds - The two bounds of the join membership pre-check (design 311 §2.5), host-settable via
Graph::set_join_precheck_bounds. - Join
Precheck Stats - Per-graph counters for the join membership pre-check (design 311 §8) — the
always-on, per-
Graphtwin of the build-gated process-globalEngineMetricscounters (join_probe_hit/join_probe_miss/join_precheck_disabled_*). PlainCelladds on a!Sendgraph, so they cost nothing measurable. - NodeId
- A handle to an operator slot in the
Grapharena.idxis the slot index;genis the slot’s generation, bumped every time the slot is freed (a pipeline teardown —Graph::destroy_pipeline). The generation is what makes slot REUSE safe: a stale handle to a torn-down pipeline carries the oldgen, so it fails the generation check inGraph::nodeinstead of silently aliasing the new tenant of a recycled slot. Distinct from physical removal (which would shift indices and is impossible here) — the slot keeps its index across reuse. - Pipeline
Manifest - The exact arena ids one
build_pipeline(+ its sink) created — captured by the graph’s recording mode (Graph::begin_recording/Graph::take_recording) so the pipeline can be torn down precisely withGraph::destroy_pipeline. - Storage
Id - Index into the graph’s parallel storage arena (foundations §6.4). A
stateful operator (
Take/Cap/Exists, spec07) is handed one of these at build time and reads/writes its scratch state viaGraph::storage. The operator never owns its store: the indirection is what lets the client keep it in RAM (MemoryStorage) while the server later spills it to SQLite (10§1.1) without touching operator code. Distinct newtype fromNodeIdso the two index spaces can’t be confused. Generational for the same reason (storage slots are freed + reused on teardown).
Enums§
- Collected
Change - A change recorded by a
Collector— the spike’s analogue ofCatch’spushes. Lets a test assert the exact change sequence a source fans out. Equality compares rows cell-by-cell viacompare_values(null == null) —OwnedValuedeliberately has no derivedPartialEq(it would invite the wrong comparator), so we spell the row equality out. - Join
Precheck State - A read-only snapshot of one join’s parent-key set (
op::join_util::ParentKeySet) for inspection and tests (Graph::join_precheck_state).
Traits§
- Source
- The connection + read contract a leaf backend owns locally (
04§4.7 /05§4.8).MemorySourceimplements it; the SQLiteTableSourceimplements the same trait, soconnect/fetch/schema/destroy— and everything downstream of theNodeStreamthey vend — are backend-identical.
Type Aliases§
- Emit
Counter - A shared per-source counter of rows a source emitted into the pipeline. One cell
per wrapped source node (so the count is already keyed per
NodeId); a child-driven join that re-fetches the same leaf under many constraints accumulates across those fetches into the same cell.Rc<Cell<..>>(not atomic) — aGraphis!Send, single-threaded by construction.