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