Line data Source code
1 : //!
2 : //! Common utilities for dealing with PostgreSQL non-relation files.
3 : //!
4 : use crate::pg_constants;
5 : use crate::transaction_id_precedes;
6 : use bytes::BytesMut;
7 : use log::*;
8 :
9 : use super::bindings::MultiXactId;
10 :
11 0 : pub fn transaction_id_set_status(xid: u32, status: u8, page: &mut BytesMut) {
12 0 : trace!(
13 0 : "handle_apply_request for RM_XACT_ID-{} (1-commit, 2-abort, 3-sub_commit)",
14 : status
15 : );
16 :
17 0 : let byteno: usize =
18 0 : ((xid % pg_constants::CLOG_XACTS_PER_PAGE) / pg_constants::CLOG_XACTS_PER_BYTE) as usize;
19 0 :
20 0 : let bshift: u8 =
21 0 : ((xid % pg_constants::CLOG_XACTS_PER_BYTE) * pg_constants::CLOG_BITS_PER_XACT as u32) as u8;
22 0 :
23 0 : page[byteno] =
24 0 : (page[byteno] & !(pg_constants::CLOG_XACT_BITMASK << bshift)) | (status << bshift);
25 0 : }
26 :
27 0 : pub fn transaction_id_get_status(xid: u32, page: &[u8]) -> u8 {
28 0 : let byteno: usize =
29 0 : ((xid % pg_constants::CLOG_XACTS_PER_PAGE) / pg_constants::CLOG_XACTS_PER_BYTE) as usize;
30 0 :
31 0 : let bshift: u8 =
32 0 : ((xid % pg_constants::CLOG_XACTS_PER_BYTE) * pg_constants::CLOG_BITS_PER_XACT as u32) as u8;
33 0 :
34 0 : (page[byteno] >> bshift) & pg_constants::CLOG_XACT_BITMASK
35 0 : }
36 :
37 : // See CLOGPagePrecedes in clog.c
38 0 : pub const fn clogpage_precedes(page1: u32, page2: u32) -> bool {
39 0 : let mut xid1 = page1 * pg_constants::CLOG_XACTS_PER_PAGE;
40 0 : xid1 += pg_constants::FIRST_NORMAL_TRANSACTION_ID + 1;
41 0 : let mut xid2 = page2 * pg_constants::CLOG_XACTS_PER_PAGE;
42 0 : xid2 += pg_constants::FIRST_NORMAL_TRANSACTION_ID + 1;
43 0 :
44 0 : transaction_id_precedes(xid1, xid2)
45 0 : && transaction_id_precedes(xid1, xid2 + pg_constants::CLOG_XACTS_PER_PAGE - 1)
46 0 : }
47 :
48 : // See SlruMayDeleteSegment() in slru.c
49 0 : pub fn slru_may_delete_clogsegment(segpage: u32, cutoff_page: u32) -> bool {
50 0 : let seg_last_page = segpage + pg_constants::SLRU_PAGES_PER_SEGMENT - 1;
51 0 :
52 0 : assert_eq!(segpage % pg_constants::SLRU_PAGES_PER_SEGMENT, 0);
53 :
54 0 : clogpage_precedes(segpage, cutoff_page) && clogpage_precedes(seg_last_page, cutoff_page)
55 0 : }
56 :
57 : // Multixact utils
58 :
59 40 : pub fn mx_offset_to_flags_offset(xid: MultiXactId) -> usize {
60 40 : ((xid / pg_constants::MULTIXACT_MEMBERS_PER_MEMBERGROUP as u32)
61 40 : % pg_constants::MULTIXACT_MEMBERGROUPS_PER_PAGE as u32
62 40 : * pg_constants::MULTIXACT_MEMBERGROUP_SIZE as u32) as usize
63 40 : }
64 :
65 20 : pub fn mx_offset_to_flags_bitshift(xid: MultiXactId) -> u16 {
66 20 : (xid as u16) % pg_constants::MULTIXACT_MEMBERS_PER_MEMBERGROUP
67 20 : * pg_constants::MXACT_MEMBER_BITS_PER_XACT
68 20 : }
69 :
70 : /* Location (byte offset within page) of TransactionId of given member */
71 20 : pub fn mx_offset_to_member_offset(xid: MultiXactId) -> usize {
72 20 : mx_offset_to_flags_offset(xid)
73 20 : + (pg_constants::MULTIXACT_FLAGBYTES_PER_GROUP
74 20 : + (xid as u16 % pg_constants::MULTIXACT_MEMBERS_PER_MEMBERGROUP) * 4) as usize
75 20 : }
76 :
77 40 : fn mx_offset_to_member_page(xid: u32) -> u32 {
78 40 : xid / pg_constants::MULTIXACT_MEMBERS_PER_PAGE as u32
79 40 : }
80 :
81 20 : pub fn mx_offset_to_member_segment(xid: u32) -> i32 {
82 20 : (mx_offset_to_member_page(xid) / pg_constants::SLRU_PAGES_PER_SEGMENT) as i32
83 20 : }
84 :
85 : #[cfg(test)]
86 : mod tests {
87 : use super::*;
88 :
89 : #[test]
90 4 : fn test_multixid_calc() {
91 4 : // Check that the mx_offset_* functions produce the same values as the
92 4 : // corresponding PostgreSQL C macros (MXOffsetTo*). These test values
93 4 : // were generated by calling the PostgreSQL macros with a little C
94 4 : // program.
95 4 : assert_eq!(mx_offset_to_member_segment(0), 0);
96 4 : assert_eq!(mx_offset_to_member_page(0), 0);
97 4 : assert_eq!(mx_offset_to_flags_offset(0), 0);
98 4 : assert_eq!(mx_offset_to_flags_bitshift(0), 0);
99 4 : assert_eq!(mx_offset_to_member_offset(0), 4);
100 4 : assert_eq!(mx_offset_to_member_segment(1), 0);
101 4 : assert_eq!(mx_offset_to_member_page(1), 0);
102 4 : assert_eq!(mx_offset_to_flags_offset(1), 0);
103 4 : assert_eq!(mx_offset_to_flags_bitshift(1), 8);
104 4 : assert_eq!(mx_offset_to_member_offset(1), 8);
105 4 : assert_eq!(mx_offset_to_member_segment(123456789), 2358);
106 4 : assert_eq!(mx_offset_to_member_page(123456789), 75462);
107 4 : assert_eq!(mx_offset_to_flags_offset(123456789), 4780);
108 4 : assert_eq!(mx_offset_to_flags_bitshift(123456789), 8);
109 4 : assert_eq!(mx_offset_to_member_offset(123456789), 4788);
110 4 : assert_eq!(mx_offset_to_member_segment(u32::MAX - 1), 82040);
111 4 : assert_eq!(mx_offset_to_member_page(u32::MAX - 1), 2625285);
112 4 : assert_eq!(mx_offset_to_flags_offset(u32::MAX - 1), 5160);
113 4 : assert_eq!(mx_offset_to_flags_bitshift(u32::MAX - 1), 16);
114 4 : assert_eq!(mx_offset_to_member_offset(u32::MAX - 1), 5172);
115 4 : assert_eq!(mx_offset_to_member_segment(u32::MAX), 82040);
116 4 : assert_eq!(mx_offset_to_member_page(u32::MAX), 2625285);
117 4 : assert_eq!(mx_offset_to_flags_offset(u32::MAX), 5160);
118 4 : assert_eq!(mx_offset_to_flags_bitshift(u32::MAX), 24);
119 4 : assert_eq!(mx_offset_to_member_offset(u32::MAX), 5176);
120 4 : }
121 : }
|