From 762e9859d66e5fb29b4f982fc935a16cf56c500f Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Fri, 4 Jun 2021 23:05:05 +0300 Subject: [PATCH] Move functions for reading/writing control file to separate source file. To follow the precedent of xlog_utils.rs and relfile_utils.rs. --- pageserver/src/branches.rs | 10 +++--- postgres_ffi/src/controlfile_utils.rs | 52 +++++++++++++++++++++++++++ postgres_ffi/src/lib.rs | 51 +------------------------- 3 files changed, 58 insertions(+), 55 deletions(-) create mode 100644 postgres_ffi/src/controlfile_utils.rs diff --git a/pageserver/src/branches.rs b/pageserver/src/branches.rs index 73dffce469..c03dd3e3a3 100644 --- a/pageserver/src/branches.rs +++ b/pageserver/src/branches.rs @@ -7,7 +7,7 @@ use anyhow::{anyhow, bail, Context, Result}; use bytes::Bytes; use fs::File; -use postgres_ffi::{pg_constants, xlog_utils}; +use postgres_ffi::{controlfile_utils, pg_constants, xlog_utils}; use rand::Rng; use serde::{Deserialize, Serialize}; use std::env; @@ -80,7 +80,7 @@ pub fn init_repo(conf: &'static PageServerConf, repo_dir: &Path) -> Result<()> { // Read control file to extract the LSN and system id let controlfile_path = tmppath.join("global").join("pg_control"); - let controlfile = postgres_ffi::decode_pg_control(Bytes::from(fs::read(controlfile_path)?))?; + let controlfile = controlfile_utils::decode_pg_control(Bytes::from(fs::read(controlfile_path)?))?; // let systemid = controlfile.system_identifier; let lsn = controlfile.checkPoint; let lsnstr = format!("{:016X}", lsn); @@ -212,7 +212,7 @@ pub(crate) fn get_system_id(conf: &PageServerConf) -> Result { let (_, main_snap_dir) = find_latest_snapshot(conf, *main_tli)?; let controlfile_path = main_snap_dir.join("global").join("pg_control"); - let controlfile = postgres_ffi::decode_pg_control(Bytes::from(fs::read(controlfile_path)?))?; + let controlfile = controlfile_utils::decode_pg_control(Bytes::from(fs::read(controlfile_path)?))?; Ok(controlfile.system_identifier) } @@ -356,13 +356,13 @@ fn force_crash_recovery(datadir: &Path) -> Result<()> { // Read in the control file let controlfilepath = datadir.to_path_buf().join("global").join("pg_control"); let mut controlfile = - postgres_ffi::decode_pg_control(Bytes::from(fs::read(controlfilepath.as_path())?))?; + controlfile_utils::decode_pg_control(Bytes::from(fs::read(controlfilepath.as_path())?))?; controlfile.state = postgres_ffi::DBState_DB_IN_PRODUCTION; fs::write( controlfilepath.as_path(), - postgres_ffi::encode_pg_control(controlfile), + controlfile_utils::encode_pg_control(controlfile), )?; Ok(()) diff --git a/postgres_ffi/src/controlfile_utils.rs b/postgres_ffi/src/controlfile_utils.rs new file mode 100644 index 0000000000..6b41c11749 --- /dev/null +++ b/postgres_ffi/src/controlfile_utils.rs @@ -0,0 +1,52 @@ +use crate::{ControlFileData, PG_CONTROLFILEDATA_OFFSETOF_CRC, PG_CONTROL_FILE_SIZE}; + +use bytes::{Buf, Bytes, BytesMut}; + +// sizeof(ControlFileData) +const SIZEOF_CONTROLDATA: usize = std::mem::size_of::(); +// offsetof(ControlFileData, crc) +const OFFSETOF_CRC: usize = PG_CONTROLFILEDATA_OFFSETOF_CRC as usize; + +pub fn decode_pg_control(mut buf: Bytes) -> Result { + let mut b: [u8; SIZEOF_CONTROLDATA] = [0u8; SIZEOF_CONTROLDATA]; + buf.copy_to_slice(&mut b); + + let controlfile: ControlFileData; + + // TODO: verify CRC + let mut data_without_crc: [u8; OFFSETOF_CRC] = [0u8; OFFSETOF_CRC]; + data_without_crc.copy_from_slice(&b[0..OFFSETOF_CRC]); + let expectedcrc = crc32c::crc32c(&data_without_crc); + + controlfile = unsafe { std::mem::transmute::<[u8; SIZEOF_CONTROLDATA], ControlFileData>(b) }; + + if expectedcrc != controlfile.crc { + anyhow::bail!( + "invalid CRC in control file: expected {:08X}, was {:08X}", + expectedcrc, + controlfile.crc + ); + } + + Ok(controlfile) +} + +pub fn encode_pg_control(controlfile: ControlFileData) -> Bytes { + let b: [u8; SIZEOF_CONTROLDATA]; + + b = unsafe { std::mem::transmute::(controlfile) }; + + // Recompute the CRC + let mut data_without_crc: [u8; OFFSETOF_CRC] = [0u8; OFFSETOF_CRC]; + data_without_crc.copy_from_slice(&b[0..OFFSETOF_CRC]); + let newcrc = crc32c::crc32c(&data_without_crc); + + let mut buf = BytesMut::with_capacity(PG_CONTROL_FILE_SIZE as usize); + + buf.extend_from_slice(&b[0..OFFSETOF_CRC]); + buf.extend_from_slice(&newcrc.to_ne_bytes()); + // Fill the rest of the control file with zeros. + buf.resize(PG_CONTROL_FILE_SIZE as usize, 0); + + buf.into() +} diff --git a/postgres_ffi/src/lib.rs b/postgres_ffi/src/lib.rs index 9bcd4b3680..56dd1f1003 100644 --- a/postgres_ffi/src/lib.rs +++ b/postgres_ffi/src/lib.rs @@ -3,56 +3,7 @@ #![allow(non_snake_case)] include!(concat!(env!("OUT_DIR"), "/bindings.rs")); +pub mod controlfile_utils; pub mod pg_constants; pub mod relfile_utils; pub mod xlog_utils; - -use bytes::{Buf, Bytes, BytesMut}; - -// sizeof(ControlFileData) -const SIZEOF_CONTROLDATA: usize = std::mem::size_of::(); -const OFFSETOF_CRC: usize = PG_CONTROLFILEDATA_OFFSETOF_CRC as usize; - -pub fn decode_pg_control(mut buf: Bytes) -> Result { - let mut b: [u8; SIZEOF_CONTROLDATA] = [0u8; SIZEOF_CONTROLDATA]; - buf.copy_to_slice(&mut b); - - let controlfile: ControlFileData; - - // TODO: verify CRC - let mut data_without_crc: [u8; OFFSETOF_CRC] = [0u8; OFFSETOF_CRC]; - data_without_crc.copy_from_slice(&b[0..OFFSETOF_CRC]); - let expectedcrc = crc32c::crc32c(&data_without_crc); - - controlfile = unsafe { std::mem::transmute::<[u8; SIZEOF_CONTROLDATA], ControlFileData>(b) }; - - if expectedcrc != controlfile.crc { - anyhow::bail!( - "invalid CRC in control file: expected {:08X}, was {:08X}", - expectedcrc, - controlfile.crc - ); - } - - Ok(controlfile) -} - -pub fn encode_pg_control(controlfile: ControlFileData) -> Bytes { - let b: [u8; SIZEOF_CONTROLDATA]; - - b = unsafe { std::mem::transmute::(controlfile) }; - - // Recompute the CRC - let mut data_without_crc: [u8; OFFSETOF_CRC] = [0u8; OFFSETOF_CRC]; - data_without_crc.copy_from_slice(&b[0..OFFSETOF_CRC]); - let newcrc = crc32c::crc32c(&data_without_crc); - - let mut buf = BytesMut::with_capacity(PG_CONTROL_FILE_SIZE as usize); - - buf.extend_from_slice(&b[0..OFFSETOF_CRC]); - buf.extend_from_slice(&newcrc.to_ne_bytes()); - // Fill the rest of the control file with zeros. - buf.resize(PG_CONTROL_FILE_SIZE as usize, 0); - - buf.into() -}