Move our p{read,write}v replacements into their own files.
authorThomas Munro <tmunro@postgresql.org>
Wed, 13 Jan 2021 22:10:24 +0000 (11:10 +1300)
committerThomas Munro <tmunro@postgresql.org>
Wed, 13 Jan 2021 22:16:59 +0000 (11:16 +1300)
macOS's ranlib issued a warning about an empty pread.o file with the
previous arrangement, on systems new enough to require no replacement
functions.  Let's go back to using configure's AC_REPLACE_FUNCS system
to build and include each .o in the library only if it's needed, which
requires moving the *v() functions to their own files.

Also move the _with_retry() wrapper to a more permanent home.

Reported-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/1283127.1610554395%40sss.pgh.pa.us

configure
configure.ac
src/backend/storage/file/fd.c
src/include/storage/fd.h
src/port/Makefile
src/port/pread.c
src/port/preadv.c [new file with mode: 0644]
src/port/pwrite.c
src/port/pwritev.c [new file with mode: 0644]
src/tools/msvc/Mkvcbuild.pm

index b917a2a1c9dbf5b4db4a517556fbd3c17e63335f..8af4b990218cc4476eb04e5fff62c93c5a700b42 100755 (executable)
--- a/configure
+++ b/configure
@@ -15155,7 +15155,7 @@ fi
 LIBS_including_readline="$LIBS"
 LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
 
-for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pread preadv pstat pthread_is_threaded_np pwrite pwritev readlink readv setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l writev
+for ac_func in backtrace_symbols clock_gettime copyfile fdatasync getifaddrs getpeerucred getrlimit kqueue mbstowcs_l memset_s poll posix_fallocate ppoll pstat pthread_is_threaded_np readlink readv setproctitle setproctitle_fast setsid shm_open strchrnul strsignal symlink sync_file_range uselocale wcstombs_l writev
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -15832,6 +15832,58 @@ esac
 
 fi
 
+ac_fn_c_check_func "$LINENO" "pread" "ac_cv_func_pread"
+if test "x$ac_cv_func_pread" = xyes; then :
+  $as_echo "#define HAVE_PREAD 1" >>confdefs.h
+
+else
+  case " $LIBOBJS " in
+  *" pread.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS pread.$ac_objext"
+ ;;
+esac
+
+fi
+
+ac_fn_c_check_func "$LINENO" "preadv" "ac_cv_func_preadv"
+if test "x$ac_cv_func_preadv" = xyes; then :
+  $as_echo "#define HAVE_PREADV 1" >>confdefs.h
+
+else
+  case " $LIBOBJS " in
+  *" preadv.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS preadv.$ac_objext"
+ ;;
+esac
+
+fi
+
+ac_fn_c_check_func "$LINENO" "pwrite" "ac_cv_func_pwrite"
+if test "x$ac_cv_func_pwrite" = xyes; then :
+  $as_echo "#define HAVE_PWRITE 1" >>confdefs.h
+
+else
+  case " $LIBOBJS " in
+  *" pwrite.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS pwrite.$ac_objext"
+ ;;
+esac
+
+fi
+
+ac_fn_c_check_func "$LINENO" "pwritev" "ac_cv_func_pwritev"
+if test "x$ac_cv_func_pwritev" = xyes; then :
+  $as_echo "#define HAVE_PWRITEV 1" >>confdefs.h
+
+else
+  case " $LIBOBJS " in
+  *" pwritev.$ac_objext "* ) ;;
+  *) LIBOBJS="$LIBOBJS pwritev.$ac_objext"
+ ;;
+esac
+
+fi
+
 ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random"
 if test "x$ac_cv_func_random" = xyes; then :
   $as_echo "#define HAVE_RANDOM 1" >>confdefs.h
index 838d47dc22e2a05299047dcf1375c67e78a725b6..868a94c9ba972a873390b1271c33b2cb4433c9c7 100644 (file)
@@ -1661,12 +1661,8 @@ AC_CHECK_FUNCS(m4_normalize([
    poll
    posix_fallocate
    ppoll
-   pread
-   preadv
    pstat
    pthread_is_threaded_np
-   pwrite
-   pwritev
    readlink
    readv
    setproctitle
@@ -1740,6 +1736,10 @@ AC_REPLACE_FUNCS(m4_normalize([
    inet_aton
    link
    mkdtemp
+   pread
+   preadv
+   pwrite
+   pwritev
    random
    srandom
    strlcat
index 931ed679307b223c61ff7da092a0de88b8560250..b58502837aa5959218da2e6c85569f25ddcb6ef1 100644 (file)
@@ -92,6 +92,7 @@
 #include "common/file_utils.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "port/pg_iovec.h"
 #include "portability/mem.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
@@ -3635,3 +3636,67 @@ data_sync_elevel(int elevel)
 {
    return data_sync_retry ? elevel : PANIC;
 }
+
+/*
+ * A convenience wrapper for pg_pwritev() that retries on partial write.  If an
+ * error is returned, it is unspecified how much has been written.
+ */
+ssize_t
+pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+   struct iovec iov_copy[PG_IOV_MAX];
+   ssize_t     sum = 0;
+   ssize_t     part;
+
+   /* We'd better have space to make a copy, in case we need to retry. */
+   if (iovcnt > PG_IOV_MAX)
+   {
+       errno = EINVAL;
+       return -1;
+   }
+
+   for (;;)
+   {
+       /* Write as much as we can. */
+       part = pg_pwritev(fd, iov, iovcnt, offset);
+       if (part < 0)
+           return -1;
+
+#ifdef SIMULATE_SHORT_WRITE
+       part = Min(part, 4096);
+#endif
+
+       /* Count our progress. */
+       sum += part;
+       offset += part;
+
+       /* Step over iovecs that are done. */
+       while (iovcnt > 0 && iov->iov_len <= part)
+       {
+           part -= iov->iov_len;
+           ++iov;
+           --iovcnt;
+       }
+
+       /* Are they all done? */
+       if (iovcnt == 0)
+       {
+           /* We don't expect the kernel to write more than requested. */
+           Assert(part == 0);
+           break;
+       }
+
+       /*
+        * Move whatever's left to the front of our mutable copy and adjust
+        * the leading iovec.
+        */
+       Assert(iovcnt > 0);
+       memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
+       Assert(iov->iov_len > part);
+       iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
+       iov_copy[0].iov_len -= part;
+       iov = iov_copy;
+   }
+
+   return sum;
+}
index f2662a96fd7bbbd0d1f31ca7fb4aa64fdf68c908..c430072af61d80ef87bf463f2b23550919f79cfc 100644 (file)
@@ -45,6 +45,7 @@
 
 #include <dirent.h>
 
+struct iovec;                  /* avoid including port/pg_iovec.h here */
 
 typedef int File;
 
@@ -161,6 +162,10 @@ extern int durable_unlink(const char *fname, int loglevel);
 extern int durable_rename_excl(const char *oldfile, const char *newfile, int loglevel);
 extern void SyncDataDirectory(void);
 extern int data_sync_elevel(int elevel);
+extern ssize_t pg_pwritev_with_retry(int fd,
+                                    const struct iovec *iov,
+                                    int iovcnt,
+                                    off_t offset);
 
 /* Filename components */
 #define PG_TEMP_FILES_DIR "pgsql_tmp"
index bc4923ce840e19da46ca1dc5a711fffe4c731a9c..e41b005c4f1bf9cd77714f608d1d351483f905fa 100644 (file)
@@ -53,8 +53,6 @@ OBJS = \
    pgstrcasecmp.o \
    pgstrsignal.o \
    pqsignal.o \
-   pread.o \
-   pwrite.o \
    qsort.o \
    qsort_arg.o \
    quotes.o \
index a5ae2759fa0e5e69fa6a86b4fa2d9de50ea34da6..486f07a7dffcc79f730edb283bccb6d7d71f0991 100644 (file)
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * pread.c
- *   Implementation of pread[v](2) for platforms that lack one.
+ *   Implementation of pread(2) for platforms that lack one.
  *
  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
  *
@@ -9,8 +9,7 @@
  *   src/port/pread.c
  *
  * Note that this implementation changes the current file position, unlike
- * the POSIX function, so we use the name pg_pread().  Likewise for the
- * iovec version.
+ * the POSIX function, so we use the name pg_pread().
  *
  *-------------------------------------------------------------------------
  */
@@ -24,9 +23,6 @@
 #include <unistd.h>
 #endif
 
-#include "port/pg_iovec.h"
-
-#ifndef HAVE_PREAD
 ssize_t
 pg_pread(int fd, void *buf, size_t size, off_t offset)
 {
@@ -60,38 +56,3 @@ pg_pread(int fd, void *buf, size_t size, off_t offset)
    return read(fd, buf, size);
 #endif
 }
-#endif
-
-#ifndef HAVE_PREADV
-ssize_t
-pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
-{
-#ifdef HAVE_READV
-   if (iovcnt == 1)
-       return pg_pread(fd, iov[0].iov_base, iov[0].iov_len, offset);
-   if (lseek(fd, offset, SEEK_SET) < 0)
-       return -1;
-   return readv(fd, iov, iovcnt);
-#else
-   ssize_t     sum = 0;
-   ssize_t     part;
-
-   for (int i = 0; i < iovcnt; ++i)
-   {
-       part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset);
-       if (part < 0)
-       {
-           if (i == 0)
-               return -1;
-           else
-               return sum;
-       }
-       sum += part;
-       offset += part;
-       if (part < iov[i].iov_len)
-           return sum;
-   }
-   return sum;
-#endif
-}
-#endif
diff --git a/src/port/preadv.c b/src/port/preadv.c
new file mode 100644 (file)
index 0000000..29c808c
--- /dev/null
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * preadv.c
+ *   Implementation of preadv(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/port/preadv.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX-like function, so we use the name pg_preadv().
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "port/pg_iovec.h"
+
+ssize_t
+pg_preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+#ifdef HAVE_READV
+   if (iovcnt == 1)
+       return pg_pread(fd, iov[0].iov_base, iov[0].iov_len, offset);
+   if (lseek(fd, offset, SEEK_SET) < 0)
+       return -1;
+   return readv(fd, iov, iovcnt);
+#else
+   ssize_t     sum = 0;
+   ssize_t     part;
+
+   for (int i = 0; i < iovcnt; ++i)
+   {
+       part = pg_pread(fd, iov[i].iov_base, iov[i].iov_len, offset);
+       if (part < 0)
+       {
+           if (i == 0)
+               return -1;
+           else
+               return sum;
+       }
+       sum += part;
+       offset += part;
+       if (part < iov[i].iov_len)
+           return sum;
+   }
+   return sum;
+#endif
+}
index a98343ec05b70614befe29c952dbc1593b500d00..282b27115e509ab22660807cbb74ce5356b6f539 100644 (file)
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * pwrite.c
- *   Implementation of pwrite[v](2) for platforms that lack one.
+ *   Implementation of pwrite(2) for platforms that lack one.
  *
  * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
  *
@@ -9,8 +9,7 @@
  *   src/port/pwrite.c
  *
  * Note that this implementation changes the current file position, unlike
- * the POSIX function, so we use the name pg_pwrite().  Likewise for the
- * iovec version.
+ * the POSIX function, so we use the name pg_pwrite().
  *
  *-------------------------------------------------------------------------
  */
@@ -24,9 +23,6 @@
 #include <unistd.h>
 #endif
 
-#include "port/pg_iovec.h"
-
-#ifndef HAVE_PWRITE
 ssize_t
 pg_pwrite(int fd, const void *buf, size_t size, off_t offset)
 {
@@ -57,102 +53,3 @@ pg_pwrite(int fd, const void *buf, size_t size, off_t offset)
    return write(fd, buf, size);
 #endif
 }
-#endif
-
-#ifndef HAVE_PWRITEV
-ssize_t
-pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
-{
-#ifdef HAVE_WRITEV
-   if (iovcnt == 1)
-       return pg_pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
-   if (lseek(fd, offset, SEEK_SET) < 0)
-       return -1;
-   return writev(fd, iov, iovcnt);
-#else
-   ssize_t     sum = 0;
-   ssize_t     part;
-
-   for (int i = 0; i < iovcnt; ++i)
-   {
-       part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
-       if (part < 0)
-       {
-           if (i == 0)
-               return -1;
-           else
-               return sum;
-       }
-       sum += part;
-       offset += part;
-       if (part < iov[i].iov_len)
-           return sum;
-   }
-   return sum;
-#endif
-}
-#endif
-
-/*
- * A convenience wrapper for pg_pwritev() that retries on partial write.  If an
- * error is returned, it is unspecified how much has been written.
- */
-ssize_t
-pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
-{
-   struct iovec iov_copy[PG_IOV_MAX];
-   ssize_t     sum = 0;
-   ssize_t     part;
-
-   /* We'd better have space to make a copy, in case we need to retry. */
-   if (iovcnt > PG_IOV_MAX)
-   {
-       errno = EINVAL;
-       return -1;
-   }
-
-   for (;;)
-   {
-       /* Write as much as we can. */
-       part = pg_pwritev(fd, iov, iovcnt, offset);
-       if (part < 0)
-           return -1;
-
-#ifdef SIMULATE_SHORT_WRITE
-       part = Min(part, 4096);
-#endif
-
-       /* Count our progress. */
-       sum += part;
-       offset += part;
-
-       /* Step over iovecs that are done. */
-       while (iovcnt > 0 && iov->iov_len <= part)
-       {
-           part -= iov->iov_len;
-           ++iov;
-           --iovcnt;
-       }
-
-       /* Are they all done? */
-       if (iovcnt == 0)
-       {
-           /* We don't expect the kernel to write more than requested. */
-           Assert(part == 0);
-           break;
-       }
-
-       /*
-        * Move whatever's left to the front of our mutable copy and adjust
-        * the leading iovec.
-        */
-       Assert(iovcnt > 0);
-       memmove(iov_copy, iov, sizeof(*iov) * iovcnt);
-       Assert(iov->iov_len > part);
-       iov_copy[0].iov_base = (char *) iov_copy[0].iov_base + part;
-       iov_copy[0].iov_len -= part;
-       iov = iov_copy;
-   }
-
-   return sum;
-}
diff --git a/src/port/pwritev.c b/src/port/pwritev.c
new file mode 100644 (file)
index 0000000..2e8ef7e
--- /dev/null
@@ -0,0 +1,58 @@
+/*-------------------------------------------------------------------------
+ *
+ * pwritev.c
+ *   Implementation of pwritev(2) for platforms that lack one.
+ *
+ * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *   src/port/pwritev.c
+ *
+ * Note that this implementation changes the current file position, unlike
+ * the POSIX-like function, so we use the name pg_pwritev().
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include "postgres.h"
+
+#ifdef WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "port/pg_iovec.h"
+
+ssize_t
+pg_pwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset)
+{
+#ifdef HAVE_WRITEV
+   if (iovcnt == 1)
+       return pg_pwrite(fd, iov[0].iov_base, iov[0].iov_len, offset);
+   if (lseek(fd, offset, SEEK_SET) < 0)
+       return -1;
+   return writev(fd, iov, iovcnt);
+#else
+   ssize_t     sum = 0;
+   ssize_t     part;
+
+   for (int i = 0; i < iovcnt; ++i)
+   {
+       part = pg_pwrite(fd, iov[i].iov_base, iov[i].iov_len, offset);
+       if (part < 0)
+       {
+           if (i == 0)
+               return -1;
+           else
+               return sum;
+       }
+       sum += part;
+       offset += part;
+       if (part < iov[i].iov_len)
+           return sum;
+   }
+   return sum;
+#endif
+}
index 7f014a12c9a4725c28d30d7a264d69e964399518..535b67e668cb0e995678f5aa2f04d537687f7b9b 100644 (file)
@@ -99,7 +99,7 @@ sub mkvcbuild
      srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
      erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
      dirent.c dlopen.c getopt.c getopt_long.c link.c
-     pread.c pwrite.c pg_bitutils.c
+     pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c
      pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
      pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c
      strerror.c tar.c thread.c