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 679147 : #[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 933 : pub fn none() -> Self {
40 933 : Self::None
41 933 : }
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 3714 : pub fn new(v: u32) -> Self {
49 3714 : Self::Valid(v)
50 3714 : }
51 :
52 1215067 : pub fn is_none(&self) -> bool {
53 1215067 : matches!(self, Self::None)
54 1215067 : }
55 :
56 : #[track_caller]
57 91388 : pub fn get_suffix(&self) -> impl std::fmt::Display {
58 91388 : match self {
59 89663 : Self::Valid(v) => GenerationFileSuffix(Some(*v)),
60 1725 : Self::None => GenerationFileSuffix(None),
61 : Self::Broken => {
62 0 : panic!("Tried to use a broken generation");
63 : }
64 : }
65 91388 : }
66 :
67 : /// `suffix` is the part after "-" in a key
68 : ///
69 : /// Returns None if parsing was unsuccessful
70 645 : pub fn parse_suffix(suffix: &str) -> Option<Generation> {
71 645 : u32::from_str_radix(suffix, 16).map(Generation::new).ok()
72 645 : }
73 :
74 : #[track_caller]
75 470 : pub fn previous(&self) -> Generation {
76 470 : match self {
77 470 : Self::Valid(n) => {
78 470 : if *n == 0 {
79 : // Since a tenant may be upgraded from a pre-generations state, interpret the "previous" generation
80 : // to 0 as being "no generation".
81 0 : Self::None
82 : } else {
83 470 : Self::Valid(n - 1)
84 : }
85 : }
86 0 : Self::None => Self::None,
87 0 : Self::Broken => panic!("Attempted to use a broken generation"),
88 : }
89 470 : }
90 :
91 : #[track_caller]
92 2 : pub fn next(&self) -> Generation {
93 2 : match self {
94 2 : Self::Valid(n) => Self::Valid(*n + 1),
95 0 : Self::None => Self::Valid(1),
96 0 : Self::Broken => panic!("Attempted to use a broken generation"),
97 : }
98 2 : }
99 :
100 4503 : pub fn into(self) -> Option<u32> {
101 4503 : if let Self::Valid(v) = self {
102 4503 : Some(v)
103 : } else {
104 0 : None
105 : }
106 4503 : }
107 : }
108 :
109 : struct GenerationFileSuffix(Option<u32>);
110 :
111 : impl std::fmt::Display for GenerationFileSuffix {
112 91388 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 91388 : if let Some(g) = self.0 {
114 89663 : write!(f, "-{g:08x}")
115 : } else {
116 1725 : Ok(())
117 : }
118 91388 : }
119 : }
120 :
121 : impl Serialize for Generation {
122 591469 : fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
123 591469 : where
124 591469 : S: serde::Serializer,
125 591469 : {
126 591469 : if let Self::Valid(v) = self {
127 591469 : v.serialize(serializer)
128 : } else {
129 : // We should never be asked to serialize a None or Broken. Structures
130 : // that include an optional generation should convert None to an
131 : // Option<Generation>::None
132 0 : Err(serde::ser::Error::custom(
133 0 : "Tried to serialize invalid generation ({self})",
134 0 : ))
135 : }
136 591469 : }
137 : }
138 :
139 : impl<'de> Deserialize<'de> for Generation {
140 55852 : fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
141 55852 : where
142 55852 : D: serde::Deserializer<'de>,
143 55852 : {
144 55852 : Ok(Self::Valid(u32::deserialize(deserializer)?))
145 55852 : }
146 : }
147 :
148 : // We intentionally do not implement Display for Generation, to reduce the
149 : // risk of a bug where the generation is used in a format!() string directly
150 : // instead of using get_suffix().
151 : impl Debug for Generation {
152 29725 : fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 29725 : match self {
154 29160 : Self::Valid(v) => {
155 29160 : write!(f, "{:08x}", v)
156 : }
157 : Self::None => {
158 565 : write!(f, "<none>")
159 : }
160 : Self::Broken => {
161 0 : write!(f, "<broken>")
162 : }
163 : }
164 29725 : }
165 : }
166 :
167 : #[cfg(test)]
168 : mod test {
169 : use super::*;
170 :
171 2 : #[test]
172 2 : fn generation_gt() {
173 2 : // Important that a None generation compares less than a valid one, during upgrades from
174 2 : // pre-generation systems.
175 2 : assert!(Generation::none() < Generation::new(0));
176 2 : assert!(Generation::none() < Generation::new(1));
177 2 : }
178 :
179 2 : #[test]
180 2 : fn suffix_is_stable() {
181 2 : use std::fmt::Write as _;
182 2 :
183 2 : // the suffix must remain stable through-out the pageserver remote storage evolution and
184 2 : // not be changed accidentially without thinking about migration
185 2 : let examples = [
186 2 : (line!(), Generation::None, ""),
187 2 : (line!(), Generation::Valid(0), "-00000000"),
188 2 : (line!(), Generation::Valid(u32::MAX), "-ffffffff"),
189 2 : ];
190 2 :
191 2 : let mut s = String::new();
192 8 : for (line, gen, expected) in examples {
193 6 : s.clear();
194 6 : write!(s, "{}", &gen.get_suffix()).expect("string grows");
195 6 : assert_eq!(s, expected, "example on {line}");
196 : }
197 2 : }
198 : }
|