Skip to main content

GraphStore

Struct GraphStore 

Source
pub struct GraphStore { /* private fields */ }

Implementations§

Source§

impl GraphStore

Source

pub fn open_file(path: impl AsRef<Path>) -> Result<Self, GraphError>

Source

pub fn open_memory() -> Result<Self, GraphError>

Source

pub fn backup_to(&self, path: impl AsRef<Path>) -> Result<(), GraphError>

Source

pub fn check_integrity(&mut self) -> Result<IntegrityReport, GraphError>

Check physical storage plus MarsDB’s graph invariants. This requires exclusive mutable access because redb may repair physical metadata.

Source

pub fn begin_write(&self) -> Result<WriteTransaction, GraphError>

Open a write transaction spanning multiple graph operations. Callers (e.g. the query executor) drive an entire Cypher statement through the *_in_txn methods below using this one transaction, then call write_txn.commit() themselves — this is the crash-safety boundary from the plan: one statement = one transaction, not one transaction per individual node/edge write.

v1 uses a write transaction even for pure-read statements (rather than a separate read-only path) to keep one code path and guarantee every statement — reads included — sees one consistent snapshot. Trade-off: this serializes concurrent readers behind redb’s single-writer lock instead of allowing true concurrent reads; a read-only transaction path is the natural follow-up if read concurrency becomes a bottleneck.

Source

pub fn begin_read(&self) -> Result<ReadTransaction, GraphError>

Open a read transaction for a statement that never mutates anything (MATCH ... RETURN) — a consistent point-in-time snapshot that runs alongside any concurrent readers or a concurrent writer without contending for redb’s single-writer lock. No commit/abort: a read transaction has nothing to roll back, it just releases on drop.

Source

pub fn commit(write_txn: WriteTransaction) -> Result<(), GraphError>

Commit a transaction obtained from begin_write.

Source

pub fn abort(write_txn: WriteTransaction) -> Result<(), GraphError>

Abort (roll back) a transaction obtained from begin_write, discarding any writes made through it.

Source

pub fn create_node( &self, labels: &[&str], props: BTreeMap<String, PropertyValue>, ) -> Result<NodeId, GraphError>

Source

pub fn create_node_in_txn( write_txn: &WriteTransaction, labels: &[&str], props: BTreeMap<String, PropertyValue>, ) -> Result<NodeId, GraphError>

Source

pub fn get_node(&self, id: NodeId) -> Result<Option<Node>, GraphError>

Source

pub fn get_node_in_txn( txn: Txn<'_>, id: NodeId, ) -> Result<Option<Node>, GraphError>

Source

pub fn lookup_prop_id_in_txn( txn: Txn<'_>, prop: &str, ) -> Result<Option<u32>, GraphError>

The id interned for a property name, if any – None means the name has never been written anywhere, so no record can hold it. Exposed for the query layer’s per-property read path: names resolve to ids once per statement there, then every row access goes through get_node_prop_in_txn/get_edge_prop_in_txn by id.

Source

pub fn get_node_prop_in_txn( txn: Txn<'_>, id: NodeId, prop_id: u32, ) -> Result<Option<Option<PropertyValue>>, GraphError>

One property of one node, by interned prop id, without decoding the rest of the record or resolving any names — a directory binary search plus one value decode (the v2 read fast path; the codec mechanism measured 79x over whole-record decode at 1-of-20 props).

Nested Option distinguishes the two kinds of missing the executor must not collapse (lookup_prop’s own docs): outer None = the node record doesn’t exist (deleted-entity error at the call site), inner None = node exists, property absent (legal null).

Source

pub fn get_edge_prop_in_txn( txn: Txn<'_>, id: EdgeId, prop_id: u32, ) -> Result<Option<Option<PropertyValue>>, GraphError>

Edge counterpart of get_node_prop_in_txn, same nested-Option contract.

Source

pub fn node_prop_reader( txn: Txn<'_>, ) -> Result<impl FnMut(NodeId, u32) -> Result<Option<Option<PropertyValue>>, GraphError> + '_, GraphError>

Per-property reader over ONE pre-opened NODES handle – for a caller probing many nodes’ properties in a loop, where get_node_prop_in_txn’s per-call table open would dominate (the mars-3va lesson: opens measured 23.67% of a bulk load). Same nested-Option contract as get_node_prop_in_txn.

Source

pub fn node_exists_in_txn(txn: Txn<'_>, id: NodeId) -> Result<bool, GraphError>

Record-existence check without any decoding — for the per-property read path when the property name was never interned (the value is necessarily absent on every record, but a deleted node must still error, not read as null).

Source

pub fn edge_exists_in_txn(txn: Txn<'_>, id: EdgeId) -> Result<bool, GraphError>

Edge counterpart of node_exists_in_txn.

Source

pub fn create_edge( &self, label: &str, src: NodeId, dst: NodeId, props: BTreeMap<String, PropertyValue>, ) -> Result<EdgeId, GraphError>

Source

pub fn create_edge_in_txn( write_txn: &WriteTransaction, label: &str, src: NodeId, dst: NodeId, props: BTreeMap<String, PropertyValue>, ) -> Result<EdgeId, GraphError>

Source

pub fn get_edge(&self, id: EdgeId) -> Result<Option<Edge>, GraphError>

Source

pub fn get_edge_in_txn( txn: Txn<'_>, id: EdgeId, ) -> Result<Option<Edge>, GraphError>

Source

pub fn neighbors( &self, node: NodeId, dir: Direction, label_filter: Option<&str>, ) -> Result<Vec<AdjEntry>, GraphError>

Neighbors of node in dir, optionally filtered by edge label. Reads directly from the adjacency multimap without touching edges.

Source

pub fn neighbors_in_txn( txn: Txn<'_>, node: NodeId, dir: Direction, label_filter: Option<&str>, ) -> Result<Vec<AdjEntry>, GraphError>

Source

pub fn delete_edge(&self, id: EdgeId) -> Result<bool, GraphError>

Source

pub fn delete_edge_in_txn( write_txn: &WriteTransaction, id: EdgeId, ) -> Result<bool, GraphError>

Source

pub fn delete_node(&self, id: NodeId, detach: bool) -> Result<bool, GraphError>

Delete a node. If detach is false and the node has incident edges, returns GraphError::NodeHasEdges instead of deleting anything.

Source

pub fn delete_node_in_txn( write_txn: &WriteTransaction, id: NodeId, detach: bool, ) -> Result<bool, GraphError>

Source

pub fn create_index( &self, label: &str, prop: &str, unique: bool, ) -> Result<(), GraphError>

Declares an index on (label, prop), backfilling it from every existing node with label — see index::create_index’s own docs for the exact semantics (idempotency, unique-violation behavior).

Source

pub fn create_index_in_txn( write_txn: &WriteTransaction, label: &str, prop: &str, unique: bool, ) -> Result<(), GraphError>

Same as create_index, but against an already-open WriteTransaction — for a caller (CREATE INDEX as a Cypher statement) that’s already inside one transaction and must commit or abort it as a whole, not open a second one (redb allows only one writer at a time; opening a second would deadlock).

Source

pub fn index_def( &self, label: &str, prop: &str, ) -> Result<Option<IndexDef>, GraphError>

None means no index is declared on (label, prop).

Source

pub fn index_def_in_txn( txn: Txn<'_>, label: &str, prop: &str, ) -> Result<Option<IndexDef>, GraphError>

Same as index_def, but against an already-open Txn — for a caller (the query planner/executor) that’s already inside one transaction and needs a consistent view, not a fresh snapshot.

Source

pub fn lookup_by_index_in_txn( txn: Txn<'_>, label: &str, prop: &str, value: &PropertyValue, ) -> Result<Vec<NodeId>, GraphError>

Same as lookup_by_index, but against an already-open Txn.

Source

pub fn lookup_by_index_limited_in_txn( txn: Txn<'_>, label: &str, prop: &str, value: &PropertyValue, limit: usize, ) -> Result<Vec<NodeId>, GraphError>

Same as lookup_by_index_in_txn, but stops once limit nodes are found — the storage-level end of LIMIT push-down through an IndexSeek (see marsdb_query::planner/executor::stream_index_seek).

Source

pub fn index_match_count_in_txn( txn: Txn<'_>, label: &str, prop: &str, value: &PropertyValue, ) -> Result<u64, GraphError>

Cheap, exact count of nodes under (label, prop) = value — for the query planner to compare selectivity between several indexed equality candidates, not for fetching the nodes themselves (see lookup_by_index_in_txn). O(1), same contract as lookup_by_index re: “no index” vs “index, no match” both reading as 0.

Source

pub fn lookup_by_index( &self, label: &str, prop: &str, value: &PropertyValue, ) -> Result<Vec<NodeId>, GraphError>

Every node currently indexed under (label, prop) = value. Empty (not an error) if no such index exists — check index_def first if the caller needs to distinguish “no index” from “index, no match”.

Source

pub fn set_node_prop( &self, id: NodeId, key: &str, value: PropertyValue, ) -> Result<bool, GraphError>

Source

pub fn set_node_prop_in_txn( write_txn: &WriteTransaction, id: NodeId, key: &str, value: PropertyValue, ) -> Result<bool, GraphError>

Source

pub fn set_edge_prop( &self, id: EdgeId, key: &str, value: PropertyValue, ) -> Result<bool, GraphError>

Source

pub fn set_edge_prop_in_txn( write_txn: &WriteTransaction, id: EdgeId, key: &str, value: PropertyValue, ) -> Result<bool, GraphError>

Source

pub fn remove_node_prop_in_txn( write_txn: &WriteTransaction, id: NodeId, key: &str, ) -> Result<bool, GraphError>

Source

pub fn remove_edge_prop_in_txn( write_txn: &WriteTransaction, id: EdgeId, key: &str, ) -> Result<bool, GraphError>

Source

pub fn add_node_label_in_txn( write_txn: &WriteTransaction, id: NodeId, label: &str, ) -> Result<bool, GraphError>

Adds label to id’s label set – a no-op (not an error) if it’s already there, same idempotent-add semantics real Cypher’s SET n:Label has.

Source

pub fn remove_node_label_in_txn( write_txn: &WriteTransaction, id: NodeId, label: &str, ) -> Result<bool, GraphError>

Removes label from id’s label set – a no-op (not an error) if it’s not there (label unknown entirely, or known but not on this node), same as real Cypher’s REMOVE n:Label.

Source

pub fn node_count_in_txn(txn: Txn<'_>) -> Result<u64, GraphError>

Total node count — O(1) (redb tracks table entry counts). For the query planner’s start-point cardinality comparison: the cost of an AllNodesScan leaf, never for fetching anything.

Source

pub fn label_count_in_txn(txn: Txn<'_>, label: &str) -> Result<u64, GraphError>

Number of nodes carrying label — O(1) via the label index’s per-key entry count (same mechanism as index_match_count_in_txn). An unknown label reads as 0, same as everywhere else. Planner cardinality use only, like node_count_in_txn.

Source

pub fn all_nodes( &self, label_filter: Option<&str>, ) -> Result<Vec<Node>, GraphError>

Full scan of all nodes, optionally filtered by label. v1 has no secondary index on label, so this is a linear scan of the table.

Source

pub fn all_node_ids_limited_in_txn( txn: Txn<'_>, label_filter: Option<&str>, limit: usize, ) -> Result<Vec<NodeId>, GraphError>

Scan only graph identities, without decoding node records. Query pipelines use this to defer record/property loading until a filter or projection actually needs it.

Source

pub fn all_nodes_in_txn( txn: Txn<'_>, label_filter: Option<&str>, ) -> Result<Vec<Node>, GraphError>

Source

pub fn all_nodes_limited_in_txn( txn: Txn<'_>, label_filter: Option<&str>, limit: usize, ) -> Result<Vec<Node>, GraphError>

Same as all_nodes_in_txn, but stops once limit nodes are found – the storage-level end of LIMIT push-down (see the executor’s scan()/eval_plan docs for the query-level half): a query whose entire plan is a bare scan feeding straight into a LIMIT doesn’t need to touch rows past the first limit, whether or not a label filter narrows it first.

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.