summaryrefslogtreecommitdiff
path: root/src/bin/pg_rewind/pg_rewind.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2020-12-03 15:57:48 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2020-12-03 15:58:02 +0200
commit0740857de7804609783eb9f11f055776c1fff4e8 (patch)
tree68a21b2960e4d2d7e53222df0f5b48a48e221f0b /src/bin/pg_rewind/pg_rewind.c
parentf00c4400270f21905305a4648d1f3d57400a2e15 (diff)
Fix pg_rewind bugs when rewinding a standby server.
If the target is a standby server, its WAL doesn't end at the last checkpoint record, but at minRecoveryPoint. We must scan all the WAL from the last common checkpoint all the way up to minRecoveryPoint for modified pages, and also consider that portion when determining whether the server needs rewinding. Backpatch to all supported versions. Author: Ian Barwick and me Discussion: https://www.postgresql.org/message-id/CABvVfJU-LDWvoz4-Yow3Ay5LZYTuPD7eSjjE4kGyNZpXC6FrVQ%40mail.gmail.com
Diffstat (limited to 'src/bin/pg_rewind/pg_rewind.c')
-rw-r--r--src/bin/pg_rewind/pg_rewind.c56
1 files changed, 34 insertions, 22 deletions
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index ce1765d0d14..77c19941158 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -97,6 +97,7 @@ main(int argc, char **argv)
XLogRecPtr chkptrec;
TimeLineID chkpttli;
XLogRecPtr chkptredo;
+ XLogRecPtr target_wal_endrec;
size_t size;
char *buffer;
bool rewind_needed;
@@ -227,42 +228,55 @@ main(int argc, char **argv)
{
printf(_("source and target cluster are on the same timeline\n"));
rewind_needed = false;
+ target_wal_endrec = 0;
}
else
{
+ XLogRecPtr chkptendrec;
+
findCommonAncestorTimeline(&divergerec, &lastcommontliIndex);
printf(_("servers diverged at WAL position %X/%X on timeline %u\n"),
(uint32) (divergerec >> 32), (uint32) divergerec,
targetHistory[lastcommontliIndex].tli);
/*
+ * Determine the end-of-WAL on the target.
+ *
+ * The WAL ends at the last shutdown checkpoint, or at
+ * minRecoveryPoint if it was a standby. (If we supported rewinding a
+ * server that was not shut down cleanly, we would need to replay
+ * until we reach the first invalid record, like crash recovery does.)
+ */
+
+ /* read the checkpoint record on the target to see where it ends. */
+ chkptendrec = readOneRecord(datadir_target,
+ ControlFile_target.checkPoint,
+ targetNentries - 1);
+
+ if (ControlFile_target.minRecoveryPoint > chkptendrec)
+ {
+ target_wal_endrec = ControlFile_target.minRecoveryPoint;
+ }
+ else
+ {
+ target_wal_endrec = chkptendrec;
+ }
+
+ /*
* 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.
*/
- if (ControlFile_target.checkPoint >= divergerec)
+ if (target_wal_endrec > divergerec)
{
rewind_needed = true;
}
else
{
- XLogRecPtr chkptendrec;
-
- /* Read the checkpoint record on the target to see where it ends. */
- chkptendrec = readOneRecord(datadir_target,
- ControlFile_target.checkPoint,
- targetNentries - 1);
-
- /*
- * If the histories diverged exactly at the end of the shutdown
- * checkpoint record on the target, there are no WAL records in
- * the target that don't belong in the source's history, and no
- * rewind is needed.
- */
- if (chkptendrec == divergerec)
- rewind_needed = false;
- else
- rewind_needed = true;
+ /* the last common checkpoint record must be part of target WAL */
+ Assert(target_wal_endrec == divergerec);
+
+ rewind_needed = false;
}
}
@@ -291,13 +305,11 @@ main(int argc, char **argv)
/*
* Read the target WAL from last checkpoint before the point of fork, to
* extract all the pages that were modified on the target cluster after
- * the fork. We can stop reading after reaching the final shutdown record.
- * XXX: If we supported rewinding a server that was not shut down cleanly,
- * we would need to replay until the end of WAL here.
+ * the fork.
*/
pg_log(PG_PROGRESS, "reading WAL in target\n");
extractPageMap(datadir_target, chkptrec, lastcommontliIndex,
- ControlFile_target.checkPoint);
+ target_wal_endrec);
filemap_finalize();
if (showprogress)