From a309bff820b9c3a1cf178388eef4bf229888cb1e Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Date: Wed, 18 Aug 2021 13:58:15 +0900
Subject: [PATCH v2] Fix basebackup to generate correct WAL-Ranges info.

While WAL-Ranges in backup_manifest is supposed to have the WAL range
to apply at recovery. it starts from the beginning of the oldest
timeline if the starting TLI > 1.  As the result pg_verifybackup may
result in a false failure for a valid backup. Adjust the logic to make
the WAL-Ranges starts with the actual start LSN.

Backpatch to PG13 where this feature has been introduced.
---
 src/backend/replication/backup_manifest.c | 17 ++++++++++++-----
 src/bin/pg_verifybackup/t/007_wal.pl      | 18 +++++++++++++++++-
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/src/backend/replication/backup_manifest.c b/src/backend/replication/backup_manifest.c
index 1e07d99e64..a672690c7d 100644
--- a/src/backend/replication/backup_manifest.c
+++ b/src/backend/replication/backup_manifest.c
@@ -236,11 +236,18 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 					errmsg("expected end timeline %u but found timeline %u",
 						   starttli, entry->tli));
 
-		if (!XLogRecPtrIsInvalid(entry->begin))
-			tl_beginptr = entry->begin;
-		else
-		{
+		/*
+		 * If this timeline entry matches with the timeline on which the backup
+		 * started, WAL needs to be checked from the start LSN of the backup.
+		 * If this entry refers to a newer timeline, WAL needs to be checked
+		 * since the beginning of this timeline, so use the LSN where the
+		 * timeline began.
+		 */
+		if (starttli == entry->tli)
 			tl_beginptr = startptr;
+		else
+		{
+			tl_beginptr = entry->begin;
 
 			/*
 			 * If we reach a TLI that has no valid beginning LSN, there can't
@@ -248,7 +255,7 @@ AddWALInfoToBackupManifest(backup_manifest_info *manifest, XLogRecPtr startptr,
 			 * better have arrived at the expected starting TLI. If not,
 			 * something's gone horribly wrong.
 			 */
-			if (starttli != entry->tli)
+			if (!XLogRecPtrIsInvalid(entry->begin))
 				ereport(ERROR,
 						errmsg("expected start timeline %u but found timeline %u",
 							   starttli, entry->tli));
diff --git a/src/bin/pg_verifybackup/t/007_wal.pl b/src/bin/pg_verifybackup/t/007_wal.pl
index 56d536675c..ae35e035eb 100644
--- a/src/bin/pg_verifybackup/t/007_wal.pl
+++ b/src/bin/pg_verifybackup/t/007_wal.pl
@@ -7,7 +7,7 @@ use Config;
 use File::Path qw(rmtree);
 use PostgresNode;
 use TestLib;
-use Test::More tests => 7;
+use Test::More tests => 9;
 
 # Start up the server and take a backup.
 my $master = get_new_node('master');
@@ -56,3 +56,19 @@ command_fails_like(
 	[ 'pg_verifybackup', $backup_path ],
 	qr/WAL parsing failed for timeline 1/,
 	'corrupt WAL file causes failure');
+
+#
+# Check that WAL-Ranges has the correct values when TLI > 1
+$master->stop;
+$master->append_conf('standby.signal');
+$master->start;
+$master->promote;
+$master->safe_psql('postgres', 'SELECT pg_switch_wal()');
+my $backup_path2 = $master->backup_dir . '/test_tli';
+# base-backup below runs a checkpoint, which removes the first segment
+# of the current timeline
+$master->command_ok([ 'pg_basebackup', '-D', $backup_path2, '--no-sync' ],
+	"base backup 2 ok");
+# Should pass this case
+command_ok([ 'pg_verifybackup', $backup_path2 ],
+	'verifybackup should pass for a valid backup on timeline > 1');
-- 
2.27.0

