LCOV - differential code coverage report
Current view: top level - libs/postgres_ffi/src - controlfile_utils.rs (source / functions) Coverage Total Hit UBC CBC
Current: f6946e90941b557c917ac98cd5a7e9506d180f3e.info Lines: 87.0 % 46 40 6 40
Current Date: 2023-10-19 02:04:12 Functions: 33.3 % 9 3 6 3
Baseline: c8637f37369098875162f194f92736355783b050.info
Baseline Date: 2023-10-18 20:25:20

           TLA  Line data    Source code
       1                 : //!
       2                 : //! Utilities for reading and writing the PostgreSQL control file.
       3                 : //!
       4                 : //! The PostgreSQL control file is one the first things that the PostgreSQL
       5                 : //! server reads when it starts up. It indicates whether the server was shut
       6                 : //! down cleanly, or if it crashed or was restored from online backup so that
       7                 : //! WAL recovery needs to be performed. It also contains a copy of the latest
       8                 : //! checkpoint record and its location in the WAL.
       9                 : //!
      10                 : //! The control file also contains fields for detecting whether the
      11                 : //! data directory is compatible with a postgres binary. That includes
      12                 : //! a version number, configuration options that can be set at
      13                 : //! compilation time like the block size, and the platform's alignment
      14                 : //! and endianness information. (The PostgreSQL on-disk file format is
      15                 : //! not portable across platforms.)
      16                 : //!
      17                 : //! The control file is stored in the PostgreSQL data directory, as
      18                 : //! `global/pg_control`. The data stored in it is designed to be smaller than
      19                 : //! 512 bytes, on the assumption that it can be updated atomically. The actual
      20                 : //! file is larger, 8192 bytes, but the rest of it is just filled with zeros.
      21                 : //!
      22                 : //! See src/include/catalog/pg_control.h in the PostgreSQL sources for more
      23                 : //! information. You can use PostgreSQL's pg_controldata utility to view its
      24                 : //! contents.
      25                 : //!
      26                 : use super::bindings::{ControlFileData, PG_CONTROL_FILE_SIZE};
      27                 : 
      28                 : use anyhow::{bail, Result};
      29                 : use bytes::{Bytes, BytesMut};
      30                 : 
      31                 : /// Equivalent to sizeof(ControlFileData) in C
      32                 : const SIZEOF_CONTROLDATA: usize = std::mem::size_of::<ControlFileData>();
      33                 : 
      34                 : impl ControlFileData {
      35                 :     /// Compute the offset of the `crc` field within the `ControlFileData` struct.
      36                 :     /// Equivalent to offsetof(ControlFileData, crc) in C.
      37                 :     // Someday this can be const when the right compiler features land.
      38 CBC        2428 :     fn pg_control_crc_offset() -> usize {
      39            2428 :         memoffset::offset_of!(ControlFileData, crc)
      40            2428 :     }
      41                 : 
      42                 :     ///
      43                 :     /// Interpret a slice of bytes as a Postgres control file.
      44                 :     ///
      45            1790 :     pub fn decode(buf: &[u8]) -> Result<ControlFileData> {
      46            1790 :         use utils::bin_ser::LeSer;
      47            1790 : 
      48            1790 :         // Check that the slice has the expected size. The control file is
      49            1790 :         // padded with zeros up to a 512 byte sector size, so accept a
      50            1790 :         // larger size too, so that the caller can just the whole file
      51            1790 :         // contents without knowing the exact size of the struct.
      52            1790 :         if buf.len() < SIZEOF_CONTROLDATA {
      53 UBC           0 :             bail!("control file is too short");
      54 CBC        1790 :         }
      55            1790 : 
      56            1790 :         // Compute the expected CRC of the content.
      57            1790 :         let OFFSETOF_CRC = Self::pg_control_crc_offset();
      58            1790 :         let expectedcrc = crc32c::crc32c(&buf[0..OFFSETOF_CRC]);
      59                 : 
      60                 :         // Use serde to deserialize the input as a ControlFileData struct.
      61            1790 :         let controlfile = ControlFileData::des_prefix(buf)?;
      62                 : 
      63                 :         // Check the CRC
      64            1790 :         if expectedcrc != controlfile.crc {
      65 UBC           0 :             bail!(
      66               0 :                 "invalid CRC in control file: expected {:08X}, was {:08X}",
      67               0 :                 expectedcrc,
      68               0 :                 controlfile.crc
      69               0 :             );
      70 CBC        1790 :         }
      71            1790 : 
      72            1790 :         Ok(controlfile)
      73            1790 :     }
      74                 : 
      75                 :     ///
      76                 :     /// Convert a struct representing a Postgres control file into raw bytes.
      77                 :     ///
      78                 :     /// The CRC is recomputed to match the contents of the fields.
      79             638 :     pub fn encode(&self) -> Bytes {
      80             638 :         use utils::bin_ser::LeSer;
      81             638 : 
      82             638 :         // Serialize into a new buffer.
      83             638 :         let b = self.ser().unwrap();
      84             638 : 
      85             638 :         // Recompute the CRC
      86             638 :         let OFFSETOF_CRC = Self::pg_control_crc_offset();
      87             638 :         let newcrc = crc32c::crc32c(&b[0..OFFSETOF_CRC]);
      88             638 : 
      89             638 :         let mut buf = BytesMut::with_capacity(PG_CONTROL_FILE_SIZE as usize);
      90             638 :         buf.extend_from_slice(&b[0..OFFSETOF_CRC]);
      91             638 :         buf.extend_from_slice(&newcrc.to_ne_bytes());
      92             638 :         // Fill the rest of the control file with zeros.
      93             638 :         buf.resize(PG_CONTROL_FILE_SIZE as usize, 0);
      94             638 : 
      95             638 :         buf.into()
      96             638 :     }
      97                 : }
        

Generated by: LCOV version 2.1-beta