Skip to main content

LpgStore

Struct LpgStore 

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

The core in-memory graph storage.

Everything lives here: nodes, edges, properties, adjacency indexes, and version chains for MVCC. Concurrent reads never block each other.

Most users should go through GrafeoDB (from the grafeo_engine crate) which adds transaction management and query execution. Use LpgStore directly when you need raw performance for algorithm implementations.

§Example

use grafeo_core::graph::lpg::LpgStore;
use grafeo_core::graph::Direction;

let store = LpgStore::new();

// Create a small social network
let alice = store.create_node(&["Person"]);
let bob = store.create_node(&["Person"]);
store.create_edge(alice, bob, "KNOWS");

// Traverse outgoing edges
for neighbor in store.neighbors(alice, Direction::Outgoing) {
    println!("Alice knows node {:?}", neighbor);
}

Implementations§

Source§

impl LpgStore

Source

pub fn new() -> Self

Creates a new LPG store with default configuration.

Source

pub fn with_config(config: LpgStoreConfig) -> Self

Creates a new LPG store with custom configuration.

Source

pub fn current_epoch(&self) -> EpochId

Returns the current epoch.

Source

pub fn new_epoch(&self) -> EpochId

Creates a new epoch.

Source

pub fn create_node(&self, labels: &[&str]) -> NodeId

Creates a new node with the given labels.

Uses the system transaction for non-transactional operations.

Source

pub fn create_node_versioned( &self, labels: &[&str], epoch: EpochId, tx_id: TxId, ) -> NodeId

Creates a new node with the given labels within a transaction context.

Source

pub fn create_node_with_props( &self, labels: &[&str], properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, ) -> NodeId

Creates a new node with labels and properties.

Source

pub fn create_node_with_props_versioned( &self, labels: &[&str], properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, epoch: EpochId, tx_id: TxId, ) -> NodeId

Creates a new node with labels and properties within a transaction context.

Source

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

Gets a node by ID (latest visible version).

Source

pub fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>

Gets a node by ID at a specific epoch.

Source

pub fn get_node_versioned( &self, id: NodeId, epoch: EpochId, tx_id: TxId, ) -> Option<Node>

Gets a node visible to a specific transaction.

Source

pub fn delete_node(&self, id: NodeId) -> bool

Deletes a node and all its edges (using latest epoch).

Source

pub fn delete_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool

Deletes a node at a specific epoch.

Source

pub fn delete_node_edges(&self, node_id: NodeId)

Deletes all edges connected to a node (implements DETACH DELETE).

Call this before delete_node() if you want to remove a node that has edges. Grafeo doesn’t auto-delete edges - you have to be explicit.

Source

pub fn set_node_property(&self, id: NodeId, key: &str, value: Value)

Sets a property on a node.

Source

pub fn set_edge_property(&self, id: EdgeId, key: &str, value: Value)

Sets a property on an edge.

Source

pub fn remove_node_property(&self, id: NodeId, key: &str) -> Option<Value>

Removes a property from a node.

Returns the previous value if it existed, or None if the property didn’t exist.

Source

pub fn remove_edge_property(&self, id: EdgeId, key: &str) -> Option<Value>

Removes a property from an edge.

Returns the previous value if it existed, or None if the property didn’t exist.

Source

pub fn get_node_property(&self, id: NodeId, key: &PropertyKey) -> Option<Value>

Gets a single property from a node without loading all properties.

This is O(1) vs O(properties) for get_node().get_property(). Use this for filter predicates where you only need one property value.

§Example
// Fast: Direct single-property lookup
let age = store.get_node_property(node_id, "age");

// Slow: Loads all properties, then extracts one
let age = store.get_node(node_id).and_then(|n| n.get_property("age").cloned());
Source

pub fn get_edge_property(&self, id: EdgeId, key: &PropertyKey) -> Option<Value>

Gets a single property from an edge without loading all properties.

This is O(1) vs O(properties) for get_edge().get_property().

Source

pub fn get_node_property_batch( &self, ids: &[NodeId], key: &PropertyKey, ) -> Vec<Option<Value>>

Gets a property for multiple nodes in a single batch operation.

More efficient than calling Self::get_node_property in a loop because it reduces lock overhead and enables better cache utilization.

§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::{NodeId, PropertyKey, Value};

let store = LpgStore::new();
let n1 = store.create_node(&["Person"]);
let n2 = store.create_node(&["Person"]);
store.set_node_property(n1, "age", Value::from(25i64));
store.set_node_property(n2, "age", Value::from(30i64));

let ages = store.get_node_property_batch(&[n1, n2], &PropertyKey::new("age"));
assert_eq!(ages, vec![Some(Value::from(25i64)), Some(Value::from(30i64))]);
Source

pub fn get_nodes_properties_batch( &self, ids: &[NodeId], ) -> Vec<FxHashMap<PropertyKey, Value>>

Gets all properties for multiple nodes in a single batch operation.

Returns a vector of property maps, one per node ID (empty map if no properties). More efficient than calling Self::get_node in a loop.

Source

pub fn find_nodes_in_range( &self, property: &str, min: Option<&Value>, max: Option<&Value>, min_inclusive: bool, max_inclusive: bool, ) -> Vec<NodeId>

Finds nodes where a property value is in a range.

This is useful for queries like n.age > 30 or n.price BETWEEN 10 AND 100. Uses zone maps to skip scanning when the range definitely doesn’t match.

§Arguments
  • property - The property to check
  • min - Optional lower bound (None for unbounded)
  • max - Optional upper bound (None for unbounded)
  • min_inclusive - Whether lower bound is inclusive (>= vs >)
  • max_inclusive - Whether upper bound is inclusive (<= vs <)
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;

let store = LpgStore::new();
let n1 = store.create_node(&["Person"]);
let n2 = store.create_node(&["Person"]);
store.set_node_property(n1, "age", Value::from(25i64));
store.set_node_property(n2, "age", Value::from(35i64));

// Find nodes where age > 30
let result = store.find_nodes_in_range(
    "age",
    Some(&Value::from(30i64)),
    None,
    false, // exclusive lower bound
    true,  // inclusive upper bound (doesn't matter since None)
);
assert_eq!(result.len(), 1); // Only n2 matches
Source

pub fn find_nodes_by_properties( &self, conditions: &[(&str, Value)], ) -> Vec<NodeId>

Finds nodes matching multiple property equality conditions.

This is more efficient than intersecting multiple single-property lookups because it can use indexes when available and short-circuits on the first miss.

§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;

let store = LpgStore::new();
let alice = store.create_node(&["Person"]);
store.set_node_property(alice, "name", Value::from("Alice"));
store.set_node_property(alice, "city", Value::from("NYC"));

// Find nodes where name = "Alice" AND city = "NYC"
let matches = store.find_nodes_by_properties(&[
    ("name", Value::from("Alice")),
    ("city", Value::from("NYC")),
]);
assert!(matches.contains(&alice));
Source

pub fn create_property_index(&self, property: &str)

Creates an index on a node property for O(1) lookups by value.

After creating an index, calls to Self::find_nodes_by_property will be O(1) instead of O(n) for this property. The index is automatically maintained when properties are set or removed.

§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;

let store = LpgStore::new();

// Create nodes with an 'id' property
let alice = store.create_node(&["Person"]);
store.set_node_property(alice, "id", Value::from("alice_123"));

// Create an index on the 'id' property
store.create_property_index("id");

// Now lookups by 'id' are O(1)
let found = store.find_nodes_by_property("id", &Value::from("alice_123"));
assert!(found.contains(&alice));
Source

pub fn drop_property_index(&self, property: &str) -> bool

Drops an index on a node property.

Returns true if the index existed and was removed.

Source

pub fn has_property_index(&self, property: &str) -> bool

Returns true if the property has an index.

Source

pub fn find_nodes_by_property( &self, property: &str, value: &Value, ) -> Vec<NodeId>

Finds all nodes that have a specific property value.

If the property is indexed, this is O(1). Otherwise, it scans all nodes which is O(n). Use Self::create_property_index for frequently queried properties.

§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;

let store = LpgStore::new();
store.create_property_index("city"); // Optional but makes lookups fast

let alice = store.create_node(&["Person"]);
let bob = store.create_node(&["Person"]);
store.set_node_property(alice, "city", Value::from("NYC"));
store.set_node_property(bob, "city", Value::from("NYC"));

let nyc_people = store.find_nodes_by_property("city", &Value::from("NYC"));
assert_eq!(nyc_people.len(), 2);
Source

pub fn add_label(&self, node_id: NodeId, label: &str) -> bool

Adds a label to a node.

Returns true if the label was added, false if the node doesn’t exist or already has the label.

Source

pub fn remove_label(&self, node_id: NodeId, label: &str) -> bool

Removes a label from a node.

Returns true if the label was removed, false if the node doesn’t exist or doesn’t have the label.

Source

pub fn node_count(&self) -> usize

Returns the number of nodes (non-deleted at current epoch).

Source

pub fn node_ids(&self) -> Vec<NodeId>

Returns all node IDs in the store.

This returns a snapshot of current node IDs. The returned vector excludes deleted nodes. Results are sorted by NodeId for deterministic iteration order.

Source

pub fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId

Creates a new edge.

Source

pub fn create_edge_versioned( &self, src: NodeId, dst: NodeId, edge_type: &str, epoch: EpochId, tx_id: TxId, ) -> EdgeId

Creates a new edge within a transaction context.

Source

pub fn create_edge_with_props( &self, src: NodeId, dst: NodeId, edge_type: &str, properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, ) -> EdgeId

Creates a new edge with properties.

Source

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

Gets an edge by ID (latest visible version).

Source

pub fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>

Gets an edge by ID at a specific epoch.

Source

pub fn get_edge_versioned( &self, id: EdgeId, epoch: EpochId, tx_id: TxId, ) -> Option<Edge>

Gets an edge visible to a specific transaction.

Source

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

Deletes an edge (using latest epoch).

Source

pub fn delete_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool

Deletes an edge at a specific epoch.

Source

pub fn edge_count(&self) -> usize

Returns the number of edges (non-deleted at current epoch).

Source

pub fn discard_uncommitted_versions(&self, tx_id: TxId)

Discards all uncommitted versions created by a transaction.

This is called during transaction rollback to clean up uncommitted changes. The method removes version chain entries created by the specified transaction.

Source

pub fn label_count(&self) -> usize

Returns the number of distinct labels in the store.

Source

pub fn property_key_count(&self) -> usize

Returns the number of distinct property keys in the store.

This counts unique property keys across both nodes and edges.

Source

pub fn edge_type_count(&self) -> usize

Returns the number of distinct edge types in the store.

Source

pub fn neighbors( &self, node: NodeId, direction: Direction, ) -> impl Iterator<Item = NodeId> + '_

Iterates over neighbors of a node in the specified direction.

This is the fast path for graph traversal - goes straight to the adjacency index without loading full node data.

Source

pub fn edges_from( &self, node: NodeId, direction: Direction, ) -> impl Iterator<Item = (NodeId, EdgeId)> + '_

Returns edges from a node with their targets.

Returns an iterator of (target_node, edge_id) pairs.

Source

pub fn edges_to(&self, node: NodeId) -> Vec<(NodeId, EdgeId)>

Returns edges to a node (where the node is the destination).

Returns (source_node, edge_id) pairs for all edges pointing TO this node. Uses the backward adjacency index for O(degree) lookup.

§Example
// For edges: A->B, C->B
let incoming = store.edges_to(B);
// Returns: [(A, edge1), (C, edge2)]
Source

pub fn out_degree(&self, node: NodeId) -> usize

Returns the out-degree of a node (number of outgoing edges).

Uses the forward adjacency index for O(1) lookup.

Source

pub fn in_degree(&self, node: NodeId) -> usize

Returns the in-degree of a node (number of incoming edges).

Uses the backward adjacency index for O(1) lookup if available, otherwise falls back to scanning edges.

Source

pub fn edge_type(&self, id: EdgeId) -> Option<Arc<str>>

Gets the type of an edge by ID.

Source

pub fn nodes_by_label(&self, label: &str) -> Vec<NodeId>

Returns all nodes with a specific label.

Uses the label index for O(1) lookup per label. Returns a snapshot - concurrent modifications won’t affect the returned vector. Results are sorted by NodeId for deterministic iteration order.

Source

pub fn all_nodes(&self) -> impl Iterator<Item = Node> + '_

Returns an iterator over all nodes in the database.

This creates a snapshot of all visible nodes at the current epoch. Useful for dump/export operations.

Source

pub fn all_edges(&self) -> impl Iterator<Item = Edge> + '_

Returns an iterator over all edges in the database.

This creates a snapshot of all visible edges at the current epoch. Useful for dump/export operations.

Source

pub fn all_labels(&self) -> Vec<String>

Returns all label names in the database.

Source

pub fn all_edge_types(&self) -> Vec<String>

Returns all edge type names in the database.

Source

pub fn all_property_keys(&self) -> Vec<String>

Returns all property keys used in the database.

Source

pub fn nodes_with_label<'a>( &'a self, label: &str, ) -> impl Iterator<Item = Node> + 'a

Returns an iterator over nodes with a specific label.

Source

pub fn edges_with_type<'a>( &'a self, edge_type: &str, ) -> impl Iterator<Item = Edge> + 'a

Returns an iterator over edges with a specific type.

Source

pub fn node_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool

Checks if a node property predicate might match any nodes.

Uses zone maps for early filtering. Returns true if there might be matching nodes, false if there definitely aren’t.

Source

pub fn edge_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool

Checks if an edge property predicate might match any edges.

Source

pub fn node_property_zone_map( &self, property: &PropertyKey, ) -> Option<ZoneMapEntry>

Gets the zone map for a node property.

Source

pub fn edge_property_zone_map( &self, property: &PropertyKey, ) -> Option<ZoneMapEntry>

Gets the zone map for an edge property.

Source

pub fn rebuild_zone_maps(&self)

Rebuilds zone maps for all properties.

Source

pub fn statistics(&self) -> Statistics

Returns the current statistics.

Source

pub fn compute_statistics(&self)

Recomputes statistics from current data.

Scans all labels and edge types to build cardinality estimates for the query optimizer. Call this periodically or after bulk data loads.

Source

pub fn estimate_label_cardinality(&self, label: &str) -> f64

Estimates cardinality for a label scan.

Source

pub fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64

Estimates average degree for an edge type.

Source

pub fn create_node_with_id(&self, id: NodeId, labels: &[&str])

Creates a node with a specific ID during recovery.

This is used for WAL recovery to restore nodes with their original IDs. The caller must ensure IDs don’t conflict with existing nodes.

Source

pub fn create_edge_with_id( &self, id: EdgeId, src: NodeId, dst: NodeId, edge_type: &str, )

Creates an edge with a specific ID during recovery.

This is used for WAL recovery to restore edges with their original IDs.

Source

pub fn set_epoch(&self, epoch: EpochId)

Sets the current epoch during recovery.

Trait Implementations§

Source§

impl Default for LpgStore

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
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.