postgres_ffi/wal_generate: add last_wal_record_xlog_switch and use it in tests

Fix #1190: WalDecoder did not return correct LSN of the next record after
processing a XLOG_SWITCH record
This commit is contained in:
Egor Suvorov
2022-06-25 00:53:45 +03:00
committed by Egor Suvorov
parent 52f445094a
commit 85bda437de
4 changed files with 26 additions and 4 deletions

View File

@@ -226,10 +226,10 @@ impl WalStreamDecoder {
self.padlen = self.lsn.calc_padding(8u32) as u32;
}
// Always align resulting LSN on 0x8 boundary -- that is important for getPage()
// and WalReceiver integration. Since this code is used both for WalReceiver and
// initial WAL import let's force alignment right here.
let result = (self.lsn.align(), recordbuf);
// We should return LSN of the next record, not the last byte of this record or
// the byte immediately after. Note that this handles both XLOG_SWITCH and usual
// records, the former "spans" until the next WAL segment (see test_xlog_switch).
let result = (self.lsn + self.padlen as u64, recordbuf);
Ok(Some(result))
}
}

View File

@@ -13,6 +13,7 @@ fn main() -> Result<()> {
.help("Type of WAL to generate")
.possible_values([
"simple",
"last_wal_record_xlog_switch",
"last_wal_record_crossing_segment",
"wal_record_crossing_segment_followed_by_small_one",
])
@@ -57,6 +58,7 @@ fn main() -> Result<()> {
let wal_generate = |arg_matches: &ArgMatches, client| {
let lsn = match arg_matches.value_of("type").unwrap() {
"simple" => generate_simple(client)?,
"last_wal_record_xlog_switch" => generate_last_wal_record_xlog_switch(client)?,
"last_wal_record_crossing_segment" => {
generate_last_wal_record_crossing_segment(client)?
}

View File

@@ -250,6 +250,25 @@ pub fn generate_simple(client: &mut impl postgres::GenericClient) -> Result<PgLs
})
}
pub fn generate_last_wal_record_xlog_switch(
client: &mut impl postgres::GenericClient,
) -> Result<PgLsn> {
// Do not use generate_internal because here we end up with flush_lsn exactly on
// the segment boundary and insert_lsn after the initial page header, which is unusual.
ensure_server_config(client)?;
client.execute("CREATE table t(x int)", &[])?;
let after_xlog_switch: PgLsn = client.query_one("SELECT pg_switch_wal()", &[])?.get(0);
let next_segment = PgLsn::from(0x0200_0000);
ensure!(
after_xlog_switch <= next_segment,
"XLOG_SWITCH message ended after the expected segment boundary: {} > {}",
after_xlog_switch,
next_segment
);
Ok(next_segment)
}
fn generate_single_logical_message(
client: &mut impl postgres::GenericClient,
transactional: bool,

View File

@@ -9,6 +9,7 @@ import pytest
@pytest.mark.parametrize('wal_type',
[
'simple',
'last_wal_record_xlog_switch',
'last_wal_record_crossing_segment',
'wal_record_crossing_segment_followed_by_small_one',
])