use crate::types::*;
use super::SingleFileDB;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FullEdge {
pub src: NodeId,
pub etype: ETypeId,
pub dst: NodeId,
}
pub struct NodeIterator {
nodes: Vec<NodeId>,
index: usize,
}
impl NodeIterator {
pub(crate) fn new(db: &SingleFileDB) -> Self {
let mut nodes = Vec::new();
let delta = db.delta.read();
let snapshot = db.snapshot.read();
if let Some(ref snap) = *snapshot {
let num_nodes = snap.header.num_nodes as u32;
for phys in 0..num_nodes {
if let Some(node_id) = snap.get_node_id(phys) {
if !delta.is_node_deleted(node_id) {
nodes.push(node_id);
}
}
}
}
for &node_id in delta.created_nodes.keys() {
if !delta.deleted_nodes.contains(&node_id) {
nodes.push(node_id);
}
}
nodes.sort_unstable();
Self { nodes, index: 0 }
}
}
impl Iterator for NodeIterator {
type Item = NodeId;
fn next(&mut self) -> Option<Self::Item> {
if self.index < self.nodes.len() {
let node_id = self.nodes[self.index];
self.index += 1;
Some(node_id)
} else {
None
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = self.nodes.len() - self.index;
(remaining, Some(remaining))
}
}
impl ExactSizeIterator for NodeIterator {}
impl SingleFileDB {
pub fn iter_nodes(&self) -> NodeIterator {
NodeIterator::new(self)
}
pub fn list_nodes(&self) -> Vec<NodeId> {
self.iter_nodes().collect()
}
pub fn count_nodes(&self) -> usize {
let delta = self.delta.read();
let snapshot = self.snapshot.read();
let mut count = if let Some(ref snap) = *snapshot {
snap.header.num_nodes as usize
} else {
0
};
for &node_id in &delta.deleted_nodes {
if !delta.created_nodes.contains_key(&node_id) {
if let Some(ref snap) = *snapshot {
if snap.get_phys_node(node_id).is_some() {
count = count.saturating_sub(1);
}
}
}
}
for &node_id in delta.created_nodes.keys() {
if !delta.deleted_nodes.contains(&node_id) {
count += 1;
}
}
count
}
pub fn count_edges(&self) -> usize {
let delta = self.delta.read();
let snapshot = self.snapshot.read();
let mut count = if let Some(ref snap) = *snapshot {
snap.header.num_edges as usize
} else {
0
};
count = count.saturating_sub(delta.total_edges_deleted());
count += delta.total_edges_added();
count
}
pub fn count_edges_by_type(&self, etype: ETypeId) -> usize {
self.list_edges(Some(etype)).len()
}
pub fn list_edges(&self, etype_filter: Option<ETypeId>) -> Vec<FullEdge> {
let delta = self.delta.read();
let snapshot = self.snapshot.read();
let mut edges = Vec::new();
if let Some(ref snap) = *snapshot {
let num_nodes = snap.header.num_nodes as u32;
for phys in 0..num_nodes {
if let Some(src) = snap.get_node_id(phys) {
if delta.is_node_deleted(src) {
continue;
}
for (dst_phys, etype) in snap.iter_out_edges(phys) {
if let Some(filter_etype) = etype_filter {
if etype != filter_etype {
continue;
}
}
if let Some(dst) = snap.get_node_id(dst_phys) {
if delta.is_edge_deleted(src, etype, dst) {
continue;
}
edges.push(FullEdge { src, etype, dst });
}
}
}
}
}
for (&src, add_set) in &delta.out_add {
for patch in add_set {
if let Some(filter_etype) = etype_filter {
if patch.etype != filter_etype {
continue;
}
}
edges.push(FullEdge {
src,
etype: patch.etype,
dst: patch.other,
});
}
}
edges
}
pub fn stats(&self) -> DbStats {
let delta = self.delta.read();
let snapshot = self.snapshot.read();
let header = self.header.read();
let (snapshot_nodes, snapshot_edges, snapshot_max_node_id) = if let Some(ref snap) = *snapshot {
(
snap.header.num_nodes,
snap.header.num_edges,
snap.header.max_node_id,
)
} else {
(0, 0, 0)
};
DbStats {
snapshot_gen: header.active_snapshot_gen,
snapshot_nodes,
snapshot_edges,
snapshot_max_node_id,
delta_nodes_created: delta.created_nodes.len(),
delta_nodes_deleted: delta.deleted_nodes.len(),
delta_edges_added: delta.total_edges_added(),
delta_edges_deleted: delta.total_edges_deleted(),
wal_segment: 0, wal_bytes: self.wal_stats().used,
recommend_compact: self.should_checkpoint(0.8),
mvcc_stats: None,
}
}
pub fn wal_stats(&self) -> crate::core::wal::buffer::WalBufferStats {
self.wal_buffer.lock().stats()
}
}