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