Rindle docs and package mapSkip to main content

BatchDelta

Struct BatchDelta 

Source
pub struct BatchDelta { /* private fields */ }
Expand description

The per-source batch delta. Interior-RefCell so one Rc<BatchDelta> can be shared between a TableSource, its forks, and the engine that drives the lifecycle (plan D1 — the same idiom as cursors_open/fetch_error).

Implementations§

Source§

impl BatchDelta

Source

pub fn new(primary_key: Vec<ColId>) -> BatchDelta

An inactive delta over primary_key with its own private DEFAULT_MAX_DELTA_BYTES budget. Every embedded caller gets one of these implicitly and never pays for it; a host driving several tables replaces it with one shared budget via set_budget.

Source

pub fn with_budget( primary_key: Vec<ColId>, budget: Rc<DeltaBudget>, ) -> BatchDelta

An inactive delta charging against budget (D4) — pass the same Rc to every table in a derivation and the ceiling bounds the whole transaction.

Source

pub fn with_max_bytes(primary_key: Vec<ColId>, max_bytes: usize) -> BatchDelta

An inactive delta with a private budget of max_bytes — the single-table convenience over with_budget.

Source

pub fn set_budget(&self, budget: Rc<DeltaBudget>)

Move this delta onto budget — how a host installs one shared ceiling across every table it registers, on a delta the source already created (and may already have forked: the budget lives behind the shared RefCell, so forks follow). Anything currently charged moves with it.

Source

pub fn budget(&self) -> Rc<DeltaBudget>

The budget this delta charges against (shared — re-tune it with DeltaBudget::set_max_bytes, read it with DeltaBudget::used).

Source

pub fn used_bytes(&self) -> usize

Estimated bytes this delta is holding (its share of budget().used()).

Source

pub fn begin(&self)

Start a derivation: clear all state and mark active. Replaces the write path’s BEGIN CONCURRENT throwaway transaction. Drops the secondary map entirely (not just its rows) so M in the fold cost is bounded by the sorts actually fetched during this transaction.

Source

pub fn end(&self)

End a derivation: clear and deactivate. Replaces execute_batch("ROLLBACK") and is strictly more reliable — there is no path on which a failed or skipped rollback leaves derivation state behind.

Source

pub fn is_active(&self) -> bool

Source

pub fn is_empty(&self) -> bool

Source

pub fn apply(&self, change: &SourceChange) -> Result<(), RindleError>

Fold one change into the delta — the stand-in for TableSource::write_change, called from exactly where the write is called (after the fan-out drains), so the I1/I2 push invariants hold by construction (design §3.1).

Erroring on an inactive delta is deliberate (plan §3.3): after the write closure becomes delta.apply unconditionally, a push outside an open snapshot must fail loudly rather than silently diverge.

A batch whose folded rows outgrow the shared DeltaBudget trips [RindleError::DeltaOverflow] (design 306 D4): the delta drops its trees on the spot — the budget is a memory bound, so overflowing must not keep holding the rows — and every further apply re-raises the same error without accumulating. The derivation for this batch is unrecoverable; the host sheds (commits the data, tears down + re-hydrates the affected queries) rather than failing the write.

The charge is net: re-touching rows already in the delta costs nothing beyond the change in their content size, so a transaction that rewrites the same working set a million times never sheds — only one that holds an unbounded amount of it does.

An Add of a pk already present is [RindleError::ConsistencyViolation] in every build (see Inner::add_row) — the loud fault the write-then-abort path’s UNIQUE constraint used to raise, never a silent overwrite.

Source

pub fn lookup_pk(&self, probe: &Row) -> DeltaLookup

What the delta says about probe’s primary key. probe is any row carrying the pk columns — the pk-sort comparator reads nothing else.

Source

pub fn suppresses(&self, row: &Row) -> bool

Whether a vended base row must be suppressed from the scan: its pk was touched, so its authoritative content lives in the delta (or nowhere). One pk-sort B-tree probe per vended base row — the merge’s per-row cost (design §5).

Source

pub fn find_by_key(&self, key: &[(ColId, OwnedValue)]) -> Option<Row>

The delta row matching every (col, value) equality of key, if any — the delta-first half of a get_row/lookup_unique point read (plan §4.4). key may be any unique key, not just the pk, so this scans primary linearly ([constraint_matches] semantics, values_equal: null never matches) — bounded by the delta, and these are build-time / consistency reads, not the hot path.

Source

pub fn rows_for_fetch( &self, req: &FetchRequest, sort: &Sort, predicate: Option<&RowPredicate>, ) -> DeltaRows

The delta side of one fetch (plan §4.2/§4.3): the rows this transaction’s delta contributes to a request, narrowed exactly as compute_overlays narrows the single-change overlay — constraint, multi-constraint any, predicate (§2.1: delta rows, like overlay rows, are never seen by SQL, so predicate — which can be strictly stronger than sql_condition — is the rule).

Lazy (plan §3.4 as amended): returns a DeltaRows pull stream over the tree’s owning cursor rather than a materialized Vec, so a fetch costs one O(log |delta|) seek plus the rows the merge actually consumes — never O(|delta|) per fetch (the O(N²)-per-batch trap under per-change ordered re-fetches). The RefCell borrow lives only inside this call; the cursor owns its Rc<BNode> spine (OQ-1), so nothing of the borrow escapes, and a later apply path-copies around any node a live stream pins.

Vended in connection-sort order (sort, honoring req.reverse): the seek index is constraint columns ++ sort (§3.2), and restricted to the group an equality constraint selects, that order is the connection sort — which is what makes the output mergeable against SQL’s ORDER BY sort stream.

start is a seek optimization only; the exact At/After cut is re-applied downstream by generate_with_start, exactly as the tiebreak path relies on.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,