]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Add recovery test for missing redo segment with backup_label
authorMichael Paquier <michael@paquier.xyz>
Mon, 13 Jul 2026 23:00:46 +0000 (08:00 +0900)
committerMichael Paquier <michael@paquier.xyz>
Mon, 13 Jul 2026 23:11:00 +0000 (08:11 +0900)
This commit adds a test case for early startup where a backup_label file
uses a checkpoint LSN and a redo LSN located in two different segments,
where the segment of the redo LSN is missing.  This code has never been
covered, and is complex enough that a test case is going to be useful in
the long-term.

Nitin has proposed a more complex approach than what is added by this
commit, by forcing a reuse of the injection points to produce a split
between redo and checkpoint.  This commit relies on the checkpoint and
redo LSNs generated by the first steps of the test, combined with a
generated backup_label, making the whole cheaper.

Author: Nitin Jadhav <nitinjadhavpostgres@gmail.com>
Author: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/CAMm1aWZ9Tv=Wrx52_2Ppw+6ULf_twRZuQm=ZWLA_a-kXWykHkQ@mail.gmail.com

src/test/recovery/t/050_redo_segment_missing.pl

index e07ff0c72fee789dd0a15269ecab8f17c1a3921a..16b83d51d012cdf0a895300b7e788378e2d8e0e9 100644 (file)
@@ -6,6 +6,7 @@
 
 use strict;
 use warnings FATAL => 'all';
+use File::Copy qw(copy);
 use PostgreSQL::Test::Cluster;
 use PostgreSQL::Test::Utils;
 use Test::More;
@@ -114,4 +115,47 @@ ok( $logfile =~
          qr/FATAL: .* could not find redo location .* referenced by checkpoint record at .*/,
        "ends with FATAL because it could not find redo location");
 
+# Test for a missing redo record specified in a backup_label file.
+# This reuses the redo and checkpoint LSNs calculated previously and
+# writes a fake backup_label into a fresh node.
+my $node_label = PostgreSQL::Test::Cluster->new('testnode_backup_label');
+$node_label->init;
+$node_label->append_conf('postgresql.conf', "archive_mode = off");
+
+# Copy pg_control from the original node so the new node recognizes the
+# system identifier and timeline.
+copy(
+       $node->data_dir . '/global/pg_control',
+       $node_label->data_dir . '/global/pg_control'
+) or BAIL_OUT("could not copy pg_control");
+
+# Provide only the checkpoint segment, omitting the redo segment.
+copy(
+       $node->data_dir . "/pg_wal/$checkpoint_walfile_name",
+       $node_label->data_dir . "/pg_wal/$checkpoint_walfile_name"
+) or BAIL_OUT("could not copy checkpoint WAL segment");
+
+# Write a fake backup_label with valid checkpoint and redo LSNs.
+open my $fh, '>', $node_label->data_dir . '/backup_label'
+  or BAIL_OUT("could not create backup_label");
+binmode $fh;
+print $fh "START WAL LOCATION: $redo_lsn (file $redo_walfile_name)\n";
+print $fh "CHECKPOINT LOCATION: $checkpoint_lsn\n";
+print $fh "BACKUP METHOD: pg_backup_start\n";
+print $fh "BACKUP FROM: primary\n";
+close $fh;
+
+run_log(
+       [
+               'pg_ctl',
+               '--pgdata' => $node_label->data_dir,
+               '--log' => $node_label->logfile,
+               'start',
+       ]);
+
+my $logfile_label = slurp_file($node_label->logfile());
+ok( $logfile_label =~
+         qr/FATAL: .* could not find redo location .* referenced by checkpoint record at .*/,
+       "ends with FATAL for missing redo location with backup_label");
+
 done_testing();