Line data Source code
1 : //!
2 : //! Helper functions for dealing with filenames of the image and delta layer files.
3 : //!
4 : use crate::repository::Key;
5 : use std::cmp::Ordering;
6 : use std::fmt;
7 : use std::ops::Range;
8 : use std::str::FromStr;
9 :
10 : use utils::lsn::Lsn;
11 :
12 : use super::PersistentLayerDesc;
13 :
14 : // Note: Timeline::load_layer_map() relies on this sort order
15 592901 : #[derive(PartialEq, Eq, Clone, Hash)]
16 : pub struct DeltaFileName {
17 : pub key_range: Range<Key>,
18 : pub lsn_range: Range<Lsn>,
19 : }
20 :
21 : impl std::fmt::Debug for DeltaFileName {
22 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 0 : use super::RangeDisplayDebug;
24 0 :
25 0 : f.debug_struct("DeltaFileName")
26 0 : .field("key_range", &RangeDisplayDebug(&self.key_range))
27 0 : .field("lsn_range", &self.lsn_range)
28 0 : .finish()
29 0 : }
30 : }
31 :
32 : impl PartialOrd for DeltaFileName {
33 0 : fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
34 0 : Some(self.cmp(other))
35 0 : }
36 : }
37 :
38 : impl Ord for DeltaFileName {
39 0 : fn cmp(&self, other: &Self) -> Ordering {
40 0 : let mut cmp = self.key_range.start.cmp(&other.key_range.start);
41 0 : if cmp != Ordering::Equal {
42 0 : return cmp;
43 0 : }
44 0 : cmp = self.key_range.end.cmp(&other.key_range.end);
45 0 : if cmp != Ordering::Equal {
46 0 : return cmp;
47 0 : }
48 0 : cmp = self.lsn_range.start.cmp(&other.lsn_range.start);
49 0 : if cmp != Ordering::Equal {
50 0 : return cmp;
51 0 : }
52 0 : cmp = self.lsn_range.end.cmp(&other.lsn_range.end);
53 0 :
54 0 : cmp
55 0 : }
56 : }
57 :
58 : /// Represents the filename of a DeltaLayer
59 : ///
60 : /// ```text
61 : /// <key start>-<key end>__<LSN start>-<LSN end>
62 : /// ```
63 : impl DeltaFileName {
64 : ///
65 : /// Parse a string as a delta file name. Returns None if the filename does not
66 : /// match the expected pattern.
67 : ///
68 73609 : pub fn parse_str(fname: &str) -> Option<Self> {
69 73609 : let mut parts = fname.split("__");
70 73609 : let mut key_parts = parts.next()?.split('-');
71 73609 : let mut lsn_parts = parts.next()?.split('-');
72 :
73 73150 : let key_start_str = key_parts.next()?;
74 73150 : let key_end_str = key_parts.next()?;
75 73150 : let lsn_start_str = lsn_parts.next()?;
76 73150 : let lsn_end_str = lsn_parts.next()?;
77 28079 : if parts.next().is_some() || key_parts.next().is_some() || key_parts.next().is_some() {
78 1 : return None;
79 28078 : }
80 :
81 28078 : let key_start = Key::from_hex(key_start_str).ok()?;
82 28078 : let key_end = Key::from_hex(key_end_str).ok()?;
83 :
84 28078 : let start_lsn = Lsn::from_hex(lsn_start_str).ok()?;
85 28078 : let end_lsn = Lsn::from_hex(lsn_end_str).ok()?;
86 :
87 28078 : if start_lsn >= end_lsn {
88 0 : return None;
89 : // or panic?
90 28078 : }
91 28078 :
92 28078 : if key_start >= key_end {
93 0 : return None;
94 : // or panic?
95 28078 : }
96 28078 :
97 28078 : Some(DeltaFileName {
98 28078 : key_range: key_start..key_end,
99 28078 : lsn_range: start_lsn..end_lsn,
100 28078 : })
101 73609 : }
102 : }
103 :
104 : impl fmt::Display for DeltaFileName {
105 920249 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 920249 : write!(
107 920249 : f,
108 920249 : "{}-{}__{:016X}-{:016X}",
109 920249 : self.key_range.start,
110 920249 : self.key_range.end,
111 920249 : u64::from(self.lsn_range.start),
112 920249 : u64::from(self.lsn_range.end),
113 920249 : )
114 920249 : }
115 : }
116 :
117 489588 : #[derive(PartialEq, Eq, Clone, Hash)]
118 : pub struct ImageFileName {
119 : pub key_range: Range<Key>,
120 : pub lsn: Lsn,
121 : }
122 :
123 : impl std::fmt::Debug for ImageFileName {
124 0 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 0 : use super::RangeDisplayDebug;
126 0 :
127 0 : f.debug_struct("ImageFileName")
128 0 : .field("key_range", &RangeDisplayDebug(&self.key_range))
129 0 : .field("lsn", &self.lsn)
130 0 : .finish()
131 0 : }
132 : }
133 :
134 : impl PartialOrd for ImageFileName {
135 0 : fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
136 0 : Some(self.cmp(other))
137 0 : }
138 : }
139 :
140 : impl Ord for ImageFileName {
141 0 : fn cmp(&self, other: &Self) -> Ordering {
142 0 : let mut cmp = self.key_range.start.cmp(&other.key_range.start);
143 0 : if cmp != Ordering::Equal {
144 0 : return cmp;
145 0 : }
146 0 : cmp = self.key_range.end.cmp(&other.key_range.end);
147 0 : if cmp != Ordering::Equal {
148 0 : return cmp;
149 0 : }
150 0 : cmp = self.lsn.cmp(&other.lsn);
151 0 :
152 0 : cmp
153 0 : }
154 : }
155 :
156 : impl ImageFileName {
157 0 : pub fn lsn_as_range(&self) -> Range<Lsn> {
158 0 : // Saves from having to copypaste this all over
159 0 : PersistentLayerDesc::image_layer_lsn_range(self.lsn)
160 0 : }
161 : }
162 :
163 : ///
164 : /// Represents the filename of an ImageLayer
165 : ///
166 : /// ```text
167 : /// <key start>-<key end>__<LSN>
168 : /// ```
169 : impl ImageFileName {
170 : ///
171 : /// Parse a string as an image file name. Returns None if the filename does not
172 : /// match the expected pattern.
173 : ///
174 73609 : pub fn parse_str(fname: &str) -> Option<Self> {
175 73609 : let mut parts = fname.split("__");
176 73609 : let mut key_parts = parts.next()?.split('-');
177 :
178 73609 : let key_start_str = key_parts.next()?;
179 73609 : let key_end_str = key_parts.next()?;
180 73197 : let lsn_str = parts.next()?;
181 73150 : if parts.next().is_some() || key_parts.next().is_some() {
182 1 : return None;
183 73149 : }
184 :
185 73149 : let key_start = Key::from_hex(key_start_str).ok()?;
186 73149 : let key_end = Key::from_hex(key_end_str).ok()?;
187 :
188 73149 : let lsn = Lsn::from_hex(lsn_str).ok()?;
189 :
190 45068 : Some(ImageFileName {
191 45068 : key_range: key_start..key_end,
192 45068 : lsn,
193 45068 : })
194 73609 : }
195 : }
196 :
197 : impl fmt::Display for ImageFileName {
198 681612 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 681612 : write!(
200 681612 : f,
201 681612 : "{}-{}__{:016X}",
202 681612 : self.key_range.start,
203 681612 : self.key_range.end,
204 681612 : u64::from(self.lsn),
205 681612 : )
206 681612 : }
207 : }
208 1082489 : #[derive(Debug, PartialEq, Eq, Hash, Clone)]
209 : pub enum LayerFileName {
210 : Image(ImageFileName),
211 : Delta(DeltaFileName),
212 : }
213 :
214 : impl LayerFileName {
215 834135 : pub fn file_name(&self) -> String {
216 834135 : self.to_string()
217 834135 : }
218 :
219 : /// Determines if this layer file is considered to be in future meaning we will discard these
220 : /// layers during timeline initialization from the given disk_consistent_lsn.
221 667980 : pub(crate) fn is_in_future(&self, disk_consistent_lsn: Lsn) -> bool {
222 : use LayerFileName::*;
223 393380 : match self {
224 274600 : Image(file_name) if file_name.lsn > disk_consistent_lsn => true,
225 393380 : Delta(file_name) if file_name.lsn_range.end > disk_consistent_lsn + 1 => true,
226 667964 : _ => false,
227 : }
228 667980 : }
229 :
230 636 : pub(crate) fn kind(&self) -> &'static str {
231 636 : use LayerFileName::*;
232 636 : match self {
233 636 : Delta(_) => "delta",
234 0 : Image(_) => "image",
235 : }
236 636 : }
237 : }
238 :
239 : impl fmt::Display for LayerFileName {
240 975859 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 975859 : match self {
242 431670 : Self::Image(fname) => write!(f, "{fname}"),
243 544189 : Self::Delta(fname) => write!(f, "{fname}"),
244 : }
245 975859 : }
246 : }
247 :
248 : impl From<ImageFileName> for LayerFileName {
249 429439 : fn from(fname: ImageFileName) -> Self {
250 429439 : Self::Image(fname)
251 429439 : }
252 : }
253 : impl From<DeltaFileName> for LayerFileName {
254 556889 : fn from(fname: DeltaFileName) -> Self {
255 556889 : Self::Delta(fname)
256 556889 : }
257 : }
258 :
259 : impl FromStr for LayerFileName {
260 : type Err = String;
261 :
262 73609 : fn from_str(value: &str) -> Result<Self, Self::Err> {
263 73609 : let delta = DeltaFileName::parse_str(value);
264 73609 : let image = ImageFileName::parse_str(value);
265 73609 : let ok = match (delta, image) {
266 : (None, None) => {
267 463 : return Err(format!(
268 463 : "neither delta nor image layer file name: {value:?}"
269 463 : ))
270 : }
271 28078 : (Some(delta), None) => Self::Delta(delta),
272 45068 : (None, Some(image)) => Self::Image(image),
273 0 : (Some(_), Some(_)) => unreachable!(),
274 : };
275 73146 : Ok(ok)
276 73609 : }
277 : }
278 :
279 : impl serde::Serialize for LayerFileName {
280 619973 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
281 619973 : where
282 619973 : S: serde::Serializer,
283 619973 : {
284 619973 : match self {
285 243913 : Self::Image(fname) => serializer.collect_str(fname),
286 376060 : Self::Delta(fname) => serializer.collect_str(fname),
287 : }
288 619973 : }
289 : }
290 :
291 : impl<'de> serde::Deserialize<'de> for LayerFileName {
292 59734 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
293 59734 : where
294 59734 : D: serde::Deserializer<'de>,
295 59734 : {
296 59734 : deserializer.deserialize_string(LayerFileNameVisitor)
297 59734 : }
298 : }
299 :
300 : struct LayerFileNameVisitor;
301 :
302 : impl<'de> serde::de::Visitor<'de> for LayerFileNameVisitor {
303 : type Value = LayerFileName;
304 :
305 0 : fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
306 0 : write!(
307 0 : formatter,
308 0 : "a string that is a valid image or delta layer file name"
309 0 : )
310 0 : }
311 59734 : fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
312 59734 : where
313 59734 : E: serde::de::Error,
314 59734 : {
315 59734 : v.parse().map_err(|e| E::custom(e))
316 59734 : }
317 : }
|