LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - key.rs (source / functions) Coverage Total Hit
Test: 07bee600374ccd486c69370d0972d9035964fe68.info Lines: 62.4 % 564 352
Test Date: 2025-02-20 13:11:02 Functions: 59.2 % 76 45

            Line data    Source code
       1              : use anyhow::{bail, Result};
       2              : use byteorder::{ByteOrder, BE};
       3              : use bytes::Bytes;
       4              : use postgres_ffi::relfile_utils::{FSM_FORKNUM, VISIBILITYMAP_FORKNUM};
       5              : use postgres_ffi::Oid;
       6              : use postgres_ffi::RepOriginId;
       7              : use serde::{Deserialize, Serialize};
       8              : use std::{fmt, ops::Range};
       9              : use utils::const_assert;
      10              : 
      11              : use crate::reltag::{BlockNumber, RelTag, SlruKind};
      12              : 
      13              : /// Key used in the Repository kv-store.
      14              : ///
      15              : /// The Repository treats this as an opaque struct, but see the code in pgdatadir_mapping.rs
      16              : /// for what we actually store in these fields.
      17            0 : #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)]
      18              : pub struct Key {
      19              :     pub field1: u8,
      20              :     pub field2: u32,
      21              :     pub field3: u32,
      22              :     pub field4: u32,
      23              :     pub field5: u8,
      24              :     pub field6: u32,
      25              : }
      26              : 
      27              : /// When working with large numbers of Keys in-memory, it is more efficient to handle them as i128 than as
      28              : /// a struct of fields.
      29              : #[derive(
      30            0 :     Clone, Copy, Default, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize, Debug,
      31              : )]
      32              : pub struct CompactKey(i128);
      33              : 
      34              : /// The storage key size.
      35              : pub const KEY_SIZE: usize = 18;
      36              : 
      37              : /// The metadata key size. 2B fewer than the storage key size because field2 is not fully utilized.
      38              : /// See [`Key::to_i128`] for more information on the encoding.
      39              : pub const METADATA_KEY_SIZE: usize = 16;
      40              : 
      41              : /// The key prefix start range for the metadata keys. All keys with the first byte >= 0x60 is a metadata key.
      42              : pub const METADATA_KEY_BEGIN_PREFIX: u8 = 0x60;
      43              : pub const METADATA_KEY_END_PREFIX: u8 = 0x7F;
      44              : 
      45              : /// The (reserved) key prefix of relation sizes.
      46              : pub const RELATION_SIZE_PREFIX: u8 = 0x61;
      47              : 
      48              : /// The key prefix of AUX file keys.
      49              : pub const AUX_KEY_PREFIX: u8 = 0x62;
      50              : 
      51              : /// The key prefix of ReplOrigin keys.
      52              : pub const REPL_ORIGIN_KEY_PREFIX: u8 = 0x63;
      53              : 
      54              : /// The key prefix of db directory keys.
      55              : pub const DB_DIR_KEY_PREFIX: u8 = 0x64;
      56              : 
      57              : /// The key prefix of rel directory keys.
      58              : pub const REL_DIR_KEY_PREFIX: u8 = 0x65;
      59              : 
      60              : #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
      61              : pub enum RelDirExists {
      62              :     Exists,
      63              :     Removed,
      64              : }
      65              : 
      66              : #[derive(Debug)]
      67              : pub struct DecodeError;
      68              : 
      69              : impl fmt::Display for DecodeError {
      70            0 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
      71            0 :         write!(f, "invalid marker")
      72            0 :     }
      73              : }
      74              : 
      75              : impl std::error::Error for DecodeError {}
      76              : 
      77              : impl RelDirExists {
      78              :     /// The value of the rel directory keys that indicates the existence of a relation.
      79              :     const REL_EXISTS_MARKER: Bytes = Bytes::from_static(b"r");
      80              : 
      81            0 :     pub fn encode(&self) -> Bytes {
      82            0 :         match self {
      83            0 :             Self::Exists => Self::REL_EXISTS_MARKER.clone(),
      84            0 :             Self::Removed => SPARSE_TOMBSTONE_MARKER.clone(),
      85              :         }
      86            0 :     }
      87              : 
      88            0 :     pub fn decode_option(data: Option<impl AsRef<[u8]>>) -> Result<Self, DecodeError> {
      89            0 :         match data {
      90            0 :             Some(marker) if marker.as_ref() == Self::REL_EXISTS_MARKER => Ok(Self::Exists),
      91              :             // Any other marker is invalid
      92            0 :             Some(_) => Err(DecodeError),
      93            0 :             None => Ok(Self::Removed),
      94              :         }
      95            0 :     }
      96              : 
      97            0 :     pub fn decode(data: impl AsRef<[u8]>) -> Result<Self, DecodeError> {
      98            0 :         let data = data.as_ref();
      99            0 :         if data == Self::REL_EXISTS_MARKER {
     100            0 :             Ok(Self::Exists)
     101            0 :         } else if data == SPARSE_TOMBSTONE_MARKER {
     102            0 :             Ok(Self::Removed)
     103              :         } else {
     104            0 :             Err(DecodeError)
     105              :         }
     106            0 :     }
     107              : }
     108              : 
     109              : /// A tombstone in the sparse keyspace, which is an empty buffer.
     110              : pub const SPARSE_TOMBSTONE_MARKER: Bytes = Bytes::from_static(b"");
     111              : 
     112              : /// Check if the key falls in the range of metadata keys.
     113           64 : pub const fn is_metadata_key_slice(key: &[u8]) -> bool {
     114           64 :     key[0] >= METADATA_KEY_BEGIN_PREFIX && key[0] < METADATA_KEY_END_PREFIX
     115           64 : }
     116              : 
     117              : impl Key {
     118              :     /// Check if the key falls in the range of metadata keys.
     119          133 :     pub const fn is_metadata_key(&self) -> bool {
     120          133 :         self.field1 >= METADATA_KEY_BEGIN_PREFIX && self.field1 < METADATA_KEY_END_PREFIX
     121          133 :     }
     122              : 
     123              :     /// Encode a metadata key to a storage key.
     124           63 :     pub fn from_metadata_key_fixed_size(key: &[u8; METADATA_KEY_SIZE]) -> Self {
     125           63 :         assert!(is_metadata_key_slice(key), "key not in metadata key range");
     126              :         // Metadata key space ends at 0x7F so it's fine to directly convert it to i128.
     127           63 :         Self::from_i128(i128::from_be_bytes(*key))
     128           63 :     }
     129              : 
     130              :     /// Encode a metadata key to a storage key.
     131            1 :     pub fn from_metadata_key(key: &[u8]) -> Self {
     132            1 :         Self::from_metadata_key_fixed_size(key.try_into().expect("expect 16 byte metadata key"))
     133            1 :     }
     134              : 
     135              :     /// Get the range of metadata keys.
     136         2544 :     pub const fn metadata_key_range() -> Range<Self> {
     137         2544 :         Key {
     138         2544 :             field1: METADATA_KEY_BEGIN_PREFIX,
     139         2544 :             field2: 0,
     140         2544 :             field3: 0,
     141         2544 :             field4: 0,
     142         2544 :             field5: 0,
     143         2544 :             field6: 0,
     144         2544 :         }..Key {
     145         2544 :             field1: METADATA_KEY_END_PREFIX,
     146         2544 :             field2: 0,
     147         2544 :             field3: 0,
     148         2544 :             field4: 0,
     149         2544 :             field5: 0,
     150         2544 :             field6: 0,
     151         2544 :         }
     152         2544 :     }
     153              : 
     154              :     /// Get the range of aux keys.
     155          668 :     pub fn metadata_aux_key_range() -> Range<Self> {
     156          668 :         Key {
     157          668 :             field1: AUX_KEY_PREFIX,
     158          668 :             field2: 0,
     159          668 :             field3: 0,
     160          668 :             field4: 0,
     161          668 :             field5: 0,
     162          668 :             field6: 0,
     163          668 :         }..Key {
     164          668 :             field1: AUX_KEY_PREFIX + 1,
     165          668 :             field2: 0,
     166          668 :             field3: 0,
     167          668 :             field4: 0,
     168          668 :             field5: 0,
     169          668 :             field6: 0,
     170          668 :         }
     171          668 :     }
     172              : 
     173          644 :     pub fn rel_dir_sparse_key_range() -> Range<Self> {
     174          644 :         Key {
     175          644 :             field1: REL_DIR_KEY_PREFIX,
     176          644 :             field2: 0,
     177          644 :             field3: 0,
     178          644 :             field4: 0,
     179          644 :             field5: 0,
     180          644 :             field6: 0,
     181          644 :         }..Key {
     182          644 :             field1: REL_DIR_KEY_PREFIX + 1,
     183          644 :             field2: 0,
     184          644 :             field3: 0,
     185          644 :             field4: 0,
     186          644 :             field5: 0,
     187          644 :             field6: 0,
     188          644 :         }
     189          644 :     }
     190              : 
     191              :     /// This function checks more extensively what keys we can take on the write path.
     192              :     /// If a key beginning with 00 does not have a global/default tablespace OID, it
     193              :     /// will be rejected on the write path.
     194              :     #[allow(dead_code)]
     195            0 :     pub fn is_valid_key_on_write_path_strong(&self) -> bool {
     196              :         use postgres_ffi::pg_constants::{DEFAULTTABLESPACE_OID, GLOBALTABLESPACE_OID};
     197            0 :         if !self.is_i128_representable() {
     198            0 :             return false;
     199            0 :         }
     200            0 :         if self.field1 == 0
     201            0 :             && !(self.field2 == GLOBALTABLESPACE_OID
     202            0 :                 || self.field2 == DEFAULTTABLESPACE_OID
     203            0 :                 || self.field2 == 0)
     204              :         {
     205            0 :             return false; // User defined tablespaces are not supported
     206            0 :         }
     207            0 :         true
     208            0 :     }
     209              : 
     210              :     /// This is a weaker version of `is_valid_key_on_write_path_strong` that simply
     211              :     /// checks if the key is i128 representable. Note that some keys can be successfully
     212              :     /// ingested into the pageserver, but will cause errors on generating basebackup.
     213      9633289 :     pub fn is_valid_key_on_write_path(&self) -> bool {
     214      9633289 :         self.is_i128_representable()
     215      9633289 :     }
     216              : 
     217     32949977 :     pub fn is_i128_representable(&self) -> bool {
     218     32949977 :         self.field2 <= 0xFFFF || self.field2 == 0xFFFFFFFF || self.field2 == 0x22222222
     219     32949977 :     }
     220              : 
     221              :     /// 'field2' is used to store tablespaceid for relations and small enum numbers for other relish.
     222              :     /// As long as Neon does not support tablespace (because of lack of access to local file system),
     223              :     /// we can assume that only some predefined namespace OIDs are used which can fit in u16
     224     23316688 :     pub fn to_i128(&self) -> i128 {
     225     23316688 :         assert!(self.is_i128_representable(), "invalid key: {self}");
     226     23316688 :         (((self.field1 & 0x7F) as i128) << 120)
     227     23316688 :             | (((self.field2 & 0xFFFF) as i128) << 104)
     228     23316688 :             | ((self.field3 as i128) << 72)
     229     23316688 :             | ((self.field4 as i128) << 40)
     230     23316688 :             | ((self.field5 as i128) << 32)
     231     23316688 :             | self.field6 as i128
     232     23316688 :     }
     233              : 
     234     21247827 :     pub const fn from_i128(x: i128) -> Self {
     235     21247827 :         Key {
     236     21247827 :             field1: ((x >> 120) & 0x7F) as u8,
     237     21247827 :             field2: ((x >> 104) & 0xFFFF) as u32,
     238     21247827 :             field3: (x >> 72) as u32,
     239     21247827 :             field4: (x >> 40) as u32,
     240     21247827 :             field5: (x >> 32) as u8,
     241     21247827 :             field6: x as u32,
     242     21247827 :         }
     243     21247827 :     }
     244              : 
     245     13754532 :     pub fn to_compact(&self) -> CompactKey {
     246     13754532 :         CompactKey(self.to_i128())
     247     13754532 :     }
     248              : 
     249     20242023 :     pub fn from_compact(k: CompactKey) -> Self {
     250     20242023 :         Self::from_i128(k.0)
     251     20242023 :     }
     252              : 
     253     16364383 :     pub const fn next(&self) -> Key {
     254     16364383 :         self.add(1)
     255     16364383 :     }
     256              : 
     257     16376872 :     pub const fn add(&self, x: u32) -> Key {
     258     16376872 :         let mut key = *self;
     259     16376872 : 
     260     16376872 :         let r = key.field6.overflowing_add(x);
     261     16376872 :         key.field6 = r.0;
     262     16376872 :         if r.1 {
     263      1102809 :             let r = key.field5.overflowing_add(1);
     264      1102809 :             key.field5 = r.0;
     265      1102809 :             if r.1 {
     266            0 :                 let r = key.field4.overflowing_add(1);
     267            0 :                 key.field4 = r.0;
     268            0 :                 if r.1 {
     269            0 :                     let r = key.field3.overflowing_add(1);
     270            0 :                     key.field3 = r.0;
     271            0 :                     if r.1 {
     272            0 :                         let r = key.field2.overflowing_add(1);
     273            0 :                         key.field2 = r.0;
     274            0 :                         if r.1 {
     275            0 :                             let r = key.field1.overflowing_add(1);
     276            0 :                             key.field1 = r.0;
     277            0 :                             assert!(!r.1);
     278            0 :                         }
     279            0 :                     }
     280            0 :                 }
     281      1102809 :             }
     282     15274063 :         }
     283     16376872 :         key
     284     16376872 :     }
     285              : 
     286              :     /// Convert a 18B slice to a key. This function should not be used for 16B metadata keys because `field2` is handled differently.
     287              :     /// Use [`Key::from_i128`] instead if you want to handle 16B keys (i.e., metadata keys). There are some restrictions on `field2`,
     288              :     /// and therefore not all 18B slices are valid page server keys.
     289     11890855 :     pub fn from_slice(b: &[u8]) -> Self {
     290     11890855 :         Key {
     291     11890855 :             field1: b[0],
     292     11890855 :             field2: u32::from_be_bytes(b[1..5].try_into().unwrap()),
     293     11890855 :             field3: u32::from_be_bytes(b[5..9].try_into().unwrap()),
     294     11890855 :             field4: u32::from_be_bytes(b[9..13].try_into().unwrap()),
     295     11890855 :             field5: b[13],
     296     11890855 :             field6: u32::from_be_bytes(b[14..18].try_into().unwrap()),
     297     11890855 :         }
     298     11890855 :     }
     299              : 
     300              :     /// Convert a key to a 18B slice. This function should not be used for getting a 16B metadata key because `field2` is handled differently.
     301              :     /// Use [`Key::to_i128`] instead if you want to get a 16B key (i.e., metadata keys).
     302     14516432 :     pub fn write_to_byte_slice(&self, buf: &mut [u8]) {
     303     14516432 :         buf[0] = self.field1;
     304     14516432 :         BE::write_u32(&mut buf[1..5], self.field2);
     305     14516432 :         BE::write_u32(&mut buf[5..9], self.field3);
     306     14516432 :         BE::write_u32(&mut buf[9..13], self.field4);
     307     14516432 :         buf[13] = self.field5;
     308     14516432 :         BE::write_u32(&mut buf[14..18], self.field6);
     309     14516432 :     }
     310              : }
     311              : 
     312              : impl CompactKey {
     313           10 :     pub fn raw(&self) -> i128 {
     314           10 :         self.0
     315           10 :     }
     316              : }
     317              : 
     318              : impl From<i128> for CompactKey {
     319            5 :     fn from(value: i128) -> Self {
     320            5 :         Self(value)
     321            5 :     }
     322              : }
     323              : 
     324              : impl fmt::Display for Key {
     325       759193 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     326       759193 :         write!(
     327       759193 :             f,
     328       759193 :             "{:02X}{:08X}{:08X}{:08X}{:02X}{:08X}",
     329       759193 :             self.field1, self.field2, self.field3, self.field4, self.field5, self.field6
     330       759193 :         )
     331       759193 :     }
     332              : }
     333              : 
     334              : impl fmt::Display for CompactKey {
     335            0 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     336            0 :         let k = Key::from_compact(*self);
     337            0 :         k.fmt(f)
     338            0 :     }
     339              : }
     340              : 
     341              : impl Key {
     342              :     pub const MIN: Key = Key {
     343              :         field1: u8::MIN,
     344              :         field2: u32::MIN,
     345              :         field3: u32::MIN,
     346              :         field4: u32::MIN,
     347              :         field5: u8::MIN,
     348              :         field6: u32::MIN,
     349              :     };
     350              :     pub const MAX: Key = Key {
     351              :         field1: u8::MAX,
     352              :         field2: u32::MAX,
     353              :         field3: u32::MAX,
     354              :         field4: u32::MAX,
     355              :         field5: u8::MAX,
     356              :         field6: u32::MAX,
     357              :     };
     358              : 
     359        80389 :     pub fn from_hex(s: &str) -> Result<Self> {
     360        80389 :         if s.len() != 36 {
     361            4 :             bail!("parse error");
     362        80385 :         }
     363        80385 :         Ok(Key {
     364        80385 :             field1: u8::from_str_radix(&s[0..2], 16)?,
     365        80385 :             field2: u32::from_str_radix(&s[2..10], 16)?,
     366        80385 :             field3: u32::from_str_radix(&s[10..18], 16)?,
     367        80385 :             field4: u32::from_str_radix(&s[18..26], 16)?,
     368        80385 :             field5: u8::from_str_radix(&s[26..28], 16)?,
     369        80385 :             field6: u32::from_str_radix(&s[28..36], 16)?,
     370              :         })
     371        80389 :     }
     372              : }
     373              : 
     374              : // Layout of the Key address space
     375              : //
     376              : // The Key struct, used to address the underlying key-value store, consists of
     377              : // 18 bytes, split into six fields. See 'Key' in repository.rs. We need to map
     378              : // all the data and metadata keys into those 18 bytes.
     379              : //
     380              : // Principles for the mapping:
     381              : //
     382              : // - Things that are often accessed or modified together, should be close to
     383              : //   each other in the key space. For example, if a relation is extended by one
     384              : //   block, we create a new key-value pair for the block data, and update the
     385              : //   relation size entry. Because of that, the RelSize key comes after all the
     386              : //   RelBlocks of a relation: the RelSize and the last RelBlock are always next
     387              : //   to each other.
     388              : //
     389              : // The key space is divided into four major sections, identified by the first
     390              : // byte, and the form a hierarchy:
     391              : //
     392              : // 00 Relation data and metadata
     393              : //
     394              : //   DbDir    () -> (dbnode, spcnode)
     395              : //   Filenodemap
     396              : //   RelDir   -> relnode forknum
     397              : //       RelBlocks
     398              : //       RelSize
     399              : //
     400              : // 01 SLRUs
     401              : //
     402              : //   SlruDir  kind
     403              : //   SlruSegBlocks segno
     404              : //   SlruSegSize
     405              : //
     406              : // 02 pg_twophase
     407              : //
     408              : // 03 misc
     409              : //    Controlfile
     410              : //    checkpoint
     411              : //    pg_version
     412              : //
     413              : // 04 aux files
     414              : //
     415              : // Below is a full list of the keyspace allocation:
     416              : //
     417              : // DbDir:
     418              : // 00 00000000 00000000 00000000 00   00000000
     419              : //
     420              : // Filenodemap:
     421              : // 00 SPCNODE  DBNODE   00000000 00   00000000
     422              : //
     423              : // RelDir:
     424              : // 00 SPCNODE  DBNODE   00000000 00   00000001 (Postgres never uses relfilenode 0)
     425              : //
     426              : // RelBlock:
     427              : // 00 SPCNODE  DBNODE   RELNODE  FORK BLKNUM
     428              : //
     429              : // RelSize:
     430              : // 00 SPCNODE  DBNODE   RELNODE  FORK FFFFFFFF
     431              : //
     432              : // SlruDir:
     433              : // 01 kind     00000000 00000000 00   00000000
     434              : //
     435              : // SlruSegBlock:
     436              : // 01 kind     00000001 SEGNO    00   BLKNUM
     437              : //
     438              : // SlruSegSize:
     439              : // 01 kind     00000001 SEGNO    00   FFFFFFFF
     440              : //
     441              : // TwoPhaseDir:
     442              : // 02 00000000 00000000 00000000 00   00000000
     443              : //
     444              : // TwoPhaseFile:
     445              : //
     446              : // 02 00000000 00000000 00XXXXXX XX   XXXXXXXX
     447              : //
     448              : //                        \______XID_________/
     449              : //
     450              : // The 64-bit XID is stored a little awkwardly in field6, field5 and
     451              : // field4. PostgreSQL v16 and below only stored a 32-bit XID, which
     452              : // fit completely in field6, but starting with PostgreSQL v17, a full
     453              : // 64-bit XID is used. Most pageserver code that accesses
     454              : // TwoPhaseFiles now deals with 64-bit XIDs even on v16, the high bits
     455              : // are just unused.
     456              : //
     457              : // ControlFile:
     458              : // 03 00000000 00000000 00000000 00   00000000
     459              : //
     460              : // Checkpoint:
     461              : // 03 00000000 00000000 00000000 00   00000001
     462              : //
     463              : // AuxFiles:
     464              : // 03 00000000 00000000 00000000 00   00000002
     465              : //
     466              : 
     467              : //-- Section 01: relation data and metadata
     468              : 
     469              : pub const DBDIR_KEY: Key = Key {
     470              :     field1: 0x00,
     471              :     field2: 0,
     472              :     field3: 0,
     473              :     field4: 0,
     474              :     field5: 0,
     475              :     field6: 0,
     476              : };
     477              : 
     478              : #[inline(always)]
     479            0 : pub fn dbdir_key_range(spcnode: Oid, dbnode: Oid) -> Range<Key> {
     480            0 :     Key {
     481            0 :         field1: 0x00,
     482            0 :         field2: spcnode,
     483            0 :         field3: dbnode,
     484            0 :         field4: 0,
     485            0 :         field5: 0,
     486            0 :         field6: 0,
     487            0 :     }..Key {
     488            0 :         field1: 0x00,
     489            0 :         field2: spcnode,
     490            0 :         field3: dbnode,
     491            0 :         field4: 0xffffffff,
     492            0 :         field5: 0xff,
     493            0 :         field6: 0xffffffff,
     494            0 :     }
     495            0 : }
     496              : 
     497              : #[inline(always)]
     498           32 : pub fn relmap_file_key(spcnode: Oid, dbnode: Oid) -> Key {
     499           32 :     Key {
     500           32 :         field1: 0x00,
     501           32 :         field2: spcnode,
     502           32 :         field3: dbnode,
     503           32 :         field4: 0,
     504           32 :         field5: 0,
     505           32 :         field6: 0,
     506           32 :     }
     507           32 : }
     508              : 
     509              : #[inline(always)]
     510         3896 : pub fn rel_dir_to_key(spcnode: Oid, dbnode: Oid) -> Key {
     511         3896 :     Key {
     512         3896 :         field1: 0x00,
     513         3896 :         field2: spcnode,
     514         3896 :         field3: dbnode,
     515         3896 :         field4: 0,
     516         3896 :         field5: 0,
     517         3896 :         field6: 1,
     518         3896 :     }
     519         3896 : }
     520              : 
     521              : #[inline(always)]
     522            0 : pub fn rel_tag_sparse_key(spcnode: Oid, dbnode: Oid, relnode: Oid, forknum: u8) -> Key {
     523            0 :     Key {
     524            0 :         field1: REL_DIR_KEY_PREFIX,
     525            0 :         field2: spcnode,
     526            0 :         field3: dbnode,
     527            0 :         field4: relnode,
     528            0 :         field5: forknum,
     529            0 :         field6: 1,
     530            0 :     }
     531            0 : }
     532              : 
     533            0 : pub fn rel_tag_sparse_key_range(spcnode: Oid, dbnode: Oid) -> Range<Key> {
     534            0 :     Key {
     535            0 :         field1: REL_DIR_KEY_PREFIX,
     536            0 :         field2: spcnode,
     537            0 :         field3: dbnode,
     538            0 :         field4: 0,
     539            0 :         field5: 0,
     540            0 :         field6: 0,
     541            0 :     }..Key {
     542            0 :         field1: REL_DIR_KEY_PREFIX,
     543            0 :         field2: spcnode,
     544            0 :         field3: dbnode,
     545            0 :         field4: u32::MAX,
     546            0 :         field5: u8::MAX,
     547            0 :         field6: u32::MAX,
     548            0 :     } // it's fine to exclude the last key b/c we only use field6 == 1
     549            0 : }
     550              : 
     551              : #[inline(always)]
     552      2583814 : pub fn rel_block_to_key(rel: RelTag, blknum: BlockNumber) -> Key {
     553      2583814 :     Key {
     554      2583814 :         field1: 0x00,
     555      2583814 :         field2: rel.spcnode,
     556      2583814 :         field3: rel.dbnode,
     557      2583814 :         field4: rel.relnode,
     558      2583814 :         field5: rel.forknum,
     559      2583814 :         field6: blknum,
     560      2583814 :     }
     561      2583814 : }
     562              : 
     563              : #[inline(always)]
     564       579508 : pub fn rel_size_to_key(rel: RelTag) -> Key {
     565       579508 :     Key {
     566       579508 :         field1: 0x00,
     567       579508 :         field2: rel.spcnode,
     568       579508 :         field3: rel.dbnode,
     569       579508 :         field4: rel.relnode,
     570       579508 :         field5: rel.forknum,
     571       579508 :         field6: 0xffff_ffff,
     572       579508 :     }
     573       579508 : }
     574              : 
     575              : impl Key {
     576              :     #[inline(always)]
     577            5 :     pub fn is_rel_size_key(&self) -> bool {
     578            5 :         self.field1 == 0 && self.field6 == u32::MAX
     579            5 :     }
     580              : }
     581              : 
     582              : #[inline(always)]
     583            4 : pub fn rel_key_range(rel: RelTag) -> Range<Key> {
     584            4 :     Key {
     585            4 :         field1: 0x00,
     586            4 :         field2: rel.spcnode,
     587            4 :         field3: rel.dbnode,
     588            4 :         field4: rel.relnode,
     589            4 :         field5: rel.forknum,
     590            4 :         field6: 0,
     591            4 :     }..Key {
     592            4 :         field1: 0x00,
     593            4 :         field2: rel.spcnode,
     594            4 :         field3: rel.dbnode,
     595            4 :         field4: rel.relnode,
     596            4 :         field5: rel.forknum + 1,
     597            4 :         field6: 0,
     598            4 :     }
     599            4 : }
     600              : 
     601              : //-- Section 02: SLRUs
     602              : 
     603              : #[inline(always)]
     604         3120 : pub fn slru_dir_to_key(kind: SlruKind) -> Key {
     605         3120 :     Key {
     606         3120 :         field1: 0x01,
     607         3120 :         field2: match kind {
     608         1040 :             SlruKind::Clog => 0x00,
     609         1040 :             SlruKind::MultiXactMembers => 0x01,
     610         1040 :             SlruKind::MultiXactOffsets => 0x02,
     611              :         },
     612              :         field3: 0,
     613              :         field4: 0,
     614              :         field5: 0,
     615              :         field6: 0,
     616              :     }
     617         3120 : }
     618              : 
     619              : #[inline(always)]
     620      2098633 : pub fn slru_dir_kind(key: &Key) -> Option<Result<SlruKind, u32>> {
     621      2098633 :     if key.field1 == 0x01
     622            0 :         && key.field3 == 0
     623            0 :         && key.field4 == 0
     624            0 :         && key.field5 == 0
     625            0 :         && key.field6 == 0
     626              :     {
     627            0 :         match key.field2 {
     628            0 :             0 => Some(Ok(SlruKind::Clog)),
     629            0 :             1 => Some(Ok(SlruKind::MultiXactMembers)),
     630            0 :             2 => Some(Ok(SlruKind::MultiXactOffsets)),
     631            0 :             x => Some(Err(x)),
     632              :         }
     633              :     } else {
     634      2098633 :         None
     635              :     }
     636      2098633 : }
     637              : 
     638              : #[inline(always)]
     639           28 : pub fn slru_block_to_key(kind: SlruKind, segno: u32, blknum: BlockNumber) -> Key {
     640           28 :     Key {
     641           28 :         field1: 0x01,
     642           28 :         field2: match kind {
     643           20 :             SlruKind::Clog => 0x00,
     644            4 :             SlruKind::MultiXactMembers => 0x01,
     645            4 :             SlruKind::MultiXactOffsets => 0x02,
     646              :         },
     647              :         field3: 1,
     648           28 :         field4: segno,
     649           28 :         field5: 0,
     650           28 :         field6: blknum,
     651           28 :     }
     652           28 : }
     653              : 
     654              : #[inline(always)]
     655           12 : pub fn slru_segment_size_to_key(kind: SlruKind, segno: u32) -> Key {
     656           12 :     Key {
     657           12 :         field1: 0x01,
     658           12 :         field2: match kind {
     659            4 :             SlruKind::Clog => 0x00,
     660            4 :             SlruKind::MultiXactMembers => 0x01,
     661            4 :             SlruKind::MultiXactOffsets => 0x02,
     662              :         },
     663              :         field3: 1,
     664           12 :         field4: segno,
     665           12 :         field5: 0,
     666           12 :         field6: 0xffff_ffff,
     667           12 :     }
     668           12 : }
     669              : 
     670              : impl Key {
     671      2098633 :     pub fn is_slru_segment_size_key(&self) -> bool {
     672      2098633 :         self.field1 == 0x01
     673            0 :             && self.field2 < 0x03
     674            0 :             && self.field3 == 0x01
     675            0 :             && self.field5 == 0
     676            0 :             && self.field6 == u32::MAX
     677      2098633 :     }
     678              : 
     679      2098633 :     pub fn is_slru_dir_key(&self) -> bool {
     680      2098633 :         slru_dir_kind(self).is_some()
     681      2098633 :     }
     682              : }
     683              : 
     684              : #[inline(always)]
     685            0 : pub fn slru_segment_key_range(kind: SlruKind, segno: u32) -> Range<Key> {
     686            0 :     let field2 = match kind {
     687            0 :         SlruKind::Clog => 0x00,
     688            0 :         SlruKind::MultiXactMembers => 0x01,
     689            0 :         SlruKind::MultiXactOffsets => 0x02,
     690              :     };
     691              : 
     692            0 :     Key {
     693            0 :         field1: 0x01,
     694            0 :         field2,
     695            0 :         field3: 1,
     696            0 :         field4: segno,
     697            0 :         field5: 0,
     698            0 :         field6: 0,
     699            0 :     }..Key {
     700            0 :         field1: 0x01,
     701            0 :         field2,
     702            0 :         field3: 1,
     703            0 :         field4: segno,
     704            0 :         field5: 1,
     705            0 :         field6: 0,
     706            0 :     }
     707            0 : }
     708              : 
     709              : //-- Section 03: pg_twophase
     710              : 
     711              : pub const TWOPHASEDIR_KEY: Key = Key {
     712              :     field1: 0x02,
     713              :     field2: 0,
     714              :     field3: 0,
     715              :     field4: 0,
     716              :     field5: 0,
     717              :     field6: 0,
     718              : };
     719              : 
     720              : #[inline(always)]
     721            0 : pub fn twophase_file_key(xid: u64) -> Key {
     722            0 :     Key {
     723            0 :         field1: 0x02,
     724            0 :         field2: 0,
     725            0 :         field3: 0,
     726            0 :         field4: ((xid & 0xFFFFFF0000000000) >> 40) as u32,
     727            0 :         field5: ((xid & 0x000000FF00000000) >> 32) as u8,
     728            0 :         field6: (xid & 0x00000000FFFFFFFF) as u32,
     729            0 :     }
     730            0 : }
     731              : 
     732              : #[inline(always)]
     733            0 : pub fn twophase_key_range(xid: u64) -> Range<Key> {
     734            0 :     // 64-bit XIDs really should not overflow
     735            0 :     let (next_xid, overflowed) = xid.overflowing_add(1);
     736            0 : 
     737            0 :     Key {
     738            0 :         field1: 0x02,
     739            0 :         field2: 0,
     740            0 :         field3: 0,
     741            0 :         field4: ((xid & 0xFFFFFF0000000000) >> 40) as u32,
     742            0 :         field5: ((xid & 0x000000FF00000000) >> 32) as u8,
     743            0 :         field6: (xid & 0x00000000FFFFFFFF) as u32,
     744            0 :     }..Key {
     745            0 :         field1: 0x02,
     746            0 :         field2: 0,
     747            0 :         field3: u32::from(overflowed),
     748            0 :         field4: ((next_xid & 0xFFFFFF0000000000) >> 40) as u32,
     749            0 :         field5: ((next_xid & 0x000000FF00000000) >> 32) as u8,
     750            0 :         field6: (next_xid & 0x00000000FFFFFFFF) as u32,
     751            0 :     }
     752            0 : }
     753              : 
     754              : //-- Section 03: Control file
     755              : pub const CONTROLFILE_KEY: Key = Key {
     756              :     field1: 0x03,
     757              :     field2: 0,
     758              :     field3: 0,
     759              :     field4: 0,
     760              :     field5: 0,
     761              :     field6: 0,
     762              : };
     763              : 
     764              : pub const CHECKPOINT_KEY: Key = Key {
     765              :     field1: 0x03,
     766              :     field2: 0,
     767              :     field3: 0,
     768              :     field4: 0,
     769              :     field5: 0,
     770              :     field6: 1,
     771              : };
     772              : 
     773              : pub const AUX_FILES_KEY: Key = Key {
     774              :     field1: 0x03,
     775              :     field2: 0,
     776              :     field3: 0,
     777              :     field4: 0,
     778              :     field5: 0,
     779              :     field6: 2,
     780              : };
     781              : 
     782              : #[inline(always)]
     783            0 : pub fn repl_origin_key(origin_id: RepOriginId) -> Key {
     784            0 :     Key {
     785            0 :         field1: REPL_ORIGIN_KEY_PREFIX,
     786            0 :         field2: 0,
     787            0 :         field3: 0,
     788            0 :         field4: 0,
     789            0 :         field5: 0,
     790            0 :         field6: origin_id as u32,
     791            0 :     }
     792            0 : }
     793              : 
     794              : /// Get the range of replorigin keys.
     795          644 : pub fn repl_origin_key_range() -> Range<Key> {
     796          644 :     Key {
     797          644 :         field1: REPL_ORIGIN_KEY_PREFIX,
     798          644 :         field2: 0,
     799          644 :         field3: 0,
     800          644 :         field4: 0,
     801          644 :         field5: 0,
     802          644 :         field6: 0,
     803          644 :     }..Key {
     804          644 :         field1: REPL_ORIGIN_KEY_PREFIX,
     805          644 :         field2: 0,
     806          644 :         field3: 0,
     807          644 :         field4: 0,
     808          644 :         field5: 0,
     809          644 :         field6: 0x10000,
     810          644 :     }
     811          644 : }
     812              : 
     813              : // Reverse mappings for a few Keys.
     814              : // These are needed by WAL redo manager.
     815              : 
     816              : /// Non inherited range for vectored get.
     817              : pub const NON_INHERITED_RANGE: Range<Key> = AUX_FILES_KEY..AUX_FILES_KEY.next();
     818              : /// Sparse keyspace range for vectored get. Missing key error will be ignored for this range.
     819              : pub const SPARSE_RANGE: Range<Key> = Key::metadata_key_range();
     820              : 
     821              : impl Key {
     822              :     // AUX_FILES currently stores only data for logical replication (slots etc), and
     823              :     // we don't preserve these on a branch because safekeepers can't follow timeline
     824              :     // switch (and generally it likely should be optional), so ignore these.
     825              :     #[inline(always)]
     826            0 :     pub fn is_inherited_key(self) -> bool {
     827            0 :         if self.is_sparse() {
     828            0 :             self.is_inherited_sparse_key()
     829              :         } else {
     830            0 :             !NON_INHERITED_RANGE.contains(&self)
     831              :         }
     832            0 :     }
     833              : 
     834              :     #[inline(always)]
     835      1482275 :     pub fn is_sparse(self) -> bool {
     836      1482275 :         self.field1 >= METADATA_KEY_BEGIN_PREFIX && self.field1 < METADATA_KEY_END_PREFIX
     837      1482275 :     }
     838              : 
     839              :     /// Check if the key belongs to the inherited keyspace.
     840            0 :     fn is_inherited_sparse_key(self) -> bool {
     841            0 :         debug_assert!(self.is_sparse());
     842            0 :         self.field1 == RELATION_SIZE_PREFIX
     843            0 :     }
     844              : 
     845      1707815 :     pub const fn sparse_non_inherited_keyspace() -> Range<Key> {
     846      1707815 :         // The two keys are adjacent; if we will have non-adjancent keys in the future, we should return a keyspace
     847      1707815 :         const_assert!(AUX_KEY_PREFIX + 1 == REPL_ORIGIN_KEY_PREFIX);
     848      1707815 :         Key {
     849      1707815 :             field1: AUX_KEY_PREFIX,
     850      1707815 :             field2: 0,
     851      1707815 :             field3: 0,
     852      1707815 :             field4: 0,
     853      1707815 :             field5: 0,
     854      1707815 :             field6: 0,
     855      1707815 :         }..Key {
     856      1707815 :             field1: REPL_ORIGIN_KEY_PREFIX + 1,
     857      1707815 :             field2: 0,
     858      1707815 :             field3: 0,
     859      1707815 :             field4: 0,
     860      1707815 :             field5: 0,
     861      1707815 :             field6: 0,
     862      1707815 :         }
     863      1707815 :     }
     864              : 
     865              :     #[inline(always)]
     866            0 :     pub fn is_rel_fsm_block_key(self) -> bool {
     867            0 :         self.field1 == 0x00
     868            0 :             && self.field4 != 0
     869            0 :             && self.field5 == FSM_FORKNUM
     870            0 :             && self.field6 != 0xffffffff
     871            0 :     }
     872              : 
     873              :     #[inline(always)]
     874            0 :     pub fn is_rel_vm_block_key(self) -> bool {
     875            0 :         self.field1 == 0x00
     876            0 :             && self.field4 != 0
     877            0 :             && self.field5 == VISIBILITYMAP_FORKNUM
     878            0 :             && self.field6 != 0xffffffff
     879            0 :     }
     880              : 
     881              :     #[inline(always)]
     882            0 :     pub fn to_slru_block(self) -> anyhow::Result<(SlruKind, u32, BlockNumber)> {
     883            0 :         Ok(match self.field1 {
     884              :             0x01 => {
     885            0 :                 let kind = match self.field2 {
     886            0 :                     0x00 => SlruKind::Clog,
     887            0 :                     0x01 => SlruKind::MultiXactMembers,
     888            0 :                     0x02 => SlruKind::MultiXactOffsets,
     889            0 :                     _ => anyhow::bail!("unrecognized slru kind 0x{:02x}", self.field2),
     890              :                 };
     891            0 :                 let segno = self.field4;
     892            0 :                 let blknum = self.field6;
     893            0 : 
     894            0 :                 (kind, segno, blknum)
     895              :             }
     896            0 :             _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
     897              :         })
     898            0 :     }
     899              : 
     900              :     #[inline(always)]
     901      3244173 :     pub fn is_slru_block_key(self) -> bool {
     902      3244173 :         self.field1 == 0x01                // SLRU-related
     903         1276 :         && self.field3 == 0x00000001   // but not SlruDir
     904           40 :         && self.field6 != 0xffffffff // and not SlruSegSize
     905      3244173 :     }
     906              : 
     907              :     #[inline(always)]
     908      7997182 :     pub fn is_rel_block_key(&self) -> bool {
     909      7997182 :         self.field1 == 0x00 && self.field4 != 0 && self.field6 != 0xffffffff
     910      7997182 :     }
     911              : 
     912              :     #[inline(always)]
     913          400 :     pub fn is_rel_dir_key(&self) -> bool {
     914          400 :         self.field1 == 0x00
     915          400 :             && self.field2 != 0
     916            0 :             && self.field3 != 0
     917            0 :             && self.field4 == 0
     918            0 :             && self.field5 == 0
     919            0 :             && self.field6 == 1
     920          400 :     }
     921              : 
     922              :     #[inline(always)]
     923      2099033 :     pub fn is_aux_file_key(&self) -> bool {
     924      2099033 :         self.field1 == AUX_KEY_PREFIX
     925      2099033 :     }
     926              : 
     927              :     /// Guaranteed to return `Ok()` if [`Self::is_rel_block_key`] returns `true` for `key`.
     928              :     #[inline(always)]
     929       291296 :     pub fn to_rel_block(self) -> anyhow::Result<(RelTag, BlockNumber)> {
     930       291296 :         Ok(match self.field1 {
     931       291296 :             0x00 => (
     932       291296 :                 RelTag {
     933       291296 :                     spcnode: self.field2,
     934       291296 :                     dbnode: self.field3,
     935       291296 :                     relnode: self.field4,
     936       291296 :                     forknum: self.field5,
     937       291296 :                 },
     938       291296 :                 self.field6,
     939       291296 :             ),
     940            0 :             _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
     941              :         })
     942       291296 :     }
     943              : }
     944              : 
     945              : impl std::str::FromStr for Key {
     946              :     type Err = anyhow::Error;
     947              : 
     948            9 :     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
     949            9 :         Self::from_hex(s)
     950            9 :     }
     951              : }
     952              : 
     953              : #[cfg(test)]
     954              : mod tests {
     955              :     use std::str::FromStr;
     956              : 
     957              :     use crate::key::is_metadata_key_slice;
     958              :     use crate::key::Key;
     959              : 
     960              :     use rand::Rng;
     961              :     use rand::SeedableRng;
     962              : 
     963              :     use super::AUX_KEY_PREFIX;
     964              : 
     965              :     #[test]
     966            1 :     fn display_fromstr_bijection() {
     967            1 :         let mut rng = rand::rngs::StdRng::seed_from_u64(42);
     968            1 : 
     969            1 :         let key = Key {
     970            1 :             field1: rng.gen(),
     971            1 :             field2: rng.gen(),
     972            1 :             field3: rng.gen(),
     973            1 :             field4: rng.gen(),
     974            1 :             field5: rng.gen(),
     975            1 :             field6: rng.gen(),
     976            1 :         };
     977            1 : 
     978            1 :         assert_eq!(key, Key::from_str(&format!("{key}")).unwrap());
     979            1 :     }
     980              : 
     981              :     #[test]
     982            1 :     fn test_metadata_keys() {
     983            1 :         let mut metadata_key = vec![AUX_KEY_PREFIX];
     984            1 :         metadata_key.extend_from_slice(&[0xFF; 15]);
     985            1 :         let encoded_key = Key::from_metadata_key(&metadata_key);
     986            1 :         let output_key = encoded_key.to_i128().to_be_bytes();
     987            1 :         assert_eq!(metadata_key, output_key);
     988            1 :         assert!(encoded_key.is_metadata_key());
     989            1 :         assert!(is_metadata_key_slice(&metadata_key));
     990            1 :     }
     991              : 
     992              :     #[test]
     993            1 :     fn test_possible_largest_key() {
     994            1 :         Key::from_i128(0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF);
     995            1 :         // TODO: put this key into the system and see if anything breaks.
     996            1 :     }
     997              : }
        

Generated by: LCOV version 2.1-beta