diff --git a/libs/postgres_ffi/src/nonrelfile_utils.rs b/libs/postgres_ffi/src/nonrelfile_utils.rs index a25e99cc0cb9..c5f74615bfb5 100644 --- a/libs/postgres_ffi/src/nonrelfile_utils.rs +++ b/libs/postgres_ffi/src/nonrelfile_utils.rs @@ -85,12 +85,12 @@ pub fn mx_offset_to_member_offset(xid: MultiXactId) -> usize { + (xid as u16 % pg_constants::MULTIXACT_MEMBERS_PER_MEMBERGROUP) * 4) as usize } -fn mx_offset_to_member_page(xid: u32) -> u32 { - xid / pg_constants::MULTIXACT_MEMBERS_PER_PAGE as u32 +fn mx_offset_to_member_page(xid: u32, region: u32) -> u32 { + ((xid / pg_constants::MULTIXACT_MEMBERS_PER_PAGE as u32) * pg_constants::MAX_REGIONS) + region } -pub fn mx_offset_to_member_segment(xid: u32) -> i32 { - (mx_offset_to_member_page(xid) / pg_constants::SLRU_PAGES_PER_SEGMENT) as i32 +pub fn mx_offset_to_member_segment(xid: u32, region: u32) -> i32 { + (mx_offset_to_member_page(xid, region) / pg_constants::SLRU_PAGES_PER_SEGMENT) as i32 } // See CSNLogPagePrecedes in csn_log.c @@ -117,28 +117,28 @@ mod tests { // corresponding PostgreSQL C macros (MXOffsetTo*). These test values // were generated by calling the PostgreSQL macros with a little C // program. - assert_eq!(mx_offset_to_member_segment(0), 0); - assert_eq!(mx_offset_to_member_page(0), 0); + assert_eq!(mx_offset_to_member_segment(0, 0), 0); + assert_eq!(mx_offset_to_member_page(0, 0), 0); assert_eq!(mx_offset_to_flags_offset(0), 0); assert_eq!(mx_offset_to_flags_bitshift(0), 0); assert_eq!(mx_offset_to_member_offset(0), 4); - assert_eq!(mx_offset_to_member_segment(1), 0); - assert_eq!(mx_offset_to_member_page(1), 0); + assert_eq!(mx_offset_to_member_segment(1, 0), 0); + assert_eq!(mx_offset_to_member_page(1, 0), 0); assert_eq!(mx_offset_to_flags_offset(1), 0); assert_eq!(mx_offset_to_flags_bitshift(1), 8); assert_eq!(mx_offset_to_member_offset(1), 8); - assert_eq!(mx_offset_to_member_segment(123456789), 2358); - assert_eq!(mx_offset_to_member_page(123456789), 75462); + assert_eq!(mx_offset_to_member_segment(123456789, 0), 150924); + assert_eq!(mx_offset_to_member_page(123456789, 0), 4829568); assert_eq!(mx_offset_to_flags_offset(123456789), 4780); assert_eq!(mx_offset_to_flags_bitshift(123456789), 8); assert_eq!(mx_offset_to_member_offset(123456789), 4788); - assert_eq!(mx_offset_to_member_segment(u32::MAX - 1), 82040); - assert_eq!(mx_offset_to_member_page(u32::MAX - 1), 2625285); + assert_eq!(mx_offset_to_member_segment(u32::MAX - 1, 0), 5250570); + assert_eq!(mx_offset_to_member_page(u32::MAX - 1, 0), 168018240); assert_eq!(mx_offset_to_flags_offset(u32::MAX - 1), 5160); assert_eq!(mx_offset_to_flags_bitshift(u32::MAX - 1), 16); assert_eq!(mx_offset_to_member_offset(u32::MAX - 1), 5172); - assert_eq!(mx_offset_to_member_segment(u32::MAX), 82040); - assert_eq!(mx_offset_to_member_page(u32::MAX), 2625285); + assert_eq!(mx_offset_to_member_segment(u32::MAX, 0), 5250570); + assert_eq!(mx_offset_to_member_page(u32::MAX, 0), 168018240); assert_eq!(mx_offset_to_flags_offset(u32::MAX), 5160); assert_eq!(mx_offset_to_flags_bitshift(u32::MAX), 24); assert_eq!(mx_offset_to_member_offset(u32::MAX), 5176); diff --git a/pageserver/src/walingest.rs b/pageserver/src/walingest.rs index 5909a0a0dbd7..211f35dbf70d 100644 --- a/pageserver/src/walingest.rs +++ b/pageserver/src/walingest.rs @@ -944,7 +944,10 @@ impl<'a> WalIngest<'a> { xlrec: &XlMultiXactCreate, ) -> Result<()> { // Create WAL record for updating the multixact-offsets page - let pageno = xlrec.mid / pg_constants::MULTIXACT_OFFSETS_PER_PAGE as u32; + let region: u32 = self.timeline.region_id.0 as u32; + let pageno = ((xlrec.mid / pg_constants::MULTIXACT_OFFSETS_PER_PAGE as u32) + * pg_constants::MAX_REGIONS) + + region; let segno = pageno / pg_constants::SLRU_PAGES_PER_SEGMENT; let rpageno = pageno % pg_constants::SLRU_PAGES_PER_SEGMENT; @@ -955,6 +958,7 @@ impl<'a> WalIngest<'a> { NeonWalRecord::MultixactOffsetCreate { mid: xlrec.mid, moff: xlrec.moff, + region, }, )?; @@ -989,6 +993,7 @@ impl<'a> WalIngest<'a> { NeonWalRecord::MultixactMembersCreate { moff: offset, members: this_page_members, + region, }, )?; @@ -1028,9 +1033,11 @@ impl<'a> WalIngest<'a> { self.checkpoint_modified = true; // PerformMembersTruncation - let maxsegment: i32 = mx_offset_to_member_segment(pg_constants::MAX_MULTIXACT_OFFSET); - let startsegment: i32 = mx_offset_to_member_segment(xlrec.start_trunc_memb); - let endsegment: i32 = mx_offset_to_member_segment(xlrec.end_trunc_memb); + let region: u32 = self.timeline.region_id.0 as u32; + let maxsegment: i32 = + mx_offset_to_member_segment(pg_constants::MAX_MULTIXACT_OFFSET, region); + let startsegment: i32 = mx_offset_to_member_segment(xlrec.start_trunc_memb, region); + let endsegment: i32 = mx_offset_to_member_segment(xlrec.end_trunc_memb, region); let mut segment: i32 = startsegment; // Delete all the segments except the last one. The last segment can still diff --git a/pageserver/src/walrecord.rs b/pageserver/src/walrecord.rs index 2e456529702f..f1a9ab66a676 100644 --- a/pageserver/src/walrecord.rs +++ b/pageserver/src/walrecord.rs @@ -37,11 +37,13 @@ pub enum NeonWalRecord { MultixactOffsetCreate { mid: MultiXactId, moff: MultiXactOffset, + region: u32, }, /// Extend multixact members SLRU. MultixactMembersCreate { moff: MultiXactOffset, members: Vec, + region: u32, }, /// Mark transaction ID as committed with the given LSN on a CsnLog page CsnLogSetCommitted { diff --git a/pageserver/src/walredo.rs b/pageserver/src/walredo.rs index b3ab5a3b1ad2..8941275f2893 100644 --- a/pageserver/src/walredo.rs +++ b/pageserver/src/walredo.rs @@ -512,7 +512,7 @@ impl PostgresRedoManager { transaction_id_set_status(xid, pg_constants::TRANSACTION_STATUS_ABORTED, page); } } - NeonWalRecord::MultixactOffsetCreate { mid, moff } => { + NeonWalRecord::MultixactOffsetCreate { mid, moff, region } => { let (slru_kind, segno, blknum) = key_to_slru_block(key).or(Err(WalRedoError::InvalidRecord))?; assert_eq!( @@ -523,7 +523,9 @@ impl PostgresRedoManager { ); // Compute the block and offset to modify. // See RecordNewMultiXact in PostgreSQL sources. - let pageno = mid / pg_constants::MULTIXACT_OFFSETS_PER_PAGE as u32; + let pageno = ((mid / pg_constants::MULTIXACT_OFFSETS_PER_PAGE as u32) + * pg_constants::MAX_REGIONS) + + *region; let entryno = mid % pg_constants::MULTIXACT_OFFSETS_PER_PAGE as u32; let offset = (entryno * 4) as usize; @@ -545,7 +547,11 @@ impl PostgresRedoManager { LittleEndian::write_u32(&mut page[offset..offset + 4], *moff); } - NeonWalRecord::MultixactMembersCreate { moff, members } => { + NeonWalRecord::MultixactMembersCreate { + moff, + members, + region, + } => { let (slru_kind, segno, blknum) = key_to_slru_block(key).or(Err(WalRedoError::InvalidRecord))?; assert_eq!( @@ -559,7 +565,9 @@ impl PostgresRedoManager { // Compute the block and offset to modify. // See RecordNewMultiXact in PostgreSQL sources. - let pageno = offset / pg_constants::MULTIXACT_MEMBERS_PER_PAGE as u32; + let pageno = ((offset / pg_constants::MULTIXACT_MEMBERS_PER_PAGE as u32) + * pg_constants::MAX_REGIONS) + + *region; let memberoff = mx_offset_to_member_offset(offset); let flagsoff = mx_offset_to_flags_offset(offset); let bshift = mx_offset_to_flags_bitshift(offset);