From 4d1b1c999285f00273ee2afe322133a18ffd23d5 Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@otacoo.com>
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

