LCOV - code coverage report
Current view: top level - pageserver/src/tenant/storage_layer - filename.rs (source / functions) Coverage Total Hit
Test: 322b88762cba8ea666f63cda880cccab6936bf37.info Lines: 59.4 % 187 111
Test Date: 2024-02-29 11:57:12 Functions: 57.9 % 38 22

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

Generated by: LCOV version 2.1-beta