TLA Line data Source code
1 : use std::{fmt, str::FromStr};
2 :
3 : use anyhow::Context;
4 : use hex::FromHex;
5 : use rand::Rng;
6 : use serde::{Deserialize, Serialize};
7 : use thiserror::Error;
8 :
9 UBC 0 : #[derive(Error, Debug)]
10 : pub enum IdError {
11 : #[error("invalid id length {0}")]
12 : SliceParseError(usize),
13 : }
14 :
15 : /// Neon ID is a 128-bit random ID.
16 : /// Used to represent various identifiers. Provides handy utility methods and impls.
17 : ///
18 : /// NOTE: It (de)serializes as an array of hex bytes, so the string representation would look
19 : /// like `[173,80,132,115,129,226,72,254,170,201,135,108,199,26,228,24]`.
20 : ///
21 : /// Use `#[serde_as(as = "DisplayFromStr")]` to (de)serialize it as hex string instead: `ad50847381e248feaac9876cc71ae418`.
22 : /// Check the `serde_with::serde_as` documentation for options for more complex types.
23 CBC 24185423 : #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
24 : struct Id([u8; 16]);
25 :
26 : impl Id {
27 UBC 0 : pub fn get_from_buf(buf: &mut impl bytes::Buf) -> Id {
28 0 : let mut arr = [0u8; 16];
29 0 : buf.copy_to_slice(&mut arr);
30 0 : Id::from(arr)
31 0 : }
32 :
33 CBC 35074 : pub fn from_slice(src: &[u8]) -> Result<Id, IdError> {
34 35074 : if src.len() != 16 {
35 UBC 0 : return Err(IdError::SliceParseError(src.len()));
36 CBC 35074 : }
37 35074 : let mut id_array = [0u8; 16];
38 35074 : id_array.copy_from_slice(src);
39 35074 : Ok(id_array.into())
40 35074 : }
41 :
42 UBC 0 : pub fn as_arr(&self) -> [u8; 16] {
43 0 : self.0
44 0 : }
45 :
46 CBC 982 : pub fn generate() -> Self {
47 982 : let mut tli_buf = [0u8; 16];
48 982 : rand::thread_rng().fill(&mut tli_buf);
49 982 : Id::from(tli_buf)
50 982 : }
51 :
52 5854105 : fn hex_encode(&self) -> String {
53 5854105 : static HEX: &[u8] = b"0123456789abcdef";
54 5854105 :
55 5854105 : let mut buf = vec![0u8; self.0.len() * 2];
56 93665680 : for (&b, chunk) in self.0.as_ref().iter().zip(buf.chunks_exact_mut(2)) {
57 93665680 : chunk[0] = HEX[((b >> 4) & 0xf) as usize];
58 93665680 : chunk[1] = HEX[(b & 0xf) as usize];
59 93665680 : }
60 5854105 : unsafe { String::from_utf8_unchecked(buf) }
61 5854105 : }
62 : }
63 :
64 : impl FromStr for Id {
65 : type Err = hex::FromHexError;
66 :
67 72008 : fn from_str(s: &str) -> Result<Id, Self::Err> {
68 72008 : Self::from_hex(s)
69 72008 : }
70 : }
71 :
72 : // this is needed for pretty serialization and deserialization of Id's using serde integration with hex crate
73 : impl FromHex for Id {
74 : type Error = hex::FromHexError;
75 :
76 72200 : fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
77 72200 : let mut buf: [u8; 16] = [0u8; 16];
78 72200 : hex::decode_to_slice(hex, &mut buf)?;
79 70697 : Ok(Id(buf))
80 72200 : }
81 : }
82 :
83 : impl AsRef<[u8]> for Id {
84 UBC 0 : fn as_ref(&self) -> &[u8] {
85 0 : &self.0
86 0 : }
87 : }
88 :
89 : impl From<[u8; 16]> for Id {
90 CBC 44326 : fn from(b: [u8; 16]) -> Self {
91 44326 : Id(b)
92 44326 : }
93 : }
94 :
95 : impl From<Id> for u128 {
96 223 : fn from(id: Id) -> Self {
97 223 : u128::from_le_bytes(id.0)
98 223 : }
99 : }
100 :
101 : impl fmt::Display for Id {
102 5843381 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 5843381 : f.write_str(&self.hex_encode())
104 5843381 : }
105 : }
106 :
107 : impl fmt::Debug for Id {
108 10724 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 10724 : f.write_str(&self.hex_encode())
110 10724 : }
111 : }
112 :
113 : macro_rules! id_newtype {
114 : ($t:ident) => {
115 : impl $t {
116 UBC 0 : pub fn get_from_buf(buf: &mut impl bytes::Buf) -> $t {
117 0 : $t(Id::get_from_buf(buf))
118 0 : }
119 :
120 CBC 35074 : pub fn from_slice(src: &[u8]) -> Result<$t, IdError> {
121 35074 : Ok($t(Id::from_slice(src)?))
122 35074 : }
123 :
124 UBC 0 : pub fn as_arr(&self) -> [u8; 16] {
125 0 : self.0.as_arr()
126 0 : }
127 :
128 CBC 982 : pub fn generate() -> Self {
129 982 : $t(Id::generate())
130 982 : }
131 :
132 12 : pub const fn from_array(b: [u8; 16]) -> Self {
133 12 : $t(Id(b))
134 12 : }
135 : }
136 :
137 : impl FromStr for $t {
138 : type Err = hex::FromHexError;
139 :
140 72008 : fn from_str(s: &str) -> Result<$t, Self::Err> {
141 72008 : let value = Id::from_str(s)?;
142 70505 : Ok($t(value))
143 72008 : }
144 : }
145 :
146 : impl From<[u8; 16]> for $t {
147 8270 : fn from(b: [u8; 16]) -> Self {
148 8270 : $t(Id::from(b))
149 8270 : }
150 : }
151 :
152 : impl FromHex for $t {
153 : type Error = hex::FromHexError;
154 :
155 192 : fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
156 192 : Ok($t(Id::from_hex(hex)?))
157 192 : }
158 : }
159 :
160 : impl AsRef<[u8]> for $t {
161 26428 : fn as_ref(&self) -> &[u8] {
162 26428 : &self.0 .0
163 26428 : }
164 : }
165 :
166 : impl From<$t> for u128 {
167 223 : fn from(id: $t) -> Self {
168 223 : u128::from(id.0)
169 223 : }
170 : }
171 :
172 : impl fmt::Display for $t {
173 5843381 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 5843381 : self.0.fmt(f)
175 5843381 : }
176 : }
177 :
178 : impl fmt::Debug for $t {
179 10724 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 10724 : self.0.fmt(f)
181 10724 : }
182 : }
183 : };
184 : }
185 :
186 : /// Neon timeline IDs are different from PostgreSQL timeline
187 : /// IDs. They serve a similar purpose though: they differentiate
188 : /// between different "histories" of the same cluster. However,
189 : /// PostgreSQL timeline IDs are a bit cumbersome, because they are only
190 : /// 32-bits wide, and they must be in ascending order in any given
191 : /// timeline history. Those limitations mean that we cannot generate a
192 : /// new PostgreSQL timeline ID by just generating a random number. And
193 : /// that in turn is problematic for the "pull/push" workflow, where you
194 : /// have a local copy of a Neon repository, and you periodically sync
195 : /// the local changes with a remote server. When you work "detached"
196 : /// from the remote server, you cannot create a PostgreSQL timeline ID
197 : /// that's guaranteed to be different from all existing timelines in
198 : /// the remote server. For example, if two people are having a clone of
199 : /// the repository on their laptops, and they both create a new branch
200 : /// with different name. What timeline ID would they assign to their
201 : /// branches? If they pick the same one, and later try to push the
202 : /// branches to the same remote server, they will get mixed up.
203 : ///
204 : /// To avoid those issues, Neon has its own concept of timelines that
205 : /// is separate from PostgreSQL timelines, and doesn't have those
206 : /// limitations. A Neon timeline is identified by a 128-bit ID, which
207 : /// is usually printed out as a hex string.
208 : ///
209 : /// NOTE: It (de)serializes as an array of hex bytes, so the string representation would look
210 : /// like `[173,80,132,115,129,226,72,254,170,201,135,108,199,26,228,24]`.
211 : /// See [`Id`] for alternative ways to serialize it.
212 13006886 : #[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd, Serialize, Deserialize)]
213 : pub struct TimelineId(Id);
214 :
215 : id_newtype!(TimelineId);
216 :
217 : impl TryFrom<Option<&str>> for TimelineId {
218 : type Error = anyhow::Error;
219 :
220 311 : fn try_from(value: Option<&str>) -> Result<Self, Self::Error> {
221 311 : value
222 311 : .unwrap_or_default()
223 311 : .parse::<TimelineId>()
224 311 : .with_context(|| format!("Could not parse timeline id from {:?}", value))
225 311 : }
226 : }
227 :
228 : /// Neon Tenant Id represents identifiar of a particular tenant.
229 : /// Is used for distinguishing requests and data belonging to different users.
230 : ///
231 : /// NOTE: It (de)serializes as an array of hex bytes, so the string representation would look
232 : /// like `[173,80,132,115,129,226,72,254,170,201,135,108,199,26,228,24]`.
233 : /// See [`Id`] for alternative ways to serialize it.
234 13025893 : #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
235 : pub struct TenantId(Id);
236 :
237 : id_newtype!(TenantId);
238 :
239 : /// Neon Connection Id identifies long-lived connections (for example a pagestream
240 : /// connection with the page_service). Is used for better logging and tracing
241 : ///
242 : /// NOTE: It (de)serializes as an array of hex bytes, so the string representation would look
243 : /// like `[173,80,132,115,129,226,72,254,170,201,135,108,199,26,228,24]`.
244 : /// See [`Id`] for alternative ways to serialize it.
245 UBC 0 : #[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
246 : pub struct ConnectionId(Id);
247 :
248 : id_newtype!(ConnectionId);
249 :
250 : // A pair uniquely identifying Neon instance.
251 CBC 24217 : #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Hash, Serialize, Deserialize)]
252 : pub struct TenantTimelineId {
253 : pub tenant_id: TenantId,
254 : pub timeline_id: TimelineId,
255 : }
256 :
257 : impl TenantTimelineId {
258 9301 : pub fn new(tenant_id: TenantId, timeline_id: TimelineId) -> Self {
259 9301 : TenantTimelineId {
260 9301 : tenant_id,
261 9301 : timeline_id,
262 9301 : }
263 9301 : }
264 :
265 2 : pub fn generate() -> Self {
266 2 : Self::new(TenantId::generate(), TimelineId::generate())
267 2 : }
268 :
269 3565 : pub fn empty() -> Self {
270 3565 : Self::new(TenantId::from([0u8; 16]), TimelineId::from([0u8; 16]))
271 3565 : }
272 : }
273 :
274 : impl fmt::Display for TenantTimelineId {
275 7637 : fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276 7637 : write!(f, "{}/{}", self.tenant_id, self.timeline_id)
277 7637 : }
278 : }
279 :
280 : impl FromStr for TenantTimelineId {
281 : type Err = anyhow::Error;
282 :
283 1 : fn from_str(s: &str) -> Result<Self, Self::Err> {
284 1 : let mut parts = s.split('/');
285 1 : let tenant_id = parts
286 1 : .next()
287 1 : .ok_or_else(|| anyhow::anyhow!("TenantTimelineId must contain tenant_id"))?
288 1 : .parse()?;
289 1 : let timeline_id = parts
290 1 : .next()
291 1 : .ok_or_else(|| anyhow::anyhow!("TenantTimelineId must contain timeline_id"))?
292 1 : .parse()?;
293 1 : if parts.next().is_some() {
294 UBC 0 : anyhow::bail!("TenantTimelineId must contain only tenant_id and timeline_id");
295 CBC 1 : }
296 1 : Ok(TenantTimelineId::new(tenant_id, timeline_id))
297 1 : }
298 : }
299 :
300 : // Unique ID of a storage node (safekeeper or pageserver). Supposed to be issued
301 : // by the console.
302 1884918 : #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Hash, Debug, Serialize, Deserialize)]
303 : #[serde(transparent)]
304 : pub struct NodeId(pub u64);
305 :
306 : impl fmt::Display for NodeId {
307 15091 : fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 15091 : write!(f, "{}", self.0)
309 15091 : }
310 : }
|