From 50b2192e0c7f64d63ab3571b62e563140485dea9 Mon Sep 17 00:00:00 2001 From: Paul Guo Date: Tue, 19 Mar 2019 12:41:30 +0800 Subject: [PATCH] Ensure target clean shutdown at beginning of pg_rewind --- src/bin/pg_rewind/pg_rewind.c | 60 +++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c index aa753bb315..946edec62c 100644 --- a/src/bin/pg_rewind/pg_rewind.c +++ b/src/bin/pg_rewind/pg_rewind.c @@ -41,6 +41,7 @@ static void updateControlFile(ControlFileData *ControlFile); static void syncTargetDirectory(void); static void sanityChecks(void); static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex); +static void ensureCleanShutdown(const char *argv0); static ControlFileData ControlFile_target; static ControlFileData ControlFile_source; @@ -235,6 +236,21 @@ main(int argc, char **argv) digestControlFile(&ControlFile_target, buffer, size); pg_free(buffer); + /* + * If the target instance was not cleanly shut down, run a single-user + * postgres session really quickly and reload the control file to get the + * new state. + */ + if (ControlFile_target.state != DB_SHUTDOWNED && + ControlFile_target.state != DB_SHUTDOWNED_IN_RECOVERY) + { + ensureCleanShutdown(argv[0]); + + buffer = slurpFile(datadir_target, "global/pg_control", &size); + digestControlFile(&ControlFile_target, buffer, size); + pg_free(buffer); + } + buffer = fetchFile("global/pg_control", &size); digestControlFile(&ControlFile_source, buffer, size); pg_free(buffer); @@ -722,3 +738,47 @@ syncTargetDirectory(void) fsync_pgdata(datadir_target, progname, PG_VERSION_NUM); } + +/* + * Ensure clean shutdown of target instance by launching single-user mode + * postgres to do crash recovery. + */ +static void +ensureCleanShutdown(const char *argv0) +{ + int ret; +#define MAXCMDLEN (2 * MAXPGPATH) + char exec_path[MAXPGPATH]; + char cmd[MAXCMDLEN]; + + /* locate postgres binary */ + if ((ret = find_other_exec(argv0, "postgres", + PG_BACKEND_VERSIONSTR, + exec_path)) < 0) + { + char full_path[MAXPGPATH]; + + if (find_my_exec(argv0, full_path) < 0) + strlcpy(full_path, progname, sizeof(full_path)); + + if (ret == -1) + pg_fatal("The program \"postgres\" is needed by %s but was \n" + "not found in the same directory as \"%s\".\n" + "Check your installation.\n", progname, full_path); + else + pg_fatal("The program \"postgres\" was found by \"%s\"\n" + "but was not the same version as %s.\n" + "Check your installation.\n", full_path, progname); + } + + /* only skip processing after ensuring presence of postgres */ + if (dry_run) + return; + + /* finally run postgres single-user mode */ + snprintf(cmd, MAXCMDLEN, "\"%s\" --single -D \"%s\" template1 < %s", + exec_path, datadir_target, DEVNULL); + + if (system(cmd) != 0) + pg_fatal("postgres single-user mode of target instance failed for command: %s\n", cmd); +} -- 2.17.2