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