TLA Line data Source code
1 : #![allow(non_upper_case_globals)]
2 : #![allow(non_camel_case_types)]
3 : #![allow(non_snake_case)]
4 : // bindgen creates some unsafe code with no doc comments.
5 : #![allow(clippy::missing_safety_doc)]
6 : // noted at 1.63 that in many cases there's a u32 -> u32 transmutes in bindgen code.
7 : #![allow(clippy::useless_transmute)]
8 : // modules included with the postgres_ffi macro depend on the types of the specific version's
9 : // types, and trigger a too eager lint.
10 : #![allow(clippy::duplicate_mod)]
11 :
12 : use bytes::Bytes;
13 : use utils::bin_ser::SerializeError;
14 : use utils::lsn::Lsn;
15 :
16 : macro_rules! postgres_ffi {
17 : ($version:ident) => {
18 : #[path = "."]
19 : pub mod $version {
20 : pub mod bindings {
21 : // bindgen generates bindings for a lot of stuff we don't need
22 : #![allow(dead_code)]
23 :
24 : use serde::{Deserialize, Serialize};
25 : include!(concat!(
26 : env!("OUT_DIR"),
27 : "/bindings_",
28 : stringify!($version),
29 : ".rs"
30 : ));
31 :
32 : include!(concat!("pg_constants_", stringify!($version), ".rs"));
33 : }
34 : pub mod controlfile_utils;
35 : pub mod nonrelfile_utils;
36 : pub mod wal_craft_test_export;
37 : pub mod waldecoder_handler;
38 : pub mod xlog_utils;
39 :
40 : pub const PG_MAJORVERSION: &str = stringify!($version);
41 :
42 : // Re-export some symbols from bindings
43 : pub use bindings::DBState_DB_SHUTDOWNED;
44 : pub use bindings::{CheckPoint, ControlFileData, XLogRecord};
45 : }
46 : };
47 : }
48 :
49 : #[macro_export]
50 : macro_rules! for_all_postgres_versions {
51 : ($macro:tt) => {
52 : $macro!(v14);
53 : $macro!(v15);
54 : $macro!(v16);
55 : };
56 : }
57 :
58 : for_all_postgres_versions! { postgres_ffi }
59 :
60 : /// dispatch_pgversion
61 : ///
62 : /// Run a code block in a context where the postgres_ffi bindings for a
63 : /// specific (supported) PostgreSQL version are `use`-ed in scope under the pgv
64 : /// identifier.
65 : /// If the provided pg_version is not supported, we panic!(), unless the
66 : /// optional third argument was provided (in which case that code will provide
67 : /// the default handling instead).
68 : ///
69 : /// Use like
70 : ///
71 : /// dispatch_pgversion!(my_pgversion, { pgv::constants::XLOG_DBASE_CREATE })
72 : /// dispatch_pgversion!(my_pgversion, pgv::constants::XLOG_DBASE_CREATE)
73 : ///
74 : /// Other uses are for macro-internal purposes only and strictly unsupported.
75 : ///
76 : #[macro_export]
77 : macro_rules! dispatch_pgversion {
78 : ($version:expr, $code:expr) => {
79 : dispatch_pgversion!($version, $code, panic!("Unknown PostgreSQL version {}", $version))
80 : };
81 : ($version:expr, $code:expr, $invalid_pgver_handling:expr) => {
82 : dispatch_pgversion!(
83 : $version => $code,
84 : default = $invalid_pgver_handling,
85 : pgversions = [
86 : 14 : v14,
87 : 15 : v15,
88 : 16 : v16,
89 : ]
90 : )
91 : };
92 : ($pgversion:expr => $code:expr,
93 : default = $default:expr,
94 : pgversions = [$($sv:literal : $vsv:ident),+ $(,)?]) => {
95 : match ($pgversion) {
96 : $($sv => {
97 : use $crate::$vsv as pgv;
98 : $code
99 : },)+
100 : _ => {
101 : $default
102 : }
103 : }
104 : };
105 : }
106 :
107 : pub mod pg_constants;
108 : pub mod relfile_utils;
109 :
110 : // Export some widely used datatypes that are unlikely to change across Postgres versions
111 : pub use v14::bindings::{uint32, uint64, Oid};
112 : pub use v14::bindings::{BlockNumber, OffsetNumber};
113 : pub use v14::bindings::{MultiXactId, TransactionId};
114 : pub use v14::bindings::{TimeLineID, TimestampTz, XLogRecPtr, XLogSegNo};
115 :
116 : // Likewise for these, although the assumption that these don't change is a little more iffy.
117 : pub use v14::bindings::{MultiXactOffset, MultiXactStatus};
118 : pub use v14::bindings::{PageHeaderData, XLogRecord};
119 : pub use v14::xlog_utils::{XLOG_SIZE_OF_XLOG_RECORD, XLOG_SIZE_OF_XLOG_SHORT_PHD};
120 :
121 : pub use v14::bindings::{CheckPoint, ControlFileData};
122 :
123 : // from pg_config.h. These can be changed with configure options --with-blocksize=BLOCKSIZE and
124 : // --with-segsize=SEGSIZE, but assume the defaults for now.
125 : pub const BLCKSZ: u16 = 8192;
126 : pub const RELSEG_SIZE: u32 = 1024 * 1024 * 1024 / (BLCKSZ as u32);
127 : pub const XLOG_BLCKSZ: usize = 8192;
128 : pub const WAL_SEGMENT_SIZE: usize = 16 * 1024 * 1024;
129 :
130 : pub const MAX_SEND_SIZE: usize = XLOG_BLCKSZ * 16;
131 :
132 : // Export some version independent functions that are used outside of this mod
133 : pub use v14::xlog_utils::encode_logical_message;
134 : pub use v14::xlog_utils::from_pg_timestamp;
135 : pub use v14::xlog_utils::get_current_timestamp;
136 : pub use v14::xlog_utils::to_pg_timestamp;
137 : pub use v14::xlog_utils::XLogFileName;
138 :
139 : pub use v14::bindings::DBState_DB_SHUTDOWNED;
140 ECB (306880) :
141 CBC 305298 : pub fn bkpimage_is_compressed(bimg_info: u8, version: u32) -> anyhow::Result<bool> {
142 305298 : dispatch_pgversion!(version, Ok(pgv::bindings::bkpimg_is_compressed(bimg_info)))
143 GIC 305298 : }
144 ECB (638) :
145 CBC 641 : pub fn generate_wal_segment(
146 641 : segno: u64,
147 641 : system_id: u64,
148 641 : pg_version: u32,
149 641 : lsn: Lsn,
150 641 : ) -> Result<Bytes, SerializeError> {
151 GIC 641 : assert_eq!(segno, lsn.segment_number(WAL_SEGMENT_SIZE));
152 :
153 ECB (638) : dispatch_pgversion!(
154 CBC 641 : pg_version,
155 GBC 641 : pgv::xlog_utils::generate_wal_segment(segno, system_id, lsn),
156 UIC 0 : Err(SerializeError::BadInput)
157 ECB (638) : )
158 GIC 641 : }
159 ECB (635) :
160 CBC 638 : pub fn generate_pg_control(
161 638 : pg_control_bytes: &[u8],
162 638 : checkpoint_bytes: &[u8],
163 638 : lsn: Lsn,
164 638 : pg_version: u32,
165 638 : ) -> anyhow::Result<(Bytes, u64)> {
166 638 : dispatch_pgversion!(
167 638 : pg_version,
168 GBC 638 : pgv::xlog_utils::generate_pg_control(pg_control_bytes, checkpoint_bytes, lsn),
169 UIC 0 : anyhow::bail!("Unknown version {}", pg_version)
170 ECB (635) : )
171 GIC 638 : }
172 :
173 : // PG timeline is always 1, changing it doesn't have any useful meaning in Neon.
174 : //
175 : // NOTE: this is not to be confused with Neon timelines; different concept!
176 : //
177 : // It's a shaky assumption, that it's always 1. We might import a
178 : // PostgreSQL data directory that has gone through timeline bumps,
179 : // for example. FIXME later.
180 : pub const PG_TLI: u32 = 1;
181 :
182 ECB (80) : // See TransactionIdIsNormal in transam.h
183 CBC 80 : pub const fn transaction_id_is_normal(id: TransactionId) -> bool {
184 80 : id > pg_constants::FIRST_NORMAL_TRANSACTION_ID
185 GIC 80 : }
186 :
187 ECB (40) : // See TransactionIdPrecedes in transam.c
188 CBC 40 : pub const fn transaction_id_precedes(id1: TransactionId, id2: TransactionId) -> bool {
189 40 : /*
190 40 : * If either ID is a permanent XID then we can just do unsigned
191 40 : * comparison. If both are normal, do a modulo-2^32 comparison.
192 40 : */
193 40 :
194 GBC 40 : if !(transaction_id_is_normal(id1)) || !transaction_id_is_normal(id2) {
195 LBC (40) : return id1 < id2;
196 CBC 40 : }
197 40 :
198 40 : let diff = id1.wrapping_sub(id2) as i32;
199 40 : diff < 0
200 GIC 40 : }
201 :
202 ECB (133277) : // Check if page is not yet initialized (port of Postgres PageIsInit() macro)
203 CBC 133267 : pub fn page_is_new(pg: &[u8]) -> bool {
204 133267 : pg[14] == 0 && pg[15] == 0 // pg_upper == 0
205 GIC 133267 : }
206 :
207 EUB : // ExtractLSN from page header
208 UBC 0 : pub fn page_get_lsn(pg: &[u8]) -> Lsn {
209 0 : Lsn(
210 0 : ((u32::from_le_bytes(pg[0..4].try_into().unwrap()) as u64) << 32)
211 0 : | u32::from_le_bytes(pg[4..8].try_into().unwrap()) as u64,
212 0 : )
213 UIC 0 : }
214 ECB (128439) :
215 CBC 128411 : pub fn page_set_lsn(pg: &mut [u8], lsn: Lsn) {
216 128411 : pg[0..4].copy_from_slice(&((lsn.0 >> 32) as u32).to_le_bytes());
217 128411 : pg[4..8].copy_from_slice(&(lsn.0 as u32).to_le_bytes());
218 GIC 128411 : }
219 :
220 : // This is port of function with the same name from freespace.c.
221 : // The only difference is that it does not have "level" parameter because XLogRecordPageWithFreeSpace
222 ECB (47) : // always call it with level=FSM_BOTTOM_LEVEL
223 CBC 44 : pub fn fsm_logical_to_physical(addr: BlockNumber) -> BlockNumber {
224 44 : let mut leafno = addr;
225 44 : const FSM_TREE_DEPTH: u32 = if pg_constants::SLOTS_PER_FSM_PAGE >= 1626 {
226 44 : 3
227 44 : } else {
228 44 : 4
229 44 : };
230 44 :
231 44 : /* Count upper level nodes required to address the leaf page */
232 44 : let mut pages: BlockNumber = 0;
233 176 : for _l in 0..FSM_TREE_DEPTH {
234 132 : pages += leafno + 1;
235 132 : leafno /= pg_constants::SLOTS_PER_FSM_PAGE;
236 GIC 132 : }
237 ECB (47) : /* Turn the page count into 0-based block number */
238 CBC 44 : pages - 1
239 GIC 44 : }
240 :
241 : pub mod waldecoder {
242 : use bytes::{Buf, Bytes, BytesMut};
243 : use std::num::NonZeroU32;
244 : use thiserror::Error;
245 : use utils::lsn::Lsn;
246 :
247 : pub enum State {
248 : WaitingForRecord,
249 : ReassemblingRecord {
250 : recordbuf: BytesMut,
251 : contlen: NonZeroU32,
252 : },
253 : SkippingEverything {
254 : skip_until_lsn: Lsn,
255 : },
256 : }
257 :
258 : pub struct WalStreamDecoder {
259 : pub lsn: Lsn,
260 : pub pg_version: u32,
261 : pub inputbuf: BytesMut,
262 : pub state: State,
263 : }
264 ECB (7) :
265 GIC 7 : #[derive(Error, Debug, Clone)]
266 : #[error("{msg} at {lsn}")]
267 : pub struct WalDecodeError {
268 : pub msg: String,
269 : pub lsn: Lsn,
270 : }
271 :
272 ECB (2396) : impl WalStreamDecoder {
273 CBC 2413 : pub fn new(lsn: Lsn, pg_version: u32) -> WalStreamDecoder {
274 2413 : WalStreamDecoder {
275 2413 : lsn,
276 2413 : pg_version,
277 2413 : inputbuf: BytesMut::new(),
278 2413 : state: State::WaitingForRecord,
279 2413 : }
280 GIC 2413 : }
281 :
282 ECB (1624995) : // The latest LSN position fed to the decoder.
283 CBC 1597831 : pub fn available(&self) -> Lsn {
284 1597831 : self.lsn + self.inputbuf.remaining() as u64
285 GIC 1597831 : }
286 ECB (2499570) :
287 CBC 2429925 : pub fn feed_bytes(&mut self, buf: &[u8]) {
288 2429925 : self.inputbuf.extend_from_slice(buf);
289 GIC 2429925 : }
290 ECB (171241544) :
291 CBC 171280692 : pub fn poll_decode(&mut self) -> Result<Option<(Lsn, Bytes)>, WalDecodeError> {
292 171280692 : dispatch_pgversion!(
293 GIC 171280692 : self.pg_version,
294 : {
295 ECB (171241544) : use pgv::waldecoder_handler::WalStreamDecoderHandler;
296 GIC 171280692 : self.poll_decode_internal()
297 EUB : },
298 UBC 0 : Err(WalDecodeError {
299 0 : msg: format!("Unknown version {}", self.pg_version),
300 0 : lsn: self.lsn,
301 UIC 0 : })
302 ECB (171241544) : )
303 GIC 171280692 : }
304 : }
305 : }
|