LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - key.rs (source / functions) Coverage Total Hit
Test: 691a4c28fe7169edd60b367c52d448a0a6605f1f.info Lines: 70.8 % 380 269
Test Date: 2024-05-10 13:18:37 Functions: 63.8 % 47 30

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

Generated by: LCOV version 2.1-beta