Line data Source code
1 : //! This module defines the WAL record format used within the pageserver.
2 :
3 : use bytes::Bytes;
4 : use postgres_ffi::walrecord::{describe_postgres_wal_record, MultiXactMember};
5 : use postgres_ffi::{MultiXactId, MultiXactOffset, TimestampTz, TransactionId};
6 : use serde::{Deserialize, Serialize};
7 : use utils::bin_ser::DeserializeError;
8 :
9 : /// Each update to a page is represented by a NeonWalRecord. It can be a wrapper
10 : /// around a PostgreSQL WAL record, or a custom neon-specific "record".
11 2277 : #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
12 : pub enum NeonWalRecord {
13 : /// Native PostgreSQL WAL record
14 : Postgres { will_init: bool, rec: Bytes },
15 :
16 : /// Clear bits in heap visibility map. ('flags' is bitmap of bits to clear)
17 : ClearVisibilityMapFlags {
18 : new_heap_blkno: Option<u32>,
19 : old_heap_blkno: Option<u32>,
20 : flags: u8,
21 : },
22 : /// Mark transaction IDs as committed on a CLOG page
23 : ClogSetCommitted {
24 : xids: Vec<TransactionId>,
25 : timestamp: TimestampTz,
26 : },
27 : /// Mark transaction IDs as aborted on a CLOG page
28 : ClogSetAborted { xids: Vec<TransactionId> },
29 : /// Extend multixact offsets SLRU
30 : MultixactOffsetCreate {
31 : mid: MultiXactId,
32 : moff: MultiXactOffset,
33 : },
34 : /// Extend multixact members SLRU.
35 : MultixactMembersCreate {
36 : moff: MultiXactOffset,
37 : members: Vec<MultiXactMember>,
38 : },
39 : /// Update the map of AUX files, either writing or dropping an entry
40 : AuxFile {
41 : file_path: String,
42 : content: Option<Bytes>,
43 : },
44 : // Truncate visibility map page
45 : TruncateVisibilityMap {
46 : trunc_byte: usize,
47 : trunc_offs: usize,
48 : },
49 :
50 : /// A testing record for unit testing purposes. It supports append data to an existing image, or clear it.
51 : #[cfg(feature = "testing")]
52 : Test {
53 : /// Append a string to the image.
54 : append: String,
55 : /// Clear the image before appending.
56 : clear: bool,
57 : /// Treat this record as an init record. `clear` should be set to true if this field is set
58 : /// to true. This record does not need the history WALs to reconstruct. See [`NeonWalRecord::will_init`] and
59 : /// its references in `timeline.rs`.
60 : will_init: bool,
61 : },
62 : }
63 :
64 : impl NeonWalRecord {
65 : /// Does replaying this WAL record initialize the page from scratch, or does
66 : /// it need to be applied over the previous image of the page?
67 146997 : pub fn will_init(&self) -> bool {
68 146997 : // If you change this function, you'll also need to change ValueBytes::will_init
69 146997 : match self {
70 145626 : NeonWalRecord::Postgres { will_init, rec: _ } => *will_init,
71 : #[cfg(feature = "testing")]
72 1351 : NeonWalRecord::Test { will_init, .. } => *will_init,
73 : // None of the special neon record types currently initialize the page
74 20 : _ => false,
75 : }
76 146997 : }
77 :
78 : #[cfg(feature = "testing")]
79 201 : pub fn wal_append(s: impl AsRef<str>) -> Self {
80 201 : Self::Test {
81 201 : append: s.as_ref().to_string(),
82 201 : clear: false,
83 201 : will_init: false,
84 201 : }
85 201 : }
86 :
87 : #[cfg(feature = "testing")]
88 2 : pub fn wal_clear(s: impl AsRef<str>) -> Self {
89 2 : Self::Test {
90 2 : append: s.as_ref().to_string(),
91 2 : clear: true,
92 2 : will_init: false,
93 2 : }
94 2 : }
95 :
96 : #[cfg(feature = "testing")]
97 52 : pub fn wal_init(s: impl AsRef<str>) -> Self {
98 52 : Self::Test {
99 52 : append: s.as_ref().to_string(),
100 52 : clear: true,
101 52 : will_init: true,
102 52 : }
103 52 : }
104 : }
105 :
106 : /// Build a human-readable string to describe a WAL record
107 : ///
108 : /// For debugging purposes
109 0 : pub fn describe_wal_record(rec: &NeonWalRecord) -> Result<String, DeserializeError> {
110 0 : match rec {
111 0 : NeonWalRecord::Postgres { will_init, rec } => Ok(format!(
112 0 : "will_init: {}, {}",
113 0 : will_init,
114 0 : describe_postgres_wal_record(rec)?
115 : )),
116 0 : _ => Ok(format!("{:?}", rec)),
117 : }
118 0 : }
|