1use super::{
10 make_graphid, usize_to_f64_exact, BTreeMap, BTreeSet, Direction, Edge, EdgeId, GraphStore,
11 GraphStoreError, GraphStoreResult, LabelKind, MemoryGraphStore, Vertex, VertexId,
12};
13
14impl GraphStore for MemoryGraphStore {
15 fn create_graph(&mut self, name: &str) {
16 self.graphs.entry(name.to_string()).or_default();
17 }
18
19 fn drop_graph(&mut self, name: &str) {
20 self.label_registries.remove(name);
23 let Some(partition) = self.graphs.remove(name) else {
24 return;
25 };
26 for vid in &partition.vertex_ids {
27 if let Some(set) = self.vertex_membership.get_mut(vid) {
28 set.remove(name);
29 }
30 }
31 for eid in &partition.edge_ids {
32 if let Some(set) = self.edge_membership.get_mut(eid) {
33 set.remove(name);
34 }
35 }
36 let orphan_vertices: Vec<VertexId> = partition.vertex_ids.iter().copied().collect();
38 for vid in orphan_vertices {
39 self.release_vertex_if_orphan(vid);
40 }
41 let orphan_edges: Vec<EdgeId> = partition.edge_ids.iter().copied().collect();
42 for eid in orphan_edges {
43 self.release_edge_if_orphan(eid);
44 }
45 }
46
47 fn graph_names(&self) -> Vec<String> {
48 self.graphs.keys().cloned().collect()
49 }
50
51 fn has_graph(&self, name: &str) -> bool {
52 self.graphs.contains_key(name)
53 }
54
55 fn union_graphs(&mut self, g1: &str, g2: &str, target: &str) -> GraphStoreResult<()> {
56 let v_union: BTreeSet<VertexId> = self
57 .require_partition(g1)?
58 .vertex_ids
59 .union(&self.require_partition(g2)?.vertex_ids)
60 .copied()
61 .collect();
62 let e_union: BTreeSet<EdgeId> = self
63 .require_partition(g1)?
64 .edge_ids
65 .union(&self.require_partition(g2)?.edge_ids)
66 .copied()
67 .collect();
68 self.populate_graph_from_ids(&v_union, &e_union, target)
69 }
70
71 fn intersect_graphs(&mut self, g1: &str, g2: &str, target: &str) -> GraphStoreResult<()> {
72 let v_inter: BTreeSet<VertexId> = self
73 .require_partition(g1)?
74 .vertex_ids
75 .intersection(&self.require_partition(g2)?.vertex_ids)
76 .copied()
77 .collect();
78 let e_inter: BTreeSet<EdgeId> = self
79 .require_partition(g1)?
80 .edge_ids
81 .intersection(&self.require_partition(g2)?.edge_ids)
82 .copied()
83 .collect();
84 self.populate_graph_from_ids(&v_inter, &e_inter, target)
85 }
86
87 fn difference_graphs(&mut self, g1: &str, g2: &str, target: &str) -> GraphStoreResult<()> {
88 let v_diff: BTreeSet<VertexId> = self
89 .require_partition(g1)?
90 .vertex_ids
91 .difference(&self.require_partition(g2)?.vertex_ids)
92 .copied()
93 .collect();
94 let e_diff: BTreeSet<EdgeId> = self
95 .require_partition(g1)?
96 .edge_ids
97 .difference(&self.require_partition(g2)?.edge_ids)
98 .copied()
99 .collect();
100 self.populate_graph_from_ids(&v_diff, &e_diff, target)
101 }
102
103 fn copy_graph(&mut self, source: &str, target: &str) -> GraphStoreResult<()> {
104 let v_copy = self.require_partition(source)?.vertex_ids.clone();
105 let e_copy = self.require_partition(source)?.edge_ids.clone();
106 self.populate_graph_from_ids(&v_copy, &e_copy, target)
107 }
108
109 fn add_vertex(&mut self, vertex: Vertex, graph: &str) -> GraphStoreResult<()> {
110 self.require_partition(graph)?;
111 let vid = vertex.vertex_id;
112 let next_vertex_id = if vid >= self.next_vertex_id {
113 vid.checked_add(1).ok_or_else(|| {
114 GraphStoreError::IdExhausted("vertex id counter overflow".to_string())
115 })?
116 } else {
117 self.next_vertex_id
118 };
119 self.vertices.insert(vid, vertex.clone());
120 self.require_partition_mut(graph)?.add_vertex(&vertex);
121 self.vertex_membership
122 .entry(vid)
123 .or_default()
124 .insert(graph.to_string());
125 self.next_vertex_id = next_vertex_id;
126 Ok(())
127 }
128
129 fn add_edge(&mut self, edge: Edge, graph: &str) -> GraphStoreResult<()> {
130 let partition = self.require_partition(graph)?;
131 if !partition.vertex_ids.contains(&edge.source_id)
132 || !partition.vertex_ids.contains(&edge.target_id)
133 {
134 return Err(GraphStoreError::InvalidMutation(format!(
135 "edge {} references endpoint outside graph {graph:?}: {} -> {}",
136 edge.edge_id, edge.source_id, edge.target_id
137 )));
138 }
139 self.require_partition_vertex(partition, edge.source_id, graph)?;
140 self.require_partition_vertex(partition, edge.target_id, graph)?;
141 let eid = edge.edge_id;
142 let next_edge_id = if eid >= self.next_edge_id {
143 eid.checked_add(1).ok_or_else(|| {
144 GraphStoreError::IdExhausted("edge id counter overflow".to_string())
145 })?
146 } else {
147 self.next_edge_id
148 };
149 self.edges.insert(eid, edge.clone());
150 self.require_partition_mut(graph)?.add_edge(&edge);
151 self.edge_membership
152 .entry(eid)
153 .or_default()
154 .insert(graph.to_string());
155 self.next_edge_id = next_edge_id;
156 Ok(())
157 }
158
159 fn remove_vertex(&mut self, vertex_id: VertexId, graph: &str) -> GraphStoreResult<()> {
160 let partition = self.require_partition_mut(graph)?;
161 if !partition.vertex_ids.remove(&vertex_id) {
162 return Ok(());
163 }
164 for vids in partition.vertex_label_index.values_mut() {
165 vids.remove(&vertex_id);
166 }
167 let out_edges: Vec<EdgeId> = partition
169 .adj_out
170 .remove(&vertex_id)
171 .map(|s| s.into_iter().collect())
172 .unwrap_or_default();
173 let in_edges: Vec<EdgeId> = partition
174 .adj_in
175 .remove(&vertex_id)
176 .map(|s| s.into_iter().collect())
177 .unwrap_or_default();
178 let edge_ids_to_drop: Vec<EdgeId> = out_edges.into_iter().chain(in_edges).collect();
179 for eid in &edge_ids_to_drop {
180 if let Some(edge) = self.edges.get(eid).cloned() {
181 if let Some(part) = self.graphs.get_mut(graph) {
182 part.remove_edge(&edge);
183 }
184 if let Some(set) = self.edge_membership.get_mut(eid) {
185 set.remove(graph);
186 }
187 }
188 }
189 if let Some(set) = self.vertex_membership.get_mut(&vertex_id) {
190 set.remove(graph);
191 }
192 for eid in edge_ids_to_drop {
193 self.release_edge_if_orphan(eid);
194 }
195 self.release_vertex_if_orphan(vertex_id);
196 Ok(())
197 }
198
199 fn remove_edge(&mut self, edge_id: EdgeId, graph: &str) -> GraphStoreResult<()> {
200 self.require_partition(graph)?;
201 let Some(edge) = self.edges.get(&edge_id).cloned() else {
202 return Ok(());
203 };
204 let partition = self.require_partition_mut(graph)?;
205 if !partition.edge_ids.contains(&edge_id) {
206 return Ok(());
207 }
208 partition.remove_edge(&edge);
209 if let Some(set) = self.edge_membership.get_mut(&edge_id) {
210 set.remove(graph);
211 }
212 self.release_edge_if_orphan(edge_id);
213 Ok(())
214 }
215
216 fn neighbors(
217 &self,
218 vertex_id: VertexId,
219 label: Option<&str>,
220 direction: Direction,
221 graph: &str,
222 ) -> GraphStoreResult<Vec<VertexId>> {
223 let partition = self.require_partition(graph)?;
224 self.require_query_vertex(partition, vertex_id, graph)?;
225 let mut result = Vec::new();
226 let mut collect = |set: &BTreeSet<EdgeId>, take_target: bool| -> GraphStoreResult<()> {
227 for eid in set {
228 let edge = self.require_partition_edge(partition, *eid, graph)?;
229 let expected_endpoint = if take_target {
230 edge.source_id
231 } else {
232 edge.target_id
233 };
234 if expected_endpoint != vertex_id {
235 return Err(GraphStoreError::CorruptGraph(format!(
236 "graph {graph:?} adjacency for vertex {vertex_id} references edge {eid} with endpoints {} -> {}",
237 edge.source_id, edge.target_id
238 )));
239 }
240 if let Some(want) = label {
241 if edge.label != want {
242 continue;
243 }
244 }
245 result.push(if take_target {
246 edge.target_id
247 } else {
248 edge.source_id
249 });
250 }
251 Ok(())
252 };
253 match direction {
254 Direction::Out => {
255 if let Some(set) = partition.adj_out.get(&vertex_id) {
256 collect(set, true)?;
257 }
258 }
259 Direction::In => {
260 if let Some(set) = partition.adj_in.get(&vertex_id) {
261 collect(set, false)?;
262 }
263 }
264 Direction::Both => {
265 if let Some(set) = partition.adj_out.get(&vertex_id) {
266 collect(set, true)?;
267 }
268 if let Some(set) = partition.adj_in.get(&vertex_id) {
269 collect(set, false)?;
270 }
271 result.sort_unstable();
272 result.dedup();
273 }
274 }
275 Ok(result)
276 }
277
278 fn vertices_by_label(&self, label: &str, graph: &str) -> GraphStoreResult<Vec<Vertex>> {
279 let partition = self.require_partition(graph)?;
280 partition
281 .vertex_label_index
282 .get(label)
283 .into_iter()
284 .flat_map(|set| set.iter())
285 .map(|vertex_id| {
286 self.require_partition_vertex(partition, *vertex_id, graph)
287 .cloned()
288 })
289 .collect()
290 }
291
292 fn vertex_ids_by_label(&self, label: &str, graph: &str) -> GraphStoreResult<Vec<VertexId>> {
293 let partition = self.require_partition(graph)?;
294 partition
295 .vertex_label_index
296 .get(label)
297 .into_iter()
298 .flat_map(|set| set.iter())
299 .map(|vertex_id| {
300 self.require_partition_vertex(partition, *vertex_id, graph)?;
301 Ok(*vertex_id)
302 })
303 .collect()
304 }
305
306 fn vertices_in_graph(&self, graph: &str) -> GraphStoreResult<Vec<Vertex>> {
307 let partition = self.require_partition(graph)?;
308 partition
309 .vertex_ids
310 .iter()
311 .map(|vertex_id| {
312 self.require_partition_vertex(partition, *vertex_id, graph)
313 .cloned()
314 })
315 .collect()
316 }
317
318 fn edges_in_graph(&self, graph: &str) -> GraphStoreResult<Vec<Edge>> {
319 let partition = self.require_partition(graph)?;
320 partition
321 .edge_ids
322 .iter()
323 .map(|edge_id| {
324 self.require_partition_edge(partition, *edge_id, graph)
325 .cloned()
326 })
327 .collect()
328 }
329
330 fn vertex_graphs(&self, vertex_id: VertexId) -> BTreeSet<String> {
331 self.vertex_membership
332 .get(&vertex_id)
333 .cloned()
334 .unwrap_or_default()
335 }
336
337 fn out_edge_ids(&self, vertex_id: VertexId, graph: &str) -> GraphStoreResult<BTreeSet<EdgeId>> {
338 let partition = self.require_partition(graph)?;
339 self.require_query_vertex(partition, vertex_id, graph)?;
340 let edges = partition
341 .adj_out
342 .get(&vertex_id)
343 .cloned()
344 .unwrap_or_default();
345 for edge_id in &edges {
346 let edge = self.require_partition_edge(partition, *edge_id, graph)?;
347 if edge.source_id != vertex_id {
348 return Err(GraphStoreError::CorruptGraph(format!(
349 "graph {graph:?} outgoing adjacency for vertex {vertex_id} references edge {edge_id} sourced at {}",
350 edge.source_id
351 )));
352 }
353 }
354 Ok(edges)
355 }
356
357 fn in_edge_ids(&self, vertex_id: VertexId, graph: &str) -> GraphStoreResult<BTreeSet<EdgeId>> {
358 let partition = self.require_partition(graph)?;
359 self.require_query_vertex(partition, vertex_id, graph)?;
360 let edges = partition
361 .adj_in
362 .get(&vertex_id)
363 .cloned()
364 .unwrap_or_default();
365 for edge_id in &edges {
366 let edge = self.require_partition_edge(partition, *edge_id, graph)?;
367 if edge.target_id != vertex_id {
368 return Err(GraphStoreError::CorruptGraph(format!(
369 "graph {graph:?} incoming adjacency for vertex {vertex_id} references edge {edge_id} targeted at {}",
370 edge.target_id
371 )));
372 }
373 }
374 Ok(edges)
375 }
376
377 fn edge_ids_by_label(&self, label: &str, graph: &str) -> GraphStoreResult<BTreeSet<EdgeId>> {
378 let partition = self.require_partition(graph)?;
379 let edges = partition
380 .label_index
381 .get(label)
382 .cloned()
383 .unwrap_or_default();
384 for edge_id in &edges {
385 let edge = self.require_partition_edge(partition, *edge_id, graph)?;
386 if edge.label != label {
387 return Err(GraphStoreError::CorruptGraph(format!(
388 "graph {graph:?} label index {label:?} references edge {edge_id} labelled {:?}",
389 edge.label
390 )));
391 }
392 }
393 Ok(edges)
394 }
395
396 fn vertex_ids_in_graph(&self, graph: &str) -> GraphStoreResult<BTreeSet<VertexId>> {
397 let partition = self.require_partition(graph)?;
398 for vertex_id in &partition.vertex_ids {
399 self.require_partition_vertex(partition, *vertex_id, graph)?;
400 }
401 Ok(partition.vertex_ids.clone())
402 }
403
404 fn require_vertex_in_graph(&self, vertex_id: VertexId, graph: &str) -> GraphStoreResult<()> {
405 let partition = self.require_partition(graph)?;
406 self.require_query_vertex(partition, vertex_id, graph)
407 }
408
409 fn degree_distribution(&self, graph: &str) -> GraphStoreResult<BTreeMap<VertexId, u64>> {
410 let partition = self.require_partition(graph)?;
411 let mut out = BTreeMap::new();
412 for vid in &partition.vertex_ids {
413 self.require_partition_vertex(partition, *vid, graph)?;
414 let edge_ids = partition.adj_out.get(vid);
415 if let Some(edge_ids) = edge_ids {
416 for edge_id in edge_ids {
417 let edge = self.require_partition_edge(partition, *edge_id, graph)?;
418 if edge.source_id != *vid {
419 return Err(GraphStoreError::CorruptGraph(format!(
420 "graph {graph:?} outgoing adjacency for vertex {vid} references edge {edge_id} sourced at {}",
421 edge.source_id
422 )));
423 }
424 }
425 }
426 let degree = u64::try_from(edge_ids.map_or(0, BTreeSet::len)).map_err(|_| {
427 GraphStoreError::CorruptGraph(format!("out-degree for vertex {vid} exceeds u64"))
428 })?;
429 out.insert(*vid, degree);
430 }
431 Ok(out)
432 }
433
434 fn label_degree(&self, label: &str, graph: &str) -> GraphStoreResult<f64> {
435 let partition = self.require_partition(graph)?;
436 let Some(eids) = partition.label_index.get(label) else {
437 return Ok(0.0);
438 };
439 if eids.is_empty() {
440 return Ok(0.0);
441 }
442 let mut sources: BTreeSet<VertexId> = BTreeSet::new();
443 for eid in eids {
444 let edge = self.require_partition_edge(partition, *eid, graph)?;
445 if edge.label != label {
446 return Err(GraphStoreError::CorruptGraph(format!(
447 "graph {graph:?} label index {label:?} references edge {eid} labelled {:?}",
448 edge.label
449 )));
450 }
451 sources.insert(edge.source_id);
452 }
453 if sources.is_empty() {
454 Ok(0.0)
455 } else {
456 Ok(usize_to_f64_exact(eids.len(), "edge label count")?
457 / usize_to_f64_exact(sources.len(), "edge label source count")?)
458 }
459 }
460
461 fn vertex_label_counts(&self, graph: &str) -> GraphStoreResult<BTreeMap<String, u64>> {
462 let partition = self.require_partition(graph)?;
463 let mut out = BTreeMap::new();
464 for (label, vids) in &partition.vertex_label_index {
465 for vertex_id in vids {
466 let vertex = self.require_partition_vertex(partition, *vertex_id, graph)?;
467 if vertex.label != *label {
468 return Err(GraphStoreError::CorruptGraph(format!(
469 "graph {graph:?} vertex label index {label:?} references vertex {vertex_id} labelled {:?}",
470 vertex.label
471 )));
472 }
473 }
474 let count = u64::try_from(vids.len()).map_err(|_| {
475 GraphStoreError::CorruptGraph(format!(
476 "vertex count for label {label:?} exceeds u64"
477 ))
478 })?;
479 if count > 0 {
480 out.insert(label.clone(), count);
481 }
482 }
483 Ok(out)
484 }
485
486 fn get_vertex(&self, vertex_id: VertexId) -> Option<&Vertex> {
487 self.vertices.get(&vertex_id)
488 }
489
490 fn get_edge(&self, edge_id: EdgeId) -> Option<&Edge> {
491 self.edges.get(&edge_id)
492 }
493
494 fn next_vertex_id(&mut self) -> GraphStoreResult<VertexId> {
495 let id = self.next_vertex_id;
496 self.next_vertex_id = id.checked_add(1).ok_or_else(|| {
497 GraphStoreError::IdExhausted("vertex id counter overflow".to_string())
498 })?;
499 Ok(id)
500 }
501
502 fn next_edge_id(&mut self) -> GraphStoreResult<EdgeId> {
503 let id = self.next_edge_id;
504 self.next_edge_id = id
505 .checked_add(1)
506 .ok_or_else(|| GraphStoreError::IdExhausted("edge id counter overflow".to_string()))?;
507 Ok(id)
508 }
509
510 fn allocate_vertex_id(&mut self, label: &str, graph: &str) -> GraphStoreResult<VertexId> {
511 if !self.has_graph(graph) {
512 return Err(GraphStoreError::UnknownGraph(graph.to_string()));
513 }
514 let mut candidate = self
515 .label_registries
516 .get(graph)
517 .cloned()
518 .unwrap_or_default();
519 let label_id = candidate.label_id(label, LabelKind::Vertex)?;
520 let id = make_graphid(label_id, candidate.next_sequence(label_id)?)?;
521 self.label_registries.insert(graph.to_string(), candidate);
522 Ok(id)
523 }
524
525 fn allocate_edge_id(&mut self, label: &str, graph: &str) -> GraphStoreResult<EdgeId> {
526 if !self.has_graph(graph) {
527 return Err(GraphStoreError::UnknownGraph(graph.to_string()));
528 }
529 let mut candidate = self
530 .label_registries
531 .get(graph)
532 .cloned()
533 .unwrap_or_default();
534 let label_id = candidate.label_id(label, LabelKind::Edge)?;
535 let id = make_graphid(label_id, candidate.next_sequence(label_id)?)?;
536 self.label_registries.insert(graph.to_string(), candidate);
537 Ok(id)
538 }
539
540 fn clear(&mut self) {
541 self.vertices.clear();
542 self.edges.clear();
543 self.graphs.clear();
544 self.vertex_membership.clear();
545 self.edge_membership.clear();
546 self.label_registries.clear();
547 self.next_vertex_id = 1;
548 self.next_edge_id = 1;
549 }
550
551 fn vertices(&self) -> BTreeMap<VertexId, Vertex> {
552 self.vertices.clone()
553 }
554
555 fn edges(&self) -> BTreeMap<EdgeId, Edge> {
556 self.edges.clone()
557 }
558}