LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - key.rs (source / functions) Coverage Total Hit
Test: 2aa98e37cd3250b9a68c97ef6050b16fe702ab33.info Lines: 64.4 % 432 278
Test Date: 2024-08-29 11:33:10 Functions: 59.3 % 54 32

            Line data    Source code
       1              : use anyhow::{bail, Result};
       2              : use byteorder::{ByteOrder, BE};
       3              : use postgres_ffi::relfile_utils::{FSM_FORKNUM, VISIBILITYMAP_FORKNUM};
       4              : use postgres_ffi::RepOriginId;
       5              : use postgres_ffi::{Oid, TransactionId};
       6              : use serde::{Deserialize, Serialize};
       7              : use std::{fmt, ops::Range};
       8              : 
       9              : use crate::reltag::{BlockNumber, RelTag, SlruKind};
      10              : 
      11              : /// Key used in the Repository kv-store.
      12              : ///
      13              : /// The Repository treats this as an opaque struct, but see the code in pgdatadir_mapping.rs
      14              : /// for what we actually store in these fields.
      15         6864 : #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd, Serialize, Deserialize)]
      16              : pub struct Key {
      17              :     pub field1: u8,
      18              :     pub field2: u32,
      19              :     pub field3: u32,
      20              :     pub field4: u32,
      21              :     pub field5: u8,
      22              :     pub field6: u32,
      23              : }
      24              : 
      25              : /// When working with large numbers of Keys in-memory, it is more efficient to handle them as i128 than as
      26              : /// a struct of fields.
      27              : #[derive(Clone, Copy, Hash, PartialEq, Eq, Ord, PartialOrd)]
      28              : pub struct CompactKey(i128);
      29              : 
      30              : /// The storage key size.
      31              : pub const KEY_SIZE: usize = 18;
      32              : 
      33              : /// The metadata key size. 2B fewer than the storage key size because field2 is not fully utilized.
      34              : /// See [`Key::to_i128`] for more information on the encoding.
      35              : pub const METADATA_KEY_SIZE: usize = 16;
      36              : 
      37              : /// The key prefix start range for the metadata keys. All keys with the first byte >= 0x60 is a metadata key.
      38              : pub const METADATA_KEY_BEGIN_PREFIX: u8 = 0x60;
      39              : pub const METADATA_KEY_END_PREFIX: u8 = 0x7F;
      40              : 
      41              : /// The (reserved) key prefix of relation sizes.
      42              : pub const RELATION_SIZE_PREFIX: u8 = 0x61;
      43              : 
      44              : /// The key prefix of AUX file keys.
      45              : pub const AUX_KEY_PREFIX: u8 = 0x62;
      46              : 
      47              : /// The key prefix of ReplOrigin keys.
      48              : pub const REPL_ORIGIN_KEY_PREFIX: u8 = 0x63;
      49              : 
      50              : /// Check if the key falls in the range of metadata keys.
      51          162 : pub const fn is_metadata_key_slice(key: &[u8]) -> bool {
      52          162 :     key[0] >= METADATA_KEY_BEGIN_PREFIX && key[0] < METADATA_KEY_END_PREFIX
      53          162 : }
      54              : 
      55              : impl Key {
      56              :     /// Check if the key falls in the range of metadata keys.
      57          204 :     pub const fn is_metadata_key(&self) -> bool {
      58          204 :         self.field1 >= METADATA_KEY_BEGIN_PREFIX && self.field1 < METADATA_KEY_END_PREFIX
      59          204 :     }
      60              : 
      61              :     /// Encode a metadata key to a storage key.
      62          156 :     pub fn from_metadata_key_fixed_size(key: &[u8; METADATA_KEY_SIZE]) -> Self {
      63          156 :         assert!(is_metadata_key_slice(key), "key not in metadata key range");
      64              :         // Metadata key space ends at 0x7F so it's fine to directly convert it to i128.
      65          156 :         Self::from_i128(i128::from_be_bytes(*key))
      66          156 :     }
      67              : 
      68              :     /// Encode a metadata key to a storage key.
      69            6 :     pub fn from_metadata_key(key: &[u8]) -> Self {
      70            6 :         Self::from_metadata_key_fixed_size(key.try_into().expect("expect 16 byte metadata key"))
      71            6 :     }
      72              : 
      73              :     /// Get the range of metadata keys.
      74         3288 :     pub const fn metadata_key_range() -> Range<Self> {
      75         3288 :         Key {
      76         3288 :             field1: METADATA_KEY_BEGIN_PREFIX,
      77         3288 :             field2: 0,
      78         3288 :             field3: 0,
      79         3288 :             field4: 0,
      80         3288 :             field5: 0,
      81         3288 :             field6: 0,
      82         3288 :         }..Key {
      83         3288 :             field1: METADATA_KEY_END_PREFIX,
      84         3288 :             field2: 0,
      85         3288 :             field3: 0,
      86         3288 :             field4: 0,
      87         3288 :             field5: 0,
      88         3288 :             field6: 0,
      89         3288 :         }
      90         3288 :     }
      91              : 
      92              :     /// Get the range of aux keys.
      93          936 :     pub fn metadata_aux_key_range() -> Range<Self> {
      94          936 :         Key {
      95          936 :             field1: AUX_KEY_PREFIX,
      96          936 :             field2: 0,
      97          936 :             field3: 0,
      98          936 :             field4: 0,
      99          936 :             field5: 0,
     100          936 :             field6: 0,
     101          936 :         }..Key {
     102          936 :             field1: AUX_KEY_PREFIX + 1,
     103          936 :             field2: 0,
     104          936 :             field3: 0,
     105          936 :             field4: 0,
     106          936 :             field5: 0,
     107          936 :             field6: 0,
     108          936 :         }
     109          936 :     }
     110              : 
     111              :     /// 'field2' is used to store tablespaceid for relations and small enum numbers for other relish.
     112              :     /// As long as Neon does not support tablespace (because of lack of access to local file system),
     113              :     /// we can assume that only some predefined namespace OIDs are used which can fit in u16
     114     33593686 :     pub fn to_i128(&self) -> i128 {
     115     33593686 :         assert!(
     116     33593686 :             self.field2 <= 0xFFFF || self.field2 == 0xFFFFFFFF || self.field2 == 0x22222222,
     117            0 :             "invalid key: {self}",
     118              :         );
     119     33593686 :         (((self.field1 & 0x7F) as i128) << 120)
     120     33593686 :             | (((self.field2 & 0xFFFF) as i128) << 104)
     121     33593686 :             | ((self.field3 as i128) << 72)
     122     33593686 :             | ((self.field4 as i128) << 40)
     123     33593686 :             | ((self.field5 as i128) << 32)
     124     33593686 :             | self.field6 as i128
     125     33593686 :     }
     126              : 
     127     16386310 :     pub const fn from_i128(x: i128) -> Self {
     128     16386310 :         Key {
     129     16386310 :             field1: ((x >> 120) & 0x7F) as u8,
     130     16386310 :             field2: ((x >> 104) & 0xFFFF) as u32,
     131     16386310 :             field3: (x >> 72) as u32,
     132     16386310 :             field4: (x >> 40) as u32,
     133     16386310 :             field5: (x >> 32) as u8,
     134     16386310 :             field6: x as u32,
     135     16386310 :         }
     136     16386310 :     }
     137              : 
     138     18910232 :     pub fn to_compact(&self) -> CompactKey {
     139     18910232 :         CompactKey(self.to_i128())
     140     18910232 :     }
     141              : 
     142     14653144 :     pub fn from_compact(k: CompactKey) -> Self {
     143     14653144 :         Self::from_i128(k.0)
     144     14653144 :     }
     145              : 
     146     26527316 :     pub const fn next(&self) -> Key {
     147     26527316 :         self.add(1)
     148     26527316 :     }
     149              : 
     150     26579984 :     pub const fn add(&self, x: u32) -> Key {
     151     26579984 :         let mut key = *self;
     152     26579984 : 
     153     26579984 :         let r = key.field6.overflowing_add(x);
     154     26579984 :         key.field6 = r.0;
     155     26579984 :         if r.1 {
     156      2481330 :             let r = key.field5.overflowing_add(1);
     157      2481330 :             key.field5 = r.0;
     158      2481330 :             if r.1 {
     159            0 :                 let r = key.field4.overflowing_add(1);
     160            0 :                 key.field4 = r.0;
     161            0 :                 if r.1 {
     162            0 :                     let r = key.field3.overflowing_add(1);
     163            0 :                     key.field3 = r.0;
     164            0 :                     if r.1 {
     165            0 :                         let r = key.field2.overflowing_add(1);
     166            0 :                         key.field2 = r.0;
     167            0 :                         if r.1 {
     168            0 :                             let r = key.field1.overflowing_add(1);
     169            0 :                             key.field1 = r.0;
     170            0 :                             assert!(!r.1);
     171            0 :                         }
     172            0 :                     }
     173            0 :                 }
     174      2481330 :             }
     175     24098654 :         }
     176     26579984 :         key
     177     26579984 :     }
     178              : 
     179              :     /// Convert a 18B slice to a key. This function should not be used for 16B metadata keys because `field2` is handled differently.
     180              :     /// Use [`Key::from_i128`] instead if you want to handle 16B keys (i.e., metadata keys). There are some restrictions on `field2`,
     181              :     /// and therefore not all 18B slices are valid page server keys.
     182     17616075 :     pub fn from_slice(b: &[u8]) -> Self {
     183     17616075 :         Key {
     184     17616075 :             field1: b[0],
     185     17616075 :             field2: u32::from_be_bytes(b[1..5].try_into().unwrap()),
     186     17616075 :             field3: u32::from_be_bytes(b[5..9].try_into().unwrap()),
     187     17616075 :             field4: u32::from_be_bytes(b[9..13].try_into().unwrap()),
     188     17616075 :             field5: b[13],
     189     17616075 :             field6: u32::from_be_bytes(b[14..18].try_into().unwrap()),
     190     17616075 :         }
     191     17616075 :     }
     192              : 
     193              :     /// Convert a key to a 18B slice. This function should not be used for getting a 16B metadata key because `field2` is handled differently.
     194              :     /// Use [`Key::to_i128`] instead if you want to get a 16B key (i.e., metadata keys).
     195     21882626 :     pub fn write_to_byte_slice(&self, buf: &mut [u8]) {
     196     21882626 :         buf[0] = self.field1;
     197     21882626 :         BE::write_u32(&mut buf[1..5], self.field2);
     198     21882626 :         BE::write_u32(&mut buf[5..9], self.field3);
     199     21882626 :         BE::write_u32(&mut buf[9..13], self.field4);
     200     21882626 :         buf[13] = self.field5;
     201     21882626 :         BE::write_u32(&mut buf[14..18], self.field6);
     202     21882626 :     }
     203              : }
     204              : 
     205              : impl fmt::Display for Key {
     206      1124908 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     207      1124908 :         write!(
     208      1124908 :             f,
     209      1124908 :             "{:02X}{:08X}{:08X}{:08X}{:02X}{:08X}",
     210      1124908 :             self.field1, self.field2, self.field3, self.field4, self.field5, self.field6
     211      1124908 :         )
     212      1124908 :     }
     213              : }
     214              : 
     215              : impl fmt::Display for CompactKey {
     216            0 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     217            0 :         let k = Key::from_compact(*self);
     218            0 :         k.fmt(f)
     219            0 :     }
     220              : }
     221              : 
     222              : impl Key {
     223              :     pub const MIN: Key = Key {
     224              :         field1: u8::MIN,
     225              :         field2: u32::MIN,
     226              :         field3: u32::MIN,
     227              :         field4: u32::MIN,
     228              :         field5: u8::MIN,
     229              :         field6: u32::MIN,
     230              :     };
     231              :     pub const MAX: Key = Key {
     232              :         field1: u8::MAX,
     233              :         field2: u32::MAX,
     234              :         field3: u32::MAX,
     235              :         field4: u32::MAX,
     236              :         field5: u8::MAX,
     237              :         field6: u32::MAX,
     238              :     };
     239              :     /// A key slightly smaller than [`Key::MAX`] for use in layer key ranges to avoid them to be confused with L0 layers
     240              :     pub const NON_L0_MAX: Key = Key {
     241              :         field1: u8::MAX,
     242              :         field2: u32::MAX,
     243              :         field3: u32::MAX,
     244              :         field4: u32::MAX,
     245              :         field5: u8::MAX,
     246              :         field6: u32::MAX - 1,
     247              :     };
     248              : 
     249       120042 :     pub fn from_hex(s: &str) -> Result<Self> {
     250       120042 :         if s.len() != 36 {
     251           24 :             bail!("parse error");
     252       120018 :         }
     253       120018 :         Ok(Key {
     254       120018 :             field1: u8::from_str_radix(&s[0..2], 16)?,
     255       120018 :             field2: u32::from_str_radix(&s[2..10], 16)?,
     256       120018 :             field3: u32::from_str_radix(&s[10..18], 16)?,
     257       120018 :             field4: u32::from_str_radix(&s[18..26], 16)?,
     258       120018 :             field5: u8::from_str_radix(&s[26..28], 16)?,
     259       120018 :             field6: u32::from_str_radix(&s[28..36], 16)?,
     260              :         })
     261       120042 :     }
     262              : }
     263              : 
     264              : // Layout of the Key address space
     265              : //
     266              : // The Key struct, used to address the underlying key-value store, consists of
     267              : // 18 bytes, split into six fields. See 'Key' in repository.rs. We need to map
     268              : // all the data and metadata keys into those 18 bytes.
     269              : //
     270              : // Principles for the mapping:
     271              : //
     272              : // - Things that are often accessed or modified together, should be close to
     273              : //   each other in the key space. For example, if a relation is extended by one
     274              : //   block, we create a new key-value pair for the block data, and update the
     275              : //   relation size entry. Because of that, the RelSize key comes after all the
     276              : //   RelBlocks of a relation: the RelSize and the last RelBlock are always next
     277              : //   to each other.
     278              : //
     279              : // The key space is divided into four major sections, identified by the first
     280              : // byte, and the form a hierarchy:
     281              : //
     282              : // 00 Relation data and metadata
     283              : //
     284              : //   DbDir    () -> (dbnode, spcnode)
     285              : //   Filenodemap
     286              : //   RelDir   -> relnode forknum
     287              : //       RelBlocks
     288              : //       RelSize
     289              : //
     290              : // 01 SLRUs
     291              : //
     292              : //   SlruDir  kind
     293              : //   SlruSegBlocks segno
     294              : //   SlruSegSize
     295              : //
     296              : // 02 pg_twophase
     297              : //
     298              : // 03 misc
     299              : //    Controlfile
     300              : //    checkpoint
     301              : //    pg_version
     302              : //
     303              : // 04 aux files
     304              : //
     305              : // Below is a full list of the keyspace allocation:
     306              : //
     307              : // DbDir:
     308              : // 00 00000000 00000000 00000000 00   00000000
     309              : //
     310              : // Filenodemap:
     311              : // 00 SPCNODE  DBNODE   00000000 00   00000000
     312              : //
     313              : // RelDir:
     314              : // 00 SPCNODE  DBNODE   00000000 00   00000001 (Postgres never uses relfilenode 0)
     315              : //
     316              : // RelBlock:
     317              : // 00 SPCNODE  DBNODE   RELNODE  FORK BLKNUM
     318              : //
     319              : // RelSize:
     320              : // 00 SPCNODE  DBNODE   RELNODE  FORK FFFFFFFF
     321              : //
     322              : // SlruDir:
     323              : // 01 kind     00000000 00000000 00   00000000
     324              : //
     325              : // SlruSegBlock:
     326              : // 01 kind     00000001 SEGNO    00   BLKNUM
     327              : //
     328              : // SlruSegSize:
     329              : // 01 kind     00000001 SEGNO    00   FFFFFFFF
     330              : //
     331              : // TwoPhaseDir:
     332              : // 02 00000000 00000000 00000000 00   00000000
     333              : //
     334              : // TwoPhaseFile:
     335              : // 02 00000000 00000000 00000000 00   XID
     336              : //
     337              : // ControlFile:
     338              : // 03 00000000 00000000 00000000 00   00000000
     339              : //
     340              : // Checkpoint:
     341              : // 03 00000000 00000000 00000000 00   00000001
     342              : //
     343              : // AuxFiles:
     344              : // 03 00000000 00000000 00000000 00   00000002
     345              : //
     346              : 
     347              : //-- Section 01: relation data and metadata
     348              : 
     349              : pub const DBDIR_KEY: Key = Key {
     350              :     field1: 0x00,
     351              :     field2: 0,
     352              :     field3: 0,
     353              :     field4: 0,
     354              :     field5: 0,
     355              :     field6: 0,
     356              : };
     357              : 
     358              : #[inline(always)]
     359            0 : pub fn dbdir_key_range(spcnode: Oid, dbnode: Oid) -> Range<Key> {
     360            0 :     Key {
     361            0 :         field1: 0x00,
     362            0 :         field2: spcnode,
     363            0 :         field3: dbnode,
     364            0 :         field4: 0,
     365            0 :         field5: 0,
     366            0 :         field6: 0,
     367            0 :     }..Key {
     368            0 :         field1: 0x00,
     369            0 :         field2: spcnode,
     370            0 :         field3: dbnode,
     371            0 :         field4: 0xffffffff,
     372            0 :         field5: 0xff,
     373            0 :         field6: 0xffffffff,
     374            0 :     }
     375            0 : }
     376              : 
     377              : #[inline(always)]
     378           48 : pub fn relmap_file_key(spcnode: Oid, dbnode: Oid) -> Key {
     379           48 :     Key {
     380           48 :         field1: 0x00,
     381           48 :         field2: spcnode,
     382           48 :         field3: dbnode,
     383           48 :         field4: 0,
     384           48 :         field5: 0,
     385           48 :         field6: 0,
     386           48 :     }
     387           48 : }
     388              : 
     389              : #[inline(always)]
     390         5844 : pub fn rel_dir_to_key(spcnode: Oid, dbnode: Oid) -> Key {
     391         5844 :     Key {
     392         5844 :         field1: 0x00,
     393         5844 :         field2: spcnode,
     394         5844 :         field3: dbnode,
     395         5844 :         field4: 0,
     396         5844 :         field5: 0,
     397         5844 :         field6: 1,
     398         5844 :     }
     399         5844 : }
     400              : 
     401              : #[inline(always)]
     402      2612322 : pub fn rel_block_to_key(rel: RelTag, blknum: BlockNumber) -> Key {
     403      2612322 :     Key {
     404      2612322 :         field1: 0x00,
     405      2612322 :         field2: rel.spcnode,
     406      2612322 :         field3: rel.dbnode,
     407      2612322 :         field4: rel.relnode,
     408      2612322 :         field5: rel.forknum,
     409      2612322 :         field6: blknum,
     410      2612322 :     }
     411      2612322 : }
     412              : 
     413              : #[inline(always)]
     414       869262 : pub fn rel_size_to_key(rel: RelTag) -> Key {
     415       869262 :     Key {
     416       869262 :         field1: 0x00,
     417       869262 :         field2: rel.spcnode,
     418       869262 :         field3: rel.dbnode,
     419       869262 :         field4: rel.relnode,
     420       869262 :         field5: rel.forknum,
     421       869262 :         field6: 0xffff_ffff,
     422       869262 :     }
     423       869262 : }
     424              : 
     425              : impl Key {
     426              :     #[inline(always)]
     427            0 :     pub fn is_rel_size_key(&self) -> bool {
     428            0 :         self.field1 == 0 && self.field6 == u32::MAX
     429            0 :     }
     430              : }
     431              : 
     432              : #[inline(always)]
     433            6 : pub fn rel_key_range(rel: RelTag) -> Range<Key> {
     434            6 :     Key {
     435            6 :         field1: 0x00,
     436            6 :         field2: rel.spcnode,
     437            6 :         field3: rel.dbnode,
     438            6 :         field4: rel.relnode,
     439            6 :         field5: rel.forknum,
     440            6 :         field6: 0,
     441            6 :     }..Key {
     442            6 :         field1: 0x00,
     443            6 :         field2: rel.spcnode,
     444            6 :         field3: rel.dbnode,
     445            6 :         field4: rel.relnode,
     446            6 :         field5: rel.forknum + 1,
     447            6 :         field6: 0,
     448            6 :     }
     449            6 : }
     450              : 
     451              : //-- Section 02: SLRUs
     452              : 
     453              : #[inline(always)]
     454         4176 : pub fn slru_dir_to_key(kind: SlruKind) -> Key {
     455         4176 :     Key {
     456         4176 :         field1: 0x01,
     457         4176 :         field2: match kind {
     458         1392 :             SlruKind::Clog => 0x00,
     459         1392 :             SlruKind::MultiXactMembers => 0x01,
     460         1392 :             SlruKind::MultiXactOffsets => 0x02,
     461              :         },
     462              :         field3: 0,
     463              :         field4: 0,
     464              :         field5: 0,
     465              :         field6: 0,
     466              :     }
     467         4176 : }
     468              : 
     469              : #[inline(always)]
     470            0 : pub fn slru_dir_kind(key: &Key) -> Option<Result<SlruKind, u32>> {
     471            0 :     if key.field1 == 0x01
     472            0 :         && key.field3 == 0
     473            0 :         && key.field4 == 0
     474            0 :         && key.field5 == 0
     475            0 :         && key.field6 == 0
     476              :     {
     477            0 :         match key.field2 {
     478            0 :             0 => Some(Ok(SlruKind::Clog)),
     479            0 :             1 => Some(Ok(SlruKind::MultiXactMembers)),
     480            0 :             2 => Some(Ok(SlruKind::MultiXactOffsets)),
     481            0 :             x => Some(Err(x)),
     482              :         }
     483              :     } else {
     484            0 :         None
     485              :     }
     486            0 : }
     487              : 
     488              : #[inline(always)]
     489           42 : pub fn slru_block_to_key(kind: SlruKind, segno: u32, blknum: BlockNumber) -> Key {
     490           42 :     Key {
     491           42 :         field1: 0x01,
     492           42 :         field2: match kind {
     493           30 :             SlruKind::Clog => 0x00,
     494            6 :             SlruKind::MultiXactMembers => 0x01,
     495            6 :             SlruKind::MultiXactOffsets => 0x02,
     496              :         },
     497              :         field3: 1,
     498           42 :         field4: segno,
     499           42 :         field5: 0,
     500           42 :         field6: blknum,
     501           42 :     }
     502           42 : }
     503              : 
     504              : #[inline(always)]
     505           18 : pub fn slru_segment_size_to_key(kind: SlruKind, segno: u32) -> Key {
     506           18 :     Key {
     507           18 :         field1: 0x01,
     508           18 :         field2: match kind {
     509            6 :             SlruKind::Clog => 0x00,
     510            6 :             SlruKind::MultiXactMembers => 0x01,
     511            6 :             SlruKind::MultiXactOffsets => 0x02,
     512              :         },
     513              :         field3: 1,
     514           18 :         field4: segno,
     515           18 :         field5: 0,
     516           18 :         field6: 0xffff_ffff,
     517           18 :     }
     518           18 : }
     519              : 
     520              : impl Key {
     521            0 :     pub fn is_slru_segment_size_key(&self) -> bool {
     522            0 :         self.field1 == 0x01
     523            0 :             && self.field2 < 0x03
     524            0 :             && self.field3 == 0x01
     525            0 :             && self.field5 == 0
     526            0 :             && self.field6 == u32::MAX
     527            0 :     }
     528              : }
     529              : 
     530              : #[inline(always)]
     531            0 : pub fn slru_segment_key_range(kind: SlruKind, segno: u32) -> Range<Key> {
     532            0 :     let field2 = match kind {
     533            0 :         SlruKind::Clog => 0x00,
     534            0 :         SlruKind::MultiXactMembers => 0x01,
     535            0 :         SlruKind::MultiXactOffsets => 0x02,
     536              :     };
     537              : 
     538            0 :     Key {
     539            0 :         field1: 0x01,
     540            0 :         field2,
     541            0 :         field3: 1,
     542            0 :         field4: segno,
     543            0 :         field5: 0,
     544            0 :         field6: 0,
     545            0 :     }..Key {
     546            0 :         field1: 0x01,
     547            0 :         field2,
     548            0 :         field3: 1,
     549            0 :         field4: segno,
     550            0 :         field5: 1,
     551            0 :         field6: 0,
     552            0 :     }
     553            0 : }
     554              : 
     555              : //-- Section 03: pg_twophase
     556              : 
     557              : pub const TWOPHASEDIR_KEY: Key = Key {
     558              :     field1: 0x02,
     559              :     field2: 0,
     560              :     field3: 0,
     561              :     field4: 0,
     562              :     field5: 0,
     563              :     field6: 0,
     564              : };
     565              : 
     566              : #[inline(always)]
     567            0 : pub fn twophase_file_key(xid: TransactionId) -> Key {
     568            0 :     Key {
     569            0 :         field1: 0x02,
     570            0 :         field2: 0,
     571            0 :         field3: 0,
     572            0 :         field4: 0,
     573            0 :         field5: 0,
     574            0 :         field6: xid,
     575            0 :     }
     576            0 : }
     577              : 
     578              : #[inline(always)]
     579            0 : pub fn twophase_key_range(xid: TransactionId) -> Range<Key> {
     580            0 :     let (next_xid, overflowed) = xid.overflowing_add(1);
     581            0 : 
     582            0 :     Key {
     583            0 :         field1: 0x02,
     584            0 :         field2: 0,
     585            0 :         field3: 0,
     586            0 :         field4: 0,
     587            0 :         field5: 0,
     588            0 :         field6: xid,
     589            0 :     }..Key {
     590            0 :         field1: 0x02,
     591            0 :         field2: 0,
     592            0 :         field3: 0,
     593            0 :         field4: 0,
     594            0 :         field5: u8::from(overflowed),
     595            0 :         field6: next_xid,
     596            0 :     }
     597            0 : }
     598              : 
     599              : //-- Section 03: Control file
     600              : pub const CONTROLFILE_KEY: Key = Key {
     601              :     field1: 0x03,
     602              :     field2: 0,
     603              :     field3: 0,
     604              :     field4: 0,
     605              :     field5: 0,
     606              :     field6: 0,
     607              : };
     608              : 
     609              : pub const CHECKPOINT_KEY: Key = Key {
     610              :     field1: 0x03,
     611              :     field2: 0,
     612              :     field3: 0,
     613              :     field4: 0,
     614              :     field5: 0,
     615              :     field6: 1,
     616              : };
     617              : 
     618              : pub const AUX_FILES_KEY: Key = Key {
     619              :     field1: 0x03,
     620              :     field2: 0,
     621              :     field3: 0,
     622              :     field4: 0,
     623              :     field5: 0,
     624              :     field6: 2,
     625              : };
     626              : 
     627              : #[inline(always)]
     628            0 : pub fn repl_origin_key(origin_id: RepOriginId) -> Key {
     629            0 :     Key {
     630            0 :         field1: REPL_ORIGIN_KEY_PREFIX,
     631            0 :         field2: 0,
     632            0 :         field3: 0,
     633            0 :         field4: 0,
     634            0 :         field5: 0,
     635            0 :         field6: origin_id as u32,
     636            0 :     }
     637            0 : }
     638              : 
     639              : /// Get the range of replorigin keys.
     640          864 : pub fn repl_origin_key_range() -> Range<Key> {
     641          864 :     Key {
     642          864 :         field1: REPL_ORIGIN_KEY_PREFIX,
     643          864 :         field2: 0,
     644          864 :         field3: 0,
     645          864 :         field4: 0,
     646          864 :         field5: 0,
     647          864 :         field6: 0,
     648          864 :     }..Key {
     649          864 :         field1: REPL_ORIGIN_KEY_PREFIX,
     650          864 :         field2: 0,
     651          864 :         field3: 0,
     652          864 :         field4: 0,
     653          864 :         field5: 0,
     654          864 :         field6: 0x10000,
     655          864 :     }
     656          864 : }
     657              : 
     658              : // Reverse mappings for a few Keys.
     659              : // These are needed by WAL redo manager.
     660              : 
     661              : /// Non inherited range for vectored get.
     662              : pub const NON_INHERITED_RANGE: Range<Key> = AUX_FILES_KEY..AUX_FILES_KEY.next();
     663              : /// Sparse keyspace range for vectored get. Missing key error will be ignored for this range.
     664              : pub const NON_INHERITED_SPARSE_RANGE: Range<Key> = Key::metadata_key_range();
     665              : 
     666              : impl Key {
     667              :     // AUX_FILES currently stores only data for logical replication (slots etc), and
     668              :     // we don't preserve these on a branch because safekeepers can't follow timeline
     669              :     // switch (and generally it likely should be optional), so ignore these.
     670              :     #[inline(always)]
     671            0 :     pub fn is_inherited_key(self) -> bool {
     672            0 :         !NON_INHERITED_RANGE.contains(&self) && !NON_INHERITED_SPARSE_RANGE.contains(&self)
     673            0 :     }
     674              : 
     675              :     #[inline(always)]
     676            0 :     pub fn is_rel_fsm_block_key(self) -> bool {
     677            0 :         self.field1 == 0x00
     678            0 :             && self.field4 != 0
     679            0 :             && self.field5 == FSM_FORKNUM
     680            0 :             && self.field6 != 0xffffffff
     681            0 :     }
     682              : 
     683              :     #[inline(always)]
     684            0 :     pub fn is_rel_vm_block_key(self) -> bool {
     685            0 :         self.field1 == 0x00
     686            0 :             && self.field4 != 0
     687            0 :             && self.field5 == VISIBILITYMAP_FORKNUM
     688            0 :             && self.field6 != 0xffffffff
     689            0 :     }
     690              : 
     691              :     #[inline(always)]
     692            0 :     pub fn to_slru_block(self) -> anyhow::Result<(SlruKind, u32, BlockNumber)> {
     693            0 :         Ok(match self.field1 {
     694              :             0x01 => {
     695            0 :                 let kind = match self.field2 {
     696            0 :                     0x00 => SlruKind::Clog,
     697            0 :                     0x01 => SlruKind::MultiXactMembers,
     698            0 :                     0x02 => SlruKind::MultiXactOffsets,
     699            0 :                     _ => anyhow::bail!("unrecognized slru kind 0x{:02x}", self.field2),
     700              :                 };
     701            0 :                 let segno = self.field4;
     702            0 :                 let blknum = self.field6;
     703            0 : 
     704            0 :                 (kind, segno, blknum)
     705              :             }
     706            0 :             _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
     707              :         })
     708            0 :     }
     709              : 
     710              :     #[inline(always)]
     711            0 :     pub fn is_slru_block_key(self) -> bool {
     712            0 :         self.field1 == 0x01                // SLRU-related
     713            0 :         && self.field3 == 0x00000001   // but not SlruDir
     714            0 :         && self.field6 != 0xffffffff // and not SlruSegSize
     715            0 :     }
     716              : 
     717              :     #[inline(always)]
     718     17552112 :     pub fn is_rel_block_key(&self) -> bool {
     719     17552112 :         self.field1 == 0x00 && self.field4 != 0 && self.field6 != 0xffffffff
     720     17552112 :     }
     721              : 
     722              :     /// Guaranteed to return `Ok()` if [`Self::is_rel_block_key`] returns `true` for `key`.
     723              :     #[inline(always)]
     724           18 :     pub fn to_rel_block(self) -> anyhow::Result<(RelTag, BlockNumber)> {
     725           18 :         Ok(match self.field1 {
     726           18 :             0x00 => (
     727           18 :                 RelTag {
     728           18 :                     spcnode: self.field2,
     729           18 :                     dbnode: self.field3,
     730           18 :                     relnode: self.field4,
     731           18 :                     forknum: self.field5,
     732           18 :                 },
     733           18 :                 self.field6,
     734           18 :             ),
     735            0 :             _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
     736              :         })
     737           18 :     }
     738              : }
     739              : 
     740              : impl std::str::FromStr for Key {
     741              :     type Err = anyhow::Error;
     742              : 
     743           54 :     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
     744           54 :         Self::from_hex(s)
     745           54 :     }
     746              : }
     747              : 
     748              : #[cfg(test)]
     749              : mod tests {
     750              :     use std::str::FromStr;
     751              : 
     752              :     use crate::key::is_metadata_key_slice;
     753              :     use crate::key::Key;
     754              : 
     755              :     use rand::Rng;
     756              :     use rand::SeedableRng;
     757              : 
     758              :     use super::AUX_KEY_PREFIX;
     759              : 
     760              :     #[test]
     761            6 :     fn display_fromstr_bijection() {
     762            6 :         let mut rng = rand::rngs::StdRng::seed_from_u64(42);
     763            6 : 
     764            6 :         let key = Key {
     765            6 :             field1: rng.gen(),
     766            6 :             field2: rng.gen(),
     767            6 :             field3: rng.gen(),
     768            6 :             field4: rng.gen(),
     769            6 :             field5: rng.gen(),
     770            6 :             field6: rng.gen(),
     771            6 :         };
     772            6 : 
     773            6 :         assert_eq!(key, Key::from_str(&format!("{key}")).unwrap());
     774            6 :     }
     775              : 
     776              :     #[test]
     777            6 :     fn test_metadata_keys() {
     778            6 :         let mut metadata_key = vec![AUX_KEY_PREFIX];
     779            6 :         metadata_key.extend_from_slice(&[0xFF; 15]);
     780            6 :         let encoded_key = Key::from_metadata_key(&metadata_key);
     781            6 :         let output_key = encoded_key.to_i128().to_be_bytes();
     782            6 :         assert_eq!(metadata_key, output_key);
     783            6 :         assert!(encoded_key.is_metadata_key());
     784            6 :         assert!(is_metadata_key_slice(&metadata_key));
     785            6 :     }
     786              : 
     787              :     #[test]
     788            6 :     fn test_possible_largest_key() {
     789            6 :         Key::from_i128(0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF);
     790            6 :         // TODO: put this key into the system and see if anything breaks.
     791            6 :     }
     792              : }
        

Generated by: LCOV version 2.1-beta