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().expect("arena allocation");
// Create a small social network
let alix = store.create_node(&["Person"]);
let gus = store.create_node(&["Person"]);
store.create_edge(alix, gus, "KNOWS");
// Traverse outgoing edges
for neighbor in store.neighbors(alix, Direction::Outgoing) {
println!("Alix knows node {:?}", neighbor);
}§Lock Ordering
LpgStore contains multiple RwLock fields that must be acquired in a
consistent order to prevent deadlocks. Always acquire locks in this order:
§Level 1 - Entity Storage (mutually exclusive via feature flag)
nodes/node_versionsedges/edge_versions
§Level 2 - Catalogs (acquire as pairs when writing)
label_to_id+id_to_labeledge_type_to_id+id_to_edge_type
§Level 3 - Indexes
label_indexnode_labelsproperty_indexes
§Level 4 - Statistics
statistics
§Level 5 - Nested Locks (internal to other structs)
PropertyStorage::columns(vianode_properties/edge_properties)ChunkedAdjacency::lists(viaforward_adj/backward_adj)
§Rules
- Catalog pairs must be acquired together when writing.
- Never hold entity locks while acquiring catalog locks in a different scope.
- Statistics lock is always last.
- Read locks are generally safe, but avoid read-to-write upgrades.
Implementations§
Source§impl LpgStore
impl LpgStore
Sourcepub fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId
pub fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId
Creates a new edge.
Sourcepub fn create_edge_with_props(
&self,
src: NodeId,
dst: NodeId,
edge_type: &str,
properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>,
) -> EdgeId
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.
Sourcepub fn get_edge(&self, id: EdgeId) -> Option<Edge>
pub fn get_edge(&self, id: EdgeId) -> Option<Edge>
Gets an edge by ID (latest visible version).
Sourcepub fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>
pub fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>
Gets an edge by ID at a specific epoch.
Sourcepub fn get_edge_history(
&self,
id: EdgeId,
) -> Vec<(EpochId, Option<EpochId>, Edge)>
pub fn get_edge_history( &self, id: EdgeId, ) -> Vec<(EpochId, Option<EpochId>, Edge)>
Returns all versions of an edge with their creation/deletion epochs, newest first.
Each entry is (created_epoch, deleted_epoch, Edge). Note that properties
reflect the current state (they are not versioned per-epoch).
Sourcepub fn delete_edge(&self, id: EdgeId) -> bool
pub fn delete_edge(&self, id: EdgeId) -> bool
Deletes an edge (using latest epoch).
Sourcepub fn edge_count(&self) -> usize
pub fn edge_count(&self) -> usize
Returns the number of edges (non-deleted at current epoch).
Sourcepub fn batch_create_edges(
&self,
edges: &[(NodeId, NodeId, &str)],
) -> Vec<EdgeId>
pub fn batch_create_edges( &self, edges: &[(NodeId, NodeId, &str)], ) -> Vec<EdgeId>
Creates multiple edges in batch, significantly faster than calling
create_edge() in a loop.
Each tuple is (src, dst, edge_type). Returns the assigned EdgeIds
in the same order. Acquires the adjacency write lock once for all
edges, rather than once per edge.
Sourcepub fn edge_type_versioned(
&self,
id: EdgeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> Option<ArcStr>
pub fn edge_type_versioned( &self, id: EdgeId, epoch: EpochId, transaction_id: TransactionId, ) -> Option<ArcStr>
Gets the type of an edge visible to a specific transaction.
Used by operators that need edge type info for PENDING (uncommitted) edges.
Sourcepub fn is_edge_visible_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool
pub fn is_edge_visible_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool
Checks if an edge is visible at the given epoch.
Only checks the version chain, skips type resolution and property loading.
Sourcepub fn is_edge_visible_versioned(
&self,
id: EdgeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> bool
pub fn is_edge_visible_versioned( &self, id: EdgeId, epoch: EpochId, transaction_id: TransactionId, ) -> bool
Checks if an edge is visible to a specific transaction.
Source§impl LpgStore
impl LpgStore
Sourcepub fn create_property_index(&self, property: &str)
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().expect("arena allocation");
// Create nodes with an 'id' property
let alix = store.create_node(&["Person"]);
store.set_node_property(alix, "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(&alix));Sourcepub fn drop_property_index(&self, property: &str) -> bool
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.
Sourcepub fn has_property_index(&self, property: &str) -> bool
pub fn has_property_index(&self, property: &str) -> bool
Returns true if the property has an index.
Source§impl LpgStore
impl LpgStore
Sourcepub fn memory_breakdown(
&self,
) -> (StoreMemory, IndexMemory, MvccMemory, StringPoolMemory)
pub fn memory_breakdown( &self, ) -> (StoreMemory, IndexMemory, MvccMemory, StringPoolMemory)
Returns a detailed memory breakdown of the store.
Acquires read locks on internal structures briefly. Safe to call concurrently with queries, but sub-totals may be slightly inconsistent if mutations are in progress.
Source§impl LpgStore
impl LpgStore
Sourcepub fn create_node(&self, labels: &[&str]) -> NodeId
pub fn create_node(&self, labels: &[&str]) -> NodeId
Creates a new node with the given labels.
Uses the system transaction for non-transactional operations.
Sourcepub fn create_node_with_props(
&self,
labels: &[&str],
properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>,
) -> NodeId
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.
Sourcepub fn create_node_with_props_versioned(
&self,
labels: &[&str],
properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>,
epoch: EpochId,
transaction_id: TransactionId,
) -> NodeId
pub fn create_node_with_props_versioned( &self, labels: &[&str], properties: impl IntoIterator<Item = (impl Into<PropertyKey>, impl Into<Value>)>, epoch: EpochId, transaction_id: TransactionId, ) -> NodeId
Creates a new node with labels and properties within a transaction context.
Sourcepub fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>
pub fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>
Gets a node by ID at a specific epoch.
Sourcepub fn get_node_history(
&self,
id: NodeId,
) -> Vec<(EpochId, Option<EpochId>, Node)>
pub fn get_node_history( &self, id: NodeId, ) -> Vec<(EpochId, Option<EpochId>, Node)>
Returns all versions of a node with their creation/deletion epochs, newest first.
Each entry is (created_epoch, deleted_epoch, Node). Note that labels and
properties reflect the current state (they are not versioned per-epoch).
Sourcepub fn delete_node(&self, id: NodeId) -> bool
pub fn delete_node(&self, id: NodeId) -> bool
Deletes a node and all its edges (using latest epoch).
Sourcepub fn delete_node_edges(&self, node_id: NodeId)
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.
Sourcepub fn is_node_visible_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool
pub fn is_node_visible_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool
Checks if a node is visible at the given epoch.
Only checks the version chain, skips label and property loading.
Sourcepub fn is_node_visible_versioned(
&self,
id: NodeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> bool
pub fn is_node_visible_versioned( &self, id: NodeId, epoch: EpochId, transaction_id: TransactionId, ) -> bool
Checks if a node is visible to a specific transaction.
Sourcepub fn filter_visible_node_ids(
&self,
ids: &[NodeId],
epoch: EpochId,
) -> Vec<NodeId>
pub fn filter_visible_node_ids( &self, ids: &[NodeId], epoch: EpochId, ) -> Vec<NodeId>
Filters node IDs to only those visible at the given epoch.
Holds a single lock for the entire batch instead of per-node locking.
Sourcepub fn filter_visible_node_ids_versioned(
&self,
ids: &[NodeId],
epoch: EpochId,
transaction_id: TransactionId,
) -> Vec<NodeId>
pub fn filter_visible_node_ids_versioned( &self, ids: &[NodeId], epoch: EpochId, transaction_id: TransactionId, ) -> Vec<NodeId>
Filters node IDs to only those visible to a specific transaction.
Holds a single lock for the entire batch instead of per-node locking.
Sourcepub fn node_count(&self) -> usize
pub fn node_count(&self) -> usize
Returns the number of nodes (non-deleted at current epoch).
Sourcepub fn node_ids(&self) -> Vec<NodeId>
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.
Sourcepub fn all_node_ids(&self) -> Vec<NodeId>
pub fn all_node_ids(&self) -> Vec<NodeId>
Returns all node IDs including uncommitted/PENDING versions.
Unlike node_ids() which pre-filters by current epoch, this returns
every node that has a version chain entry. Used by scan operators that
perform their own MVCC visibility filtering with transaction context.
Source§impl LpgStore
impl LpgStore
Sourcepub fn set_node_property(&self, id: NodeId, key: &str, value: Value)
pub fn set_node_property(&self, id: NodeId, key: &str, value: Value)
Sets a property on a node.
Sourcepub fn set_edge_property(&self, id: EdgeId, key: &str, value: Value)
pub fn set_edge_property(&self, id: EdgeId, key: &str, value: Value)
Sets a property on an edge.
Sourcepub fn remove_node_property(&self, id: NodeId, key: &str) -> Option<Value>
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.
Sourcepub fn remove_edge_property(&self, id: EdgeId, key: &str) -> Option<Value>
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.
Sourcepub fn get_node_property(&self, id: NodeId, key: &PropertyKey) -> Option<Value>
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
let store = LpgStore::new().expect("arena allocation");
let node_id = store.create_node(&["Person"]);
store.set_node_property(node_id, "age", Value::from(30i64));
// Fast: Direct single-property lookup
let age = store.get_node_property(node_id, &PropertyKey::new("age"));
// Slow: Loads all properties, then extracts one
let age = store.get_node(node_id).and_then(|n| n.get_property("age").cloned());Sourcepub fn get_edge_property(&self, id: EdgeId, key: &PropertyKey) -> Option<Value>
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().
Sourcepub fn get_node_property_batch(
&self,
ids: &[NodeId],
key: &PropertyKey,
) -> Vec<Option<Value>>
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().expect("arena allocation");
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))]);Sourcepub fn get_nodes_properties_batch(
&self,
ids: &[NodeId],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
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.
Sourcepub fn get_nodes_properties_selective_batch(
&self,
ids: &[NodeId],
keys: &[PropertyKey],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
pub fn get_nodes_properties_selective_batch( &self, ids: &[NodeId], keys: &[PropertyKey], ) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
Gets selected properties for multiple nodes (projection pushdown).
This is more efficient than Self::get_nodes_properties_batch when you only
need a subset of properties. It only iterates the requested columns instead of
all columns.
Use this for: Queries with explicit projections like RETURN n.name, n.age
instead of RETURN n (which requires all properties).
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::{PropertyKey, Value};
let store = LpgStore::new().expect("arena allocation");
let n1 = store.create_node(&["Person"]);
store.set_node_property(n1, "name", Value::from("Alix"));
store.set_node_property(n1, "age", Value::from(30i64));
store.set_node_property(n1, "email", Value::from("alix@example.com"));
// Only fetch name and age (faster than get_nodes_properties_batch)
let keys = vec![PropertyKey::new("name"), PropertyKey::new("age")];
let props = store.get_nodes_properties_selective_batch(&[n1], &keys);
assert_eq!(props[0].len(), 2); // Only name and age, not emailSourcepub fn get_edges_properties_selective_batch(
&self,
ids: &[EdgeId],
keys: &[PropertyKey],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
pub fn get_edges_properties_selective_batch( &self, ids: &[EdgeId], keys: &[PropertyKey], ) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
Gets selected properties for multiple edges (projection pushdown).
Edge-property version of Self::get_nodes_properties_selective_batch.
Sourcepub fn set_node_property_versioned(
&self,
id: NodeId,
key: &str,
value: Value,
transaction_id: TransactionId,
)
pub fn set_node_property_versioned( &self, id: NodeId, key: &str, value: Value, transaction_id: TransactionId, )
Sets a node property within a transaction, recording the previous value in the undo log so it can be restored on rollback.
Sourcepub fn set_edge_property_versioned(
&self,
id: EdgeId,
key: &str,
value: Value,
transaction_id: TransactionId,
)
pub fn set_edge_property_versioned( &self, id: EdgeId, key: &str, value: Value, transaction_id: TransactionId, )
Sets an edge property within a transaction, recording the previous value in the undo log so it can be restored on rollback.
Sourcepub fn remove_node_property_versioned(
&self,
id: NodeId,
key: &str,
transaction_id: TransactionId,
) -> Option<Value>
pub fn remove_node_property_versioned( &self, id: NodeId, key: &str, transaction_id: TransactionId, ) -> Option<Value>
Removes a node property within a transaction, recording the previous value in the undo log so it can be restored on rollback.
Sourcepub fn remove_edge_property_versioned(
&self,
id: EdgeId,
key: &str,
transaction_id: TransactionId,
) -> Option<Value>
pub fn remove_edge_property_versioned( &self, id: EdgeId, key: &str, transaction_id: TransactionId, ) -> Option<Value>
Removes an edge property within a transaction, recording the previous value in the undo log so it can be restored on rollback.
Sourcepub fn rollback_transaction_properties(&self, transaction_id: TransactionId)
pub fn rollback_transaction_properties(&self, transaction_id: TransactionId)
Replays the undo log for a transaction in reverse order, restoring all property values to their pre-transaction state.
Called during rollback.
Sourcepub fn commit_transaction_properties(&self, transaction_id: TransactionId)
pub fn commit_transaction_properties(&self, transaction_id: TransactionId)
Discards the undo log entries for a committed transaction.
Called during commit: properties are already written, so just clean up the log.
Sourcepub fn property_undo_log_position(&self, transaction_id: TransactionId) -> usize
pub fn property_undo_log_position(&self, transaction_id: TransactionId) -> usize
Returns the current number of undo log entries for a transaction.
Used by savepoints to record the position so that partial rollback can replay only entries added after the savepoint.
Sourcepub fn rollback_transaction_properties_to(
&self,
transaction_id: TransactionId,
since: usize,
)
pub fn rollback_transaction_properties_to( &self, transaction_id: TransactionId, since: usize, )
Rolls back property mutations recorded after position since in the undo log.
Replays entries from since..end in reverse order, then truncates the
log to since. Used by savepoint rollback.
Source§impl LpgStore
impl LpgStore
Sourcepub fn add_label(&self, node_id: NodeId, label: &str) -> bool
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.
Sourcepub fn remove_label(&self, node_id: NodeId, label: &str) -> bool
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.
Sourcepub fn nodes_by_label(&self, label: &str) -> Vec<NodeId>
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.
Sourcepub fn label_count(&self) -> usize
pub fn label_count(&self) -> usize
Returns the number of distinct labels in the store.
Sourcepub fn property_key_count(&self) -> usize
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.
Sourcepub fn edge_type_count(&self) -> usize
pub fn edge_type_count(&self) -> usize
Returns the number of distinct edge types in the store.
Sourcepub fn all_labels(&self) -> Vec<String>
pub fn all_labels(&self) -> Vec<String>
Returns all label names in the database.
Sourcepub fn all_edge_types(&self) -> Vec<String>
pub fn all_edge_types(&self) -> Vec<String>
Returns all edge type names in the database.
Sourcepub fn all_property_keys(&self) -> Vec<String>
pub fn all_property_keys(&self) -> Vec<String>
Returns all property keys used in the database.
Sourcepub fn peek_next_node_id(&self) -> u64
pub fn peek_next_node_id(&self) -> u64
Returns the next node ID that will be allocated.
Sourcepub fn peek_next_edge_id(&self) -> u64
pub fn peek_next_edge_id(&self) -> u64
Returns the next edge ID that will be allocated.
Sourcepub fn add_label_versioned(
&self,
node_id: NodeId,
label: &str,
transaction_id: TransactionId,
) -> bool
pub fn add_label_versioned( &self, node_id: NodeId, label: &str, transaction_id: TransactionId, ) -> bool
Adds a label to a node within a transaction, recording the change in the undo log so it can be reversed on rollback.
Sourcepub fn remove_label_versioned(
&self,
node_id: NodeId,
label: &str,
transaction_id: TransactionId,
) -> bool
pub fn remove_label_versioned( &self, node_id: NodeId, label: &str, transaction_id: TransactionId, ) -> bool
Removes a label from a node within a transaction, recording the change in the undo log so it can be restored on rollback.
Source§impl LpgStore
impl LpgStore
Sourcepub fn find_nodes_in_range(
&self,
property: &str,
min: Option<&Value>,
max: Option<&Value>,
min_inclusive: bool,
max_inclusive: bool,
) -> Vec<NodeId>
pub fn find_nodes_in_range( &self, property: &str, min: Option<&Value>, max: Option<&Value>, min_inclusive: bool, max_inclusive: bool, ) -> Vec<NodeId>
Finds all nodes whose property value falls within a range.
Uses zone maps to skip the scan entirely when no values could possibly match. This is the primary building block for range predicates in query execution.
§Arguments
property- The property key to checkmin- Optional lower boundmax- Optional upper boundmin_inclusive- Whether the lower bound is inclusivemax_inclusive- Whether the upper bound is inclusive
§Example
use grafeo_core::graph::lpg::LpgStore;
use grafeo_common::types::Value;
let store = LpgStore::new().expect("arena allocation");
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 matchesSourcepub fn find_nodes_by_properties(
&self,
conditions: &[(&str, Value)],
) -> Vec<NodeId>
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().expect("arena allocation");
let alix = store.create_node(&["Person"]);
store.set_node_property(alix, "name", Value::from("Alix"));
store.set_node_property(alix, "city", Value::from("NYC"));
// Find nodes where name = "Alix" AND city = "NYC"
let matches = store.find_nodes_by_properties(&[
("name", Value::from("Alix")),
("city", Value::from("NYC")),
]);
assert!(matches.contains(&alix));Sourcepub fn find_nodes_by_property(
&self,
property: &str,
value: &Value,
) -> Vec<NodeId>
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().expect("arena allocation");
store.create_property_index("city"); // Optional but makes lookups fast
let alix = store.create_node(&["Person"]);
let gus = store.create_node(&["Person"]);
store.set_node_property(alix, "city", Value::from("NYC"));
store.set_node_property(gus, "city", Value::from("NYC"));
let nyc_people = store.find_nodes_by_property("city", &Value::from("NYC"));
assert_eq!(nyc_people.len(), 2);Sourcepub fn find_nodes_matching_filter(
&self,
property: &str,
filter_value: &Value,
) -> Vec<NodeId>
pub fn find_nodes_matching_filter( &self, property: &str, filter_value: &Value, ) -> Vec<NodeId>
Finds nodes whose property matches an operator filter.
The filter_value is either a scalar (equality) or a Value::Map with
$-prefixed operator keys like $gt, $lt, $gte, $lte, $in,
$nin, $ne, $contains.
Sourcepub fn node_property_might_match(
&self,
property: &PropertyKey,
op: CompareOp,
value: &Value,
) -> bool
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.
Sourcepub fn edge_property_might_match(
&self,
property: &PropertyKey,
op: CompareOp,
value: &Value,
) -> bool
pub fn edge_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool
Checks if an edge property predicate might match any edges.
Sourcepub fn node_property_zone_map(
&self,
property: &PropertyKey,
) -> Option<ZoneMapEntry>
pub fn node_property_zone_map( &self, property: &PropertyKey, ) -> Option<ZoneMapEntry>
Gets the zone map for a node property.
Sourcepub fn edge_property_zone_map(
&self,
property: &PropertyKey,
) -> Option<ZoneMapEntry>
pub fn edge_property_zone_map( &self, property: &PropertyKey, ) -> Option<ZoneMapEntry>
Gets the zone map for an edge property.
Source§impl LpgStore
impl LpgStore
Sourcepub fn statistics(&self) -> Arc<Statistics>
pub fn statistics(&self) -> Arc<Statistics>
Returns the current statistics (cheap Arc clone, no deep copy).
Sourcepub fn estimate_label_cardinality(&self, label: &str) -> f64
pub fn estimate_label_cardinality(&self, label: &str) -> f64
Estimates cardinality for a label scan.
Sourcepub fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64
pub fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64
Estimates average degree for an edge type.
Source§impl LpgStore
impl LpgStore
Sourcepub fn neighbors(
&self,
node: NodeId,
direction: Direction,
) -> impl Iterator<Item = NodeId> + '_
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.
Sourcepub fn edges_from(
&self,
node: NodeId,
direction: Direction,
) -> impl Iterator<Item = (NodeId, EdgeId)> + '_
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.
Sourcepub fn edges_to(&self, node: NodeId) -> Vec<(NodeId, EdgeId)>
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
let store = LpgStore::new().expect("arena allocation");
let a = store.create_node(&["Node"]);
let b = store.create_node(&["Node"]);
let c = store.create_node(&["Node"]);
let _e1 = store.create_edge(a, b, "LINKS");
let _e2 = store.create_edge(c, b, "LINKS");
// For edges: A->B, C->B
let incoming = store.edges_to(b);
assert_eq!(incoming.len(), 2);Sourcepub fn out_degree(&self, node: NodeId) -> usize
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.
Sourcepub fn in_degree(&self, node: NodeId) -> usize
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.
Sourcepub fn all_nodes(&self) -> impl Iterator<Item = Node> + '_
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.
Sourcepub fn all_edges(&self) -> impl Iterator<Item = Edge> + '_
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.
Sourcepub fn nodes_with_label<'a>(
&'a self,
label: &str,
) -> impl Iterator<Item = Node> + 'a
pub fn nodes_with_label<'a>( &'a self, label: &str, ) -> impl Iterator<Item = Node> + 'a
Returns an iterator over nodes with a specific label.
Sourcepub fn edges_with_type<'a>(
&'a self,
edge_type: &str,
) -> impl Iterator<Item = Edge> + 'a
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§impl LpgStore
impl LpgStore
Sourcepub fn new() -> Result<Self, AllocError>
pub fn new() -> Result<Self, AllocError>
Creates a new LPG store with default configuration.
§Errors
Returns AllocError if the arena allocator cannot be initialized
(only possible with the tiered-storage feature).
Sourcepub fn with_config(config: LpgStoreConfig) -> Result<Self, AllocError>
pub fn with_config(config: LpgStoreConfig) -> Result<Self, AllocError>
Creates a new LPG store with custom configuration.
§Errors
Returns AllocError if the arena allocator cannot be initialized
(only possible with the tiered-storage feature).
Sourcepub fn current_epoch(&self) -> EpochId
pub fn current_epoch(&self) -> EpochId
Returns the current epoch.
Sourcepub fn clear(&self)
pub fn clear(&self)
Removes all data from the store, resetting it to an empty state.
Acquires locks in the documented ordering to prevent deadlocks. After clearing, the store behaves as if freshly constructed.
Sourcepub fn has_backward_adjacency(&self) -> bool
pub fn has_backward_adjacency(&self) -> bool
Returns whether backward adjacency (incoming edge index) is available.
When backward adjacency is enabled (the default), bidirectional search algorithms can traverse from the target toward the source.
Sourcepub fn graph(&self, name: &str) -> Option<Arc<LpgStore>>
pub fn graph(&self, name: &str) -> Option<Arc<LpgStore>>
Returns a named graph by name, or None if it does not exist.
Sourcepub fn graph_or_create(&self, name: &str) -> Result<Arc<LpgStore>, AllocError>
pub fn graph_or_create(&self, name: &str) -> Result<Arc<LpgStore>, AllocError>
Returns a named graph, creating it if it does not exist.
§Errors
Returns AllocError if a new store cannot be allocated.
Sourcepub fn create_graph(&self, name: &str) -> Result<bool, AllocError>
pub fn create_graph(&self, name: &str) -> Result<bool, AllocError>
Creates a named graph. Returns true on success, false if it already exists.
§Errors
Returns AllocError if the new store cannot be allocated.
Sourcepub fn drop_graph(&self, name: &str) -> bool
pub fn drop_graph(&self, name: &str) -> bool
Drops a named graph. Returns false if it did not exist.
Sourcepub fn graph_names(&self) -> Vec<String>
pub fn graph_names(&self) -> Vec<String>
Returns all named graph names.
Sourcepub fn graph_count(&self) -> usize
pub fn graph_count(&self) -> usize
Returns the number of named graphs.
Sourcepub fn clear_graph(&self, name: Option<&str>)
pub fn clear_graph(&self, name: Option<&str>)
Clears a specific graph, or the default graph if name is None.
Sourcepub fn copy_graph(
&self,
source: Option<&str>,
dest: Option<&str>,
) -> Result<(), AllocError>
pub fn copy_graph( &self, source: Option<&str>, dest: Option<&str>, ) -> Result<(), AllocError>
Copies all data from the source graph to the destination graph. Creates the destination graph if it does not exist.
§Errors
Returns AllocError if the destination store cannot be allocated.
Trait Implementations§
Source§impl GraphStore for LpgStore
impl GraphStore for LpgStore
Source§fn get_node(&self, id: NodeId) -> Option<Node>
fn get_node(&self, id: NodeId) -> Option<Node>
Source§fn get_edge(&self, id: EdgeId) -> Option<Edge>
fn get_edge(&self, id: EdgeId) -> Option<Edge>
Source§fn get_node_versioned(
&self,
id: NodeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> Option<Node>
fn get_node_versioned( &self, id: NodeId, epoch: EpochId, transaction_id: TransactionId, ) -> Option<Node>
Source§fn get_edge_versioned(
&self,
id: EdgeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> Option<Edge>
fn get_edge_versioned( &self, id: EdgeId, epoch: EpochId, transaction_id: TransactionId, ) -> Option<Edge>
Source§fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>
fn get_node_at_epoch(&self, id: NodeId, epoch: EpochId) -> Option<Node>
Source§fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>
fn get_edge_at_epoch(&self, id: EdgeId, epoch: EpochId) -> Option<Edge>
Source§fn get_node_property(&self, id: NodeId, key: &PropertyKey) -> Option<Value>
fn get_node_property(&self, id: NodeId, key: &PropertyKey) -> Option<Value>
Source§fn get_edge_property(&self, id: EdgeId, key: &PropertyKey) -> Option<Value>
fn get_edge_property(&self, id: EdgeId, key: &PropertyKey) -> Option<Value>
Source§fn get_node_property_batch(
&self,
ids: &[NodeId],
key: &PropertyKey,
) -> Vec<Option<Value>>
fn get_node_property_batch( &self, ids: &[NodeId], key: &PropertyKey, ) -> Vec<Option<Value>>
Source§fn get_nodes_properties_batch(
&self,
ids: &[NodeId],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
fn get_nodes_properties_batch( &self, ids: &[NodeId], ) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
Source§fn get_nodes_properties_selective_batch(
&self,
ids: &[NodeId],
keys: &[PropertyKey],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
fn get_nodes_properties_selective_batch( &self, ids: &[NodeId], keys: &[PropertyKey], ) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
Source§fn get_edges_properties_selective_batch(
&self,
ids: &[EdgeId],
keys: &[PropertyKey],
) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
fn get_edges_properties_selective_batch( &self, ids: &[EdgeId], keys: &[PropertyKey], ) -> Vec<FxHashMap<PropertyKey, Value>> ⓘ
Source§fn neighbors(&self, node: NodeId, direction: Direction) -> Vec<NodeId>
fn neighbors(&self, node: NodeId, direction: Direction) -> Vec<NodeId>
Source§fn edges_from(
&self,
node: NodeId,
direction: Direction,
) -> Vec<(NodeId, EdgeId)>
fn edges_from( &self, node: NodeId, direction: Direction, ) -> Vec<(NodeId, EdgeId)>
Source§fn out_degree(&self, node: NodeId) -> usize
fn out_degree(&self, node: NodeId) -> usize
Source§fn in_degree(&self, node: NodeId) -> usize
fn in_degree(&self, node: NodeId) -> usize
Source§fn has_backward_adjacency(&self) -> bool
fn has_backward_adjacency(&self) -> bool
Source§fn all_node_ids(&self) -> Vec<NodeId>
fn all_node_ids(&self) -> Vec<NodeId>
Source§fn node_count(&self) -> usize
fn node_count(&self) -> usize
Source§fn edge_count(&self) -> usize
fn edge_count(&self) -> usize
Source§fn edge_type_versioned(
&self,
id: EdgeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> Option<ArcStr>
fn edge_type_versioned( &self, id: EdgeId, epoch: EpochId, transaction_id: TransactionId, ) -> Option<ArcStr>
Source§fn has_property_index(&self, property: &str) -> bool
fn has_property_index(&self, property: &str) -> bool
true if a property index exists for the given property. Read moreSource§fn find_nodes_by_property(&self, property: &str, value: &Value) -> Vec<NodeId>
fn find_nodes_by_property(&self, property: &str, value: &Value) -> Vec<NodeId>
Source§fn find_nodes_by_properties(&self, conditions: &[(&str, Value)]) -> Vec<NodeId>
fn find_nodes_by_properties(&self, conditions: &[(&str, Value)]) -> Vec<NodeId>
Source§fn find_nodes_in_range(
&self,
property: &str,
min: Option<&Value>,
max: Option<&Value>,
min_inclusive: bool,
max_inclusive: bool,
) -> Vec<NodeId>
fn find_nodes_in_range( &self, property: &str, min: Option<&Value>, max: Option<&Value>, min_inclusive: bool, max_inclusive: bool, ) -> Vec<NodeId>
Source§fn node_property_might_match(
&self,
property: &PropertyKey,
op: CompareOp,
value: &Value,
) -> bool
fn node_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool
true if a node property predicate might match any nodes.
Uses zone maps for early filtering.Source§fn edge_property_might_match(
&self,
property: &PropertyKey,
op: CompareOp,
value: &Value,
) -> bool
fn edge_property_might_match( &self, property: &PropertyKey, op: CompareOp, value: &Value, ) -> bool
true if an edge property predicate might match any edges.Source§fn statistics(&self) -> Arc<Statistics>
fn statistics(&self) -> Arc<Statistics>
Source§fn estimate_label_cardinality(&self, label: &str) -> f64
fn estimate_label_cardinality(&self, label: &str) -> f64
Source§fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64
fn estimate_avg_degree(&self, edge_type: &str, outgoing: bool) -> f64
Source§fn current_epoch(&self) -> EpochId
fn current_epoch(&self) -> EpochId
Source§fn all_labels(&self) -> Vec<String>
fn all_labels(&self) -> Vec<String>
Source§fn all_edge_types(&self) -> Vec<String>
fn all_edge_types(&self) -> Vec<String>
Source§fn all_property_keys(&self) -> Vec<String>
fn all_property_keys(&self) -> Vec<String>
Source§fn is_node_visible_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool
fn is_node_visible_at_epoch(&self, id: NodeId, epoch: EpochId) -> bool
Source§fn is_node_visible_versioned(
&self,
id: NodeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> bool
fn is_node_visible_versioned( &self, id: NodeId, epoch: EpochId, transaction_id: TransactionId, ) -> bool
Source§fn is_edge_visible_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool
fn is_edge_visible_at_epoch(&self, id: EdgeId, epoch: EpochId) -> bool
Source§fn is_edge_visible_versioned(
&self,
id: EdgeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> bool
fn is_edge_visible_versioned( &self, id: EdgeId, epoch: EpochId, transaction_id: TransactionId, ) -> bool
Source§fn filter_visible_node_ids(&self, ids: &[NodeId], epoch: EpochId) -> Vec<NodeId>
fn filter_visible_node_ids(&self, ids: &[NodeId], epoch: EpochId) -> Vec<NodeId>
Source§fn filter_visible_node_ids_versioned(
&self,
ids: &[NodeId],
epoch: EpochId,
transaction_id: TransactionId,
) -> Vec<NodeId>
fn filter_visible_node_ids_versioned( &self, ids: &[NodeId], epoch: EpochId, transaction_id: TransactionId, ) -> Vec<NodeId>
Source§impl GraphStoreMut for LpgStore
impl GraphStoreMut for LpgStore
Source§fn create_node(&self, labels: &[&str]) -> NodeId
fn create_node(&self, labels: &[&str]) -> NodeId
Source§fn create_node_versioned(
&self,
labels: &[&str],
epoch: EpochId,
transaction_id: TransactionId,
) -> NodeId
fn create_node_versioned( &self, labels: &[&str], epoch: EpochId, transaction_id: TransactionId, ) -> NodeId
Source§fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId
fn create_edge(&self, src: NodeId, dst: NodeId, edge_type: &str) -> EdgeId
Source§fn create_edge_versioned(
&self,
src: NodeId,
dst: NodeId,
edge_type: &str,
epoch: EpochId,
transaction_id: TransactionId,
) -> EdgeId
fn create_edge_versioned( &self, src: NodeId, dst: NodeId, edge_type: &str, epoch: EpochId, transaction_id: TransactionId, ) -> EdgeId
Source§fn batch_create_edges(&self, edges: &[(NodeId, NodeId, &str)]) -> Vec<EdgeId>
fn batch_create_edges(&self, edges: &[(NodeId, NodeId, &str)]) -> Vec<EdgeId>
Source§fn delete_node(&self, id: NodeId) -> bool
fn delete_node(&self, id: NodeId) -> bool
true if the node existed.Source§fn delete_node_versioned(
&self,
id: NodeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> bool
fn delete_node_versioned( &self, id: NodeId, epoch: EpochId, transaction_id: TransactionId, ) -> bool
true if the node existed.Source§fn delete_node_edges(&self, node_id: NodeId)
fn delete_node_edges(&self, node_id: NodeId)
Source§fn delete_edge(&self, id: EdgeId) -> bool
fn delete_edge(&self, id: EdgeId) -> bool
true if the edge existed.Source§fn delete_edge_versioned(
&self,
id: EdgeId,
epoch: EpochId,
transaction_id: TransactionId,
) -> bool
fn delete_edge_versioned( &self, id: EdgeId, epoch: EpochId, transaction_id: TransactionId, ) -> bool
true if the edge existed.Source§fn set_node_property_versioned(
&self,
id: NodeId,
key: &str,
value: Value,
transaction_id: TransactionId,
)
fn set_node_property_versioned( &self, id: NodeId, key: &str, value: Value, transaction_id: TransactionId, )
Source§fn set_edge_property_versioned(
&self,
id: EdgeId,
key: &str,
value: Value,
transaction_id: TransactionId,
)
fn set_edge_property_versioned( &self, id: EdgeId, key: &str, value: Value, transaction_id: TransactionId, )
Source§fn remove_node_property(&self, id: NodeId, key: &str) -> Option<Value>
fn remove_node_property(&self, id: NodeId, key: &str) -> Option<Value>
Source§fn remove_edge_property(&self, id: EdgeId, key: &str) -> Option<Value>
fn remove_edge_property(&self, id: EdgeId, key: &str) -> Option<Value>
Source§fn remove_node_property_versioned(
&self,
id: NodeId,
key: &str,
transaction_id: TransactionId,
) -> Option<Value>
fn remove_node_property_versioned( &self, id: NodeId, key: &str, transaction_id: TransactionId, ) -> Option<Value>
Source§fn remove_edge_property_versioned(
&self,
id: EdgeId,
key: &str,
transaction_id: TransactionId,
) -> Option<Value>
fn remove_edge_property_versioned( &self, id: EdgeId, key: &str, transaction_id: TransactionId, ) -> Option<Value>
Source§fn add_label(&self, node_id: NodeId, label: &str) -> bool
fn add_label(&self, node_id: NodeId, label: &str) -> bool
true if the label was new.Source§fn remove_label(&self, node_id: NodeId, label: &str) -> bool
fn remove_label(&self, node_id: NodeId, label: &str) -> bool
true if the label existed.Source§fn add_label_versioned(
&self,
node_id: NodeId,
label: &str,
transaction_id: TransactionId,
) -> bool
fn add_label_versioned( &self, node_id: NodeId, label: &str, transaction_id: TransactionId, ) -> bool
Source§fn remove_label_versioned(
&self,
node_id: NodeId,
label: &str,
transaction_id: TransactionId,
) -> bool
fn remove_label_versioned( &self, node_id: NodeId, label: &str, transaction_id: TransactionId, ) -> bool
Source§fn create_node_with_props(
&self,
labels: &[&str],
properties: &[(PropertyKey, Value)],
) -> NodeId
fn create_node_with_props( &self, labels: &[&str], properties: &[(PropertyKey, Value)], ) -> NodeId
Source§fn create_edge_with_props(
&self,
src: NodeId,
dst: NodeId,
edge_type: &str,
properties: &[(PropertyKey, Value)],
) -> EdgeId
fn create_edge_with_props( &self, src: NodeId, dst: NodeId, edge_type: &str, properties: &[(PropertyKey, Value)], ) -> EdgeId
Auto Trait Implementations§
impl !Freeze for LpgStore
impl !RefUnwindSafe for LpgStore
impl Send for LpgStore
impl Sync for LpgStore
impl Unpin for LpgStore
impl UnsafeUnpin for LpgStore
impl !UnwindSafe for LpgStore
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> 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