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 296176 : #[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 10574 : pub fn parse_str(fname: &str) -> Option<Self> {
69 10574 : let mut parts = fname.split("__");
70 10574 : let mut key_parts = parts.next()?.split('-');
71 10574 : let mut lsn_parts = parts.next()?.split('-');
72 :
73 10165 : let key_start_str = key_parts.next()?;
74 10165 : let key_end_str = key_parts.next()?;
75 10165 : let lsn_start_str = lsn_parts.next()?;
76 10165 : let lsn_end_str = lsn_parts.next()?;
77 9194 : if parts.next().is_some() || key_parts.next().is_some() || key_parts.next().is_some() {
78 5 : return None;
79 9189 : }
80 :
81 9189 : let key_start = Key::from_hex(key_start_str).ok()?;
82 9189 : let key_end = Key::from_hex(key_end_str).ok()?;
83 :
84 9189 : let start_lsn = Lsn::from_hex(lsn_start_str).ok()?;
85 9189 : let end_lsn = Lsn::from_hex(lsn_end_str).ok()?;
86 :
87 9189 : if start_lsn >= end_lsn {
88 0 : return None;
89 : // or panic?
90 9189 : }
91 9189 :
92 9189 : if key_start >= key_end {
93 0 : return None;
94 : // or panic?
95 9189 : }
96 9189 :
97 9189 : Some(DeltaFileName {
98 9189 : key_range: key_start..key_end,
99 9189 : lsn_range: start_lsn..end_lsn,
100 9189 : })
101 10574 : }
102 : }
103 :
104 : impl fmt::Display for DeltaFileName {
105 354336 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 354336 : write!(
107 354336 : f,
108 354336 : "{}-{}__{:016X}-{:016X}",
109 354336 : self.key_range.start,
110 354336 : self.key_range.end,
111 354336 : u64::from(self.lsn_range.start),
112 354336 : u64::from(self.lsn_range.end),
113 354336 : )
114 354336 : }
115 : }
116 :
117 118669 : #[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 10574 : pub fn parse_str(fname: &str) -> Option<Self> {
175 10574 : let mut parts = fname.split("__");
176 10574 : let mut key_parts = parts.next()?.split('-');
177 :
178 10574 : let key_start_str = key_parts.next()?;
179 10574 : let key_end_str = key_parts.next()?;
180 10248 : let lsn_str = parts.next()?;
181 10165 : if parts.next().is_some() || key_parts.next().is_some() {
182 5 : return None;
183 10160 : }
184 :
185 10160 : let key_start = Key::from_hex(key_start_str).ok()?;
186 10160 : let key_end = Key::from_hex(key_end_str).ok()?;
187 :
188 10160 : let lsn = Lsn::from_hex(lsn_str).ok()?;
189 :
190 971 : Some(ImageFileName {
191 971 : key_range: key_start..key_end,
192 971 : lsn,
193 971 : })
194 10574 : }
195 : }
196 :
197 : impl fmt::Display for ImageFileName {
198 120453 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 120453 : write!(
200 120453 : f,
201 120453 : "{}-{}__{:016X}",
202 120453 : self.key_range.start,
203 120453 : self.key_range.end,
204 120453 : u64::from(self.lsn),
205 120453 : )
206 120453 : }
207 : }
208 414845 : #[derive(Debug, PartialEq, Eq, Hash, Clone)]
209 : pub enum LayerFileName {
210 : Image(ImageFileName),
211 : Delta(DeltaFileName),
212 : }
213 :
214 : impl LayerFileName {
215 37396 : pub fn file_name(&self) -> String {
216 37396 : self.to_string()
217 37396 : }
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 : pub(crate) fn is_in_future(&self, disk_consistent_lsn: Lsn) -> bool {
222 : use LayerFileName::*;
223 236013 : match self {
224 109428 : Image(file_name) if file_name.lsn > disk_consistent_lsn => true,
225 236013 : Delta(file_name) if file_name.lsn_range.end > disk_consistent_lsn + 1 => true,
226 345435 : _ => false,
227 : }
228 345441 : }
229 : }
230 :
231 : impl fmt::Display for LayerFileName {
232 66801 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233 66801 : match self {
234 7003 : Self::Image(fname) => write!(f, "{fname}"),
235 59798 : Self::Delta(fname) => write!(f, "{fname}"),
236 : }
237 66801 : }
238 : }
239 :
240 : impl From<ImageFileName> for LayerFileName {
241 4117 : fn from(fname: ImageFileName) -> Self {
242 4117 : Self::Image(fname)
243 4117 : }
244 : }
245 : impl From<DeltaFileName> for LayerFileName {
246 27736 : fn from(fname: DeltaFileName) -> Self {
247 27736 : Self::Delta(fname)
248 27736 : }
249 : }
250 :
251 : impl FromStr for LayerFileName {
252 : type Err = String;
253 :
254 10574 : fn from_str(value: &str) -> Result<Self, Self::Err> {
255 10574 : let delta = DeltaFileName::parse_str(value);
256 10574 : let image = ImageFileName::parse_str(value);
257 10574 : let ok = match (delta, image) {
258 : (None, None) => {
259 414 : return Err(format!(
260 414 : "neither delta nor image layer file name: {value:?}"
261 414 : ))
262 : }
263 9189 : (Some(delta), None) => Self::Delta(delta),
264 971 : (None, Some(image)) => Self::Image(image),
265 0 : (Some(_), Some(_)) => unreachable!(),
266 : };
267 10160 : Ok(ok)
268 10574 : }
269 : }
270 :
271 : impl serde::Serialize for LayerFileName {
272 345190 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
273 345190 : where
274 345190 : S: serde::Serializer,
275 345190 : {
276 345190 : match self {
277 108464 : Self::Image(fname) => serializer.collect_str(fname),
278 236726 : Self::Delta(fname) => serializer.collect_str(fname),
279 : }
280 345190 : }
281 : }
282 :
283 : impl<'de> serde::Deserialize<'de> for LayerFileName {
284 6294 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
285 6294 : where
286 6294 : D: serde::Deserializer<'de>,
287 6294 : {
288 6294 : deserializer.deserialize_string(LayerFileNameVisitor)
289 6294 : }
290 : }
291 :
292 : struct LayerFileNameVisitor;
293 :
294 : impl<'de> serde::de::Visitor<'de> for LayerFileNameVisitor {
295 : type Value = LayerFileName;
296 :
297 0 : fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
298 0 : write!(
299 0 : formatter,
300 0 : "a string that is a valid image or delta layer file name"
301 0 : )
302 0 : }
303 6294 : fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
304 6294 : where
305 6294 : E: serde::de::Error,
306 6294 : {
307 6294 : v.parse().map_err(|e| E::custom(e))
308 6294 : }
309 : }
|