1include!("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}