1pub mod libc;
26
27#[cfg(feature = "testing")]
28pub mod testing;
29
30use alloc::{boxed::Box, collections::BTreeMap, string::String, vec, vec::Vec};
31use core::ops::Bound;
32
33use buggy::{Bug, BugExt as _, bug};
34use serde::{Deserialize, Serialize};
35use vec1::Vec1;
36
37use crate::{
38 Address, Bytes, Checkpoint, CmdId, Command, CommandExt as _, Fact, FactIndex, FactPerspective,
39 GraphId, HeadSet, HeadSetOffset, Keys, LocatedAddress, Location, MaxCut, Perspective, PolicyId,
40 Prior, Priority, Query, QueryMut, Revertable, Segment, SegmentIndex, Storage, StorageError,
41 StorageProvider,
42};
43
44pub mod io;
45pub use io::*;
46
47const MAX_FACT_INDEX_DEPTH: u64 = 16;
59
60pub struct LinearStorageProvider<FM: IoManager> {
61 manager: FM,
62 storage: BTreeMap<GraphId, LinearStorage<FM::Writer>>,
63}
64
65pub struct LinearStorage<W> {
66 writer: W,
67 cached_heads: HeadSet,
71}
72
73#[derive(Debug)]
74pub struct LinearSegment<R> {
75 repr: SegmentRepr,
76 reader: R,
77}
78
79#[derive(Debug, Serialize, Deserialize)]
80struct SegmentRepr {
81 offset: SegmentIndex,
83 prior: Prior<Location>,
84 parents: Prior<Address>,
85 policy: PolicyId,
86 facts: u64,
88 prior_facts: Option<u64>,
90 commands: Vec1<CommandData>,
91 max_cut: MaxCut,
92 skip_list: Vec<Location>,
93}
94
95#[derive(Debug, Serialize, Deserialize)]
96struct CommandData {
97 id: CmdId,
98 priority: Priority,
99 policy: Option<Bytes>,
100 data: Bytes,
101 updates: Vec<Update>,
102}
103
104pub struct LinearCommand<'a> {
105 id: &'a CmdId,
106 parent: Prior<Address>,
107 priority: Priority,
108 policy: Option<&'a [u8]>,
109 data: &'a [u8],
110}
111
112type Update = (String, Keys, Option<Bytes>);
113type FactMap = BTreeMap<Keys, Option<Box<[u8]>>>;
114type NamedFactMap = BTreeMap<String, FactMap>;
115
116#[derive(Debug)]
117pub struct LinearFactIndex<R> {
118 repr: FactIndexRepr,
119 reader: R,
120}
121
122#[derive(Debug, Serialize, Deserialize)]
123struct FactIndexRepr {
124 offset: u64,
126 prior: Option<u64>,
128 depth: u64,
132 facts: NamedFactMap,
134}
135
136#[derive(Debug)]
137pub struct LinearPerspective<R> {
138 prior: Prior<Location>,
139 parents: Prior<Address>,
140 policy: PolicyId,
141 facts: LinearFactPerspective<R>,
142 commands: Vec<CommandData>,
143 current_updates: Vec<Update>,
144 max_cut: MaxCut,
145 last_common_ancestor: Option<Location>,
146}
147
148impl<R> LinearPerspective<R> {
149 fn new(
150 prior: Prior<Location>,
151 parents: Prior<Address>,
152 policy: PolicyId,
153 prior_facts: FactPerspectivePrior<R>,
154 max_cut: MaxCut,
155 last_common_ancestor: Option<Location>,
156 ) -> Self {
157 Self {
158 prior,
159 parents,
160 policy,
161 facts: LinearFactPerspective::new(prior_facts),
162 commands: Vec::new(),
163 current_updates: Vec::new(),
164 max_cut,
165 last_common_ancestor,
166 }
167 }
168}
169
170#[derive(Debug)]
171pub struct LinearFactPerspective<R> {
172 map: BTreeMap<String, BTreeMap<Keys, Option<Bytes>>>,
173 prior: FactPerspectivePrior<R>,
174}
175
176impl<R> LinearFactPerspective<R> {
177 fn new(prior: FactPerspectivePrior<R>) -> Self {
178 Self {
179 map: BTreeMap::new(),
180 prior,
181 }
182 }
183}
184
185#[derive(Debug)]
186enum FactPerspectivePrior<R> {
187 None,
188 FactPerspective(Box<LinearFactPerspective<R>>),
189 FactIndex { offset: u64, reader: R },
190}
191
192impl<R> FactPerspectivePrior<R> {
193 fn is_none(&self) -> bool {
194 matches!(self, Self::None)
195 }
196}
197
198impl<FM: IoManager + Default> Default for LinearStorageProvider<FM> {
199 fn default() -> Self {
200 Self {
201 manager: FM::default(),
202 storage: BTreeMap::new(),
203 }
204 }
205}
206
207impl<FM: IoManager> LinearStorageProvider<FM> {
208 pub fn new(manager: FM) -> Self {
209 Self {
210 manager,
211 storage: BTreeMap::new(),
212 }
213 }
214}
215
216impl<FM: IoManager> StorageProvider for LinearStorageProvider<FM> {
217 type Perspective = LinearPerspective<<FM::Writer as Write>::ReadOnly>;
218 type Segment = LinearSegment<<FM::Writer as Write>::ReadOnly>;
219 type Storage = LinearStorage<FM::Writer>;
220
221 fn new_perspective(&mut self, policy_id: PolicyId) -> Self::Perspective {
222 LinearPerspective::new(
223 Prior::None,
224 Prior::None,
225 policy_id,
226 FactPerspectivePrior::None,
227 MaxCut::new(0),
228 None,
229 )
230 }
231
232 fn new_storage(
233 &mut self,
234 init: Self::Perspective,
235 ) -> Result<(GraphId, &mut Self::Storage), StorageError> {
236 use alloc::collections::btree_map::Entry;
237
238 if init.commands.is_empty() {
239 return Err(StorageError::EmptyPerspective);
240 }
241 let graph_id = GraphId::transmute(init.commands[0].id);
242 let Entry::Vacant(entry) = self.storage.entry(graph_id) else {
243 return Err(StorageError::StorageExists);
244 };
245
246 let file = self.manager.create(graph_id)?;
247 Ok((graph_id, entry.insert(LinearStorage::create(file, init)?)))
248 }
249
250 fn get_storage(&mut self, graph: GraphId) -> Result<&mut Self::Storage, StorageError> {
251 use alloc::collections::btree_map::Entry;
252
253 let entry = match self.storage.entry(graph) {
254 Entry::Vacant(v) => v,
255 Entry::Occupied(o) => return Ok(o.into_mut()),
256 };
257
258 let file = self
259 .manager
260 .open(graph)?
261 .ok_or(StorageError::NoSuchStorage)?;
262 Ok(entry.insert(LinearStorage::open(file)?))
263 }
264
265 fn remove_storage(&mut self, graph: GraphId) -> Result<(), StorageError> {
266 self.manager.remove(graph)?;
267
268 self.storage
269 .remove(&graph)
270 .ok_or(StorageError::NoSuchStorage)?;
271
272 Ok(())
273 }
274
275 fn list_graph_ids(
276 &mut self,
277 ) -> Result<impl Iterator<Item = Result<GraphId, StorageError>>, StorageError> {
278 self.manager.list()
279 }
280}
281
282const MIN_SKIP_GAP: u64 = 10;
286
287fn skip_target_boundaries(n: u64) -> Result<Vec<MaxCut>, StorageError> {
294 let mut targets = vec![];
295 let mut boundary = n / 2;
296 while boundary > 0 {
297 targets.push(MaxCut::new(boundary));
298 let gap = n
299 .checked_sub(boundary)
300 .assume("boundary < n by loop invariant")?;
301 if gap <= MIN_SKIP_GAP {
302 break;
303 }
304 boundary = boundary
305 .checked_add(gap / 2)
306 .assume("boundary + gap/2 <= n <= u64::MAX")?;
307 }
308 Ok(targets)
309}
310
311impl<W: Write> LinearStorage<W> {
312 fn create(mut writer: W, init: LinearPerspective<W::ReadOnly>) -> Result<Self, StorageError> {
313 assert!(matches!(init.prior, Prior::None));
314 assert!(matches!(init.parents, Prior::None));
315 assert!(matches!(init.facts.prior, FactPerspectivePrior::None));
316
317 let mut map = init.facts.map;
318 map.retain(|_, kv| !kv.is_empty());
319
320 let facts = writer
321 .append(|offset| FactIndexRepr {
322 offset,
323 prior: None,
324 depth: 1,
325 facts: map,
326 })?
327 .offset;
328
329 let commands = init
330 .commands
331 .try_into()
332 .map_err(|_| StorageError::EmptyPerspective)?;
333 let segment = writer.append(|offset| SegmentRepr {
334 offset: SegmentIndex::new(offset),
335 prior: Prior::None,
336 parents: Prior::None,
337 policy: init.policy,
338 facts,
339 prior_facts: None,
340 commands,
341 max_cut: MaxCut::new(0),
342 skip_list: vec![],
343 })?;
344
345 let max_cut = segment
346 .max_cut
347 .checked_add(
348 segment
349 .commands
350 .len()
351 .checked_sub(1)
352 .assume("vec1 length >= 1")? as u64,
353 )
354 .assume("valid max cut")?;
355 let head = LocatedAddress {
356 id: segment.commands.last().id,
357 segment: segment.offset,
358 max_cut,
359 };
360
361 let cached_heads = HeadSet::single(head);
364 writer.commit(&cached_heads, FactCacheOffset::new(facts))?;
365
366 let storage = Self {
367 writer,
368 cached_heads,
369 };
370
371 Ok(storage)
372 }
373
374 fn open(writer: W) -> Result<Self, StorageError> {
375 let cached_heads = writer.heads()?;
376 Ok(Self {
377 writer,
378 cached_heads,
379 })
380 }
381
382 fn compact(&mut self, mut repr: FactIndexRepr) -> Result<FactIndexRepr, StorageError> {
383 let mut map = NamedFactMap::new();
384 let reader = self.writer.readonly();
385 loop {
386 for (name, kv) in repr.facts {
387 let sub = map.entry(name).or_default();
388 for (k, v) in kv {
389 sub.entry(k).or_insert(v);
390 }
391 }
392 let Some(offset) = repr.prior else { break };
393 repr = reader.fetch(offset)?;
394 }
395
396 map.retain(|_, kv| {
398 kv.retain(|_, v| v.is_some());
399 !kv.is_empty()
400 });
401
402 Ok(self
403 .write_facts(LinearFactPerspective {
404 map,
405 prior: FactPerspectivePrior::None,
406 })?
407 .repr)
408 }
409
410 fn has_nearby_rich_anchor(&self, start: Location) -> Result<bool, StorageError> {
415 let mut check = start;
416 for _ in 0..MIN_SKIP_GAP {
417 let seg = self.get_segment(check)?;
418 if seg.skip_list().len() > 1 {
419 return Ok(true);
420 }
421 match seg.prior() {
422 Prior::Single(p) => check = p,
423 Prior::Merge(_, _) => {
424 check = seg
425 .skip_list()
426 .last()
427 .copied()
428 .assume("merge skip list must end with LCA")?;
429 }
430 Prior::None => return Ok(false),
431 }
432 }
433 Ok(false)
434 }
435
436 fn build_skip_list(
446 &self,
447 prior: Prior<Location>,
448 last_common_ancestor: Option<Location>,
449 n: u64,
450 ) -> Result<Vec<Location>, StorageError> {
451 let (walk_start, lca) = match prior {
452 Prior::None => return Ok(vec![]),
453 Prior::Merge(_, _) => {
454 let lca = last_common_ancestor.assume("lca must exist")?;
455 (lca, Some(lca))
456 }
457 Prior::Single(l) => (l, None),
458 };
459
460 if self.has_nearby_rich_anchor(walk_start)? || n < MIN_SKIP_GAP {
461 return Ok(lca.into_iter().collect());
462 }
463
464 let targets = skip_target_boundaries(n)?;
465 let mut skips = self.walk_collecting_skips(walk_start, targets)?;
466
467 if let Some(lca) = lca
469 && !skips.contains(&lca)
470 {
471 skips.push(lca);
472 }
473
474 skips.sort_by_key(|loc| loc.max_cut);
475 skips.dedup();
476 Ok(skips)
477 }
478
479 fn walk_collecting_skips(
486 &self,
487 start: Location,
488 mut targets: Vec<MaxCut>,
489 ) -> Result<Vec<Location>, StorageError> {
490 let mut skips = vec![];
491 let mut current = start;
492
493 loop {
494 let seg = self.get_segment(current)?;
495 let seg_min = seg.shortest_max_cut();
496
497 while let Some(&t) = targets.last() {
499 if t >= seg_min {
500 skips.push(seg.first_location());
501 targets.pop();
502 } else {
503 break;
504 }
505 }
506
507 let Some(&next_target) = targets.last() else {
508 break;
509 };
510
511 let best = seg
514 .skip_list()
515 .iter()
516 .copied()
517 .filter(|s| s.max_cut >= next_target && s.max_cut < current.max_cut)
518 .min_by_key(|s| s.max_cut);
519 if let Some(skip) = best {
520 current = skip;
521 continue;
522 }
523
524 match seg.prior() {
525 Prior::Single(p) if p.max_cut >= next_target => current = p,
526 _ => break,
527 }
528 }
529
530 Ok(skips)
531 }
532
533 fn write_facts_with_prior(
535 &mut self,
536 facts: <Self as Storage>::FactPerspective,
537 ) -> Result<(<Self as Storage>::FactIndex, Option<u64>), StorageError> {
538 let mut prior = match facts.prior {
539 FactPerspectivePrior::None => None,
540 FactPerspectivePrior::FactPerspective(prior) => {
541 let prior = self.write_facts(*prior)?;
542 if facts.map.is_empty() {
543 let offset = prior.repr.offset;
544 return Ok((prior, Some(offset)));
545 }
546 Some(prior.repr)
547 }
548 FactPerspectivePrior::FactIndex { offset, reader } => {
549 let repr: FactIndexRepr = reader.fetch(offset)?;
550 if facts.map.is_empty() {
551 let offset = repr.offset;
552 return Ok((LinearFactIndex { repr, reader }, Some(offset)));
553 }
554 Some(repr)
555 }
556 };
557
558 let depth = if let Some(mut p) = prior.take() {
559 if p.depth > MAX_FACT_INDEX_DEPTH - 1 {
560 p = self.compact(p)?;
561 }
562 prior.insert(p).depth
563 } else {
564 0
565 };
566
567 let depth = depth.checked_add(1).assume("depth won't overflow")?;
568
569 if depth > MAX_FACT_INDEX_DEPTH {
570 bug!("fact index too deep");
571 }
572
573 let prior_offset = prior.map(|p| p.offset);
574 let repr = self.writer.append(|offset| FactIndexRepr {
575 offset,
576 prior: prior_offset,
577 depth,
578 facts: facts.map,
579 })?;
580
581 Ok((
582 LinearFactIndex {
583 repr,
584 reader: self.writer.readonly(),
585 },
586 prior_offset,
587 ))
588 }
589}
590
591impl<F: Write> Storage for LinearStorage<F> {
592 type Perspective = LinearPerspective<F::ReadOnly>;
593 type FactPerspective = LinearFactPerspective<F::ReadOnly>;
594 type Segment = LinearSegment<F::ReadOnly>;
595 type FactIndex = LinearFactIndex<F::ReadOnly>;
596
597 fn get_linear_perspective(&self, parent: Location) -> Result<Self::Perspective, StorageError> {
598 let segment = self.get_segment(parent)?;
599 let command = segment
600 .get_command(parent)
601 .ok_or(StorageError::CommandOutOfBounds(parent))?;
602 let policy = segment.repr.policy;
603 let prior_facts: FactPerspectivePrior<F::ReadOnly> = if parent == segment.head_location()? {
604 FactPerspectivePrior::FactIndex {
605 offset: segment.repr.facts,
606 reader: self.writer.readonly(),
607 }
608 } else {
609 let prior = match segment.repr.prior_facts {
610 Some(offset) => FactPerspectivePrior::FactIndex {
611 offset,
612 reader: self.writer.readonly(),
613 },
614 None => FactPerspectivePrior::None,
615 };
616 let mut facts = LinearFactPerspective::new(prior);
617 for data in &segment.repr.commands[..=segment.repr.cmd_index(parent.max_cut)?] {
618 facts.apply_updates(&data.updates)?;
619 }
620 if facts.prior.is_none() {
621 facts.map.retain(|_, kv| !kv.is_empty());
622 }
623 if facts.map.is_empty() {
624 facts.prior
625 } else {
626 FactPerspectivePrior::FactPerspective(Box::new(facts))
627 }
628 };
629 let prior = Prior::Single(parent);
630
631 let perspective = LinearPerspective::new(
632 prior,
633 Prior::Single(command.address()?),
634 policy,
635 prior_facts,
636 command
637 .max_cut()?
638 .checked_add(1)
639 .assume("must not overflow")?,
640 None,
641 );
642
643 Ok(perspective)
644 }
645
646 fn get_fact_perspective(
647 &self,
648 location: Location,
649 ) -> Result<Self::FactPerspective, StorageError> {
650 let segment = self.get_segment(location)?;
651
652 if location == segment.head_location()?
655 || segment
656 .repr
657 .commands
658 .iter()
659 .all(|cmd| cmd.updates.is_empty())
660 {
661 return Ok(LinearFactPerspective::new(
662 FactPerspectivePrior::FactIndex {
663 offset: segment.repr.facts,
664 reader: self.writer.readonly(),
665 },
666 ));
667 }
668
669 let prior = match segment.repr.prior_facts {
670 Some(offset) => FactPerspectivePrior::FactIndex {
671 offset,
672 reader: self.writer.readonly(),
673 },
674 None => FactPerspectivePrior::None,
675 };
676 let mut facts = LinearFactPerspective::new(prior);
677 for data in &segment.repr.commands[..=segment.repr.cmd_index(location.max_cut)?] {
678 facts.apply_updates(&data.updates)?;
679 }
680
681 Ok(facts)
682 }
683
684 fn new_merge_perspective(
685 &self,
686 left: Location,
687 right: Location,
688 last_common_ancestor: Location,
689 policy_id: PolicyId,
690 braid: Self::FactIndex,
691 ) -> Result<Self::Perspective, StorageError> {
692 let left_segment = self.get_segment(left)?;
695 let left_command = left_segment
696 .get_command(left)
697 .ok_or(StorageError::CommandOutOfBounds(left))?;
698 let right_segment = self.get_segment(right)?;
699 let right_command = right_segment
700 .get_command(right)
701 .ok_or(StorageError::CommandOutOfBounds(right))?;
702
703 let parent = Prior::Merge(left_command.address()?, right_command.address()?);
704
705 if policy_id != left_segment.policy() && policy_id != right_segment.policy() {
706 return Err(StorageError::PolicyMismatch);
707 }
708
709 let prior = Prior::Merge(left, right);
710
711 let perspective = LinearPerspective::new(
712 prior,
713 parent,
714 policy_id,
715 FactPerspectivePrior::FactIndex {
716 offset: braid.repr.offset,
717 reader: braid.reader,
718 },
719 left_command
720 .max_cut()?
721 .max(right_command.max_cut()?)
722 .checked_add(1)
723 .assume("must not overflow")?,
724 Some(last_common_ancestor),
725 );
726
727 Ok(perspective)
728 }
729
730 fn get_segment(&self, location: Location) -> Result<Self::Segment, StorageError> {
731 let reader = self.writer.readonly();
732 let repr = reader.fetch(location.segment.get())?;
733 let seg = LinearSegment { repr, reader };
734
735 Ok(seg)
736 }
737
738 fn get_heads(&self) -> Result<&HeadSet, StorageError> {
739 Ok(&self.cached_heads)
740 }
741
742 fn heads_offset(&self) -> Result<HeadSetOffset, StorageError> {
743 self.writer.heads_offset()
744 }
745
746 fn fact_cache(&self) -> Result<Self::FactIndex, StorageError> {
747 let offset = self.writer.fact_cache()?;
748 Ok(LinearFactIndex {
749 repr: self.writer.readonly().fetch(offset.get())?,
750 reader: self.writer.readonly(),
751 })
752 }
753
754 fn commit_heads(
755 &mut self,
756 heads: HeadSet,
757 fact_cache: Self::FactIndex,
758 ) -> Result<(), StorageError> {
759 self.writer
760 .commit(&heads, FactCacheOffset::new(fact_cache.repr.offset))?;
761 self.cached_heads = heads;
762 Ok(())
763 }
764
765 fn write(&mut self, perspective: Self::Perspective) -> Result<Self::Segment, StorageError> {
766 let (facts, prior_facts) = self.write_facts_with_prior(perspective.facts)?;
769 let facts = facts.repr.offset;
770
771 let commands: Vec1<CommandData> = perspective
772 .commands
773 .try_into()
774 .map_err(|_| StorageError::EmptyPerspective)?;
775
776 let skip_list = self.build_skip_list(
777 perspective.prior,
778 perspective.last_common_ancestor,
779 perspective.max_cut.get(),
780 )?;
781
782 let repr = self.writer.append(|offset| SegmentRepr {
783 offset: SegmentIndex::new(offset),
784 prior: perspective.prior,
785 parents: perspective.parents,
786 policy: perspective.policy,
787 facts,
788 prior_facts,
789 commands,
790 max_cut: perspective.max_cut,
791 skip_list,
792 })?;
793
794 Ok(LinearSegment {
795 repr,
796 reader: self.writer.readonly(),
797 })
798 }
799
800 fn write_facts(
801 &mut self,
802 facts: Self::FactPerspective,
803 ) -> Result<Self::FactIndex, StorageError> {
804 self.write_facts_with_prior(facts)
805 .map(|(fact_index, _)| fact_index)
806 }
807}
808
809impl<R: Read> Segment for LinearSegment<R> {
810 type FactIndex = LinearFactIndex<R>;
811 type Command<'a>
812 = LinearCommand<'a>
813 where
814 R: 'a;
815
816 fn index(&self) -> SegmentIndex {
817 self.repr.offset
818 }
819
820 fn head_id(&self) -> CmdId {
821 self.repr.commands.last().id
822 }
823
824 fn first_location(&self) -> Location {
825 Location::new(self.repr.offset, self.repr.max_cut)
826 }
827
828 fn policy(&self) -> PolicyId {
829 self.repr.policy
830 }
831
832 fn prior(&self) -> Prior<Location> {
833 self.repr.prior
834 }
835
836 fn get_command(&self, location: Location) -> Option<Self::Command<'_>> {
837 if self.repr.offset != location.segment {
838 return None;
839 }
840 let cmd_idx = self.repr.cmd_index(location.max_cut).ok()?;
841 let data = self.repr.commands.get(cmd_idx)?;
842 let parent = if let Some(prev) = usize::checked_sub(cmd_idx, 1) {
843 if let Some(max_cut) = self.repr.max_cut.checked_add(prev as u64) {
844 Prior::Single(Address {
845 id: self.repr.commands[prev].id,
846 max_cut,
847 })
848 } else {
849 return None;
850 }
851 } else {
852 self.repr.parents
853 };
854 Some(LinearCommand {
855 id: &data.id,
856 parent,
857 priority: data.priority.clone(),
858 policy: data.policy.as_deref(),
859 data: &data.data,
860 })
861 }
862
863 fn facts(&self) -> Result<Self::FactIndex, StorageError> {
864 Ok(LinearFactIndex {
865 repr: self.reader.fetch(self.repr.facts)?,
866 reader: self.reader.clone(),
867 })
868 }
869
870 fn skip_list(&self) -> &[Location] {
871 &self.repr.skip_list
872 }
873
874 fn shortest_max_cut(&self) -> MaxCut {
875 self.repr.max_cut
876 }
877
878 fn longest_max_cut(&self) -> Result<MaxCut, StorageError> {
879 Ok(self
880 .repr
881 .max_cut
882 .checked_add(
883 self.repr
884 .commands
885 .len()
886 .checked_sub(1)
887 .assume("must not overflow")? as u64,
888 )
889 .assume("must not overflow")?)
890 }
891}
892
893impl SegmentRepr {
894 fn cmd_index(&self, max_cut: MaxCut) -> Result<usize, StorageError> {
895 max_cut
896 .distance_from(self.max_cut)
897 .and_then(|x| usize::try_from(x).ok())
898 .ok_or(StorageError::CommandOutOfBounds(Location::new(
899 self.offset,
900 max_cut,
901 )))
902 }
903}
904
905impl<R: Read> FactIndex for LinearFactIndex<R> {}
906
907#[cfg(all(test, feature = "graphviz"))]
908impl<R: Read> crate::storage::FactIndexExtra for LinearFactIndex<R> {
909 fn name(&self) -> String {
910 use alloc::string::ToString as _;
911 self.repr.offset.to_string()
912 }
913
914 fn prior(&self) -> Result<Option<Self>, StorageError> {
915 self.repr
916 .prior
917 .map(|p| {
918 let repr = self.reader.fetch(p)?;
919 Ok(Self {
920 repr,
921 reader: self.reader.clone(),
922 })
923 })
924 .transpose()
925 }
926}
927
928type MapIter = alloc::collections::btree_map::IntoIter<Keys, Option<Bytes>>;
929pub struct QueryIterator {
930 it: MapIter,
931}
932
933impl QueryIterator {
934 fn new(it: MapIter) -> Self {
935 Self { it }
936 }
937}
938
939impl Iterator for QueryIterator {
940 type Item = Result<Fact, StorageError>;
941 fn next(&mut self) -> Option<Self::Item> {
942 loop {
943 if let (key, Some(value)) = self.it.next()? {
945 return Some(Ok(Fact { key, value }));
946 }
947 }
948 }
949}
950
951impl<R: Read> Query for LinearFactIndex<R> {
952 fn query(&self, name: &str, keys: &[Bytes]) -> Result<Option<Bytes>, StorageError> {
953 let mut prior = Some(&self.repr);
954 let mut slot; while let Some(facts) = prior {
956 if let Some(v) = facts.facts.get(name).and_then(|m| m.get(keys)) {
957 return Ok(v.clone());
958 }
959 slot = facts.prior.map(|p| self.reader.fetch(p)).transpose()?;
960 prior = slot.as_ref();
961 }
962 Ok(None)
963 }
964
965 type QueryIterator = QueryIterator;
966 fn query_prefix(&self, name: &str, prefix: &[Bytes]) -> Result<QueryIterator, StorageError> {
967 Ok(QueryIterator::new(
968 self.query_prefix_inner(name, prefix)?.into_iter(),
969 ))
970 }
971}
972
973impl<R: Read> LinearFactIndex<R> {
974 fn query_prefix_inner(&self, name: &str, prefix: &[Bytes]) -> Result<FactMap, StorageError> {
975 let mut matches = BTreeMap::new();
976 let mut prior = Some(&self.repr);
977 let mut slot; while let Some(facts) = prior {
979 if let Some(map) = facts.facts.get(name) {
980 for (k, v) in find_prefixes(map, prefix) {
981 if !matches.contains_key(k) {
983 matches.insert(k.clone(), v.map(Into::into));
984 }
985 }
986 }
987 slot = facts.prior.map(|p| self.reader.fetch(p)).transpose()?;
988 prior = slot.as_ref();
989 }
990 Ok(matches)
991 }
992}
993
994impl<R> LinearFactPerspective<R> {
995 fn clear(&mut self) {
996 self.map.clear();
997 }
998
999 fn apply_updates(&mut self, updates: &[Update]) -> Result<(), StorageError> {
1000 for (name, keys, value) in updates {
1001 if self.prior.is_none() {
1002 if let Some(value) = value {
1003 self.map
1004 .entry(name.clone())
1005 .or_default()
1006 .insert(keys.clone(), Some(value.clone()));
1007 } else if let Some(e) = self.map.get_mut(name) {
1008 e.remove(keys);
1009 }
1010 } else {
1011 self.map
1012 .entry(name.clone())
1013 .or_default()
1014 .insert(keys.clone(), value.clone());
1015 }
1016 }
1017 Ok(())
1018 }
1019}
1020
1021impl<R: Read> FactPerspective for LinearFactPerspective<R> {}
1022
1023impl<R: Read> Query for LinearFactPerspective<R> {
1024 fn query(&self, name: &str, keys: &[Bytes]) -> Result<Option<Bytes>, StorageError> {
1025 if let Some(wrapped) = self.map.get(name).and_then(|m| m.get(keys)) {
1026 return Ok(wrapped.as_deref().map(Bytes::from));
1027 }
1028 match &self.prior {
1029 FactPerspectivePrior::None => Ok(None),
1030 FactPerspectivePrior::FactPerspective(prior) => prior.query(name, keys),
1031 FactPerspectivePrior::FactIndex { offset, reader } => {
1032 let repr: FactIndexRepr = reader.fetch(*offset)?;
1033 let prior = LinearFactIndex {
1034 repr,
1035 reader: reader.clone(),
1036 };
1037 prior.query(name, keys)
1038 }
1039 }
1040 }
1041
1042 type QueryIterator = QueryIterator;
1043 fn query_prefix(&self, name: &str, prefix: &[Bytes]) -> Result<QueryIterator, StorageError> {
1044 Ok(QueryIterator::new(
1045 self.query_prefix_inner(name, prefix)?.into_iter(),
1046 ))
1047 }
1048}
1049
1050impl<R: Read> LinearFactPerspective<R> {
1051 fn query_prefix_inner(&self, name: &str, prefix: &[Bytes]) -> Result<FactMap, StorageError> {
1052 let mut matches = match &self.prior {
1053 FactPerspectivePrior::None => BTreeMap::new(),
1054 FactPerspectivePrior::FactPerspective(prior) => {
1055 prior.query_prefix_inner(name, prefix)?
1056 }
1057 FactPerspectivePrior::FactIndex { offset, reader } => {
1058 let repr: FactIndexRepr = reader.fetch(*offset)?;
1059 let prior = LinearFactIndex {
1060 repr,
1061 reader: reader.clone(),
1062 };
1063 prior.query_prefix_inner(name, prefix)?
1064 }
1065 };
1066 if let Some(map) = self.map.get(name) {
1067 for (k, v) in find_prefixes(map, prefix) {
1068 matches.insert(k.clone(), v.map(Into::into));
1070 }
1071 }
1072 Ok(matches)
1073 }
1074}
1075
1076impl<R: Read> QueryMut for LinearFactPerspective<R> {
1077 fn insert(&mut self, name: String, keys: Keys, value: Bytes) -> Result<(), StorageError> {
1078 self.map.entry(name).or_default().insert(keys, Some(value));
1079 Ok(())
1080 }
1081
1082 fn delete(&mut self, name: String, keys: Keys) -> Result<(), StorageError> {
1083 if self.prior.is_none() {
1084 if let Some(kv) = self.map.get_mut(&name) {
1086 kv.remove(&keys);
1087 }
1088 } else {
1089 self.map.entry(name).or_default().insert(keys, None);
1090 }
1091 Ok(())
1092 }
1093}
1094
1095impl<R: Read> FactPerspective for LinearPerspective<R> {}
1096
1097impl<R: Read> Query for LinearPerspective<R> {
1098 fn query(&self, name: &str, keys: &[Bytes]) -> Result<Option<Bytes>, StorageError> {
1099 self.facts.query(name, keys)
1100 }
1101
1102 type QueryIterator = QueryIterator;
1103 fn query_prefix(&self, name: &str, prefix: &[Bytes]) -> Result<QueryIterator, StorageError> {
1104 self.facts.query_prefix(name, prefix)
1105 }
1106}
1107
1108impl<R: Read> QueryMut for LinearPerspective<R> {
1109 fn insert(&mut self, name: String, keys: Keys, value: Bytes) -> Result<(), StorageError> {
1110 self.facts
1111 .insert(name.clone(), keys.clone(), value.clone())?;
1112 self.current_updates.push((name, keys, Some(value)));
1113 Ok(())
1114 }
1115
1116 fn delete(&mut self, name: String, keys: Keys) -> Result<(), StorageError> {
1117 self.facts.delete(name.clone(), keys.clone())?;
1118 self.current_updates.push((name, keys, None));
1119 Ok(())
1120 }
1121}
1122
1123impl<R: Read> Revertable for LinearPerspective<R> {
1124 fn checkpoint(&self) -> Checkpoint {
1125 Checkpoint {
1126 index: self.commands.len(),
1127 }
1128 }
1129
1130 fn revert(&mut self, checkpoint: Checkpoint) -> Result<(), StorageError> {
1131 if checkpoint.index == self.commands.len() && self.current_updates.is_empty() {
1138 return Ok(());
1139 }
1140
1141 if checkpoint.index > self.commands.len() {
1142 bug!(
1143 "A checkpoint's index should always be less than or equal to the length of a perspective's command history!"
1144 );
1145 }
1146
1147 self.commands.truncate(checkpoint.index);
1148 self.facts.clear();
1149 self.current_updates.clear();
1150 for data in &self.commands {
1151 self.facts.apply_updates(&data.updates)?;
1152 }
1153
1154 Ok(())
1155 }
1156}
1157
1158impl<R: Read> Perspective for LinearPerspective<R> {
1159 fn policy(&self) -> PolicyId {
1160 self.policy
1161 }
1162
1163 fn add_command(&mut self, command: &impl Command) -> Result<usize, StorageError> {
1164 if command.parent() != self.head_address()? {
1165 return Err(StorageError::PerspectiveHeadMismatch);
1166 }
1167
1168 self.commands.push(CommandData {
1169 id: command.id(),
1170 priority: command.priority(),
1171 policy: command.policy().map(Bytes::from),
1172 data: command.bytes().into(),
1173 updates: core::mem::take(&mut self.current_updates),
1174 });
1175 Ok(self.commands.len())
1176 }
1177
1178 fn includes(&self, id: CmdId) -> bool {
1179 self.commands.iter().any(|cmd| cmd.id == id)
1180 }
1181
1182 fn head_address(&self) -> Result<Prior<Address>, Bug> {
1183 Ok(if let Some(last) = self.commands.last() {
1184 Prior::Single(Address {
1185 id: last.id,
1186 max_cut: self
1187 .max_cut
1188 .checked_add(
1189 self.commands
1190 .len()
1191 .checked_sub(1)
1192 .assume("must not overflow")? as u64,
1193 )
1194 .assume("must not overflow")?,
1195 })
1196 } else {
1197 self.parents
1198 })
1199 }
1200}
1201
1202impl From<Prior<Address>> for Prior<CmdId> {
1203 fn from(p: Prior<Address>) -> Self {
1204 match p {
1205 Prior::None => Self::None,
1206 Prior::Single(l) => Self::Single(l.id),
1207 Prior::Merge(l, r) => Self::Merge(l.id, r.id),
1208 }
1209 }
1210}
1211
1212impl Command for LinearCommand<'_> {
1213 fn priority(&self) -> Priority {
1214 self.priority.clone()
1215 }
1216
1217 fn id(&self) -> CmdId {
1218 *self.id
1219 }
1220
1221 fn parent(&self) -> Prior<Address> {
1222 self.parent
1223 }
1224
1225 fn policy(&self) -> Option<&[u8]> {
1226 self.policy
1227 }
1228
1229 fn bytes(&self) -> &[u8] {
1230 self.data
1231 }
1232}
1233
1234fn find_prefixes<'m, 'p: 'm>(
1235 map: &'m FactMap,
1236 prefix: &'p [Bytes],
1237) -> impl Iterator<Item = (&'m Keys, Option<&'m [u8]>)> + 'm {
1238 map.range::<[Bytes], _>((Bound::Included(prefix), Bound::Unbounded))
1239 .take_while(|(k, _)| k.starts_with(prefix))
1240 .map(|(k, v)| (k, v.as_deref()))
1241}
1242
1243#[cfg(test)]
1244mod test {
1245 use testing::Manager;
1246
1247 use super::*;
1248 use crate::testing::dsl::{StorageBackend, test_suite};
1249
1250 #[test]
1251 fn test_query_prefix() {
1252 let mut provider = LinearStorageProvider::new(Manager::new());
1253 let mut fp = provider.new_perspective(PolicyId::new(0));
1254
1255 let name = "x";
1256
1257 let keys: &[&[&str]] = &[
1258 &["aa", "xy", "123"],
1259 &["aa", "xz", "123"],
1260 &["bb", "ccc"],
1261 &["bc", ""],
1262 ];
1263 let keys: Vec<Keys> = keys
1264 .iter()
1265 .map(|ks| ks.iter().map(|k| Bytes::from(k.as_bytes())).collect())
1266 .collect();
1267
1268 for ks in &keys {
1269 fp.insert(
1270 name.into(),
1271 ks.clone(),
1272 format!("{ks:?}").into_bytes().into(),
1273 )
1274 .unwrap();
1275 }
1276
1277 let prefixes: &[&[&str]] = &[
1278 &["aa", "xy", "12"],
1279 &["aa", "xy"],
1280 &["aa", "xz"],
1281 &["aa", "x"],
1282 &["bb", ""],
1283 &["bb", "ccc"],
1284 &["bc", ""],
1285 ];
1286
1287 for prefix in prefixes {
1288 let prefix: Keys = prefix.iter().map(|k| Bytes::from(k.as_bytes())).collect();
1289 let found: Vec<_> = fp.query_prefix(name, &prefix).unwrap().collect();
1290 let mut expected: Vec<_> = keys.iter().filter(|k| k.starts_with(&prefix)).collect();
1291 expected.sort();
1292 assert_eq!(found.len(), expected.len());
1293 for (a, b) in std::iter::zip(found, expected) {
1294 let a = a.unwrap();
1295 assert_eq!(&a.key, b);
1296 assert_eq!(a.value.as_ref(), format!("{b:?}").as_bytes());
1297 }
1298 }
1299 }
1300
1301 #[test]
1309 fn test_revert_clears_writes_made_after_checkpoint() {
1310 let mut provider = LinearStorageProvider::new(Manager::new());
1311 let mut p = provider.new_perspective(PolicyId::new(0));
1312
1313 let checkpoint = p.checkpoint();
1314 p.insert("x".into(), Keys::default(), Bytes::from(&b"1"[..]))
1315 .unwrap();
1316 p.revert(checkpoint).unwrap();
1317
1318 assert!(
1319 p.query("x", &[]).unwrap().is_none(),
1320 "revert must clear fact writes made after the checkpoint"
1321 );
1322 assert!(
1323 p.current_updates.is_empty(),
1324 "revert must clear pending updates made after the checkpoint"
1325 );
1326 }
1327
1328 struct LinearBackend;
1329 impl StorageBackend for LinearBackend {
1330 type StorageProvider = LinearStorageProvider<Manager>;
1331
1332 fn provider(&mut self, _client_id: u64) -> Self::StorageProvider {
1333 LinearStorageProvider::new(Manager::new())
1334 }
1335 }
1336 test_suite!(|| LinearBackend);
1337}