graft_kernel/
snapshot.rs

1use std::ops::RangeInclusive;
2
3use graft_core::{
4    VolumeId,
5    lsn::{LSN, LSNRangeExt},
6    volume_ref::VolumeRef,
7};
8use smallvec::SmallVec;
9
10/// A `Snapshot` represents a logical view of a Volume, possibly made
11/// up of LSN ranges from multiple physical Volumes.
12#[derive(Clone, Hash)]
13pub struct Snapshot {
14    path: SmallVec<[VolumeRangeRef; 1]>,
15}
16
17/// A reference to a volume and a range of LSNs within that volume.
18#[derive(Clone, PartialEq, Eq, Hash)]
19pub struct VolumeRangeRef {
20    pub vid: VolumeId,
21    pub lsns: RangeInclusive<LSN>,
22}
23
24impl std::fmt::Debug for VolumeRangeRef {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        write!(f, "{:?}[{}]", self.vid, self.lsns.to_string())
27    }
28}
29
30impl VolumeRangeRef {
31    pub fn start_ref(&self) -> VolumeRef {
32        VolumeRef::new(self.vid.clone(), *self.lsns.start())
33    }
34
35    pub fn end_ref(&self) -> VolumeRef {
36        VolumeRef::new(self.vid.clone(), *self.lsns.end())
37    }
38}
39
40impl Snapshot {
41    pub const EMPTY: Self = Self { path: SmallVec::new_const() };
42
43    pub fn new(vid: VolumeId, lsns: RangeInclusive<LSN>) -> Self {
44        assert!(!lsns.is_empty());
45        Self {
46            path: SmallVec::from_const([VolumeRangeRef { vid, lsns }]),
47        }
48    }
49
50    pub fn head(&self) -> Option<(&VolumeId, LSN)> {
51        self.path
52            .first()
53            .map(|entry| (&entry.vid, *entry.lsns.end()))
54    }
55
56    pub fn is_empty(&self) -> bool {
57        self.path.is_empty()
58    }
59
60    pub fn append(&mut self, vid: VolumeId, lsns: RangeInclusive<LSN>) {
61        assert!(!lsns.is_empty());
62        self.path.push(VolumeRangeRef { vid, lsns });
63    }
64
65    /// iterate through all of the volume range references in the snapshot
66    pub fn iter(&self) -> std::slice::Iter<'_, VolumeRangeRef> {
67        self.path.iter()
68    }
69}
70
71impl IntoIterator for Snapshot {
72    type Item = VolumeRangeRef;
73    type IntoIter = smallvec::IntoIter<[VolumeRangeRef; 1]>;
74    fn into_iter(self) -> Self::IntoIter {
75        self.path.into_iter()
76    }
77}
78
79impl std::fmt::Debug for Snapshot {
80    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
81        f.debug_tuple("Snapshot").field(&self.path).finish()
82    }
83}