rudb_exec/lib.rs
1//! Operators, morsels, the scheduler, hash tables, sorting and spilling.
2//!
3//! Rank 12 in the layer rule. See `xtask/layers.toml` and `spec/18-package-layout.md`.
4//!
5//! This is tier 0 of `spec/08-codegen.md` section 8.1: a pull based tree of operators, one variant
6//! per logical operator the binder can produce, every one of them written the simplest way that is
7//! correct. Tier 0 is never removed and never optional, because it is the reference every faster
8//! tier is differentially tested against, and a reference that is clever is a reference nobody can
9//! read the answer out of when the clever tier disagrees with it.
10//!
11//! # What pull based means here and what it does not mean
12//!
13//! [`Operator::next`] returns the next [`Chunk`](rudb_vector::Chunk) or `None` when there are no
14//! more. A pipeline of a scan, a filter and a projection is three of those calls deep and nothing
15//! is materialized between them. An operator that cannot answer without seeing all of its input,
16//! which is the aggregate, the sort, the join build side, the distinct and the set operations, does
17//! all of its work on the first call to `next` and then hands out what it built one chunk at a
18//! time. That is what `spec/07-execution.md` calls a pipeline breaker and it is the boundary the
19//! morsel driven scheduler will later cut pipelines at.
20//!
21//! What this is not is the scheduler. There is one thread, there are no morsels, there is no
22//! spilling and the hash join is a nested loop. Every one of those is M1 or later work and every
23//! one of them replaces an operator here without changing the tree that builds it, because the
24//! thing that builds the tree is [`build`] and the thing it builds against is a trait with two
25//! methods.
26//!
27//! # The move to push
28//!
29//! The interface every operator ends up behind is in `rudb-pipeline`, and they are moving to it one
30//! at a time rather than in one commit. The filter, the projection and the limit are
31//! [`Stream`](rudb_pipeline::Stream) implementations, and the sort and the top N are
32//! [`Sink`](rudb_pipeline::Sink) implementations. All of them take `&self` and are handed the
33//! mutable part separately, so one of them can be instantiated on as many threads as F4 wants
34//! without copying its predicate or its key list.
35//!
36//! A sink finalises into a `buffer::Buffered`, which is a separate source that reads the finished
37//! chunks back out, rather than handing them back from `finalize`. That split is what makes the
38//! parallel read possible later and it costs nothing now.
39//!
40//! Everything else in here is still a pull operator, and `adapt` is the one thing that knows how to
41//! put a pushing operator in a pulling tree. It goes away with the rest of the pull side when the
42//! last operator has moved.
43//!
44//! # Why a schema per operator
45//!
46//! A bound plan refers to columns by [`ColumnBinding`](rudb_plan::ColumnBinding), which is a table
47//! index and a position, and a chunk is a row of vectors with no names on it. Something has to turn
48//! one into the other, and that something is [`Schema`]: it is what an operator says it produces,
49//! it carries the binding alongside the name and the type, and [`Schema::position_of`] is the whole
50//! of expression column resolution. Building it is where the operators agree with the binder about
51//! what a table index means, and it is checked rather than assumed, because a schema that is one
52//! column out produces a wrong answer instead of an error.
53
54#![forbid(unsafe_code)]
55
56mod adapt;
57mod buffer;
58mod build;
59mod cancel;
60mod expr;
61mod group;
62mod join;
63mod key;
64mod operator;
65mod prepared;
66mod register;
67mod rows;
68mod schema;
69mod setop;
70mod sort;
71mod source;
72mod spill;
73mod strategies;
74mod stream;
75mod table;
76mod topn;
77mod written;
78
79#[cfg(test)]
80mod tests;
81
82pub use build::{build, build_with};
83pub use expr::{evaluate, evaluate_all};
84pub use operator::Operator;
85pub use prepared::{Prepared, Scratch};
86pub use schema::Schema;
87pub use written::written;