pub mod backend;
pub mod column_store;
pub mod disk;
pub(crate) mod forked;
pub mod interner;
pub mod lookups;
pub mod mapped;
pub mod mapped_graph_impl;
pub mod memory;
mod memory_graph_impl;
pub mod mode;
pub mod node_view;
pub mod overflow;
pub(crate) mod packed_codec;
pub mod property_storage;
pub(crate) mod slot_mirror;
pub mod type_build_meta;
pub mod undo;
use crate::datatypes::Value;
use crate::graph::core::iterators::GraphEdgeRef;
use crate::graph::schema::{EdgeData, InternedKey, NodeData};
pub use crate::graph::storage::column_store::ColumnStore;
pub use crate::graph::storage::node_view::NodeView;
use crate::graph::storage::slot_mirror::SlotMirror;
use crate::graph::storage::undo::UndoJournal;
use petgraph::graph::{EdgeIndex, NodeIndex};
use petgraph::stable_graph::StableDiGraph;
use petgraph::Direction;
use rustc_hash::FxHashMap;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::time::Instant;
#[derive(Debug, Clone, PartialEq)]
pub enum StrField<'a> {
Str(std::borrow::Cow<'a, str>),
NotString,
Absent,
}
impl StrField<'_> {
#[inline]
pub fn is(&self, test: impl FnOnce(&str) -> bool) -> bool {
match self {
StrField::Str(s) => test(s),
StrField::NotString | StrField::Absent => false,
}
}
}
pub trait GraphRead {
type NodeIndicesIter<'a>: Iterator<Item = NodeIndex>
where
Self: 'a;
type EdgeIndicesIter<'a>: Iterator<Item = EdgeIndex>
where
Self: 'a;
type EdgesIter<'a>: Iterator<Item = GraphEdgeRef<'a>>
where
Self: 'a;
type EdgeReferencesIter<'a>: Iterator<Item = GraphEdgeRef<'a>>
where
Self: 'a;
type EdgesConnectingIter<'a>: Iterator<Item = GraphEdgeRef<'a>>
where
Self: 'a;
type NeighborsIter<'a>: Iterator<Item = NodeIndex>
where
Self: 'a;
fn node_count(&self) -> usize;
fn edge_count(&self) -> usize;
fn node_bound(&self) -> usize;
fn edge_bound(&self) -> usize;
fn is_memory(&self) -> bool;
fn is_mapped(&self) -> bool {
false
}
fn is_disk(&self) -> bool {
false
}
fn node_type_of(&self, idx: NodeIndex) -> Option<InternedKey>;
fn node_labels_of(&self, idx: NodeIndex) -> Vec<InternedKey> {
match self.node_type_of(idx) {
Some(key) => vec![key],
None => Vec::new(),
}
}
fn node_weight(&self, idx: NodeIndex) -> Option<&NodeData>;
fn get_node_property(&self, idx: NodeIndex, key: InternedKey) -> Option<Value>;
fn get_node_id(&self, idx: NodeIndex) -> Option<Value>;
fn get_node_title(&self, idx: NodeIndex) -> Option<Value>;
fn str_prop_eq(&self, idx: NodeIndex, key: InternedKey, target: &str) -> Option<bool>;
#[inline]
fn node_view(&self, idx: NodeIndex) -> Option<NodeView<'_>> {
let data = self.node_weight(idx)?;
let store = data.properties.columnar_row_id().and_then(|row_id| {
self.column_store(data.node_type)
.map(|store| (&**store, row_id))
});
Some(NodeView::new(data, store))
}
#[inline]
fn node_row_properties(&self, idx: NodeIndex) -> Vec<(InternedKey, Value)> {
self.node_view(idx)
.map(|v| v.property_pairs())
.unwrap_or_default()
}
#[inline]
fn node_property_keys(&self, idx: NodeIndex) -> Vec<InternedKey> {
self.node_row_properties(idx)
.into_iter()
.map(|(k, _)| k)
.collect()
}
#[inline]
fn node_has_property(&self, idx: NodeIndex, key: InternedKey) -> bool {
self.node_view(idx).is_some_and(|v| v.contains(key))
}
#[inline]
fn node_property_count(&self, idx: NodeIndex) -> usize {
self.node_view(idx).map_or(0, |v| v.property_count())
}
fn column_store(&self, type_key: InternedKey) -> Option<&Arc<ColumnStore>>;
fn column_stores_iter(&self)
-> Box<dyn Iterator<Item = (InternedKey, &Arc<ColumnStore>)> + '_>;
fn has_column_stores(&self) -> bool {
self.column_stores_iter().next().is_some()
}
fn node_indices(&self) -> Self::NodeIndicesIter<'_>;
fn edge_indices(&self) -> Self::EdgeIndicesIter<'_>;
fn edge_references(&self) -> Self::EdgeReferencesIter<'_>;
fn edge_weights<'a>(&'a self) -> Box<dyn Iterator<Item = &'a EdgeData> + 'a>;
fn edges_directed(&self, idx: NodeIndex, dir: Direction) -> Self::EdgesIter<'_>;
fn edges(&self, idx: NodeIndex) -> Self::EdgesIter<'_>;
fn edges_directed_filtered(
&self,
idx: NodeIndex,
dir: Direction,
conn_type_filter: Option<InternedKey>,
) -> Self::EdgesIter<'_>;
fn edges_connecting(&self, a: NodeIndex, b: NodeIndex) -> Self::EdgesConnectingIter<'_>;
fn edge_weight(&self, idx: EdgeIndex) -> Option<&EdgeData>;
fn find_edge(&self, a: NodeIndex, b: NodeIndex) -> Option<EdgeIndex>;
fn edge_endpoints(&self, idx: EdgeIndex) -> Option<(NodeIndex, NodeIndex)>;
fn edge_endpoint_keys<'a>(
&'a self,
) -> Box<dyn Iterator<Item = (NodeIndex, NodeIndex, InternedKey)> + 'a>;
fn neighbors_directed(&self, idx: NodeIndex, dir: Direction) -> Self::NeighborsIter<'_>;
fn neighbors_undirected(&self, idx: NodeIndex) -> Self::NeighborsIter<'_>;
fn sources_for_conn_type_bounded(
&self,
_conn_type: InternedKey,
_max: Option<usize>,
) -> Option<Vec<u32>> {
None
}
fn lookup_peer_counts(&self, _conn_type: InternedKey) -> Option<HashMap<u32, i64>> {
None
}
fn lookup_by_property_eq(
&self,
_node_type: &str,
_property: &str,
_value: &str,
) -> Option<Vec<NodeIndex>> {
None
}
fn lookup_by_property_prefix(
&self,
_node_type: &str,
_property: &str,
_prefix: &str,
_limit: usize,
) -> Option<Vec<NodeIndex>> {
None
}
fn lookup_by_property_eq_any_type(
&self,
_property: &str,
_value: &str,
) -> Option<Vec<NodeIndex>> {
None
}
fn lookup_by_property_prefix_any_type(
&self,
_property: &str,
_prefix: &str,
_limit: usize,
) -> Option<Vec<NodeIndex>> {
None
}
fn count_edges_grouped_by_peer(
&self,
conn_type: InternedKey,
dir: Direction,
deadline: Option<Instant>,
) -> Result<HashMap<u32, i64>, String>;
fn count_edges_filtered(
&self,
node: NodeIndex,
dir: Direction,
conn_type: Option<InternedKey>,
other_node_type: Option<InternedKey>,
deadline: Option<Instant>,
) -> Result<usize, String>;
fn iter_peers_filtered<'a>(
&'a self,
node: NodeIndex,
dir: Direction,
conn_type: Option<u64>,
) -> Box<dyn Iterator<Item = (NodeIndex, EdgeIndex)> + 'a> {
let iter = self.edges_directed(node, dir).filter_map(move |er| {
if let Some(want) = conn_type {
if er.weight().connection_type.as_u64() != want {
return None;
}
}
let peer = match dir {
Direction::Outgoing => er.target(),
Direction::Incoming => er.source(),
};
Some((peer, er.id()))
});
Box::new(iter)
}
fn reset_arenas(&self) {}
}
pub trait GraphWrite: GraphRead {
fn node_weight_mut(&mut self, idx: NodeIndex) -> Option<&mut NodeData>;
fn node_weight_mut_silent(&mut self, idx: NodeIndex) -> Option<&mut NodeData> {
self.node_weight_mut(idx)
}
fn edge_weight_mut(&mut self, idx: EdgeIndex) -> Option<&mut EdgeData>;
fn install_column_store(&mut self, type_key: InternedKey, store: Arc<ColumnStore>);
fn column_store_mut(&mut self, type_key: InternedKey) -> Option<&mut Arc<ColumnStore>>;
fn take_column_store(&mut self, type_key: InternedKey) -> Option<Arc<ColumnStore>>;
fn clear_column_stores(&mut self);
fn set_node_property(&mut self, idx: NodeIndex, key: InternedKey, value: Value);
fn set_node_property_if_absent(&mut self, idx: NodeIndex, key: InternedKey, value: Value);
fn remove_node_property(&mut self, idx: NodeIndex, key: InternedKey) -> Option<Value>;
fn clear_node_property(&mut self, idx: NodeIndex, key: InternedKey) -> Option<Value>;
fn replace_node_properties(&mut self, idx: NodeIndex, pairs: Vec<(InternedKey, Value)>);
fn set_node_title(&mut self, idx: NodeIndex, value: Value) {
if let Some(node) = self.node_weight_mut(idx) {
node.title = value;
}
}
fn add_node(&mut self, data: NodeData) -> NodeIndex;
fn remove_node(&mut self, idx: NodeIndex) -> Option<NodeData>;
fn add_edge(&mut self, a: NodeIndex, b: NodeIndex, data: EdgeData) -> EdgeIndex;
fn remove_edge(&mut self, idx: EdgeIndex) -> Option<EdgeData>;
fn update_row_id(&mut self, _node_idx: NodeIndex, _row_id: u32) {}
fn flush_pending_writes(&mut self) {}
}
#[derive(Debug, Default)]
pub struct MemoryGraph {
pub(crate) inner: StableDiGraph<NodeData, EdgeData>,
pub(crate) column_stores: FxHashMap<InternedKey, Arc<ColumnStore>>,
pub(crate) peer_counts: RwLock<HashMap<u64, Arc<MemoryPeerCounts>>>,
pub(crate) undo: Option<Box<UndoJournal>>,
pub(crate) slot_mirror: SlotMirror,
}
#[derive(Debug, Default)]
pub(crate) struct MemoryPeerCounts {
pub(crate) by_target: Arc<HashMap<u32, i64>>,
pub(crate) by_source: Arc<HashMap<u32, i64>>,
}
pub mod impls;
pub mod recording;
pub use mapped::{MappedGraph, MappedPropertyIndex, MappedTypeIndex};
#[cfg(test)]
#[path = "column_ownership_tests.rs"]
mod column_ownership_tests;
#[cfg(test)]
#[path = "mapped_property_index_tests.rs"]
mod mapped_property_index_tests;
#[allow(unused_imports)]
pub use recording::RecordingGraph;