LCOV - differential code coverage report
Current view: top level - libs/utils/src - generation.rs (source / functions) Coverage Total Hit UBC CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 77.0 % 61 47 14 47
Current Date: 2023-10-19 02:04:12 Functions: 57.1 % 28 16 12 16
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           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      470495 : #[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
      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            7879 :     pub fn none() -> Self {
      40            7879 :         Self::None
      41            7879 :     }
      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         102 :     pub fn new(v: u32) -> Self {
      49             102 :         Self::Valid(v)
      50             102 :     }
      51                 : 
      52          852207 :     pub fn is_none(&self) -> bool {
      53          852207 :         matches!(self, Self::None)
      54          852207 :     }
      55                 : 
      56                 :     #[track_caller]
      57           46151 :     pub fn get_suffix(&self) -> String {
      58           46151 :         match self {
      59            8125 :             Self::Valid(v) => {
      60            8125 :                 format!("-{:08x}", v)
      61                 :             }
      62           38026 :             Self::None => "".into(),
      63                 :             Self::Broken => {
      64 UBC           0 :                 panic!("Tried to use a broken generation");
      65                 :             }
      66                 :         }
      67 CBC       46151 :     }
      68                 : 
      69                 :     /// `suffix` is the part after "-" in a key
      70                 :     ///
      71                 :     /// Returns None if parsing was unsuccessful
      72              11 :     pub fn parse_suffix(suffix: &str) -> Option<Generation> {
      73              11 :         u32::from_str_radix(suffix, 16).map(Generation::new).ok()
      74              11 :     }
      75                 : 
      76                 :     #[track_caller]
      77              24 :     pub fn previous(&self) -> Generation {
      78              24 :         match self {
      79              24 :             Self::Valid(n) => {
      80              24 :                 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          24 :                     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          24 :     }
      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                 :     pub fn into(self) -> Option<u32> {
     102              10 :         if let Self::Valid(v) = self {
     103              10 :             Some(v)
     104                 :         } else {
     105 UBC           0 :             None
     106                 :         }
     107 CBC          10 :     }
     108                 : }
     109                 : 
     110                 : impl Serialize for Generation {
     111                 :     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     112                 :     where
     113                 :         S: serde::Serializer,
     114                 :     {
     115           28292 :         if let Self::Valid(v) = self {
     116           28292 :             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       28292 :     }
     126                 : }
     127                 : 
     128                 : impl<'de> Deserialize<'de> for Generation {
     129            2060 :     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     130            2060 :     where
     131            2060 :         D: serde::Deserializer<'de>,
     132            2060 :     {
     133            2060 :         Ok(Self::Valid(u32::deserialize(deserializer)?))
     134            2060 :     }
     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            4320 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     142            4320 :         match self {
     143              48 :             Self::Valid(v) => {
     144              48 :                 write!(f, "{:08x}", v)
     145                 :             }
     146                 :             Self::None => {
     147            4272 :                 write!(f, "<none>")
     148                 :             }
     149                 :             Self::Broken => {
     150 UBC           0 :                 write!(f, "<broken>")
     151                 :             }
     152                 :         }
     153 CBC        4320 :     }
     154                 : }
        

Generated by: LCOV version 2.1-beta