From 4127d39582b350b0b29e6b2681a88a67bcd4c9f2 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Fri, 14 Jul 2023 21:51:44 +1200
Subject: [PATCH v2 2/2] Remove fsync_writethrough, add fsync=full (macOS
 only).

Previously, wal_sync_method=fsync_writethrough affected pg_fsync() of
WAL, control, data and other files, by causing pg_fsync() to use the
fcntl(F_FULLFSYNC) call that Apple recommends for databases.

That's a little confusing, because the GUC purports to affect only WAL
files, and it was also not used by default, exposing users to data loss
risk.  New approach:

1.  wal_sync_method=fsync_writethrough is removed.  Instead, we will
make the existing fsync and fdatasync methods do what Apple recommends.

2.  Introduce a new setting fsync=full.  This refactoring reflects the
fact that all pg_fsync() calls are affected, not just those for WAL
files.  According to expectations established by other modern platforms,
fcntl(F_FULLFSYNC) is the "true" fsync operation on this platform, and
fsync=full will select that.  The traditional fsync() system call is
still available by setting fsync=on.

3.  Use fcntl(F_FULLSYNC) for pg_fdatasync() too, if fsync=full.  Apple
doesn't exactly implement fdatasync().  It's not documented, but exists
in some partially implemented form, without a declaration.  As far as we
can tell, it behaves just like fsync().  We'll still use it if you ask
for it with fsync=on.

4.  Use fsync=full by default on Macs, following Apple's recommendation
for applications such as databases.  It is not available on non-Macs, to
avoid confusing people on other operating systems.  Since
wal_sync_method's default was changed to fdatasync by an earlier commit,
the net effect is that Macs now use F_FULLSYNC for all file
synchronization (data, control, WAL, ...) by default.

While here, also get rid of configure probes for F_FULLFSYNC, and just
test for its existence with #ifdef.

Discussion: https://postgr.es/m/CA%2BhUKG%2BF0EL4Up6yVYbbcWse4xKaqW4wc2xpw67Pq9FjmByWVg%40mail.gmail.com
---
 configure                                     | 14 ----
 configure.ac                                  |  3 -
 doc/src/sgml/config.sgml                      | 31 ++++++--
 doc/src/sgml/monitoring.sgml                  |  8 +-
 doc/src/sgml/wal.sgml                         | 14 +---
 meson.build                                   |  1 -
 src/backend/access/transam/xlog.c             | 18 +----
 src/backend/storage/file/fd.c                 | 74 +++++++------------
 src/backend/storage/sync/sync.c               |  2 +-
 src/backend/utils/init/globals.c              |  2 +-
 src/backend/utils/misc/guc_tables.c           | 41 +++++++---
 src/backend/utils/misc/postgresql.conf.sample |  2 +-
 src/bin/pg_test_fsync/pg_test_fsync.c         | 33 ++-------
 src/include/access/xlog.h                     |  1 -
 src/include/access/xlogdefs.h                 |  2 +-
 src/include/miscadmin.h                       | 15 +++-
 src/include/pg_config.h.in                    |  4 -
 src/include/port/darwin.h                     |  5 --
 src/include/storage/fd.h                      |  2 -
 19 files changed, 118 insertions(+), 154 deletions(-)

diff --git a/configure b/configure
index 46859a4244..0aa7e4c86b 100755
--- a/configure
+++ b/configure
@@ -15804,20 +15804,6 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-# This is probably only present on macOS, but may as well check always
-ac_fn_c_check_decl "$LINENO" "F_FULLFSYNC" "ac_cv_have_decl_F_FULLFSYNC" "#include <fcntl.h>
-"
-if test "x$ac_cv_have_decl_F_FULLFSYNC" = xyes; then :
-  ac_have_decl=1
-else
-  ac_have_decl=0
-fi
-
-cat >>confdefs.h <<_ACEOF
-#define HAVE_DECL_F_FULLFSYNC $ac_have_decl
-_ACEOF
-
-
 ac_fn_c_check_func "$LINENO" "explicit_bzero" "ac_cv_func_explicit_bzero"
 if test "x$ac_cv_func_explicit_bzero" = xyes; then :
   $as_echo "#define HAVE_EXPLICIT_BZERO 1" >>confdefs.h
diff --git a/configure.ac b/configure.ac
index 88b75a7696..a3f0a0575f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1801,9 +1801,6 @@ AC_CHECK_DECLS([strlcat, strlcpy, strnlen])
 AC_CHECK_DECLS([preadv], [], [], [#include <sys/uio.h>])
 AC_CHECK_DECLS([pwritev], [], [], [#include <sys/uio.h>])
 
-# This is probably only present on macOS, but may as well check always
-AC_CHECK_DECLS(F_FULLFSYNC, [], [], [#include <fcntl.h>])
-
 AC_REPLACE_FUNCS(m4_normalize([
 	explicit_bzero
 	getopt
diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 9235caa0c0..b571cd69c7 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -2948,7 +2948,7 @@ include_dir 'conf.d'
      </varlistentry>
 
      <varlistentry id="guc-fsync" xreflabel="fsync">
-      <term><varname>fsync</varname> (<type>boolean</type>)
+      <term><varname>fsync</varname> (<type>enum</type>)
       <indexterm>
        <primary><varname>fsync</varname> configuration parameter</primary>
       </indexterm>
@@ -2963,6 +2963,22 @@ include_dir 'conf.d'
         consistent state after an operating system or hardware crash.
        </para>
 
+       <para>
+        On macOS only, the parameter can also be set to
+        <literal>full</literal>, and that is the default.
+        This value causes <productname>PostgreSQL</productname> to replace all
+        calls to <function>fsync()</function> with
+        <function>fcntl(fd, F_FULLFSYNC)</function>, as recommended by
+        Apple's documentation.  It also does the same for calls to
+        <function>fdatasync()</function>, a function that exists but is not
+        documented by Apple.
+        Setting it to <literal>on</literal> causes macOS's regular
+        <function>fsync()</function> and <function>fdatasync()</function>
+        functions to be used as on other platforms.  They are known to be
+        considerably faster, but users should consult the warnings in Apple's
+        manual page for <function>fsync</function> first.
+       </para>
+
        <para>
         While turning off <varname>fsync</varname> is often a performance
         benefit, this can result in unrecoverable data corruption in
@@ -3194,11 +3210,6 @@ include_dir 'conf.d'
         </para>
         </listitem>
         <listitem>
-        <para>
-         <literal>fsync_writethrough</literal> (call <function>fsync()</function> at each commit, forcing write-through of any disk write cache)
-        </para>
-        </listitem>
-        <listitem>
         <para>
          <literal>open_sync</literal> (write WAL files with <function>open()</function> option <symbol>O_SYNC</symbol>)
         </para>
@@ -3215,6 +3226,14 @@ include_dir 'conf.d'
         This parameter can only be set in the <filename>postgresql.conf</filename>
         file or on the server command line.
        </para>
+       <para>
+        Note that on macOS, the <xref linkend="guc-fsync"/> setting can modify
+        the behavior of the <literal>fdatasync</literal> and
+        <literal>fsync</literal> levels, since
+        it can cause all calls to <function>fdatasync()</function> and
+        <function>fsync()</function> to be replaced with an Apple-specific
+        <function>fcntl()</function> call.
+       </para>
       </listitem>
      </varlistentry>
 
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4b8b38b70e..4116dc3c09 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -3138,8 +3138,8 @@ description | Waiting for a newly initialized WAL file to reach durable storage
        <function>issue_xlog_fsync</function> request
        (if <xref linkend="guc-fsync"/> is <literal>on</literal> and
        <xref linkend="guc-wal-sync-method"/> is either
-       <literal>fdatasync</literal>, <literal>fsync</literal> or
-       <literal>fsync_writethrough</literal>, otherwise zero).
+       <literal>fdatasync</literal> or <literal>fsync</literal>,
+       otherwise zero).
        See <xref linkend="wal-configuration"/> for more information about
        the internal WAL function <function>issue_xlog_fsync</function>.
       </para></entry>
@@ -3169,8 +3169,8 @@ description | Waiting for a newly initialized WAL file to reach durable storage
        (if <varname>track_wal_io_timing</varname> is enabled,
        <varname>fsync</varname> is <literal>on</literal>, and
        <varname>wal_sync_method</varname> is either
-       <literal>fdatasync</literal>, <literal>fsync</literal> or
-       <literal>fsync_writethrough</literal>, otherwise zero).
+       <literal>fdatasync</literal> or <literal>fsync</literal>,
+       otherwise zero).
       </para></entry>
      </row>
 
diff --git a/doc/src/sgml/wal.sgml b/doc/src/sgml/wal.sgml
index 05e2a8f8be..d73f0c1480 100644
--- a/doc/src/sgml/wal.sgml
+++ b/doc/src/sgml/wal.sgml
@@ -114,12 +114,6 @@
       </para>
     </listitem>
 
-    <listitem>
-      <para>
-        On <productname>macOS</productname>, write caching can be prevented by
-        setting <varname>wal_sync_method</varname> to <literal>fsync_writethrough</literal>.
-      </para>
-    </listitem>
   </itemizedlist>
 
   <para>
@@ -785,10 +779,6 @@
    The <xref linkend="guc-wal-sync-method"/> parameter determines how
    <productname>PostgreSQL</productname> will ask the kernel to force
    <acronym>WAL</acronym> updates out to disk.
-   All the options should be the same in terms of reliability, with
-   the exception of <literal>fsync_writethrough</literal>, which can sometimes
-   force a flush of the disk cache even when other options do not do so.
-   However, it's quite platform-specific which one will be the fastest.
    You can test the speeds of different options using the <xref
    linkend="pgtestfsync"/> program.
    Note that this parameter is irrelevant if <varname>fsync</varname>
@@ -822,8 +812,8 @@
    <literal>open_datasync</literal> or <literal>open_sync</literal>,
    a write operation in <function>XLogWrite</function> guarantees to sync written
    WAL data to disk and <function>issue_xlog_fsync</function> does nothing.
-   If <varname>wal_sync_method</varname> is either <literal>fdatasync</literal>,
-   <literal>fsync</literal>, or <literal>fsync_writethrough</literal>,
+   If <varname>wal_sync_method</varname> is either <literal>fdatasync</literal>
+   or <literal>fsync</literal>,
    the write operation moves WAL buffers to kernel cache and
    <function>issue_xlog_fsync</function> syncs them to disk. Regardless
    of the setting of <varname>track_wal_io_timing</varname>, the number
diff --git a/meson.build b/meson.build
index a198eca25d..84aa4ff8a1 100644
--- a/meson.build
+++ b/meson.build
@@ -2188,7 +2188,6 @@ endforeach
 
 
 decl_checks = [
-  ['F_FULLFSYNC', 'fcntl.h'],
   ['fdatasync', 'unistd.h'],
   ['posix_fadvise', 'fcntl.h'],
   ['strlcat', 'string.h'],
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index eb02e3b6a6..d8190323b6 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -174,9 +174,6 @@ static bool check_wal_consistency_checking_deferred = false;
  */
 const struct config_enum_entry wal_sync_method_options[] = {
 	{"fsync", WAL_SYNC_METHOD_FSYNC, false},
-#ifdef HAVE_FSYNC_WRITETHROUGH
-	{"fsync_writethrough", WAL_SYNC_METHOD_FSYNC_WRITETHROUGH, false},
-#endif
 	{"fdatasync", WAL_SYNC_METHOD_FDATASYNC, false},
 #ifdef O_SYNC
 	{"open_sync", WAL_SYNC_METHOD_OPEN, false},
@@ -2832,7 +2829,7 @@ XLogFlush(XLogRecPtr record)
 		 * We do not sleep if enableFsync is not turned on, nor if there are
 		 * fewer than CommitSiblings other backends with active transactions.
 		 */
-		if (CommitDelay > 0 && enableFsync &&
+		if (CommitDelay > 0 && enableFsync != ENABLE_FSYNC_OFF &&
 			MinimumActiveBackends(CommitSiblings))
 		{
 			pg_usleep(CommitDelay);
@@ -8435,7 +8432,7 @@ get_sync_bit(int method)
 		o_direct_flag = PG_O_DIRECT;
 
 	/* If fsync is disabled, never open in sync mode */
-	if (!enableFsync)
+	if (enableFsync == ENABLE_FSYNC_OFF)
 		return o_direct_flag;
 
 	switch (method)
@@ -8447,7 +8444,6 @@ get_sync_bit(int method)
 			 * be seen here.
 			 */
 		case WAL_SYNC_METHOD_FSYNC:
-		case WAL_SYNC_METHOD_FSYNC_WRITETHROUGH:
 		case WAL_SYNC_METHOD_FDATASYNC:
 			return o_direct_flag;
 #ifdef O_SYNC
@@ -8522,7 +8518,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
 	 * Quick exit if fsync is disabled or write() has already synced the WAL
 	 * file.
 	 */
-	if (!enableFsync ||
+	if (enableFsync == ENABLE_FSYNC_OFF ||
 		wal_sync_method == WAL_SYNC_METHOD_OPEN ||
 		wal_sync_method == WAL_SYNC_METHOD_OPEN_DSYNC)
 		return;
@@ -8537,15 +8533,9 @@ issue_xlog_fsync(int fd, XLogSegNo segno, TimeLineID tli)
 	switch (wal_sync_method)
 	{
 		case WAL_SYNC_METHOD_FSYNC:
-			if (pg_fsync_no_writethrough(fd) != 0)
+			if (pg_fsync(fd) != 0)
 				msg = _("could not fsync file \"%s\": %m");
 			break;
-#ifdef HAVE_FSYNC_WRITETHROUGH
-		case WAL_SYNC_METHOD_FSYNC_WRITETHROUGH:
-			if (pg_fsync_writethrough(fd) != 0)
-				msg = _("could not fsync write-through file \"%s\": %m");
-			break;
-#endif
 		case WAL_SYNC_METHOD_FDATASYNC:
 			if (pg_fdatasync(fd) != 0)
 				msg = _("could not fdatasync file \"%s\": %m");
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index d298e4842c..1f4fb70ab6 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -380,11 +380,12 @@ ResourceOwnerForgetFile(ResourceOwner owner, File file)
 }
 
 /*
- * pg_fsync --- do fsync with or without writethrough
+ * pg_fsync --- do fsync, if enabled, or redirect to Apple's F_FULLFSYNC.
  */
 int
 pg_fsync(int fd)
 {
+	int			rc;
 #if !defined(WIN32) && defined(USE_ASSERT_CHECKING)
 	struct stat st;
 
@@ -423,30 +424,20 @@ pg_fsync(int fd)
 	errno = 0;
 #endif
 
-	/* #if is to skip the wal_sync_method test if there's no need for it */
-#if defined(HAVE_FSYNC_WRITETHROUGH)
-	if (wal_sync_method == WAL_SYNC_METHOD_FSYNC_WRITETHROUGH)
-		return pg_fsync_writethrough(fd);
-	else
-#endif
-		return pg_fsync_no_writethrough(fd);
-}
-
-
-/*
- * pg_fsync_no_writethrough --- same as fsync except does nothing if
- *	enableFsync is off
- */
-int
-pg_fsync_no_writethrough(int fd)
-{
-	int			rc;
-
-	if (!enableFsync)
+	if (enableFsync == ENABLE_FSYNC_OFF)
 		return 0;
 
 retry:
-	rc = fsync(fd);
+#if defined(ENABLE_FSYNC_FULL)
+	if (enableFsync == ENABLE_FSYNC_FULL)
+	{
+		rc = fcntl(fd, F_FULLFSYNC);
+	}
+	else
+#endif
+	{
+		rc = fsync(fd);
+	}
 
 	if (rc == -1 && errno == EINTR)
 		goto retry;
@@ -455,37 +446,28 @@ retry:
 }
 
 /*
- * pg_fsync_writethrough
- */
-int
-pg_fsync_writethrough(int fd)
-{
-	if (enableFsync)
-	{
-#if defined(F_FULLFSYNC)
-		return (fcntl(fd, F_FULLFSYNC, 0) == -1) ? -1 : 0;
-#else
-		errno = ENOSYS;
-		return -1;
-#endif
-	}
-	else
-		return 0;
-}
-
-/*
- * pg_fdatasync --- same as fdatasync except does nothing if enableFsync is off
+ * pg_fdatasync --- same as fdatasync except does nothing if enableFsync is off,
+ * and redirects to Apple's F_FULLFSYNC if configured.
  */
 int
 pg_fdatasync(int fd)
 {
 	int			rc;
 
-	if (!enableFsync)
+	if (enableFsync == ENABLE_FSYNC_OFF)
 		return 0;
 
 retry:
-	rc = fdatasync(fd);
+#if defined(ENABLE_FSYNC_FULL)
+	if (enableFsync == ENABLE_FSYNC_FULL)
+	{
+		rc = fcntl(fd, F_FULLFSYNC);
+	}
+	else
+#endif
+	{
+		rc = fdatasync(fd);
+	}
 
 	if (rc == -1 && errno == EINTR)
 		goto retry;
@@ -530,7 +512,7 @@ pg_flush_data(int fd, off_t offset, off_t nbytes)
 	 * if fsyncs are disabled - that's a decision we might want to make
 	 * configurable at some point.
 	 */
-	if (!enableFsync)
+	if (enableFsync == ENABLE_FSYNC_OFF)
 		return;
 
 	/*
@@ -3546,7 +3528,7 @@ SyncDataDirectory(void)
 	bool		xlog_is_symlink;
 
 	/* We can skip this whole thing if fsync is disabled. */
-	if (!enableFsync)
+	if (enableFsync == ENABLE_FSYNC_OFF)
 		return;
 
 	/*
diff --git a/src/backend/storage/sync/sync.c b/src/backend/storage/sync/sync.c
index 581faf5f29..224a01e7aa 100644
--- a/src/backend/storage/sync/sync.c
+++ b/src/backend/storage/sync/sync.c
@@ -386,7 +386,7 @@ ProcessSyncRequests(void)
 		 * all.  (We delay checking until this point so that changing fsync on
 		 * the fly behaves sensibly.)
 		 */
-		if (enableFsync)
+		if (enableFsync != ENABLE_FSYNC_OFF)
 		{
 			/*
 			 * If in checkpointer, we want to absorb pending requests every so
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 5eaee88d96..8c1c24004b 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -123,7 +123,7 @@ int			DateStyle = USE_ISO_DATES;
 int			DateOrder = DATEORDER_MDY;
 int			IntervalStyle = INTSTYLE_POSTGRES;
 
-bool		enableFsync = true;
+int			enableFsync = DEFAULT_ENABLE_FSYNC;
 bool		allowSystemTableMods = false;
 int			work_mem = 4096;
 double		hash_mem_multiplier = 2.0;
diff --git a/src/backend/utils/misc/guc_tables.c b/src/backend/utils/misc/guc_tables.c
index 93ded31ed9..06a4414e14 100644
--- a/src/backend/utils/misc/guc_tables.c
+++ b/src/backend/utils/misc/guc_tables.c
@@ -482,6 +482,22 @@ static const struct config_enum_entry wal_compression_options[] = {
 	{NULL, 0, false}
 };
 
+static const struct config_enum_entry enable_fsync_options[] = {
+	{"on", ENABLE_FSYNC_ON, false},
+	{"off", ENABLE_FSYNC_OFF, false},
+	{"true", ENABLE_FSYNC_ON, true},
+	{"false", ENABLE_FSYNC_OFF, true},
+	{"yes", ENABLE_FSYNC_ON, true},
+	{"no", ENABLE_FSYNC_OFF, true},
+	{"1", ENABLE_FSYNC_ON, true},
+	{"0", ENABLE_FSYNC_OFF, true},
+#ifdef ENABLE_FSYNC_FULL
+	{"full", ENABLE_FSYNC_FULL, false},
+#endif
+	{NULL, 0, false}
+};
+
+
 /*
  * Options for enum values stored in other modules
  */
@@ -1085,18 +1101,6 @@ struct config_bool ConfigureNamesBool[] =
 		true,
 		NULL, NULL, NULL
 	},
-	{
-		{"fsync", PGC_SIGHUP, WAL_SETTINGS,
-			gettext_noop("Forces synchronization of updates to disk."),
-			gettext_noop("The server will use the fsync() system call in several places to make "
-						 "sure that updates are physically written to disk. This ensures "
-						 "that a database cluster will recover to a consistent state after "
-						 "an operating system or hardware crash.")
-		},
-		&enableFsync,
-		true,
-		NULL, NULL, NULL
-	},
 	{
 		{"ignore_checksum_failure", PGC_SUSET, DEVELOPER_OPTIONS,
 			gettext_noop("Continues processing after a checksum failure."),
@@ -4753,6 +4757,19 @@ struct config_enum ConfigureNamesEnum[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"fsync", PGC_SIGHUP, WAL_SETTINGS,
+			gettext_noop("Forces synchronization of updates to disk."),
+			gettext_noop("Whether to use syncronization APIs to make "
+						 "sure that updates are physically written to disk. This insures "
+						 "that a database cluster will recover to a consistent state after "
+						 "an operating system or hardware crash.")
+		},
+		&enableFsync,
+		DEFAULT_ENABLE_FSYNC, enable_fsync_options,
+		NULL, NULL, NULL
+	},
+
 	{
 		{"transaction_isolation", PGC_USERSET, CLIENT_CONN_STATEMENT,
 			gettext_noop("Sets the current transaction's isolation level."),
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 9b6765ceb5..ff65ae8c46 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -224,7 +224,7 @@
 					# unrecoverable data corruption)
 #synchronous_commit = on		# synchronization level;
 					# off, local, remote_write, remote_apply, or on
-#wal_sync_method = fdatasync		# fsync, fdatasync, fsync_writethrough,
+#wal_sync_method = fdatasync		# fsync, fdatasync,
 					# open_sync, open_datasync
 #full_page_writes = on			# recover from partial page writes
 #wal_log_hints = off			# also do full page writes of non-critical updates
diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c
index 04dcd77152..41cd537a84 100644
--- a/src/bin/pg_test_fsync/pg_test_fsync.c
+++ b/src/bin/pg_test_fsync/pg_test_fsync.c
@@ -93,9 +93,6 @@ static DWORD WINAPI process_alarm(LPVOID param);
 #endif
 static void signal_cleanup(SIGNAL_ARGS);
 
-#ifdef HAVE_FSYNC_WRITETHROUGH
-static int	pg_fsync_writethrough(int fd);
-#endif
 static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops);
 
 #define die(msg) pg_fatal("%s: %m", _(msg))
@@ -298,7 +295,7 @@ test_sync(int writes_per_op)
 		printf(_("\nCompare file sync methods using one %dkB write:\n"), XLOG_BLCKSZ_K);
 	else
 		printf(_("\nCompare file sync methods using two %dkB writes:\n"), XLOG_BLCKSZ_K);
-	printf(_("(fdatasync is the default)\n"));
+	printf(_("(fdatasync is the default, but see docs for macOS)\n"));
 
 	/*
 	 * Test open_datasync if available
@@ -377,12 +374,13 @@ test_sync(int writes_per_op)
 	close(tmpfile);
 
 /*
- * If fsync_writethrough is available, test as well
+ * Test the macOS fcntl that use instead of fsync/fdatasync levels if
+ * fsync=full.
  */
-	printf(LABEL_FORMAT, "fsync_writethrough");
+	printf(LABEL_FORMAT, "fcntl(F_FULLFSYNC)");
 	fflush(stdout);
 
-#ifdef HAVE_FSYNC_WRITETHROUGH
+#ifdef F_FULLFSYNC
 	if ((tmpfile = open(filename, O_RDWR | PG_BINARY, 0)) == -1)
 		die("could not open output file");
 	START_TIMER;
@@ -394,8 +392,8 @@ test_sync(int writes_per_op)
 						  XLOG_BLCKSZ,
 						  writes * XLOG_BLCKSZ) != XLOG_BLCKSZ)
 				die("write failed");
-		if (pg_fsync_writethrough(tmpfile) != 0)
-			die("fsync failed");
+		if (fcntl(tmpfile, F_FULLFSYNC) != 0)
+			die("fcntl failed");
 	}
 	STOP_TIMER;
 	close(tmpfile);
@@ -510,8 +508,7 @@ test_file_descriptor_sync(void)
 	/*
 	 * Test whether fsync can sync data written on a different descriptor for
 	 * the same file.  This checks the efficiency of multi-process fsyncs
-	 * against the same file. Possibly this should be done with writethrough
-	 * on platforms which support it.
+	 * against the same file.
 	 */
 	printf(_("\nTest if fsync on non-write file descriptor is honored:\n"));
 	printf(_("(If the times are similar, fsync() can sync data written on a different\n"
@@ -609,20 +606,6 @@ signal_cleanup(SIGNAL_ARGS)
 	_exit(1);
 }
 
-#ifdef HAVE_FSYNC_WRITETHROUGH
-
-static int
-pg_fsync_writethrough(int fd)
-{
-#if defined(F_FULLFSYNC)
-	return (fcntl(fd, F_FULLFSYNC, 0) == -1) ? -1 : 0;
-#else
-	errno = ENOSYS;
-	return -1;
-#endif
-}
-#endif
-
 /*
  * print out the writes per second for tests
  */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 76787a8267..4028738eca 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -24,7 +24,6 @@ typedef enum WalSyncMethod
 	WAL_SYNC_METHOD_FSYNC = 0,
 	WAL_SYNC_METHOD_FDATASYNC,
 	WAL_SYNC_METHOD_OPEN,		/* for O_SYNC */
-	WAL_SYNC_METHOD_FSYNC_WRITETHROUGH,
 	WAL_SYNC_METHOD_OPEN_DSYNC	/* for O_DSYNC */
 } WalSyncMethod;
 extern PGDLLIMPORT int wal_sync_method;
diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h
index 0c0dce91c7..27c04a3053 100644
--- a/src/include/access/xlogdefs.h
+++ b/src/include/access/xlogdefs.h
@@ -65,6 +65,6 @@ typedef uint32 TimeLineID;
 typedef uint16 RepOriginId;
 
 /* Default synchronization method for WAL. */
-#define DEFAULT_WAL_SYNC_METHOD		SYNC_METHOD_FDATASYNC
+#define DEFAULT_WAL_SYNC_METHOD		WAL_SYNC_METHOD_FDATASYNC
 
 #endif							/* XLOG_DEFS_H */
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index 756d144c32..0563d18b09 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -23,6 +23,7 @@
 #ifndef MISCADMIN_H
 #define MISCADMIN_H
 
+#include <fcntl.h>
 #include <signal.h>
 
 #include "datatype/timestamp.h" /* for TimestampTz */
@@ -267,7 +268,19 @@ extern PGDLLIMPORT int IntervalStyle;
 
 #define MAXTZLEN		10		/* max TZ name len, not counting tr. null */
 
-extern PGDLLIMPORT bool enableFsync;
+#define ENABLE_FSYNC_OFF			0
+#define ENABLE_FSYNC_ON				1
+#ifdef F_FULLFSYNC
+#define ENABLE_FSYNC_FULL			2
+#endif
+
+#ifdef ENABLE_FSYNC_FULL
+#define DEFAULT_ENABLE_FSYNC ENABLE_FSYNC_FULL
+#else
+#define DEFAULT_ENABLE_FSYNC ENABLE_FSYNC_ON
+#endif
+
+extern PGDLLIMPORT int enableFsync;
 extern PGDLLIMPORT bool allowSystemTableMods;
 extern PGDLLIMPORT int work_mem;
 extern PGDLLIMPORT double hash_mem_multiplier;
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 07e73567dc..1d4925bfc4 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -88,10 +88,6 @@
    don't. */
 #undef HAVE_DECL_FDATASYNC
 
-/* Define to 1 if you have the declaration of `F_FULLFSYNC', and to 0 if you
-   don't. */
-#undef HAVE_DECL_F_FULLFSYNC
-
 /* Define to 1 if you have the declaration of
    `LLVMCreateGDBRegistrationListener', and to 0 if you don't. */
 #undef HAVE_DECL_LLVMCREATEGDBREGISTRATIONLISTENER
diff --git a/src/include/port/darwin.h b/src/include/port/darwin.h
index 15fb69d6db..41e2a427d3 100644
--- a/src/include/port/darwin.h
+++ b/src/include/port/darwin.h
@@ -1,8 +1,3 @@
 /* src/include/port/darwin.h */
 
 #define __darwin__	1
-
-#if HAVE_DECL_F_FULLFSYNC		/* not present before macOS 10.3 */
-#define HAVE_FSYNC_WRITETHROUGH
-
-#endif
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index 60bba5c970..ecbefce3d2 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -179,8 +179,6 @@ extern void RemovePgTempFilesInDir(const char *tmpdirname, bool missing_ok,
 extern bool looks_like_temp_rel_name(const char *name);
 
 extern int	pg_fsync(int fd);
-extern int	pg_fsync_no_writethrough(int fd);
-extern int	pg_fsync_writethrough(int fd);
 extern int	pg_fdatasync(int fd);
 extern bool pg_file_exists(const char *fname);
 extern void pg_flush_data(int fd, off_t offset, off_t nbytes);
-- 
2.39.3 (Apple Git-145)

