From 4d1b1c999285f00273ee2afe322133a18ffd23d5 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 18 Mar 2016 14:53:53 +0900 Subject: [PATCH 2/3] fsync properly files modified by pg_rewind Files updated by pg_rewind may have their changes lost in case of crashes if those are not flushed correctly to disk, making a potential PGDATA directory corrupted. pg_rewind invokes initdb -S for this purpose, flushing all dirty files at once for performance purposes because a short execution time matters with pg_rewind. --- src/bin/pg_rewind/file_ops.c | 3 ++- src/bin/pg_rewind/pg_rewind.c | 54 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/bin/pg_rewind/file_ops.c b/src/bin/pg_rewind/file_ops.c index 32eab3a..e775685 100644 --- a/src/bin/pg_rewind/file_ops.c +++ b/src/bin/pg_rewind/file_ops.c @@ -79,7 +79,8 @@ close_target_file(void) dstpath, strerror(errno)); dstfd = -1; - /* fsync? */ + + /* fsync is done globally at the end of processing */ } void diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c index c5589b9..5377bd4 100644 --- a/src/bin/pg_rewind/pg_rewind.c +++ b/src/bin/pg_rewind/pg_rewind.c @@ -36,6 +36,7 @@ static void createBackupLabel(XLogRecPtr startpoint, TimeLineID starttli, static void digestControlFile(ControlFileData *ControlFile, char *source, size_t size); static void updateControlFile(ControlFileData *ControlFile); +static void syncTargetDirectory(const char *argv0); static void sanityChecks(void); static void findCommonAncestorTimeline(XLogRecPtr *recptr, int *tliIndex); @@ -349,6 +350,9 @@ main(int argc, char **argv) ControlFile_new.state = DB_IN_ARCHIVE_RECOVERY; updateControlFile(&ControlFile_new); + pg_log(PG_PROGRESS, "syncing target data directory via initdb -S\n"); + syncTargetDirectory(argv[0]); + printf(_("Done!\n")); return 0; @@ -650,3 +654,53 @@ updateControlFile(ControlFileData *ControlFile) close_target_file(); } + +/* + * Sync data directory to ensure that what has been generated up to now is + * persistent in case of a crash, and this is done once globally for + * performance reasons as sync requests on individual files would be + * a negative impact on the running time of pg_rewind. This is invoked at + * the end of processing once everything has been processed and written. + */ +static void +syncTargetDirectory(const char *argv0) +{ + int ret; + char exec_path[MAXPGPATH]; + char cmd[MAXPGPATH]; + + if (dry_run) + return; + + /* Grab and invoke initdb to perform the sync */ + if ((ret = find_other_exec(argv0, "initdb", + "initdb (PostgreSQL) " PG_VERSION "\n", + 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 \"initdb\" 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\" but was \n" + "not the same version as %s.\n" + "Check your installation.\n", progname, full_path); + } + + /* now run initdb */ + if (debug) + snprintf(cmd, MAXPGPATH, "\"%s\" -D \"%s\" -S", + exec_path, datadir_target); + else + snprintf(cmd, MAXPGPATH, "\"%s\" -D \"%s\" -S > \"%s\"", + exec_path, datadir_target, DEVNULL); + + if (system(cmd) != 0) + pg_fatal("sync of target directory with initdb -S failed\n"); + pg_log(PG_PROGRESS, "sync of target directory with initdb -S done\n"); +} -- 2.7.3