27.08.2026, 16:17, "Andrey Borodin" <[email protected]>:
> It seems to me that 002_archiving.pl has a race. Generating and
> archiving WAL on timeline 2 does not guarantee that standby2 replays it
> before promotion. It can still be promoted while lastRecTLI is 1, so
> the test would not prove that the restored timeline 2 history was used.
> I think it needs to wait for the recorded timeline_2_lsn before calling
> promote(), for example:
>
> $caughtup_query =
> "SELECT '$timeline_2_lsn'::pg_lsn <= pg_last_wal_replay_lsn()";
> $node_standby2->poll_query_until('postgres', $caughtup_query)
> or die "Timed out while waiting for standby2 to reach timeline 2";
Hi, Andrey!
Thank you for the review. You are right, there is a race.
In v2 i added suggested query to wait timeline_2_lsn. This will help
to avoid promotion before timeline2 is applied.
Best regards, Stepan Filippov.
Best regards, Stepan Filippov.
From 30250e100b8be4beaf5566a3b58da4edc161f097 Mon Sep 17 00:00:00 2001 From: debebantur <[email protected]> Date: Mon, 7 Sep 2026 08:37:02 +0000 Subject: [PATCH] changed end of recovery timeline
---
src/backend/access/transam/xlog.c | 2 +-
src/test/recovery/t/002_archiving.pl | 18 ++++++++++++++++++
src/test/recovery/t/028_pitr_timelines.pl | 9 +++++++++
3 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f85b528608..6b0b27d853 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6408,7 +6408,7 @@ StartupXLOG(void)
* To minimize the window for that, try to do as little as possible
* between here and writing the end-of-recovery record.
*/
- writeTimeLineHistory(newTLI, recoveryTargetTLI,
+ writeTimeLineHistory(newTLI, endOfRecoveryInfo->lastRecTLI,
EndOfLog, endOfRecoveryInfo->recoveryStopReason);
ereport(LOG,
diff --git a/src/test/recovery/t/002_archiving.pl b/src/test/recovery/t/002_archiving.pl
index aa40f58e6d..b66aaefbfd 100644
--- a/src/test/recovery/t/002_archiving.pl
+++ b/src/test/recovery/t/002_archiving.pl
@@ -100,6 +100,20 @@ $caughtup_query =
$node_primary->poll_query_until('postgres', $caughtup_query)
or die "Timed out while waiting for archiving of 00000002.history";
+# Generate and archive some WAL on timeline 2. This ensures that standby2
+# actually reaches timeline 2, so that its history file is needed again when
+# standby2 is promoted.
+$node_standby->safe_psql('postgres', "CREATE TABLE timeline_2_marker (a int)");
+my $timeline_2_lsn =
+ $node_standby->safe_psql('postgres', "SELECT pg_current_wal_lsn()");
+my $timeline_2_walfile = $node_standby->safe_psql(
+ 'postgres', "SELECT pg_walfile_name('$timeline_2_lsn')");
+$node_standby->safe_psql('postgres', "SELECT pg_switch_wal()");
+$caughtup_query =
+ "SELECT size IS NOT NULL FROM pg_stat_file('$primary_archive/$timeline_2_walfile', true)";
+$node_primary->poll_query_until('postgres', $caughtup_query)
+ or die "Timed out while waiting for archiving of $timeline_2_walfile";
+
# recovery_end_command should have been triggered on promotion.
ok( -f "$data_dir/$recovery_end_command_file",
'recovery_end_command executed after promotion');
@@ -131,6 +145,10 @@ $node_standby2->start;
# Save the log location, to see the failure of recovery_end_command.
my $log_location = -s $node_standby2->logfile;
+$caughtup_query = "SELECT '$timeline_2_lsn'::pg_lsn <= pg_last_wal_replay_lsn()";
+$node_standby2->poll_query_until('postgres', $caughtup_query)
+ or die "Timed out while waiting for standby2 to reach timeline 2";
+
# Now promote standby2, and check that temporary files specifically
# generated during archive recovery are removed by the end of recovery.
$node_standby2->promote;
diff --git a/src/test/recovery/t/028_pitr_timelines.pl b/src/test/recovery/t/028_pitr_timelines.pl
index ae617f6195..429b6e8220 100644
--- a/src/test/recovery/t/028_pitr_timelines.pl
+++ b/src/test/recovery/t/028_pitr_timelines.pl
@@ -150,6 +150,15 @@ $node_pitr->poll_query_until('postgres',
# Stop the node. This archives the last segment.
$node_pitr->stop();
+# The new timeline branched from timeline 1 at the recovery target, before
+# timeline 2 branched from timeline 1. Its history must therefore name
+# timeline 1 as its direct parent, rather than copying timeline 2's history.
+my $history = slurp_file($node_primary->archive_dir . '/00000003.history');
+like(
+ $history,
+ qr/^1\t[0-9A-F]+\/[0-9A-F]+\t[^\r\n]*(?:\r?\n)?\z/,
+ "new timeline history has the timeline containing the target as parent");
+
# Test archive recovery on the timeline created by the PITR. This
# replays the end-of-recovery record that switches from timeline 1 to
# 3.
--
2.34.1
