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 575368 : #[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 69460 : pub fn parse_str(fname: &str) -> Option<Self> {
69 69460 : let mut parts = fname.split("__");
70 69460 : let mut key_parts = parts.next()?.split('-');
71 69460 : let mut lsn_parts = parts.next()?.split('-');
72 :
73 68976 : let key_start_str = key_parts.next()?;
74 68976 : let key_end_str = key_parts.next()?;
75 68976 : let lsn_start_str = lsn_parts.next()?;
76 68976 : let lsn_end_str = lsn_parts.next()?;
77 27707 : if parts.next().is_some() || key_parts.next().is_some() || key_parts.next().is_some() {
78 1 : return None;
79 27706 : }
80 :
81 27706 : let key_start = Key::from_hex(key_start_str).ok()?;
82 27706 : let key_end = Key::from_hex(key_end_str).ok()?;
83 :
84 27706 : let start_lsn = Lsn::from_hex(lsn_start_str).ok()?;
85 27706 : let end_lsn = Lsn::from_hex(lsn_end_str).ok()?;
86 :
87 27706 : if start_lsn >= end_lsn {
88 0 : return None;
89 : // or panic?
90 27706 : }
91 27706 :
92 27706 : if key_start >= key_end {
93 0 : return None;
94 : // or panic?
95 27706 : }
96 27706 :
97 27706 : Some(DeltaFileName {
98 27706 : key_range: key_start..key_end,
99 27706 : lsn_range: start_lsn..end_lsn,
100 27706 : })
101 69460 : }
102 : }
103 :
104 : impl fmt::Display for DeltaFileName {
105 900395 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 900395 : write!(
107 900395 : f,
108 900395 : "{}-{}__{:016X}-{:016X}",
109 900395 : self.key_range.start,
110 900395 : self.key_range.end,
111 900395 : u64::from(self.lsn_range.start),
112 900395 : u64::from(self.lsn_range.end),
113 900395 : )
114 900395 : }
115 : }
116 :
117 465950 : #[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 69460 : pub fn parse_str(fname: &str) -> Option<Self> {
175 69460 : let mut parts = fname.split("__");
176 69460 : let mut key_parts = parts.next()?.split('-');
177 :
178 69460 : let key_start_str = key_parts.next()?;
179 69460 : let key_end_str = key_parts.next()?;
180 69027 : let lsn_str = parts.next()?;
181 68976 : if parts.next().is_some() || key_parts.next().is_some() {
182 1 : return None;
183 68975 : }
184 :
185 68975 : let key_start = Key::from_hex(key_start_str).ok()?;
186 68975 : let key_end = Key::from_hex(key_end_str).ok()?;
187 :
188 68975 : let lsn = Lsn::from_hex(lsn_str).ok()?;
189 :
190 41269 : Some(ImageFileName {
191 41269 : key_range: key_start..key_end,
192 41269 : lsn,
193 41269 : })
194 69460 : }
195 : }
196 :
197 : impl fmt::Display for ImageFileName {
198 664606 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 664606 : write!(
200 664606 : f,
201 664606 : "{}-{}__{:016X}",
202 664606 : self.key_range.start,
203 664606 : self.key_range.end,
204 664606 : u64::from(self.lsn),
205 664606 : )
206 664606 : }
207 : }
208 1041318 : #[derive(Debug, PartialEq, Eq, Hash, Clone)]
209 : pub enum LayerFileName {
210 : Image(ImageFileName),
211 : Delta(DeltaFileName),
212 : }
213 :
214 : impl LayerFileName {
215 818813 : pub fn file_name(&self) -> String {
216 818813 : self.to_string()
217 818813 : }
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 646415 : pub(crate) fn is_in_future(&self, disk_consistent_lsn: Lsn) -> bool {
222 : use LayerFileName::*;
223 378977 : match self {
224 267438 : Image(file_name) if file_name.lsn > disk_consistent_lsn => true,
225 378977 : Delta(file_name) if file_name.lsn_range.end > disk_consistent_lsn + 1 => true,
226 646402 : _ => false,
227 : }
228 646415 : }
229 :
230 392 : pub(crate) fn kind(&self) -> &'static str {
231 392 : use LayerFileName::*;
232 392 : match self {
233 391 : Delta(_) => "delta",
234 1 : Image(_) => "image",
235 : }
236 392 : }
237 : }
238 :
239 : impl fmt::Display for LayerFileName {
240 956979 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241 956979 : match self {
242 418797 : Self::Image(fname) => write!(f, "{fname}"),
243 538182 : Self::Delta(fname) => write!(f, "{fname}"),
244 : }
245 956979 : }
246 : }
247 :
248 : impl From<ImageFileName> for LayerFileName {
249 415711 : fn from(fname: ImageFileName) -> Self {
250 415711 : Self::Image(fname)
251 415711 : }
252 : }
253 : impl From<DeltaFileName> for LayerFileName {
254 549814 : fn from(fname: DeltaFileName) -> Self {
255 549814 : Self::Delta(fname)
256 549814 : }
257 : }
258 :
259 : impl FromStr for LayerFileName {
260 : type Err = String;
261 :
262 69460 : fn from_str(value: &str) -> Result<Self, Self::Err> {
263 69460 : let delta = DeltaFileName::parse_str(value);
264 69460 : let image = ImageFileName::parse_str(value);
265 69460 : let ok = match (delta, image) {
266 : (None, None) => {
267 485 : return Err(format!(
268 485 : "neither delta nor image layer file name: {value:?}"
269 485 : ))
270 : }
271 27706 : (Some(delta), None) => Self::Delta(delta),
272 41269 : (None, Some(image)) => Self::Image(image),
273 0 : (Some(_), Some(_)) => unreachable!(),
274 : };
275 68975 : Ok(ok)
276 69460 : }
277 : }
278 :
279 : impl serde::Serialize for LayerFileName {
280 601550 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
281 601550 : where
282 601550 : S: serde::Serializer,
283 601550 : {
284 601550 : match self {
285 239337 : Self::Image(fname) => serializer.collect_str(fname),
286 362213 : Self::Delta(fname) => serializer.collect_str(fname),
287 : }
288 601550 : }
289 : }
290 :
291 : impl<'de> serde::Deserialize<'de> for LayerFileName {
292 56090 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
293 56090 : where
294 56090 : D: serde::Deserializer<'de>,
295 56090 : {
296 56090 : deserializer.deserialize_string(LayerFileNameVisitor)
297 56090 : }
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 56090 : fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
312 56090 : where
313 56090 : E: serde::de::Error,
314 56090 : {
315 56090 : v.parse().map_err(|e| E::custom(e))
316 56090 : }
317 : }
|