pub mod builder;
pub mod column;
pub mod csr;
mod graph_store_impl;
pub mod id;
pub mod node_table;
pub mod rel_table;
pub mod schema;
#[cfg(test)]
mod tests;
pub mod zone_map;
pub use builder::{CompactStoreBuilder, from_graph_store};
use std::sync::Arc;
use arcstr::ArcStr;
use grafeo_common::types::{EdgeId, NodeId};
use grafeo_common::utils::hash::FxHashMap;
use self::node_table::NodeTable;
use self::rel_table::RelTable;
use crate::graph::Direction;
use crate::statistics::Statistics;
pub struct CompactStore {
node_tables_by_id: Vec<NodeTable>,
label_to_table_id: FxHashMap<ArcStr, u16>,
rel_tables_by_id: Vec<RelTable>,
edge_type_to_rel_id: FxHashMap<ArcStr, Vec<u16>>,
table_id_to_label: Vec<ArcStr>,
rel_table_id_to_type: Vec<ArcStr>,
src_rel_table_ids: Vec<Vec<u16>>,
dst_rel_table_ids: Vec<Vec<u16>>,
statistics: Arc<Statistics>,
}
impl std::fmt::Debug for CompactStore {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CompactStore")
.field("node_tables_by_id", &self.node_tables_by_id)
.field("rel_tables_by_id", &self.rel_tables_by_id)
.field("table_id_to_label", &self.table_id_to_label)
.field("rel_table_id_to_type", &self.rel_table_id_to_type)
.finish_non_exhaustive()
}
}
impl CompactStore {
#[must_use]
pub(crate) fn new(
node_tables_by_id: Vec<NodeTable>,
label_to_table_id: FxHashMap<ArcStr, u16>,
rel_tables_by_id: Vec<RelTable>,
edge_type_to_rel_id: FxHashMap<ArcStr, Vec<u16>>,
table_id_to_label: Vec<ArcStr>,
rel_table_id_to_type: Vec<ArcStr>,
statistics: Statistics,
) -> Self {
let node_table_count = node_tables_by_id.len();
let mut src_rel_table_ids = vec![Vec::new(); node_table_count];
let mut dst_rel_table_ids = vec![Vec::new(); node_table_count];
for (rel_idx, rt) in rel_tables_by_id.iter().enumerate() {
let rel_id = rel_idx as u16;
let src_tid = rt.src_table_id() as usize;
let dst_tid = rt.dst_table_id() as usize;
if src_tid < node_table_count {
src_rel_table_ids[src_tid].push(rel_id);
}
if dst_tid < node_table_count {
dst_rel_table_ids[dst_tid].push(rel_id);
}
}
Self {
node_tables_by_id,
label_to_table_id,
rel_tables_by_id,
edge_type_to_rel_id,
table_id_to_label,
rel_table_id_to_type,
src_rel_table_ids,
dst_rel_table_ids,
statistics: Arc::new(statistics),
}
}
#[inline]
fn resolve_node_table(&self, table_id: u16) -> Option<&NodeTable> {
self.node_tables_by_id.get(table_id as usize)
}
#[inline]
fn resolve_rel_table(&self, rel_table_id: u16) -> Option<&RelTable> {
self.rel_tables_by_id.get(rel_table_id as usize)
}
#[must_use]
pub fn node_table(&self, label: &str) -> Option<&NodeTable> {
let &tid = self.label_to_table_id.get(label)?;
self.node_tables_by_id.get(tid as usize)
}
#[must_use]
pub fn rel_table(&self, edge_type: &str) -> Option<&RelTable> {
let rids = self.edge_type_to_rel_id.get(edge_type)?;
let &rid = rids.first()?;
self.rel_tables_by_id.get(rid as usize)
}
#[must_use]
pub fn rel_tables_for_type(&self, edge_type: &str) -> Vec<&RelTable> {
self.edge_type_to_rel_id
.get(edge_type)
.map(|rids| {
rids.iter()
.filter_map(|&rid| self.rel_tables_by_id.get(rid as usize))
.collect()
})
.unwrap_or_default()
}
#[must_use]
pub fn label_for_table_id(&self, table_id: u16) -> Option<&ArcStr> {
self.table_id_to_label.get(table_id as usize)
}
#[must_use]
pub fn edge_type_for_rel_table_id(&self, rel_table_id: u16) -> Option<&ArcStr> {
self.rel_table_id_to_type.get(rel_table_id as usize)
}
fn collect_edges(
&self,
node_table_id: u16,
node_offset: u32,
direction: Direction,
) -> Vec<(NodeId, EdgeId)> {
let tid = node_table_id as usize;
let mut results = Vec::new();
if matches!(direction, Direction::Outgoing | Direction::Both)
&& let Some(rel_ids) = self.src_rel_table_ids.get(tid)
{
for &rel_id in rel_ids {
let rt = &self.rel_tables_by_id[rel_id as usize];
results.extend(rt.edges_from_source(node_offset));
}
}
if matches!(direction, Direction::Incoming | Direction::Both)
&& let Some(rel_ids) = self.dst_rel_table_ids.get(tid)
{
for &rel_id in rel_ids {
let rt = &self.rel_tables_by_id[rel_id as usize];
if let Some(edges) = rt.edges_to_target(node_offset) {
results.extend(edges);
}
}
}
results
}
#[must_use]
pub fn memory_bytes(&self) -> usize {
let node_bytes: usize = self
.node_tables_by_id
.iter()
.map(|nt| nt.memory_bytes())
.sum();
let rel_bytes: usize = self
.rel_tables_by_id
.iter()
.map(|rt| rt.memory_bytes())
.sum();
node_bytes + rel_bytes
}
}