LCOV - code coverage report
Current view: top level - libs/pageserver_api/src - record.rs (source / functions) Coverage Total Hit
Test: 98683a8629f0f7f0031d02e04512998d589d76ea.info Lines: 83.3 % 48 40
Test Date: 2025-04-11 16:58:57 Functions: 36.4 % 22 8

            Line data    Source code
       1              : //! This module defines the WAL record format used within the pageserver.
       2              : 
       3              : use bytes::Bytes;
       4              : use postgres_ffi::walrecord::{MultiXactMember, describe_postgres_wal_record};
       5              : use postgres_ffi::{MultiXactId, MultiXactOffset, TimestampTz, TransactionId};
       6              : use serde::{Deserialize, Serialize};
       7              : use utils::bin_ser::DeserializeError;
       8              : 
       9              : /// Each update to a page is represented by a NeonWalRecord. It can be a wrapper
      10              : /// around a PostgreSQL WAL record, or a custom neon-specific "record".
      11         2119 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
      12              : pub enum NeonWalRecord {
      13              :     /// Native PostgreSQL WAL record
      14              :     Postgres { will_init: bool, rec: Bytes },
      15              : 
      16              :     /// Clear bits in heap visibility map. ('flags' is bitmap of bits to clear)
      17              :     ClearVisibilityMapFlags {
      18              :         new_heap_blkno: Option<u32>,
      19              :         old_heap_blkno: Option<u32>,
      20              :         flags: u8,
      21              :     },
      22              :     /// Mark transaction IDs as committed on a CLOG page
      23              :     ClogSetCommitted {
      24              :         xids: Vec<TransactionId>,
      25              :         timestamp: TimestampTz,
      26              :     },
      27              :     /// Mark transaction IDs as aborted on a CLOG page
      28              :     ClogSetAborted { xids: Vec<TransactionId> },
      29              :     /// Extend multixact offsets SLRU
      30              :     MultixactOffsetCreate {
      31              :         mid: MultiXactId,
      32              :         moff: MultiXactOffset,
      33              :     },
      34              :     /// Extend multixact members SLRU.
      35              :     MultixactMembersCreate {
      36              :         moff: MultiXactOffset,
      37              :         members: Vec<MultiXactMember>,
      38              :     },
      39              :     /// Update the map of AUX files, either writing or dropping an entry
      40              :     AuxFile {
      41              :         file_path: String,
      42              :         content: Option<Bytes>,
      43              :     },
      44              :     // Truncate visibility map page
      45              :     TruncateVisibilityMap {
      46              :         trunc_byte: usize,
      47              :         trunc_offs: usize,
      48              :     },
      49              : 
      50              :     /// A testing record for unit testing purposes. It supports append data to an existing image, or clear it.
      51              :     #[cfg(feature = "testing")]
      52              :     Test {
      53              :         /// Append a string to the image.
      54              :         append: String,
      55              :         /// Clear the image before appending.
      56              :         clear: bool,
      57              :         /// Treat this record as an init record. `clear` should be set to true if this field is set
      58              :         /// to true. This record does not need the history WALs to reconstruct. See [`NeonWalRecord::will_init`] and
      59              :         /// its references in `timeline.rs`.
      60              :         will_init: bool,
      61              :         /// Only append the record if the current image is the same as the one specified in this field.
      62              :         only_if: Option<String>,
      63              :     },
      64              : }
      65              : 
      66              : impl NeonWalRecord {
      67              :     /// Does replaying this WAL record initialize the page from scratch, or does
      68              :     /// it need to be applied over the previous image of the page?
      69       293519 :     pub fn will_init(&self) -> bool {
      70       293519 :         // If you change this function, you'll also need to change ValueBytes::will_init
      71       293519 :         match self {
      72       291252 :             NeonWalRecord::Postgres { will_init, rec: _ } => *will_init,
      73              :             #[cfg(feature = "testing")]
      74         2227 :             NeonWalRecord::Test { will_init, .. } => *will_init,
      75              :             // None of the special neon record types currently initialize the page
      76           40 :             _ => false,
      77              :         }
      78       293519 :     }
      79              : 
      80              :     #[cfg(feature = "testing")]
      81          507 :     pub fn wal_append(s: impl AsRef<str>) -> Self {
      82          507 :         Self::Test {
      83          507 :             append: s.as_ref().to_string(),
      84          507 :             clear: false,
      85          507 :             will_init: false,
      86          507 :             only_if: None,
      87          507 :         }
      88          507 :     }
      89              : 
      90              :     #[cfg(feature = "testing")]
      91           12 :     pub fn wal_append_conditional(s: impl AsRef<str>, only_if: impl AsRef<str>) -> Self {
      92           12 :         Self::Test {
      93           12 :             append: s.as_ref().to_string(),
      94           12 :             clear: false,
      95           12 :             will_init: false,
      96           12 :             only_if: Some(only_if.as_ref().to_string()),
      97           12 :         }
      98           12 :     }
      99              : 
     100              :     #[cfg(feature = "testing")]
     101            4 :     pub fn wal_clear(s: impl AsRef<str>) -> Self {
     102            4 :         Self::Test {
     103            4 :             append: s.as_ref().to_string(),
     104            4 :             clear: true,
     105            4 :             will_init: false,
     106            4 :             only_if: None,
     107            4 :         }
     108            4 :     }
     109              : 
     110              :     #[cfg(feature = "testing")]
     111          116 :     pub fn wal_init(s: impl AsRef<str>) -> Self {
     112          116 :         Self::Test {
     113          116 :             append: s.as_ref().to_string(),
     114          116 :             clear: true,
     115          116 :             will_init: true,
     116          116 :             only_if: None,
     117          116 :         }
     118          116 :     }
     119              : }
     120              : 
     121              : /// Build a human-readable string to describe a WAL record
     122              : ///
     123              : /// For debugging purposes
     124            0 : pub fn describe_wal_record(rec: &NeonWalRecord) -> Result<String, DeserializeError> {
     125            0 :     match rec {
     126            0 :         NeonWalRecord::Postgres { will_init, rec } => Ok(format!(
     127            0 :             "will_init: {}, {}",
     128            0 :             will_init,
     129            0 :             describe_postgres_wal_record(rec)?
     130              :         )),
     131            0 :         _ => Ok(format!("{:?}", rec)),
     132              :     }
     133            0 : }
        

Generated by: LCOV version 2.1-beta