It seems to me that we could implement prefetching support (USE_PREFETCH) on macOS using the fcntl() command F_RDADVISE. The man page description is a bit terse:

     F_RDADVISE       Issue an advisory read async with no copy to user.

But it seems to be the right idea. Was this looked into before? I couldn't find anything in the archives.

Attached is a patch to implement this. It seems to work, but of course it's kind of hard to tell whether it actually does anything useful.

(Even if the performance effects were negligible, this would be useful to get the prefetch code some exercise on this platform.)

Thoughts?
From d69804b540d0bf168f0706af289ea3583353a30c Mon Sep 17 00:00:00 2001
From: Peter Eisentraut <pe...@eisentraut.org>
Date: Wed, 14 Aug 2024 08:50:15 +0200
Subject: [PATCH] Add prefetching support on macOS

macOS doesn't have posix_fadvise(), but fcntl() with the F_RDADVISE
command does the same thing.

TODO: docs update
---
 src/backend/commands/variable.c |  4 +--
 src/backend/storage/file/fd.c   | 52 +++++++++++++++++++++++----------
 src/include/pg_config_manual.h  |  7 ++---
 3 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
index 6202c5ebe44..c1c6c2811c9 100644
--- a/src/backend/commands/variable.c
+++ b/src/backend/commands/variable.c
@@ -1212,7 +1212,7 @@ check_effective_io_concurrency(int *newval, void **extra, 
GucSource source)
 #ifndef USE_PREFETCH
        if (*newval != 0)
        {
-               GUC_check_errdetail("\"effective_io_concurrency\" must be set 
to 0 on platforms that lack posix_fadvise().");
+               GUC_check_errdetail("\"effective_io_concurrency\" must be set 
to 0 on platforms that lack prefetching support.");
                return false;
        }
 #endif                                                 /* USE_PREFETCH */
@@ -1225,7 +1225,7 @@ check_maintenance_io_concurrency(int *newval, void 
**extra, GucSource source)
 #ifndef USE_PREFETCH
        if (*newval != 0)
        {
-               GUC_check_errdetail("\"maintenance_io_concurrency\" must be set 
to 0 on platforms that lack posix_fadvise().");
+               GUC_check_errdetail("\"maintenance_io_concurrency\" must be set 
to 0 on platforms that lack prefetching support.");
                return false;
        }
 #endif                                                 /* USE_PREFETCH */
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 3944321ff37..8fe3ac58d97 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -2068,7 +2068,9 @@ FileClose(File file)
 /*
  * FilePrefetch - initiate asynchronous read of a given range of the file.
  *
- * Currently the only implementation of this function is using posix_fadvise
+ * Returns 0 on success, otherwise an errno error code.
+ *
+ * XXX Currently the only implementation of this function is using 
posix_fadvise
  * which is the simplest standardized interface that accomplishes this.
  * We could add an implementation using libaio in the future; but note that
  * this API is inappropriate for libaio, which wants to have a buffer provided
@@ -2077,31 +2079,51 @@ FileClose(File file)
 int
 FilePrefetch(File file, off_t offset, off_t amount, uint32 wait_event_info)
 {
-#if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
-       int                     returnCode;
-
        Assert(FileIsValid(file));
 
        DO_DB(elog(LOG, "FilePrefetch: %d (%s) " INT64_FORMAT " " INT64_FORMAT,
                           file, VfdCache[file].fileName,
                           (int64) offset, (int64) amount));
 
-       returnCode = FileAccess(file);
-       if (returnCode < 0)
-               return returnCode;
+#if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
+       {
+               int                     returnCode;
+
+               returnCode = FileAccess(file);
+               if (returnCode < 0)
+                       return returnCode;
 
 retry:
-       pgstat_report_wait_start(wait_event_info);
-       returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
-                                                          POSIX_FADV_WILLNEED);
-       pgstat_report_wait_end();
+               pgstat_report_wait_start(wait_event_info);
+               returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
+                                                                  
POSIX_FADV_WILLNEED);
+               pgstat_report_wait_end();
 
-       if (returnCode == EINTR)
-               goto retry;
+               if (returnCode == EINTR)
+                       goto retry;
 
-       return returnCode;
+               return returnCode;
+       }
+#elif defined(__darwin__)
+       {
+               struct radvisory
+               {
+                       off_t           ra_offset;      /* offset into the file 
*/
+                       int                     ra_count;       /* size of the 
read     */
+               }                       ra;
+               int                     returnCode;
+
+               ra.ra_offset = offset;
+               ra.ra_count = amount;
+               pgstat_report_wait_start(wait_event_info);
+               returnCode = fcntl(VfdCache[file].fd, F_RDADVISE, &ra);
+               pgstat_report_wait_end();
+               if (returnCode != -1)
+                       return 0;
+               else
+                       return errno;
+       }
 #else
-       Assert(FileIsValid(file));
        return 0;
 #endif
 }
diff --git a/src/include/pg_config_manual.h b/src/include/pg_config_manual.h
index b769030d8fa..84bb5368b3d 100644
--- a/src/include/pg_config_manual.h
+++ b/src/include/pg_config_manual.h
@@ -138,12 +138,9 @@
 
 /*
  * USE_PREFETCH code should be compiled only if we have a way to implement
- * prefetching.  (This is decoupled from USE_POSIX_FADVISE because there
- * might in future be support for alternative low-level prefetch APIs.
- * If you change this, you probably need to adjust the error message in
- * check_effective_io_concurrency.)
+ * prefetching.
  */
-#ifdef USE_POSIX_FADVISE
+#if defined(USE_POSIX_FADVISE) || defined(__darwin__)
 #define USE_PREFETCH
 #endif
 
-- 
2.46.0

Reply via email to