LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - key.rs (source / functions) Coverage Total Hit
Test: ccf45ed1c149555259baec52d6229a81013dcd6a.info Lines: 64.4 % 432 278
Test Date: 2024-08-21 17:32:46 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         2296 : #[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           38 : pub const fn is_metadata_key_slice(key: &[u8]) -> bool {
      52           38 :     key[0] >= METADATA_KEY_BEGIN_PREFIX && key[0] < METADATA_KEY_END_PREFIX
      53           38 : }
      54              : 
      55              : impl Key {
      56              :     /// Check if the key falls in the range of metadata keys.
      57           74 :     pub const fn is_metadata_key(&self) -> bool {
      58           74 :         self.field1 >= METADATA_KEY_BEGIN_PREFIX && self.field1 < METADATA_KEY_END_PREFIX
      59           74 :     }
      60              : 
      61              :     /// Encode a metadata key to a storage key.
      62           36 :     pub fn from_metadata_key_fixed_size(key: &[u8; METADATA_KEY_SIZE]) -> Self {
      63           36 :         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           36 :         Self::from_i128(i128::from_be_bytes(*key))
      66           36 :     }
      67              : 
      68              :     /// Encode a metadata key to a storage key.
      69            2 :     pub fn from_metadata_key(key: &[u8]) -> Self {
      70            2 :         Self::from_metadata_key_fixed_size(key.try_into().expect("expect 16 byte metadata key"))
      71            2 :     }
      72              : 
      73              :     /// Get the range of metadata keys.
      74          920 :     pub const fn metadata_key_range() -> Range<Self> {
      75          920 :         Key {
      76          920 :             field1: METADATA_KEY_BEGIN_PREFIX,
      77          920 :             field2: 0,
      78          920 :             field3: 0,
      79          920 :             field4: 0,
      80          920 :             field5: 0,
      81          920 :             field6: 0,
      82          920 :         }..Key {
      83          920 :             field1: METADATA_KEY_END_PREFIX,
      84          920 :             field2: 0,
      85          920 :             field3: 0,
      86          920 :             field4: 0,
      87          920 :             field5: 0,
      88          920 :             field6: 0,
      89          920 :         }
      90          920 :     }
      91              : 
      92              :     /// Get the range of aux keys.
      93          294 :     pub fn metadata_aux_key_range() -> Range<Self> {
      94          294 :         Key {
      95          294 :             field1: AUX_KEY_PREFIX,
      96          294 :             field2: 0,
      97          294 :             field3: 0,
      98          294 :             field4: 0,
      99          294 :             field5: 0,
     100          294 :             field6: 0,
     101          294 :         }..Key {
     102          294 :             field1: AUX_KEY_PREFIX + 1,
     103          294 :             field2: 0,
     104          294 :             field3: 0,
     105          294 :             field4: 0,
     106          294 :             field5: 0,
     107          294 :             field6: 0,
     108          294 :         }
     109          294 :     }
     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     11195674 :     pub fn to_i128(&self) -> i128 {
     115     11195674 :         assert!(
     116     11195674 :             self.field2 <= 0xFFFF || self.field2 == 0xFFFFFFFF || self.field2 == 0x22222222,
     117            0 :             "invalid key: {self}",
     118              :         );
     119     11195674 :         (((self.field1 & 0x7F) as i128) << 120)
     120     11195674 :             | (((self.field2 & 0xFFFF) as i128) << 104)
     121     11195674 :             | ((self.field3 as i128) << 72)
     122     11195674 :             | ((self.field4 as i128) << 40)
     123     11195674 :             | ((self.field5 as i128) << 32)
     124     11195674 :             | self.field6 as i128
     125     11195674 :     }
     126              : 
     127      5460250 :     pub const fn from_i128(x: i128) -> Self {
     128      5460250 :         Key {
     129      5460250 :             field1: ((x >> 120) & 0x7F) as u8,
     130      5460250 :             field2: ((x >> 104) & 0xFFFF) as u32,
     131      5460250 :             field3: (x >> 72) as u32,
     132      5460250 :             field4: (x >> 40) as u32,
     133      5460250 :             field5: (x >> 32) as u8,
     134      5460250 :             field6: x as u32,
     135      5460250 :         }
     136      5460250 :     }
     137              : 
     138      6303228 :     pub fn to_compact(&self) -> CompactKey {
     139      6303228 :         CompactKey(self.to_i128())
     140      6303228 :     }
     141              : 
     142      4884526 :     pub fn from_compact(k: CompactKey) -> Self {
     143      4884526 :         Self::from_i128(k.0)
     144      4884526 :     }
     145              : 
     146      8842852 :     pub const fn next(&self) -> Key {
     147      8842852 :         self.add(1)
     148      8842852 :     }
     149              : 
     150      8860368 :     pub const fn add(&self, x: u32) -> Key {
     151      8860368 :         let mut key = *self;
     152      8860368 : 
     153      8860368 :         let r = key.field6.overflowing_add(x);
     154      8860368 :         key.field6 = r.0;
     155      8860368 :         if r.1 {
     156       827110 :             let r = key.field5.overflowing_add(1);
     157       827110 :             key.field5 = r.0;
     158       827110 :             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       827110 :             }
     175      8033258 :         }
     176      8860368 :         key
     177      8860368 :     }
     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      5871446 :     pub fn from_slice(b: &[u8]) -> Self {
     183      5871446 :         Key {
     184      5871446 :             field1: b[0],
     185      5871446 :             field2: u32::from_be_bytes(b[1..5].try_into().unwrap()),
     186      5871446 :             field3: u32::from_be_bytes(b[5..9].try_into().unwrap()),
     187      5871446 :             field4: u32::from_be_bytes(b[9..13].try_into().unwrap()),
     188      5871446 :             field5: b[13],
     189      5871446 :             field6: u32::from_be_bytes(b[14..18].try_into().unwrap()),
     190      5871446 :         }
     191      5871446 :     }
     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      7281354 :     pub fn write_to_byte_slice(&self, buf: &mut [u8]) {
     196      7281354 :         buf[0] = self.field1;
     197      7281354 :         BE::write_u32(&mut buf[1..5], self.field2);
     198      7281354 :         BE::write_u32(&mut buf[5..9], self.field3);
     199      7281354 :         BE::write_u32(&mut buf[9..13], self.field4);
     200      7281354 :         buf[13] = self.field5;
     201      7281354 :         BE::write_u32(&mut buf[14..18], self.field6);
     202      7281354 :     }
     203              : }
     204              : 
     205              : impl fmt::Display for Key {
     206       374514 :     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
     207       374514 :         write!(
     208       374514 :             f,
     209       374514 :             "{:02X}{:08X}{:08X}{:08X}{:02X}{:08X}",
     210       374514 :             self.field1, self.field2, self.field3, self.field4, self.field5, self.field6
     211       374514 :         )
     212       374514 :     }
     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              : 
     240        27654 :     pub fn from_hex(s: &str) -> Result<Self> {
     241        27654 :         if s.len() != 36 {
     242            8 :             bail!("parse error");
     243        27646 :         }
     244        27646 :         Ok(Key {
     245        27646 :             field1: u8::from_str_radix(&s[0..2], 16)?,
     246        27646 :             field2: u32::from_str_radix(&s[2..10], 16)?,
     247        27646 :             field3: u32::from_str_radix(&s[10..18], 16)?,
     248        27646 :             field4: u32::from_str_radix(&s[18..26], 16)?,
     249        27646 :             field5: u8::from_str_radix(&s[26..28], 16)?,
     250        27646 :             field6: u32::from_str_radix(&s[28..36], 16)?,
     251              :         })
     252        27654 :     }
     253              : }
     254              : 
     255              : // Layout of the Key address space
     256              : //
     257              : // The Key struct, used to address the underlying key-value store, consists of
     258              : // 18 bytes, split into six fields. See 'Key' in repository.rs. We need to map
     259              : // all the data and metadata keys into those 18 bytes.
     260              : //
     261              : // Principles for the mapping:
     262              : //
     263              : // - Things that are often accessed or modified together, should be close to
     264              : //   each other in the key space. For example, if a relation is extended by one
     265              : //   block, we create a new key-value pair for the block data, and update the
     266              : //   relation size entry. Because of that, the RelSize key comes after all the
     267              : //   RelBlocks of a relation: the RelSize and the last RelBlock are always next
     268              : //   to each other.
     269              : //
     270              : // The key space is divided into four major sections, identified by the first
     271              : // byte, and the form a hierarchy:
     272              : //
     273              : // 00 Relation data and metadata
     274              : //
     275              : //   DbDir    () -> (dbnode, spcnode)
     276              : //   Filenodemap
     277              : //   RelDir   -> relnode forknum
     278              : //       RelBlocks
     279              : //       RelSize
     280              : //
     281              : // 01 SLRUs
     282              : //
     283              : //   SlruDir  kind
     284              : //   SlruSegBlocks segno
     285              : //   SlruSegSize
     286              : //
     287              : // 02 pg_twophase
     288              : //
     289              : // 03 misc
     290              : //    Controlfile
     291              : //    checkpoint
     292              : //    pg_version
     293              : //
     294              : // 04 aux files
     295              : //
     296              : // Below is a full list of the keyspace allocation:
     297              : //
     298              : // DbDir:
     299              : // 00 00000000 00000000 00000000 00   00000000
     300              : //
     301              : // Filenodemap:
     302              : // 00 SPCNODE  DBNODE   00000000 00   00000000
     303              : //
     304              : // RelDir:
     305              : // 00 SPCNODE  DBNODE   00000000 00   00000001 (Postgres never uses relfilenode 0)
     306              : //
     307              : // RelBlock:
     308              : // 00 SPCNODE  DBNODE   RELNODE  FORK BLKNUM
     309              : //
     310              : // RelSize:
     311              : // 00 SPCNODE  DBNODE   RELNODE  FORK FFFFFFFF
     312              : //
     313              : // SlruDir:
     314              : // 01 kind     00000000 00000000 00   00000000
     315              : //
     316              : // SlruSegBlock:
     317              : // 01 kind     00000001 SEGNO    00   BLKNUM
     318              : //
     319              : // SlruSegSize:
     320              : // 01 kind     00000001 SEGNO    00   FFFFFFFF
     321              : //
     322              : // TwoPhaseDir:
     323              : // 02 00000000 00000000 00000000 00   00000000
     324              : //
     325              : // TwoPhaseFile:
     326              : // 02 00000000 00000000 00000000 00   XID
     327              : //
     328              : // ControlFile:
     329              : // 03 00000000 00000000 00000000 00   00000000
     330              : //
     331              : // Checkpoint:
     332              : // 03 00000000 00000000 00000000 00   00000001
     333              : //
     334              : // AuxFiles:
     335              : // 03 00000000 00000000 00000000 00   00000002
     336              : //
     337              : 
     338              : //-- Section 01: relation data and metadata
     339              : 
     340              : pub const DBDIR_KEY: Key = Key {
     341              :     field1: 0x00,
     342              :     field2: 0,
     343              :     field3: 0,
     344              :     field4: 0,
     345              :     field5: 0,
     346              :     field6: 0,
     347              : };
     348              : 
     349              : #[inline(always)]
     350            0 : pub fn dbdir_key_range(spcnode: Oid, dbnode: Oid) -> Range<Key> {
     351            0 :     Key {
     352            0 :         field1: 0x00,
     353            0 :         field2: spcnode,
     354            0 :         field3: dbnode,
     355            0 :         field4: 0,
     356            0 :         field5: 0,
     357            0 :         field6: 0,
     358            0 :     }..Key {
     359            0 :         field1: 0x00,
     360            0 :         field2: spcnode,
     361            0 :         field3: dbnode,
     362            0 :         field4: 0xffffffff,
     363            0 :         field5: 0xff,
     364            0 :         field6: 0xffffffff,
     365            0 :     }
     366            0 : }
     367              : 
     368              : #[inline(always)]
     369           16 : pub fn relmap_file_key(spcnode: Oid, dbnode: Oid) -> Key {
     370           16 :     Key {
     371           16 :         field1: 0x00,
     372           16 :         field2: spcnode,
     373           16 :         field3: dbnode,
     374           16 :         field4: 0,
     375           16 :         field5: 0,
     376           16 :         field6: 0,
     377           16 :     }
     378           16 : }
     379              : 
     380              : #[inline(always)]
     381         1948 : pub fn rel_dir_to_key(spcnode: Oid, dbnode: Oid) -> Key {
     382         1948 :     Key {
     383         1948 :         field1: 0x00,
     384         1948 :         field2: spcnode,
     385         1948 :         field3: dbnode,
     386         1948 :         field4: 0,
     387         1948 :         field5: 0,
     388         1948 :         field6: 1,
     389         1948 :     }
     390         1948 : }
     391              : 
     392              : #[inline(always)]
     393       870774 : pub fn rel_block_to_key(rel: RelTag, blknum: BlockNumber) -> Key {
     394       870774 :     Key {
     395       870774 :         field1: 0x00,
     396       870774 :         field2: rel.spcnode,
     397       870774 :         field3: rel.dbnode,
     398       870774 :         field4: rel.relnode,
     399       870774 :         field5: rel.forknum,
     400       870774 :         field6: blknum,
     401       870774 :     }
     402       870774 : }
     403              : 
     404              : #[inline(always)]
     405       289754 : pub fn rel_size_to_key(rel: RelTag) -> Key {
     406       289754 :     Key {
     407       289754 :         field1: 0x00,
     408       289754 :         field2: rel.spcnode,
     409       289754 :         field3: rel.dbnode,
     410       289754 :         field4: rel.relnode,
     411       289754 :         field5: rel.forknum,
     412       289754 :         field6: 0xffff_ffff,
     413       289754 :     }
     414       289754 : }
     415              : 
     416              : impl Key {
     417              :     #[inline(always)]
     418            0 :     pub fn is_rel_size_key(&self) -> bool {
     419            0 :         self.field1 == 0 && self.field6 == u32::MAX
     420            0 :     }
     421              : }
     422              : 
     423              : #[inline(always)]
     424            2 : pub fn rel_key_range(rel: RelTag) -> Range<Key> {
     425            2 :     Key {
     426            2 :         field1: 0x00,
     427            2 :         field2: rel.spcnode,
     428            2 :         field3: rel.dbnode,
     429            2 :         field4: rel.relnode,
     430            2 :         field5: rel.forknum,
     431            2 :         field6: 0,
     432            2 :     }..Key {
     433            2 :         field1: 0x00,
     434            2 :         field2: rel.spcnode,
     435            2 :         field3: rel.dbnode,
     436            2 :         field4: rel.relnode,
     437            2 :         field5: rel.forknum + 1,
     438            2 :         field6: 0,
     439            2 :     }
     440            2 : }
     441              : 
     442              : //-- Section 02: SLRUs
     443              : 
     444              : #[inline(always)]
     445         1356 : pub fn slru_dir_to_key(kind: SlruKind) -> Key {
     446         1356 :     Key {
     447         1356 :         field1: 0x01,
     448         1356 :         field2: match kind {
     449          452 :             SlruKind::Clog => 0x00,
     450          452 :             SlruKind::MultiXactMembers => 0x01,
     451          452 :             SlruKind::MultiXactOffsets => 0x02,
     452              :         },
     453              :         field3: 0,
     454              :         field4: 0,
     455              :         field5: 0,
     456              :         field6: 0,
     457              :     }
     458         1356 : }
     459              : 
     460              : #[inline(always)]
     461            0 : pub fn slru_dir_kind(key: &Key) -> Option<Result<SlruKind, u32>> {
     462            0 :     if key.field1 == 0x01
     463            0 :         && key.field3 == 0
     464            0 :         && key.field4 == 0
     465            0 :         && key.field5 == 0
     466            0 :         && key.field6 == 0
     467              :     {
     468            0 :         match key.field2 {
     469            0 :             0 => Some(Ok(SlruKind::Clog)),
     470            0 :             1 => Some(Ok(SlruKind::MultiXactMembers)),
     471            0 :             2 => Some(Ok(SlruKind::MultiXactOffsets)),
     472            0 :             x => Some(Err(x)),
     473              :         }
     474              :     } else {
     475            0 :         None
     476              :     }
     477            0 : }
     478              : 
     479              : #[inline(always)]
     480           14 : pub fn slru_block_to_key(kind: SlruKind, segno: u32, blknum: BlockNumber) -> Key {
     481           14 :     Key {
     482           14 :         field1: 0x01,
     483           14 :         field2: match kind {
     484           10 :             SlruKind::Clog => 0x00,
     485            2 :             SlruKind::MultiXactMembers => 0x01,
     486            2 :             SlruKind::MultiXactOffsets => 0x02,
     487              :         },
     488              :         field3: 1,
     489           14 :         field4: segno,
     490           14 :         field5: 0,
     491           14 :         field6: blknum,
     492           14 :     }
     493           14 : }
     494              : 
     495              : #[inline(always)]
     496            6 : pub fn slru_segment_size_to_key(kind: SlruKind, segno: u32) -> Key {
     497            6 :     Key {
     498            6 :         field1: 0x01,
     499            6 :         field2: match kind {
     500            2 :             SlruKind::Clog => 0x00,
     501            2 :             SlruKind::MultiXactMembers => 0x01,
     502            2 :             SlruKind::MultiXactOffsets => 0x02,
     503              :         },
     504              :         field3: 1,
     505            6 :         field4: segno,
     506            6 :         field5: 0,
     507            6 :         field6: 0xffff_ffff,
     508            6 :     }
     509            6 : }
     510              : 
     511              : impl Key {
     512            0 :     pub fn is_slru_segment_size_key(&self) -> bool {
     513            0 :         self.field1 == 0x01
     514            0 :             && self.field2 < 0x03
     515            0 :             && self.field3 == 0x01
     516            0 :             && self.field5 == 0
     517            0 :             && self.field6 == u32::MAX
     518            0 :     }
     519              : }
     520              : 
     521              : #[inline(always)]
     522            0 : pub fn slru_segment_key_range(kind: SlruKind, segno: u32) -> Range<Key> {
     523            0 :     let field2 = match kind {
     524            0 :         SlruKind::Clog => 0x00,
     525            0 :         SlruKind::MultiXactMembers => 0x01,
     526            0 :         SlruKind::MultiXactOffsets => 0x02,
     527              :     };
     528              : 
     529            0 :     Key {
     530            0 :         field1: 0x01,
     531            0 :         field2,
     532            0 :         field3: 1,
     533            0 :         field4: segno,
     534            0 :         field5: 0,
     535            0 :         field6: 0,
     536            0 :     }..Key {
     537            0 :         field1: 0x01,
     538            0 :         field2,
     539            0 :         field3: 1,
     540            0 :         field4: segno,
     541            0 :         field5: 1,
     542            0 :         field6: 0,
     543            0 :     }
     544            0 : }
     545              : 
     546              : //-- Section 03: pg_twophase
     547              : 
     548              : pub const TWOPHASEDIR_KEY: Key = Key {
     549              :     field1: 0x02,
     550              :     field2: 0,
     551              :     field3: 0,
     552              :     field4: 0,
     553              :     field5: 0,
     554              :     field6: 0,
     555              : };
     556              : 
     557              : #[inline(always)]
     558            0 : pub fn twophase_file_key(xid: TransactionId) -> Key {
     559            0 :     Key {
     560            0 :         field1: 0x02,
     561            0 :         field2: 0,
     562            0 :         field3: 0,
     563            0 :         field4: 0,
     564            0 :         field5: 0,
     565            0 :         field6: xid,
     566            0 :     }
     567            0 : }
     568              : 
     569              : #[inline(always)]
     570            0 : pub fn twophase_key_range(xid: TransactionId) -> Range<Key> {
     571            0 :     let (next_xid, overflowed) = xid.overflowing_add(1);
     572            0 : 
     573            0 :     Key {
     574            0 :         field1: 0x02,
     575            0 :         field2: 0,
     576            0 :         field3: 0,
     577            0 :         field4: 0,
     578            0 :         field5: 0,
     579            0 :         field6: xid,
     580            0 :     }..Key {
     581            0 :         field1: 0x02,
     582            0 :         field2: 0,
     583            0 :         field3: 0,
     584            0 :         field4: 0,
     585            0 :         field5: u8::from(overflowed),
     586            0 :         field6: next_xid,
     587            0 :     }
     588            0 : }
     589              : 
     590              : //-- Section 03: Control file
     591              : pub const CONTROLFILE_KEY: Key = Key {
     592              :     field1: 0x03,
     593              :     field2: 0,
     594              :     field3: 0,
     595              :     field4: 0,
     596              :     field5: 0,
     597              :     field6: 0,
     598              : };
     599              : 
     600              : pub const CHECKPOINT_KEY: Key = Key {
     601              :     field1: 0x03,
     602              :     field2: 0,
     603              :     field3: 0,
     604              :     field4: 0,
     605              :     field5: 0,
     606              :     field6: 1,
     607              : };
     608              : 
     609              : pub const AUX_FILES_KEY: Key = Key {
     610              :     field1: 0x03,
     611              :     field2: 0,
     612              :     field3: 0,
     613              :     field4: 0,
     614              :     field5: 0,
     615              :     field6: 2,
     616              : };
     617              : 
     618              : #[inline(always)]
     619            0 : pub fn repl_origin_key(origin_id: RepOriginId) -> Key {
     620            0 :     Key {
     621            0 :         field1: REPL_ORIGIN_KEY_PREFIX,
     622            0 :         field2: 0,
     623            0 :         field3: 0,
     624            0 :         field4: 0,
     625            0 :         field5: 0,
     626            0 :         field6: origin_id as u32,
     627            0 :     }
     628            0 : }
     629              : 
     630              : /// Get the range of replorigin keys.
     631          282 : pub fn repl_origin_key_range() -> Range<Key> {
     632          282 :     Key {
     633          282 :         field1: REPL_ORIGIN_KEY_PREFIX,
     634          282 :         field2: 0,
     635          282 :         field3: 0,
     636          282 :         field4: 0,
     637          282 :         field5: 0,
     638          282 :         field6: 0,
     639          282 :     }..Key {
     640          282 :         field1: REPL_ORIGIN_KEY_PREFIX,
     641          282 :         field2: 0,
     642          282 :         field3: 0,
     643          282 :         field4: 0,
     644          282 :         field5: 0,
     645          282 :         field6: 0x10000,
     646          282 :     }
     647          282 : }
     648              : 
     649              : // Reverse mappings for a few Keys.
     650              : // These are needed by WAL redo manager.
     651              : 
     652              : /// Non inherited range for vectored get.
     653              : pub const NON_INHERITED_RANGE: Range<Key> = AUX_FILES_KEY..AUX_FILES_KEY.next();
     654              : /// Sparse keyspace range for vectored get. Missing key error will be ignored for this range.
     655              : pub const NON_INHERITED_SPARSE_RANGE: Range<Key> = Key::metadata_key_range();
     656              : 
     657              : impl Key {
     658              :     // AUX_FILES currently stores only data for logical replication (slots etc), and
     659              :     // we don't preserve these on a branch because safekeepers can't follow timeline
     660              :     // switch (and generally it likely should be optional), so ignore these.
     661              :     #[inline(always)]
     662            0 :     pub fn is_inherited_key(self) -> bool {
     663            0 :         !NON_INHERITED_RANGE.contains(&self) && !NON_INHERITED_SPARSE_RANGE.contains(&self)
     664            0 :     }
     665              : 
     666              :     #[inline(always)]
     667            0 :     pub fn is_rel_fsm_block_key(self) -> bool {
     668            0 :         self.field1 == 0x00
     669            0 :             && self.field4 != 0
     670            0 :             && self.field5 == FSM_FORKNUM
     671            0 :             && self.field6 != 0xffffffff
     672            0 :     }
     673              : 
     674              :     #[inline(always)]
     675            0 :     pub fn is_rel_vm_block_key(self) -> bool {
     676            0 :         self.field1 == 0x00
     677            0 :             && self.field4 != 0
     678            0 :             && self.field5 == VISIBILITYMAP_FORKNUM
     679            0 :             && self.field6 != 0xffffffff
     680            0 :     }
     681              : 
     682              :     #[inline(always)]
     683            0 :     pub fn to_slru_block(self) -> anyhow::Result<(SlruKind, u32, BlockNumber)> {
     684            0 :         Ok(match self.field1 {
     685              :             0x01 => {
     686            0 :                 let kind = match self.field2 {
     687            0 :                     0x00 => SlruKind::Clog,
     688            0 :                     0x01 => SlruKind::MultiXactMembers,
     689            0 :                     0x02 => SlruKind::MultiXactOffsets,
     690            0 :                     _ => anyhow::bail!("unrecognized slru kind 0x{:02x}", self.field2),
     691              :                 };
     692            0 :                 let segno = self.field4;
     693            0 :                 let blknum = self.field6;
     694            0 : 
     695            0 :                 (kind, segno, blknum)
     696              :             }
     697            0 :             _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
     698              :         })
     699            0 :     }
     700              : 
     701              :     #[inline(always)]
     702            0 :     pub fn is_slru_block_key(self) -> bool {
     703            0 :         self.field1 == 0x01                // SLRU-related
     704            0 :         && self.field3 == 0x00000001   // but not SlruDir
     705            0 :         && self.field6 != 0xffffffff // and not SlruSegSize
     706            0 :     }
     707              : 
     708              :     #[inline(always)]
     709      5850525 :     pub fn is_rel_block_key(&self) -> bool {
     710      5850525 :         self.field1 == 0x00 && self.field4 != 0 && self.field6 != 0xffffffff
     711      5850525 :     }
     712              : 
     713              :     /// Guaranteed to return `Ok()` if [`Self::is_rel_block_key`] returns `true` for `key`.
     714              :     #[inline(always)]
     715            6 :     pub fn to_rel_block(self) -> anyhow::Result<(RelTag, BlockNumber)> {
     716            6 :         Ok(match self.field1 {
     717            6 :             0x00 => (
     718            6 :                 RelTag {
     719            6 :                     spcnode: self.field2,
     720            6 :                     dbnode: self.field3,
     721            6 :                     relnode: self.field4,
     722            6 :                     forknum: self.field5,
     723            6 :                 },
     724            6 :                 self.field6,
     725            6 :             ),
     726            0 :             _ => anyhow::bail!("unexpected value kind 0x{:02x}", self.field1),
     727              :         })
     728            6 :     }
     729              : }
     730              : 
     731              : impl std::str::FromStr for Key {
     732              :     type Err = anyhow::Error;
     733              : 
     734           18 :     fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
     735           18 :         Self::from_hex(s)
     736           18 :     }
     737              : }
     738              : 
     739              : #[cfg(test)]
     740              : mod tests {
     741              :     use std::str::FromStr;
     742              : 
     743              :     use crate::key::is_metadata_key_slice;
     744              :     use crate::key::Key;
     745              : 
     746              :     use rand::Rng;
     747              :     use rand::SeedableRng;
     748              : 
     749              :     use super::AUX_KEY_PREFIX;
     750              : 
     751              :     #[test]
     752            2 :     fn display_fromstr_bijection() {
     753            2 :         let mut rng = rand::rngs::StdRng::seed_from_u64(42);
     754            2 : 
     755            2 :         let key = Key {
     756            2 :             field1: rng.gen(),
     757            2 :             field2: rng.gen(),
     758            2 :             field3: rng.gen(),
     759            2 :             field4: rng.gen(),
     760            2 :             field5: rng.gen(),
     761            2 :             field6: rng.gen(),
     762            2 :         };
     763            2 : 
     764            2 :         assert_eq!(key, Key::from_str(&format!("{key}")).unwrap());
     765            2 :     }
     766              : 
     767              :     #[test]
     768            2 :     fn test_metadata_keys() {
     769            2 :         let mut metadata_key = vec![AUX_KEY_PREFIX];
     770            2 :         metadata_key.extend_from_slice(&[0xFF; 15]);
     771            2 :         let encoded_key = Key::from_metadata_key(&metadata_key);
     772            2 :         let output_key = encoded_key.to_i128().to_be_bytes();
     773            2 :         assert_eq!(metadata_key, output_key);
     774            2 :         assert!(encoded_key.is_metadata_key());
     775            2 :         assert!(is_metadata_key_slice(&metadata_key));
     776            2 :     }
     777              : 
     778              :     #[test]
     779            2 :     fn test_possible_largest_key() {
     780            2 :         Key::from_i128(0x7FFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF);
     781            2 :         // TODO: put this key into the system and see if anything breaks.
     782            2 :     }
     783              : }
        

Generated by: LCOV version 2.1-beta