LCOV - code coverage report
Current view: top level - libs/utils/src - generation.rs (source / functions) Coverage Total Hit
Test: 8ac049b474321fdc72ddcb56d7165153a1a900e8.info Lines: 74.4 % 39 29
Test Date: 2023-09-06 10:18:01 Functions: 56.2 % 16 9

            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       370721 : #[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         7029 :     pub fn none() -> Self {
      40         7029 :         Self::None
      41         7029 :     }
      42              : 
      43              :     // Create a new generation that will panic if you try to use get_suffix
      44            0 :     pub fn broken() -> Self {
      45            0 :         Self::Broken
      46            0 :     }
      47              : 
      48           36 :     pub fn new(v: u32) -> Self {
      49           36 :         Self::Valid(v)
      50           36 :     }
      51              : 
      52       690380 :     pub fn is_none(&self) -> bool {
      53       690380 :         matches!(self, Self::None)
      54       690380 :     }
      55              : 
      56        30602 :     pub fn get_suffix(&self) -> String {
      57        30602 :         match self {
      58          657 :             Self::Valid(v) => {
      59          657 :                 format!("-{:08x}", v)
      60              :             }
      61        29945 :             Self::None => "".into(),
      62              :             Self::Broken => {
      63            0 :                 panic!("Tried to use a broken generation");
      64              :             }
      65              :         }
      66        30602 :     }
      67              : }
      68              : 
      69              : impl Serialize for Generation {
      70              :     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
      71              :     where
      72              :         S: serde::Serializer,
      73              :     {
      74         1030 :         if let Self::Valid(v) = self {
      75         1030 :             v.serialize(serializer)
      76              :         } else {
      77              :             // We should never be asked to serialize a None or Broken.  Structures
      78              :             // that include an optional generation should convert None to an
      79              :             // Option<Generation>::None
      80            0 :             Err(serde::ser::Error::custom(
      81            0 :                 "Tried to serialize invalid generation ({self})",
      82            0 :             ))
      83              :         }
      84         1030 :     }
      85              : }
      86              : 
      87              : impl<'de> Deserialize<'de> for Generation {
      88           12 :     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
      89           12 :     where
      90           12 :         D: serde::Deserializer<'de>,
      91           12 :     {
      92           12 :         Ok(Self::Valid(u32::deserialize(deserializer)?))
      93           12 :     }
      94              : }
      95              : 
      96              : // We intentionally do not implement Display for Generation, to reduce the
      97              : // risk of a bug where the generation is used in a format!() string directly
      98              : // instead of using get_suffix().
      99              : impl Debug for Generation {
     100         7712 :     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
     101         7712 :         match self {
     102            0 :             Self::Valid(v) => {
     103            0 :                 write!(f, "{:08x}", v)
     104              :             }
     105              :             Self::None => {
     106         7712 :                 write!(f, "<none>")
     107              :             }
     108              :             Self::Broken => {
     109            0 :                 write!(f, "<broken>")
     110              :             }
     111              :         }
     112         7712 :     }
     113              : }
        

Generated by: LCOV version 2.1-beta