Skip to main content

velesdb_core/collection/graph/edge_concurrent/
persistence.rs

1//! `ConcurrentEdgeStore` persistence (serialization/deserialization).
2//!
3//! Extracted from `edge_concurrent/mod.rs` to reduce NLOC below the 500 threshold.
4
5use super::super::edge::EdgeStore;
6use super::ConcurrentEdgeStore;
7
8impl ConcurrentEdgeStore {
9    /// Builds a `ConcurrentEdgeStore` from a persisted `EdgeStore`.
10    ///
11    /// Re-distributes edges across shards based on source node ID.
12    ///
13    /// Issue #905: uses [`add_edges_batch`](Self::add_edges_batch) (one
14    /// `edge_ids` write-lock acquisition for the whole set, snapshot
15    /// invalidated once) instead of a per-edge `add_edge` loop (one lock
16    /// cycle + one snapshot-dirty flip per edge). The single
17    /// [`build_read_snapshot`](Self::build_read_snapshot) at the end performs
18    /// exactly one O(N+E) CSR build for the whole reconstruction.
19    #[must_use]
20    pub fn from_edge_store(store: &EdgeStore) -> Self {
21        let edges: Vec<_> = store.all_edges().into_iter().cloned().collect();
22        let concurrent = Self::with_estimated_edges(edges.len());
23
24        let expected = edges.len();
25        let added = concurrent.add_edges_batch(edges);
26        if added != expected {
27            tracing::warn!(
28                "skipped {} duplicate edge(s) during CES reconstruction",
29                expected - added
30            );
31        }
32
33        concurrent.build_read_snapshot();
34        concurrent
35    }
36
37    /// Saves the concurrent edge store to a file.
38    ///
39    /// # Errors
40    ///
41    /// Returns an error if serialization or file I/O fails.
42    pub fn save_to_file(&self, path: &std::path::Path) -> std::io::Result<()> {
43        self.to_merged_edge_store().save_to_file(path)
44    }
45
46    /// Loads a concurrent edge store from a persisted file.
47    ///
48    /// # Errors
49    ///
50    /// Returns an error if file I/O or deserialization fails.
51    pub fn load_from_file(path: &std::path::Path) -> std::io::Result<Self> {
52        let store = EdgeStore::load_from_file(path)?;
53        Ok(Self::from_edge_store(&store))
54    }
55
56    /// Merges all shards into a single `EdgeStore` for serialization.
57    fn to_merged_edge_store(&self) -> EdgeStore {
58        let ids = self.edge_ids.read();
59        let mut merged = EdgeStore::with_capacity(ids.len(), ids.len());
60
61        for (&edge_id, &source_id) in ids.iter() {
62            let shard_idx = self.shard_index(source_id);
63            let guard = self.shards[shard_idx].read();
64            if let Some(edge) = guard.get_edge(edge_id) {
65                let _ = merged.add_edge(edge.clone());
66            }
67        }
68        merged
69    }
70}