LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - key.rs (source / functions) Coverage Total Hit
Test: a2f0f8a80fbf1089336086fa360ce27fa555cb1a.info Lines: 62.9 % 464 292
Test Date: 2024-11-20 17:59:39 Functions: 56.2 % 64 36

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

Generated by: LCOV version 2.1-beta