graphannis_core/graph/storage/
mod.rs1pub mod adjacencylist;
2pub mod dense_adjacency;
3pub mod disk_adjacency;
4pub mod disk_path;
5pub mod linear;
6pub mod prepost;
7pub mod registry;
8pub mod union;
9
10pub(crate) mod legacy;
11
12use crate::annostorage::{EdgeAnnotationStorage, NodeAnnotationStorage};
13use crate::{
14 annostorage::AnnotationStorage,
15 errors::Result,
16 types::{AnnoKey, Annotation, Edge, NodeID},
17};
18use itertools::Itertools;
19use serde::{Deserialize, Serialize};
20use std::{self, path::Path};
21
22#[derive(Serialize, Deserialize, Clone)]
24pub struct GraphStatistic {
25 pub cyclic: bool,
27
28 pub rooted_tree: bool,
30
31 pub nodes: usize,
33
34 pub root_nodes: usize,
36
37 pub avg_fan_out: f64,
39 pub fan_out_99_percentile: usize,
41
42 pub inverse_fan_out_99_percentile: usize,
44
45 pub max_fan_out: usize,
47 pub max_depth: usize,
49
50 pub dfs_visit_ratio: f64,
52}
53
54impl std::fmt::Display for GraphStatistic {
55 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
56 write!(
57 f,
58 "nodes={}, root nodes={}, avg_fan_out={:.2}, max_fan_out={}, fan_out_99%={}, inv_fan_out_99%={}, max_depth={}",
59 self.nodes,
60 self.root_nodes,
61 self.avg_fan_out,
62 self.max_fan_out,
63 self.fan_out_99_percentile,
64 self.inverse_fan_out_99_percentile,
65 self.max_depth
66 )?;
67 if self.cyclic {
68 write!(f, ", cyclic")?;
69 }
70 if self.rooted_tree {
71 write!(f, ", tree")?;
72 }
73 Ok(())
74 }
75}
76
77pub trait EdgeContainer: Sync + Send {
79 fn get_outgoing_edges<'a>(
81 &'a self,
82 node: NodeID,
83 ) -> Box<dyn Iterator<Item = Result<NodeID>> + 'a>;
84
85 fn has_outgoing_edges(&self, node: NodeID) -> Result<bool> {
87 if let Some(outgoing) = self.get_outgoing_edges(node).next() {
88 outgoing?;
89 Ok(true)
90 } else {
91 Ok(false)
92 }
93 }
94
95 fn get_ingoing_edges<'a>(
97 &'a self,
98 node: NodeID,
99 ) -> Box<dyn Iterator<Item = Result<NodeID>> + 'a>;
100
101 fn has_ingoing_edges(&self, node: NodeID) -> Result<bool> {
103 if let Some(ingoing) = self.get_ingoing_edges(node).next() {
104 ingoing?;
105 Ok(true)
106 } else {
107 Ok(false)
108 }
109 }
110
111 fn get_statistics(&self) -> Option<&GraphStatistic> {
112 None
113 }
114
115 fn source_nodes<'a>(&'a self) -> Box<dyn Iterator<Item = Result<NodeID>> + 'a>;
117
118 fn root_nodes<'a>(&'a self) -> Box<dyn Iterator<Item = Result<NodeID>> + 'a> {
120 let it = self
122 .source_nodes()
123 .map(move |n| -> Result<Option<NodeID>> {
124 let n = n?;
125 if !self.has_ingoing_edges(n)? {
126 Ok(Some(n))
127 } else {
128 Ok(None)
129 }
130 })
131 .filter_map_ok(|n| n);
132 Box::new(it)
133 }
134}
135
136pub trait GraphStorage: EdgeContainer {
139 fn find_connected<'a>(
141 &'a self,
142 node: NodeID,
143 min_distance: usize,
144 max_distance: std::ops::Bound<usize>,
145 ) -> Box<dyn Iterator<Item = Result<NodeID>> + 'a>;
146
147 fn find_connected_inverse<'a>(
149 &'a self,
150 node: NodeID,
151 min_distance: usize,
152 max_distance: std::ops::Bound<usize>,
153 ) -> Box<dyn Iterator<Item = Result<NodeID>> + 'a>;
154
155 fn distance(&self, source: NodeID, target: NodeID) -> Result<Option<usize>>;
157
158 fn is_connected(
160 &self,
161 source: NodeID,
162 target: NodeID,
163 min_distance: usize,
164 max_distance: std::ops::Bound<usize>,
165 ) -> Result<bool>;
166
167 fn get_anno_storage(&self) -> &dyn EdgeAnnotationStorage;
169
170 fn copy(
173 &mut self,
174 node_annos: &dyn NodeAnnotationStorage,
175 orig: &dyn GraphStorage,
176 ) -> Result<()>;
177
178 fn as_edgecontainer(&self) -> &dyn EdgeContainer;
180
181 fn as_writeable(&mut self) -> Option<&mut dyn WriteableGraphStorage> {
184 None
185 }
186
187 fn inverse_has_same_cost(&self) -> bool {
189 false
190 }
191
192 fn serialization_id(&self) -> String;
194
195 fn load_from(location: &Path) -> Result<Self>
197 where
198 Self: std::marker::Sized;
199
200 fn save_to(&self, location: &Path) -> Result<()>;
202}
203
204pub fn serialize_gs_field<T>(field: &T, field_name: &str, location: &Path) -> Result<()>
205where
206 T: Serialize,
207{
208 let data_path = location.join(format!("{field_name}.bin"));
209 let f_data = std::fs::File::create(data_path)?;
210 let mut writer = std::io::BufWriter::new(f_data);
211 bincode::serialize_into(&mut writer, field)?;
212 Ok(())
213}
214
215pub fn deserialize_gs_field<T>(location: &Path, field_name: &str) -> Result<T>
216where
217 for<'de> T: std::marker::Sized + Deserialize<'de>,
218{
219 let data_path = location.join(format!("{field_name}.bin"));
220 let f_data = std::fs::File::open(data_path)?;
221 let input = std::io::BufReader::new(f_data);
222
223 let result = bincode::deserialize_from(input)?;
224 Ok(result)
225}
226
227const STATISTICS_FILE_NAME: &str = "stats.toml";
228
229pub fn load_statistics_from_location(location: &Path) -> Result<Option<GraphStatistic>> {
230 let stats_path_toml = location.join(STATISTICS_FILE_NAME);
231 let legacy_stats_path_bin = location.join("edge_stats.bin");
232
233 let stats = if stats_path_toml.is_file() {
234 let file_content = std::fs::read_to_string(stats_path_toml)?;
235 let stats: GraphStatistic = toml::from_str(&file_content)?;
236 Some(stats)
237 } else if legacy_stats_path_bin.is_file() {
238 let f_stats = std::fs::File::open(legacy_stats_path_bin)?;
239 let input = std::io::BufReader::new(f_stats);
240 let legacy_stats: Option<legacy::GraphStatisticV1> = bincode::deserialize_from(input)?;
242 legacy_stats.map(|s| s.into())
243 } else {
244 None
245 };
246 Ok(stats)
247}
248
249pub fn save_statistics_to_toml(location: &Path, stats: Option<&GraphStatistic>) -> Result<()> {
250 let file_path = location.join(STATISTICS_FILE_NAME);
251 if file_path.is_file() {
252 std::fs::remove_file(&file_path)?;
253 }
254
255 if let Some(stats) = stats {
256 let file_content = toml::to_string(stats)?;
257 std::fs::write(file_path, file_content)?;
258 }
259 Ok(())
260}
261
262pub trait WriteableGraphStorage: GraphStorage {
264 fn add_edge(&mut self, edge: Edge) -> Result<()>;
266
267 fn add_edge_annotation(&mut self, edge: Edge, anno: Annotation) -> Result<()>;
270
271 fn delete_edge(&mut self, edge: &Edge) -> Result<()>;
273
274 fn delete_edge_annotation(&mut self, edge: &Edge, anno_key: &AnnoKey) -> Result<()>;
276
277 fn delete_node(&mut self, node: NodeID) -> Result<()>;
280
281 fn calculate_statistics(&mut self) -> Result<()>;
283
284 fn clear(&mut self) -> Result<()>;
286}