LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - key.rs (source / functions) Coverage Total Hit
Test: 02e8c57acd6e2b986849f552ca30280d54699b79.info Lines: 65.2 % 420 274
Test Date: 2024-06-26 17:13:54 Functions: 60.8 % 51 31

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

Generated by: LCOV version 2.1-beta