zeppelin_embed/lifecycle/
durability.rs1use crate::vfs::SyncKind;
4
5#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
20pub enum DurabilityMode {
21 #[default]
24 Derived,
25 Durable,
27 Attached,
29}
30
31#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
38pub enum CommitTier {
39 None,
42 #[default]
49 Ordered,
50 Durable,
54}
55
56#[derive(Clone, Copy, Debug, Eq, PartialEq)]
58pub enum SyncRequirement {
59 Skip,
61 Sync(SyncKind),
63}
64
65#[derive(Clone, Copy, Debug, Eq, PartialEq)]
70pub struct DurabilityPolicy {
71 data_file: SyncRequirement,
72 directory: SyncRequirement,
73}
74
75impl DurabilityPolicy {
76 pub const fn new(
78 mode: DurabilityMode,
79 tier: CommitTier,
80 ) -> Result<Self, DurabilityPolicyError> {
81 let requirement = match (mode, tier) {
82 (DurabilityMode::Attached, _) => {
83 return Err(DurabilityPolicyError::AttachedNotYetSupported);
84 }
85 (DurabilityMode::Derived, _) | (DurabilityMode::Durable, CommitTier::None) => {
86 SyncRequirement::Skip
87 }
88 (DurabilityMode::Durable, CommitTier::Ordered) => {
89 SyncRequirement::Sync(SyncKind::Barrier)
90 }
91 (DurabilityMode::Durable, CommitTier::Durable) => SyncRequirement::Sync(SyncKind::Full),
92 };
93 Ok(Self {
94 data_file: requirement,
95 directory: requirement,
96 })
97 }
98
99 #[must_use]
101 pub const fn data_file_sync(self) -> SyncRequirement {
102 self.data_file
103 }
104
105 #[must_use]
107 pub const fn directory_sync(self) -> SyncRequirement {
108 self.directory
109 }
110}
111
112#[derive(Clone, Copy, Debug, Eq, PartialEq)]
114pub enum DurabilityPolicyError {
115 AttachedNotYetSupported,
117}
118
119impl std::fmt::Display for DurabilityPolicyError {
120 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
121 match self {
122 Self::AttachedNotYetSupported => {
123 formatter.write_str("attached durability mode is not yet supported")
124 }
125 }
126 }
127}
128
129impl std::error::Error for DurabilityPolicyError {}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 #[allow(clippy::expect_used)]
137 fn default_policy_skips_every_synchronization() {
138 let policy = DurabilityPolicy::new(DurabilityMode::default(), CommitTier::default())
139 .expect("default policy");
140
141 assert_eq!(policy.data_file_sync(), SyncRequirement::Skip);
142 assert_eq!(policy.directory_sync(), SyncRequirement::Skip);
143 }
144
145 #[test]
146 #[allow(clippy::expect_used)]
147 fn derived_and_durable_none_resolve_to_the_same_policy() {
148 let durable_none = DurabilityPolicy::new(DurabilityMode::Durable, CommitTier::None)
149 .expect("durable none policy");
150
151 for tier in [CommitTier::None, CommitTier::Ordered, CommitTier::Durable] {
152 let derived =
153 DurabilityPolicy::new(DurabilityMode::Derived, tier).expect("derived policy");
154 assert_eq!(
155 derived, durable_none,
156 "Derived with {tier:?} must match Durable with None"
157 );
158 }
159 }
160
161 #[test]
162 #[allow(clippy::expect_used)]
163 fn maps_every_mode_and_tier_without_attached_fallback() {
164 let cases = [
165 (
166 DurabilityMode::Derived,
167 CommitTier::None,
168 SyncRequirement::Skip,
169 ),
170 (
171 DurabilityMode::Derived,
172 CommitTier::Ordered,
173 SyncRequirement::Skip,
174 ),
175 (
176 DurabilityMode::Derived,
177 CommitTier::Durable,
178 SyncRequirement::Skip,
179 ),
180 (
181 DurabilityMode::Durable,
182 CommitTier::None,
183 SyncRequirement::Skip,
184 ),
185 (
186 DurabilityMode::Durable,
187 CommitTier::Ordered,
188 SyncRequirement::Sync(SyncKind::Barrier),
189 ),
190 (
191 DurabilityMode::Durable,
192 CommitTier::Durable,
193 SyncRequirement::Sync(SyncKind::Full),
194 ),
195 ];
196 for (mode, tier, expected) in cases {
197 let policy = DurabilityPolicy::new(mode, tier).expect("supported policy");
198 assert_eq!(
199 (policy.data_file_sync(), policy.directory_sync()),
200 (expected, expected),
201 "policy mismatch for ({mode:?}, {tier:?})"
202 );
203 }
204 for tier in [CommitTier::None, CommitTier::Ordered, CommitTier::Durable] {
205 let error = DurabilityPolicy::new(DurabilityMode::Attached, tier)
206 .expect_err("Attached must fail rather than fall back");
207 assert_eq!(error, DurabilityPolicyError::AttachedNotYetSupported);
208 assert_eq!(
209 error.to_string(),
210 "attached durability mode is not yet supported"
211 );
212 }
213 assert_eq!(DurabilityMode::default(), DurabilityMode::Derived);
214 assert_eq!(CommitTier::default(), CommitTier::Ordered);
215 }
216}