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 : }
|