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::{MultiXactMember, describe_postgres_wal_record};
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 2119 : #[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 : /// Only append the record if the current image is the same as the one specified in this field.
62 : only_if: Option<String>,
63 : },
64 : }
65 :
66 : impl NeonWalRecord {
67 : /// Does replaying this WAL record initialize the page from scratch, or does
68 : /// it need to be applied over the previous image of the page?
69 293519 : pub fn will_init(&self) -> bool {
70 293519 : // If you change this function, you'll also need to change ValueBytes::will_init
71 293519 : match self {
72 291252 : NeonWalRecord::Postgres { will_init, rec: _ } => *will_init,
73 : #[cfg(feature = "testing")]
74 2227 : NeonWalRecord::Test { will_init, .. } => *will_init,
75 : // None of the special neon record types currently initialize the page
76 40 : _ => false,
77 : }
78 293519 : }
79 :
80 : #[cfg(feature = "testing")]
81 507 : pub fn wal_append(s: impl AsRef<str>) -> Self {
82 507 : Self::Test {
83 507 : append: s.as_ref().to_string(),
84 507 : clear: false,
85 507 : will_init: false,
86 507 : only_if: None,
87 507 : }
88 507 : }
89 :
90 : #[cfg(feature = "testing")]
91 12 : pub fn wal_append_conditional(s: impl AsRef<str>, only_if: impl AsRef<str>) -> Self {
92 12 : Self::Test {
93 12 : append: s.as_ref().to_string(),
94 12 : clear: false,
95 12 : will_init: false,
96 12 : only_if: Some(only_if.as_ref().to_string()),
97 12 : }
98 12 : }
99 :
100 : #[cfg(feature = "testing")]
101 4 : pub fn wal_clear(s: impl AsRef<str>) -> Self {
102 4 : Self::Test {
103 4 : append: s.as_ref().to_string(),
104 4 : clear: true,
105 4 : will_init: false,
106 4 : only_if: None,
107 4 : }
108 4 : }
109 :
110 : #[cfg(feature = "testing")]
111 116 : pub fn wal_init(s: impl AsRef<str>) -> Self {
112 116 : Self::Test {
113 116 : append: s.as_ref().to_string(),
114 116 : clear: true,
115 116 : will_init: true,
116 116 : only_if: None,
117 116 : }
118 116 : }
119 : }
120 :
121 : /// Build a human-readable string to describe a WAL record
122 : ///
123 : /// For debugging purposes
124 0 : pub fn describe_wal_record(rec: &NeonWalRecord) -> Result<String, DeserializeError> {
125 0 : match rec {
126 0 : NeonWalRecord::Postgres { will_init, rec } => Ok(format!(
127 0 : "will_init: {}, {}",
128 0 : will_init,
129 0 : describe_postgres_wal_record(rec)?
130 : )),
131 0 : _ => Ok(format!("{:?}", rec)),
132 : }
133 0 : }
|