LCOV - code coverage report
Current view: top level - libs/utils/src - id.rs (source / functions) Coverage Total Hit
Test: 8ac049b474321fdc72ddcb56d7165153a1a900e8.info Lines: 84.8 % 138 117
Test Date: 2023-09-06 10:18:01 Functions: 47.5 % 183 87

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

Generated by: LCOV version 2.1-beta