pub struct Engine {
pub snapshot: ReadSnapshot,
pub params: HashMap<String, Value>,
pub prop_index: RefCell<PropertyIndex>,
pub text_index: RefCell<TextIndex>,
pub deadline: Option<Instant>,
pub degree_cache: RefCell<Option<DegreeCache>>,
pub unique_constraints: HashSet<(u32, u32)>,
pub use_chunked_pipeline: bool,
pub memory_limit_bytes: usize,
}Expand description
The execution engine holds references to the storage layer.
Fields§
§snapshot: ReadSnapshot§params: HashMap<String, Value>Runtime query parameters supplied by the caller (e.g. $name → Value).
prop_index: RefCell<PropertyIndex>In-memory B-tree property equality index (SPA-249).
Loaded lazily on first use for each (label_id, col_id) pair that a
query actually filters on. Queries with no property filter (e.g.
COUNT(*), hop traversals) never touch this and pay zero build cost.
RefCell provides interior mutability so that build_for can be called
from &self scan helpers without changing every method signature.
text_index: RefCell<TextIndex>In-memory text search index for CONTAINS and STARTS WITH (SPA-251, SPA-274).
Loaded lazily — only when a query has a CONTAINS or STARTS WITH
predicate on a specific (label_id, col_id) pair, via
TextIndex::build_for. Queries with no text predicates (e.g.
COUNT(*), hop traversals) never trigger any TextIndex I/O.
RefCell provides interior mutability so that build_for can be called
from &self scan helpers without changing every method signature.
Stores sorted (decoded_string, slot) pairs per (label_id, col_id).
- CONTAINS: linear scan avoids per-slot property-decode overhead.
- STARTS WITH: binary-search prefix range — O(log n + k).
deadline: Option<Instant>Optional per-query deadline (SPA-254).
When Some, the engine checks this deadline at the top of each hot
scan / traversal loop iteration. If Instant::now() >= deadline,
Error::QueryTimeout is returned immediately. None means no
deadline (backward-compatible default).
degree_cache: RefCell<Option<DegreeCache>>Pre-computed out-degree for every node slot across all relationship types (SPA-272).
Initialized lazily on first call to Engine::top_k_by_degree or
Engine::out_degree. Queries that never need degree information
(point lookups, full scans, hop traversals) pay zero cost at engine-open
time: no CSR iteration, no delta-log I/O.
RefCell provides interior mutability so the cache can be populated
from &self methods without changing the signature of top_k_by_degree.
unique_constraints: HashSet<(u32, u32)>Set of (label_id, col_id) pairs that carry a UNIQUE constraint (SPA-234).
Populated by CREATE CONSTRAINT ON (n:Label) ASSERT n.property IS UNIQUE.
Checked in execute_create before writing each node: if the property
value already exists in prop_index for that (label_id, col_id), the
insert is rejected with Error::InvalidArgument.
use_chunked_pipeline: boolOpt-in flag for the Phase 1 chunked vectorized pipeline (#299).
When true, qualifying queries (currently: simple single-label scans with
no hops) route through the chunked pipeline instead of the row-at-a-time
engine. Defaults to false so all existing behaviour is unchanged.
Activate with Engine::with_chunked_pipeline.
memory_limit_bytes: usizePer-query memory limit in bytes for Phase 3 BFS expansion (Phase 3+).
When the accumulated frontier size exceeds this during 2-hop expansion,
the engine returns Error::QueryMemoryExceeded instead of OOM-ing.
Defaults to usize::MAX (unlimited).
Set via EngineBuilder::with_memory_limit.
Implementations§
Source§impl Engine
impl Engine
Sourcepub fn scan_match_mutate(
&self,
mm: &MatchMutateStatement,
) -> Result<Vec<NodeId>>
pub fn scan_match_mutate( &self, mm: &MatchMutateStatement, ) -> Result<Vec<NodeId>>
Scan nodes matching the MATCH patterns in a MatchMutate statement and
return the list of matching NodeIds. The caller is responsible for
applying the actual mutations inside a write transaction.
Sourcepub fn mutation_from_match_mutate(mm: &MatchMutateStatement) -> &Mutation
pub fn mutation_from_match_mutate(mm: &MatchMutateStatement) -> &Mutation
Return the mutation carried by a MatchMutate statement, exposing it
to the caller (GraphDb) so it can apply it inside a write transaction.
Sourcepub fn scan_match_mutate_edges(
&self,
mm: &MatchMutateStatement,
) -> Result<Vec<(NodeId, NodeId, String)>>
pub fn scan_match_mutate_edges( &self, mm: &MatchMutateStatement, ) -> Result<Vec<(NodeId, NodeId, String)>>
Scan edges matching a MATCH pattern with exactly one hop and return
(src, dst, rel_type) tuples for edge deletion.
Supports MATCH (a:Label)-[r:REL]->(b:Label) DELETE r with optional
inline property filters on source and destination node patterns.
Includes both checkpointed (CSR) and uncheckpointed (delta) edges.
Sourcepub fn scan_match_create(
&self,
mc: &MatchCreateStatement,
) -> Result<HashMap<String, Vec<NodeId>>>
pub fn scan_match_create( &self, mc: &MatchCreateStatement, ) -> Result<HashMap<String, Vec<NodeId>>>
Scan nodes matching the MATCH patterns in a MatchCreateStatement and
return a map of variable name → Vec
The caller (GraphDb) uses this to resolve variable bindings before
calling WriteTx::create_edge for each edge in the CREATE clause.
Sourcepub fn scan_match_create_rows(
&self,
mc: &MatchCreateStatement,
) -> Result<Vec<HashMap<String, NodeId>>>
pub fn scan_match_create_rows( &self, mc: &MatchCreateStatement, ) -> Result<Vec<HashMap<String, NodeId>>>
Execute the MATCH portion of a MatchCreateStatement and return one
binding map per matched row.
Each element of the returned Vec is a HashMap<variable_name, NodeId>
that represents one fully-correlated result row from the MATCH clause.
The caller uses these to drive WriteTx::create_edge — one call per row.
§Algorithm
For each PathPattern in match_patterns:
- No relationships (node-only pattern): scan the node store applying inline prop filters; collect one candidate set per named variable. Cross-join these sets with the rows accumulated so far.
- One relationship hop (
(a)-[:R]->(b)): traverse the CSR + delta log to enumerate actual (src, dst) pairs that are connected by an edge, then filter each node against its inline prop predicates. Only correlated pairs are yielded — this is the key difference from the oldscan_match_createwhich treated every node as an independent candidate and then took a full Cartesian product.
Patterns beyond a single hop are not yet supported and return an error.
Sourcepub fn scan_match_merge_rel_rows(
&self,
mm: &MatchMergeRelStatement,
) -> Result<Vec<HashMap<String, NodeId>>>
pub fn scan_match_merge_rel_rows( &self, mm: &MatchMergeRelStatement, ) -> Result<Vec<HashMap<String, NodeId>>>
Scan the MATCH patterns of a MatchMergeRelStatement and return
correlated (variable → NodeId) binding rows — identical semantics to
scan_match_create_rows but taking the MERGE form’s match patterns (SPA-233).
Source§impl Engine
impl Engine
Sourcepub fn try_plan_chunked_match(&self, m: &MatchStatement) -> Option<ChunkedPlan>
pub fn try_plan_chunked_match(&self, m: &MatchStatement) -> Option<ChunkedPlan>
Select a ChunkedPlan for the given MatchStatement (Phase 4, spec §2.3).
Returns Some(plan) when the query shape maps to a known chunked fast-path,
or None when the row engine should handle it. The caller dispatches via
match — no further can_use_* calls are made after this returns.
§Precedence
MutualNeighbors is checked before TwoHop because it is a more specific pattern (both endpoints bound) that would otherwise fall into TwoHop.
Source§impl Engine
impl Engine
Sourcepub fn new(
store: NodeStore,
catalog: Catalog,
csrs: HashMap<u32, CsrForward>,
db_root: &Path,
) -> Self
pub fn new( store: NodeStore, catalog: Catalog, csrs: HashMap<u32, CsrForward>, db_root: &Path, ) -> Self
Create an engine with a pre-built per-type CSR map.
The csrs map associates each RelTableId (u32) with its forward CSR.
Use Engine::with_single_csr in tests or legacy code that only has
one CSR.
Sourcepub fn new_with_cached_index(
store: NodeStore,
catalog: Catalog,
csrs: HashMap<u32, CsrForward>,
db_root: &Path,
cached_index: Option<&RwLock<PropertyIndex>>,
) -> Self
pub fn new_with_cached_index( store: NodeStore, catalog: Catalog, csrs: HashMap<u32, CsrForward>, db_root: &Path, cached_index: Option<&RwLock<PropertyIndex>>, ) -> Self
Create an engine, optionally seeding the property index from a shared
cache. When cached_index is Some, the index is cloned out of the
RwLock at construction time so the engine can use RefCell internally
without holding the lock.
When cached_row_counts is Some, the pre-built label row-count map is
used directly instead of re-reading each label’s HWM from disk. This
eliminates O(n_labels) syscalls on every read query (SPA-190).
Sourcepub fn new_with_all_caches(
store: NodeStore,
catalog: Catalog,
csrs: HashMap<u32, CsrForward>,
db_root: &Path,
cached_index: Option<&RwLock<PropertyIndex>>,
cached_row_counts: Option<HashMap<LabelId, usize>>,
shared_edge_props_cache: Option<Arc<RwLock<HashMap<u32, HashMap<(u64, u64), Vec<(u32, u64)>>>>>>,
) -> Self
pub fn new_with_all_caches( store: NodeStore, catalog: Catalog, csrs: HashMap<u32, CsrForward>, db_root: &Path, cached_index: Option<&RwLock<PropertyIndex>>, cached_row_counts: Option<HashMap<LabelId, usize>>, shared_edge_props_cache: Option<Arc<RwLock<HashMap<u32, HashMap<(u64, u64), Vec<(u32, u64)>>>>>>, ) -> Self
Like Engine::new_with_cached_index but also accepts a pre-built
label_row_counts map to avoid the per-query HWM disk reads (SPA-190).
Sourcepub fn with_single_csr(
store: NodeStore,
catalog: Catalog,
csr: CsrForward,
db_root: &Path,
) -> Self
pub fn with_single_csr( store: NodeStore, catalog: Catalog, csr: CsrForward, db_root: &Path, ) -> Self
Convenience constructor for tests and legacy callers that have a single
CsrForward (stored at RelTableId(0)).
SPA-185: prefer Engine::new with a full HashMap<u32, CsrForward> for
production use so that per-type filtering is correct.
Sourcepub fn with_params(self, params: HashMap<String, Value>) -> Self
pub fn with_params(self, params: HashMap<String, Value>) -> Self
Attach runtime query parameters to this engine instance.
Parameters are looked up when evaluating $name expressions (e.g. in
UNWIND $items AS x).
Sourcepub fn with_deadline(self, deadline: Instant) -> Self
pub fn with_deadline(self, deadline: Instant) -> Self
Set a per-query deadline (SPA-254).
The engine will return sparrowdb_common::Error::QueryTimeout if
Instant::now() >= deadline during any hot scan or traversal loop.
Sourcepub fn with_chunked_pipeline(self) -> Self
pub fn with_chunked_pipeline(self) -> Self
Enable the Phase 1 chunked vectorized pipeline (#299).
When enabled, qualifying queries route through the pull-based chunked
pipeline instead of the row-at-a-time engine. The existing engine
remains the default (use_chunked_pipeline = false) and all non-
qualifying queries continue to use it unchanged.
Sourcepub fn chunk_capacity(&self) -> usize
pub fn chunk_capacity(&self) -> usize
Return the chunk_capacity field (used by Phase 2+ operators when
building pipeline nodes). Defaults to CHUNK_CAPACITY until
EngineBuilder::with_chunk_capacity is wired into pipeline construction.
Sourcepub fn memory_limit_bytes(&self) -> usize
pub fn memory_limit_bytes(&self) -> usize
Return the configured per-query memory limit in bytes.
Defaults to usize::MAX (unlimited). Set via
EngineBuilder::with_memory_limit to enforce a budget on Phase 3
BFS expansion. When the frontier exceeds this, the engine returns
Error::QueryMemoryExceeded.
Sourcepub fn write_back_prop_index(&self, shared: &RwLock<PropertyIndex>)
pub fn write_back_prop_index(&self, shared: &RwLock<PropertyIndex>)
Merge the engine’s lazily-populated property index into the shared cache so that future read queries can skip I/O for columns we already loaded.
Uses union/merge semantics: only columns not yet present in the shared cache are added. This prevents last-writer-wins races when multiple concurrent read queries write back to the shared cache simultaneously.
Called from GraphDb read paths after execute_statement.
Write lazily-loaded index columns back to the shared per-GraphDb cache.
Only merges data back when the shared cache’s generation matches the
generation this engine’s index was cloned from (SPA-242). If a write
transaction committed and cleared the shared cache while this engine was
executing, the shared cache’s generation will have advanced, indicating
that this engine’s index data is derived from a stale on-disk snapshot.
In that case the write-back is skipped entirely so the next engine that
runs will rebuild the index from the freshly committed column files.
Sourcepub fn out_degree(&self, slot: u64) -> u32
pub fn out_degree(&self, slot: u64) -> u32
Return the total out-degree for slot across all relationship types.
Triggers lazy initialization of the DegreeCache on first call.
Returns 0 for slots with no outgoing edges.
Sourcepub fn top_k_by_degree(
&self,
label_id: u32,
k: usize,
) -> Result<Vec<(u64, u32)>>
pub fn top_k_by_degree( &self, label_id: u32, k: usize, ) -> Result<Vec<(u64, u32)>>
Return the top-k nodes of label_id ordered by out-degree descending.
Each element of the returned Vec is (slot, out_degree). Ties in
degree are broken by slot number (lower slot first) for determinism.
Returns an empty Vec when k == 0 or the label has no nodes.
Uses DegreeCache for O(1) per-node lookups (SPA-272).
The cache is built lazily on first call — queries that never call this
method pay zero cost.
Sourcepub fn execute(&mut self, cypher: &str) -> Result<QueryResult>
pub fn execute(&mut self, cypher: &str) -> Result<QueryResult>
Parse, bind, plan, and execute a Cypher query.
Takes &mut self because CREATE statements auto-register labels in
the catalog and write nodes to the node store (SPA-156).
Sourcepub fn execute_statement(&mut self, stmt: Statement) -> Result<QueryResult>
pub fn execute_statement(&mut self, stmt: Statement) -> Result<QueryResult>
Execute an already-bound Statement directly.
Useful for callers (e.g. WriteTx) that have already parsed and bound
the statement and want to dispatch CHECKPOINT/OPTIMIZE themselves.
pub fn is_mutation(stmt: &Statement) -> bool
Auto Trait Implementations§
impl !Freeze for Engine
impl !RefUnwindSafe for Engine
impl Send for Engine
impl !Sync for Engine
impl Unpin for Engine
impl UnsafeUnpin for Engine
impl UnwindSafe for Engine
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more