graft_client/runtime/storage/
snapshot.rs1#![allow(non_camel_case_types)]
5
6use std::fmt::{Debug, Display};
7
8use culprit::{Culprit, ResultExt};
9use fjall::Slice;
10use graft_core::{lsn::LSN, page_count::PageCount};
11use serde::Serialize;
12use zerocopy::{ByteHash, Immutable, IntoBytes, KnownLayout, TryFromBytes};
13
14use super::{StorageErr, volume_state::VolumeStateTag};
15
16#[derive(KnownLayout, Immutable, TryFromBytes, IntoBytes, Clone, PartialEq, Eq, Serialize)]
19#[repr(u8)]
20pub enum RemoteMapping {
21 Unmapped {
22 #[serde(skip)]
23 _padding: [u8; 23],
24 },
25 Mapped {
26 #[serde(skip)]
27 _padding: [u8; 7],
28
29 local: LSN,
31
32 remote: LSN,
34 },
35}
36
37impl RemoteMapping {
38 #[inline]
39 pub fn new(remote: LSN, local: LSN) -> Self {
40 Self::Mapped { _padding: [0; 7], remote, local }
41 }
42
43 #[inline]
44 pub fn lsn(&self) -> Option<LSN> {
45 match self {
46 Self::Mapped { remote, .. } => Some(*remote),
47 Self::Unmapped { .. } => None,
48 }
49 }
50
51 #[inline]
52 pub fn local(&self) -> Option<LSN> {
53 match self {
54 Self::Mapped { local, .. } => Some(*local),
55 Self::Unmapped { .. } => None,
56 }
57 }
58
59 #[inline]
61 pub fn splat(&self) -> Option<(LSN, LSN)> {
62 match self {
63 Self::Mapped { remote, local, .. } => Some((*remote, *local)),
64 Self::Unmapped { .. } => None,
65 }
66 }
67}
68
69impl Default for RemoteMapping {
70 #[inline]
71 fn default() -> Self {
72 Self::Unmapped { _padding: [0; 23] }
73 }
74}
75
76#[derive(
77 KnownLayout, Immutable, TryFromBytes, IntoBytes, ByteHash, Clone, PartialEq, Eq, Serialize,
78)]
79#[repr(C)]
80pub struct Snapshot {
81 local: LSN,
83 remote: RemoteMapping,
85 pages: PageCount,
87
88 #[serde(skip)]
89 _padding: [u8; 4],
90}
91
92impl Snapshot {
93 #[inline]
94 pub fn new(local: LSN, remote: RemoteMapping, pages: PageCount) -> Self {
95 Self { local, remote, pages, _padding: [0; 4] }
96 }
97
98 #[track_caller]
99 pub(crate) fn try_from_bytes(bytes: &[u8]) -> Result<Self, Culprit<StorageErr>> {
100 Self::try_read_from_bytes(bytes)
101 .or_ctx(|e| StorageErr::CorruptVolumeState(VolumeStateTag::Snapshot, e.into()))
102 }
103
104 #[inline]
106 pub fn local(&self) -> LSN {
107 self.local
108 }
109
110 #[inline]
112 pub fn remote(&self) -> Option<LSN> {
113 self.remote.lsn()
114 }
115
116 #[inline]
118 pub fn remote_local(&self) -> Option<LSN> {
119 self.remote.local()
120 }
121
122 #[inline]
125 pub fn remote_mapping(&self) -> &RemoteMapping {
126 &self.remote
127 }
128
129 #[inline]
130 pub fn pages(&self) -> PageCount {
131 self.pages
132 }
133}
134
135impl Debug for Snapshot {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 Display::fmt(self, f)
138 }
139}
140
141impl Display for Snapshot {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(f, "Snapshot[{};{}]", self.local(), self.pages(),)?;
146 if let Some((r, l)) = self.remote.splat() {
147 write!(f, "[{l}r{r}]")?;
148 }
149 Ok(())
150 }
151}
152
153impl From<Snapshot> for Slice {
154 fn from(snapshot: Snapshot) -> Slice {
155 snapshot.as_bytes().into()
156 }
157}