diff --git a/pageserver/src/restore_local_repo.rs b/pageserver/src/restore_local_repo.rs index 581be9c005..3677d4a3e4 100644 --- a/pageserver/src/restore_local_repo.rs +++ b/pageserver/src/restore_local_repo.rs @@ -3,6 +3,8 @@ //! zenith Timeline. //! use log::*; +use postgres_ffi::nonrelfile_utils::clogpage_precedes; +use postgres_ffi::nonrelfile_utils::slru_may_delete_clogsegment; use std::cmp::min; use std::fs; use std::fs::File; @@ -19,8 +21,8 @@ use crate::repository::*; use crate::waldecoder::*; use postgres_ffi::relfile_utils::*; use postgres_ffi::xlog_utils::*; +use postgres_ffi::Oid; use postgres_ffi::{pg_constants, CheckPoint, ControlFileData}; -use postgres_ffi::{Oid, TransactionId}; use zenith_utils::lsn::Lsn; const MAX_MBR_BLKNO: u32 = @@ -736,44 +738,6 @@ fn save_xact_record( Ok(()) } -// See TransactionIdPrecedes in transam.c -fn transaction_id_precedes(id1: TransactionId, id2: TransactionId) -> bool { - /* - * If either ID is a permanent XID then we can just do unsigned - * comparison. If both are normal, do a modulo-2^32 comparison. - */ - - if !(id1 >= pg_constants::FIRST_NORMAL_TRANSACTION_ID) - || !(id2 >= pg_constants::FIRST_NORMAL_TRANSACTION_ID) - { - return id1 < id2; - } - - let diff = id1.wrapping_sub(id2) as i32; - return diff < 0; -} - -// See CLOGPagePrecedes in clog.c -fn clogpage_precedes(page1: u32, page2: u32) -> bool { - let mut xid1 = page1 * pg_constants::CLOG_XACTS_PER_PAGE; - xid1 += pg_constants::FIRST_NORMAL_TRANSACTION_ID + 1; - let mut xid2 = page2 * pg_constants::CLOG_XACTS_PER_PAGE; - xid2 += pg_constants::FIRST_NORMAL_TRANSACTION_ID + 1; - - return transaction_id_precedes(xid1, xid2) - && transaction_id_precedes(xid1, xid2 + pg_constants::CLOG_XACTS_PER_PAGE - 1); -} - -// See SlruMayDeleteSegment() in slru.c -fn slru_may_delete_clogsegment(segpage: u32, cutoff_page: u32) -> bool { - let seg_last_page = segpage + pg_constants::SLRU_PAGES_PER_SEGMENT - 1; - - assert_eq!(segpage % pg_constants::SLRU_PAGES_PER_SEGMENT, 0); - - return clogpage_precedes(segpage, cutoff_page) - && clogpage_precedes(seg_last_page, cutoff_page); -} - fn save_clog_truncate_record( checkpoint: &mut CheckPoint, timeline: &dyn Timeline, diff --git a/postgres_ffi/src/lib.rs b/postgres_ffi/src/lib.rs index d7fe9b951d..3021d4cf00 100644 --- a/postgres_ffi/src/lib.rs +++ b/postgres_ffi/src/lib.rs @@ -14,3 +14,23 @@ pub mod nonrelfile_utils; pub mod pg_constants; pub mod relfile_utils; pub mod xlog_utils; + +// See TransactionIdIsNormal in transam.h +pub const fn transaction_id_is_normal(id: TransactionId) -> bool { + id > pg_constants::FIRST_NORMAL_TRANSACTION_ID +} + +// See TransactionIdPrecedes in transam.c +pub const fn transaction_id_precedes(id1: TransactionId, id2: TransactionId) -> bool { + /* + * If either ID is a permanent XID then we can just do unsigned + * comparison. If both are normal, do a modulo-2^32 comparison. + */ + + if !(transaction_id_is_normal(id1)) || !transaction_id_is_normal(id2) { + return id1 < id2; + } + + let diff = id1.wrapping_sub(id2) as i32; + return diff < 0; +} diff --git a/postgres_ffi/src/nonrelfile_utils.rs b/postgres_ffi/src/nonrelfile_utils.rs index a0dee29a9c..a0f1f61c18 100644 --- a/postgres_ffi/src/nonrelfile_utils.rs +++ b/postgres_ffi/src/nonrelfile_utils.rs @@ -1,7 +1,7 @@ //! //! Common utilities for dealing with PostgreSQL non-relation files. //! -use crate::pg_constants; +use crate::{pg_constants, transaction_id_precedes}; use bytes::BytesMut; use log::*; @@ -30,3 +30,23 @@ pub fn transaction_id_get_status(xid: u32, page: &[u8]) -> u8 { ((page[byteno] >> bshift) & pg_constants::CLOG_XACT_BITMASK) as u8 } + +// See CLOGPagePrecedes in clog.c +pub const fn clogpage_precedes(page1: u32, page2: u32) -> bool { + let mut xid1 = page1 * pg_constants::CLOG_XACTS_PER_PAGE; + xid1 += pg_constants::FIRST_NORMAL_TRANSACTION_ID + 1; + let mut xid2 = page2 * pg_constants::CLOG_XACTS_PER_PAGE; + xid2 += pg_constants::FIRST_NORMAL_TRANSACTION_ID + 1; + + transaction_id_precedes(xid1, xid2) + && transaction_id_precedes(xid1, xid2 + pg_constants::CLOG_XACTS_PER_PAGE - 1) +} + +// See SlruMayDeleteSegment() in slru.c +pub fn slru_may_delete_clogsegment(segpage: u32, cutoff_page: u32) -> bool { + let seg_last_page = segpage + pg_constants::SLRU_PAGES_PER_SEGMENT - 1; + + assert_eq!(segpage % pg_constants::SLRU_PAGES_PER_SEGMENT, 0); + + clogpage_precedes(segpage, cutoff_page) && clogpage_precedes(seg_last_page, cutoff_page) +}