0004-Update-minRecoveryPoint-when-no-rewind-is-required.patch
text/x-patch
Filename: 0004-Update-minRecoveryPoint-when-no-rewind-is-required.patch
Type: text/x-patch
Part: 3
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0004
Subject: Update minRecoveryPoint when no rewind is required
| File | + | − |
|---|---|---|
| src/bin/pg_rewind/pg_rewind.c | 38 | 2 |
| src/bin/pg_rewind/t/010_target_is_ancestor.pl | 14 | 7 |
From 6d534f6d1f1b8a0a375a57cde9479543efb87f14 Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Fri, 9 Aug 2024 18:23:02 +0300
Subject: [PATCH 4/4] Update minRecoveryPoint when no rewind is required
Alternatively, perhaps just copying the history file would be enough?
---
src/bin/pg_rewind/pg_rewind.c | 40 ++++++++++++++++++-
src/bin/pg_rewind/t/010_target_is_ancestor.pl | 21 ++++++----
2 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 101e92b549..e2767ba9ec 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -77,6 +77,9 @@ bool do_sync = true;
static bool restore_wal = false;
DataDirSyncMethod sync_method = DATA_DIR_SYNC_METHOD_FSYNC;
+static char *sourceHistfile;
+static char *sourceHistfileName;
+
/* Target history */
TimeLineHistoryEntry *targetHistory;
int targetNentries;
@@ -372,7 +375,7 @@ main(int argc, char **argv)
*/
if (target_tli == source_tli)
{
- pg_log_info("source and target cluster are on the same timeline");
+ pg_log_info("no rewind required, source and target cluster are on the same timeline");
rewind_needed = false;
target_wal_endrec = 0;
}
@@ -431,12 +434,39 @@ main(int argc, char **argv)
/*
* Check for the possibility that the target is in fact a direct
* ancestor of the source. In that case, there is no divergent history
- * in the target that needs rewinding.
+ * in the target that needs rewinding, but we still update the
+ * target's minRecoveryPoint, so that when you start it up, it will
+ * recover to that timeline. (Otherwise, if it has more WAL locally in
+ * pg_wal or available from the archive, it might choose to follow
+ * some other timeline.)
*/
if (target_wal_endrec > divergerec)
rewind_needed = true;
else
+ {
+ ControlFileData ControlFile_new;
+
rewind_needed = false;
+
+ memcpy(&ControlFile_new, &ControlFile_target, sizeof(ControlFileData));
+ ControlFile_new.minRecoveryPoint = Max(ControlFile_source.minRecoveryPoint,
+ ControlFile_source.checkPoint);
+ ControlFile_new.minRecoveryPointTLI = source_tli;
+ pg_log_info("no rewind required, updating target to source's timeline",
+ LSN_FORMAT_ARGS(ControlFile_new.minRecoveryPoint),
+ ControlFile_new.minRecoveryPointTLI);
+ if (!dry_run)
+ update_controlfile(datadir_target, &ControlFile_new, do_sync);
+
+ /*
+ * Make the timeline history file available to the target. Avoids
+ * having to fetch it immediately at startup, and ensures that it
+ * has the same idea of what the timeline is as we did.
+ */
+ open_target_file(sourceHistfileName, true);
+ write_target_range(sourceHistfile, 0, strlen(sourceHistfile));
+ close_target_file();
+ }
}
if (!rewind_needed)
@@ -872,6 +902,12 @@ getTimelineHistory(TimeLineID tli, bool is_source, int *nentries)
histfile = slurpFile(datadir_target, path, NULL);
history = rewind_parseTimeLineHistory(histfile, tli, nentries);
+ if (is_source)
+ {
+ sourceHistfileName = pstrdup(path);
+ sourceHistfile = histfile;
+ }
+ else
pg_free(histfile);
}
diff --git a/src/bin/pg_rewind/t/010_target_is_ancestor.pl b/src/bin/pg_rewind/t/010_target_is_ancestor.pl
index 541581a4e8..15aaa60f2d 100644
--- a/src/bin/pg_rewind/t/010_target_is_ancestor.pl
+++ b/src/bin/pg_rewind/t/010_target_is_ancestor.pl
@@ -67,8 +67,8 @@ $orig_node->backup_fs_cold('backup_C');
my $source_node = $node_2;
my $source_pgdata = $source_node->data_dir;
-# Create a new node from a backup, and run pg_rewind to rewind it as a
-# follower of $source_node
+# Create a new node from a backup, and rewind it as a follower of
+# $source_node
sub rewind_from_backup
{
my ($backup, $expected_stderr) = @_;
@@ -90,22 +90,29 @@ sub rewind_from_backup
],
0,
[],
- [$expected_stderr],
+ $expected_stderr,
"pg_rewind on node restored from $backup");
# Now move back postgresql.conf with old settings
move("$tmp_folder/postgresql.conf.tmp", "$target_pgdata/postgresql.conf");
+ # Make the more recent WAL from timeline 1 available to the
+ # restored server. It doesn't need it, the point of this is to
+ # test that the server ignores this extra WAL.
+ copy($orig_node->data_dir . "/pg_wal/000000010000000000000001",
+ $target_node->data_dir . "/pg_wal/000000010000000000000001")
+ || die "copying 000000010000000000000001: $!";
+
# Configure it to connect to the new primary
my $node_2_connstr = $node_2->connstr();
$target_node->append_conf(
'postgresql.conf', qq(
primary_conninfo = '$node_2_connstr'
));
+ $node_2->start;
$target_node->set_standby_mode();
$target_node->start;
- $node_2->start;
$node_2->wait_for_catchup($target_node->name);
my $result =
$target_node->safe_psql('postgres', "SELECT * FROM test_tab");
@@ -119,8 +126,8 @@ in node_2),
}
rewind_from_backup('backup_C',
- qr/pg_rewind: rewinding from last common checkpoint at .* on timeline 1/);
-rewind_from_backup('backup_B', qr/pg_rewind: no rewind required/);
-rewind_from_backup('backup_A', qr/pg_rewind: no rewind required/);
+ [qr/pg_rewind: rewinding from last common checkpoint at .* on timeline 1/]);
+rewind_from_backup('backup_B', [qr/no rewind required, updating target to source's timeline/]);
+rewind_from_backup('backup_A', [qr/no rewind required, updating target to source's timeline/]);
done_testing();
--
2.39.2