LCOV - differential code coverage report
Current view: top level - libs/utils/src - generation.rs (source / functions) Coverage Total Hit UBC CBC
Current: cd44433dd675caa99df17a61b18949c8387e2242.info Lines: 80.3 % 71 57 14 57
Current Date: 2024-01-09 02:06:09 Functions: 63.6 % 33 21 12 21
Baseline: 66c52a629a0f4a503e193045e0df4c77139e344b.info
Baseline Date: 2024-01-08 15:34:46

           TLA  Line data    Source code
       1                 : use std::fmt::Debug;
       2                 : 
       3                 : use serde::{Deserialize, Serialize};
       4                 : 
       5                 : /// Tenant generations are used to provide split-brain safety and allow
       6                 : /// multiple pageservers to attach the same tenant concurrently.
       7                 : ///
       8                 : /// See docs/rfcs/025-generation-numbers.md for detail on how generation
       9                 : /// numbers are used.
      10 CBC      570334 : #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
      11                 : pub enum Generation {
      12                 :     // Generations with this magic value will not add a suffix to S3 keys, and will not
      13                 :     // be included in persisted index_part.json.  This value is only to be used
      14                 :     // during migration from pre-generation metadata to generation-aware metadata,
      15                 :     // and should eventually go away.
      16                 :     //
      17                 :     // A special Generation is used rather than always wrapping Generation in an Option,
      18                 :     // so that code handling generations doesn't have to be aware of the legacy
      19                 :     // case everywhere it touches a generation.
      20                 :     None,
      21                 :     // Generations with this magic value may never be used to construct S3 keys:
      22                 :     // we will panic if someone tries to.  This is for Tenants in the "Broken" state,
      23                 :     // so that we can satisfy their constructor with a Generation without risking
      24                 :     // a code bug using it in an S3 write (broken tenants should never write)
      25                 :     Broken,
      26                 :     Valid(u32),
      27                 : }
      28                 : 
      29                 : /// The Generation type represents a number associated with a Tenant, which
      30                 : /// increments every time the tenant is attached to a new pageserver, or
      31                 : /// an attached pageserver restarts.
      32                 : ///
      33                 : /// It is included as a suffix in S3 keys, as a protection against split-brain
      34                 : /// scenarios where pageservers might otherwise issue conflicting writes to
      35                 : /// remote storage
      36                 : impl Generation {
      37                 :     /// Create a new Generation that represents a legacy key format with
      38                 :     /// no generation suffix
      39             896 :     pub fn none() -> Self {
      40             896 :         Self::None
      41             896 :     }
      42                 : 
      43                 :     // Create a new generation that will panic if you try to use get_suffix
      44 UBC           0 :     pub fn broken() -> Self {
      45               0 :         Self::Broken
      46               0 :     }
      47                 : 
      48 CBC        1422 :     pub fn new(v: u32) -> Self {
      49            1422 :         Self::Valid(v)
      50            1422 :     }
      51                 : 
      52          982084 :     pub fn is_none(&self) -> bool {
      53          982084 :         matches!(self, Self::None)
      54          982084 :     }
      55                 : 
      56                 :     #[track_caller]
      57           82287 :     pub fn get_suffix(&self) -> String {
      58           82287 :         match self {
      59           80747 :             Self::Valid(v) => {
      60           80747 :                 format!("-{:08x}", v)
      61                 :             }
      62            1540 :             Self::None => "".into(),
      63                 :             Self::Broken => {
      64 UBC           0 :                 panic!("Tried to use a broken generation");
      65                 :             }
      66                 :         }
      67 CBC       82287 :     }
      68                 : 
      69                 :     /// `suffix` is the part after "-" in a key
      70                 :     ///
      71                 :     /// Returns None if parsing was unsuccessful
      72             572 :     pub fn parse_suffix(suffix: &str) -> Option<Generation> {
      73             572 :         u32::from_str_radix(suffix, 16).map(Generation::new).ok()
      74             572 :     }
      75                 : 
      76                 :     #[track_caller]
      77             411 :     pub fn previous(&self) -> Generation {
      78             411 :         match self {
      79             411 :             Self::Valid(n) => {
      80             411 :                 if *n == 0 {
      81                 :                     // Since a tenant may be upgraded from a pre-generations state, interpret the "previous" generation
      82                 :                     // to 0 as being "no generation".
      83 UBC           0 :                     Self::None
      84                 :                 } else {
      85 CBC         411 :                     Self::Valid(n - 1)
      86                 :                 }
      87                 :             }
      88 UBC           0 :             Self::None => Self::None,
      89               0 :             Self::Broken => panic!("Attempted to use a broken generation"),
      90                 :         }
      91 CBC         411 :     }
      92                 : 
      93               1 :     pub fn next(&self) -> Generation {
      94               1 :         match self {
      95               1 :             Self::Valid(n) => Self::Valid(*n + 1),
      96 UBC           0 :             Self::None => Self::Valid(1),
      97               0 :             Self::Broken => panic!("Attempted to use a broken generation"),
      98                 :         }
      99 CBC           1 :     }
     100                 : 
     101             514 :     pub fn into(self) -> Option<u32> {
     102             514 :         if let Self::Valid(v) = self {
     103             514 :             Some(v)
     104                 :         } else {
     105 UBC           0 :             None
     106                 :         }
     107 CBC         514 :     }
     108                 : }
     109                 : 
     110                 : impl Serialize for Generation {
     111          475517 :     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     112          475517 :     where
     113          475517 :         S: serde::Serializer,
     114          475517 :     {
     115          475517 :         if let Self::Valid(v) = self {
     116          475517 :             v.serialize(serializer)
     117                 :         } else {
     118                 :             // We should never be asked to serialize a None or Broken.  Structures
     119                 :             // that include an optional generation should convert None to an
     120                 :             // Option<Generation>::None
     121 UBC           0 :             Err(serde::ser::Error::custom(
     122               0 :                 "Tried to serialize invalid generation ({self})",
     123               0 :             ))
     124                 :         }
     125 CBC      475517 :     }
     126                 : }
     127                 : 
     128                 : impl<'de> Deserialize<'de> for Generation {
     129           61599 :     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     130           61599 :     where
     131           61599 :         D: serde::Deserializer<'de>,
     132           61599 :     {
     133           61599 :         Ok(Self::Valid(u32::deserialize(deserializer)?))
     134           61599 :     }
     135                 : }
     136                 : 
     137                 : // We intentionally do not implement Display for Generation, to reduce the
     138                 : // risk of a bug where the generation is used in a format!() string directly
     139                 : // instead of using get_suffix().
     140                 : impl Debug for Generation {
     141            5804 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     142            5804 :         match self {
     143            5802 :             Self::Valid(v) => {
     144            5802 :                 write!(f, "{:08x}", v)
     145                 :             }
     146                 :             Self::None => {
     147               2 :                 write!(f, "<none>")
     148                 :             }
     149                 :             Self::Broken => {
     150 UBC           0 :                 write!(f, "<broken>")
     151                 :             }
     152                 :         }
     153 CBC        5804 :     }
     154                 : }
     155                 : 
     156                 : #[cfg(test)]
     157                 : mod test {
     158                 :     use super::*;
     159                 : 
     160               1 :     #[test]
     161               1 :     fn generation_gt() {
     162                 :         // Important that a None generation compares less than a valid one, during upgrades from
     163                 :         // pre-generation systems.
     164               1 :         assert!(Generation::none() < Generation::new(0));
     165               1 :         assert!(Generation::none() < Generation::new(1));
     166               1 :     }
     167                 : }
        

Generated by: LCOV version 2.1-beta