LCOV - code coverage report
Current view: top level - libs/postgres_ffi/src - controlfile_utils.rs (source / functions) Coverage Total Hit
Test: 49aa928ec5b4b510172d8b5c6d154da28e70a46c.info Lines: 43.2 % 37 16
Test Date: 2024-11-13 18:23:39 Functions: 16.7 % 12 2

            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 = 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            4 :     fn pg_control_crc_offset() -> usize {
      39            4 :         memoffset::offset_of!(ControlFileData, crc)
      40            4 :     }
      41              : 
      42              :     ///
      43              :     /// Interpret a slice of bytes as a Postgres control file.
      44              :     ///
      45            4 :     pub fn decode(buf: &[u8]) -> Result<ControlFileData> {
      46              :         use utils::bin_ser::LeSer;
      47              : 
      48              :         // Check that the slice has the expected size. The control file is
      49              :         // padded with zeros up to a 512 byte sector size, so accept a
      50              :         // larger size too, so that the caller can just the whole file
      51              :         // contents without knowing the exact size of the struct.
      52            4 :         if buf.len() < SIZEOF_CONTROLDATA {
      53            0 :             bail!("control file is too short");
      54            4 :         }
      55            4 : 
      56            4 :         // Compute the expected CRC of the content.
      57            4 :         let OFFSETOF_CRC = Self::pg_control_crc_offset();
      58            4 :         let expectedcrc = crc32c::crc32c(&buf[0..OFFSETOF_CRC]);
      59              : 
      60              :         // Use serde to deserialize the input as a ControlFileData struct.
      61            4 :         let controlfile = ControlFileData::des_prefix(buf)?;
      62              : 
      63              :         // Check the CRC
      64            4 :         if expectedcrc != controlfile.crc {
      65            0 :             bail!(
      66            0 :                 "invalid CRC in control file: expected {:08X}, was {:08X}",
      67            0 :                 expectedcrc,
      68            0 :                 controlfile.crc
      69            0 :             );
      70            4 :         }
      71            4 : 
      72            4 :         Ok(controlfile)
      73            4 :     }
      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            0 :     pub fn encode(&self) -> Bytes {
      80              :         use utils::bin_ser::LeSer;
      81              : 
      82              :         // Serialize into a new buffer.
      83            0 :         let b = self.ser().unwrap();
      84            0 : 
      85            0 :         // Recompute the CRC
      86            0 :         let OFFSETOF_CRC = Self::pg_control_crc_offset();
      87            0 :         let newcrc = crc32c::crc32c(&b[0..OFFSETOF_CRC]);
      88            0 : 
      89            0 :         let mut buf = BytesMut::with_capacity(PG_CONTROL_FILE_SIZE as usize);
      90            0 :         buf.extend_from_slice(&b[0..OFFSETOF_CRC]);
      91            0 :         buf.extend_from_slice(&newcrc.to_ne_bytes());
      92            0 :         // Fill the rest of the control file with zeros.
      93            0 :         buf.resize(PG_CONTROL_FILE_SIZE as usize, 0);
      94            0 : 
      95            0 :         buf.into()
      96            0 :     }
      97              : }
        

Generated by: LCOV version 2.1-beta