graft_proto/
lib.rs

1// pull in the generated types
2include!("mod.rs");
3
4use std::{error::Error, fmt::Display, ops::RangeBounds, time::SystemTime};
5
6use bytes::Bytes;
7use common::v1::{Commit, GraftErr, LsnRange, SegmentInfo};
8use culprit::{Culprit, ResultExt};
9use graft_core::{
10    PageCount, PageIdx, SegmentId, VolumeId,
11    gid::{ClientId, GidParseErr},
12    lsn::{InvalidLSN, LSN, LSNRangeExt},
13    page::{Page, PageSizeErr},
14    page_idx::ConvertToPageIdxErr,
15};
16use pagestore::v1::PageAtIdx;
17use prost_types::TimestampError;
18
19pub use graft::common::v1::{GraftErrCode, Snapshot};
20pub use graft::*;
21use splinter_rs::{DecodeErr, SplinterRef};
22
23impl Error for GraftErr {}
24impl Display for GraftErr {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        write!(f, "{:?}: {}", self.code(), self.message)
27    }
28}
29
30impl GraftErrCode {
31    pub fn is_client(self) -> bool {
32        let code = self as i32;
33        code >= GraftErrCode::Client as i32 && code < GraftErrCode::Server as i32
34    }
35}
36
37impl Commit {
38    pub fn snapshot(&self) -> &Snapshot {
39        self.snapshot.as_ref().expect("snapshot is required")
40    }
41}
42
43impl SegmentInfo {
44    pub fn new(sid: &SegmentId, graft: Bytes) -> Self {
45        Self { sid: sid.copy_to_bytes(), graft }
46    }
47
48    pub fn sid(&self) -> Result<&SegmentId, Culprit<GidParseErr>> {
49        Ok(self.sid.as_ref().try_into()?)
50    }
51
52    pub fn graft(&self) -> Result<SplinterRef<Bytes>, Culprit<DecodeErr>> {
53        SplinterRef::from_bytes(self.graft.clone())
54    }
55}
56
57impl Snapshot {
58    pub fn new(
59        vid: &VolumeId,
60        cid: &ClientId,
61        lsn: LSN,
62        checkpoint_lsn: LSN,
63        page_count: PageCount,
64        timestamp: SystemTime,
65    ) -> Self {
66        Self {
67            vid: vid.copy_to_bytes(),
68            cid: cid.copy_to_bytes(),
69            lsn: lsn.into(),
70            checkpoint_lsn: checkpoint_lsn.into(),
71            page_count: page_count.into(),
72            timestamp: Some(timestamp.into()),
73        }
74    }
75
76    pub fn vid(&self) -> Result<&VolumeId, Culprit<GidParseErr>> {
77        Ok(self.vid.as_ref().try_into()?)
78    }
79
80    pub fn cid(&self) -> Result<&ClientId, Culprit<GidParseErr>> {
81        Ok(self.cid.as_ref().try_into()?)
82    }
83
84    pub fn lsn(&self) -> Result<LSN, Culprit<InvalidLSN>> {
85        LSN::try_from(self.lsn).or_into_ctx()
86    }
87
88    pub fn checkpoint(&self) -> Result<LSN, Culprit<InvalidLSN>> {
89        LSN::try_from(self.checkpoint_lsn).or_into_ctx()
90    }
91
92    pub fn pages(&self) -> PageCount {
93        self.page_count.into()
94    }
95
96    pub fn system_time(&self) -> Result<Option<SystemTime>, TimestampError> {
97        self.timestamp.map(|ts| ts.try_into()).transpose()
98    }
99}
100
101impl LsnRange {
102    pub fn from_range<T: RangeBounds<LSN>>(range: T) -> Self {
103        let inclusive_start = range.try_start().unwrap_or(LSN::FIRST).into();
104        let inclusive_end = range.try_end().map(|lsn| lsn.into());
105        Self { inclusive_start, inclusive_end }
106    }
107
108    pub fn start(&self) -> Result<LSN, Culprit<InvalidLSN>> {
109        LSN::try_from(self.inclusive_start).or_into_ctx()
110    }
111
112    pub fn end(&self) -> Result<Option<LSN>, Culprit<InvalidLSN>> {
113        match self.inclusive_end {
114            Some(end) => LSN::try_from(end).or_into_ctx().map(Some),
115            None => Ok(None),
116        }
117    }
118}
119
120impl PageAtIdx {
121    pub fn new(pageidx: PageIdx, page: Page) -> Self {
122        Self {
123            pageidx: pageidx.into(),
124            data: page.into(),
125        }
126    }
127
128    #[inline]
129    pub fn pageidx(&self) -> Result<PageIdx, Culprit<ConvertToPageIdxErr>> {
130        PageIdx::try_from(self.pageidx).or_into_ctx()
131    }
132
133    #[inline]
134    pub fn page(&self) -> Result<Page, Culprit<PageSizeErr>> {
135        self.data.clone().try_into()
136    }
137}