Move pg_pwritev_with_retry() to src/common/file_utils.c
authorMichael Paquier <[email protected]>
Thu, 27 Oct 2022 05:39:42 +0000 (14:39 +0900)
committerMichael Paquier <[email protected]>
Thu, 27 Oct 2022 05:39:42 +0000 (14:39 +0900)
This commit moves pg_pwritev_with_retry(), a convenience wrapper of
pg_writev() able to handle partial writes, to common/file_utils.c so
that the frontend code is able to use it.  A first use-case targetted
for this routine is pg_basebackup and pg_receivewal, for the
zero-padding of a newly-initialized WAL segment.  This is used currently
in the backend when the GUC wal_init_zero is enabled (default).

Author: Bharath Rupireddy
Reviewed-by: Nathan Bossart, Thomas Munro
Discussion: https://postgr.es/m/CALj2ACUq7nAb7=bJNbK3yYmp-SZhJcXFR_pLk8un6XgDzDF3OA@mail.gmail.com

src/backend/storage/file/fd.c
src/common/file_utils.c
src/include/common/file_utils.h
src/include/storage/fd.h

index e4d954578c8a564b1a85e4f8d59473744fa5de93..4151cafec5472a437ca62f0e706e7b6de689ffd4 100644 (file)
@@ -93,7 +93,6 @@
 #include "common/pg_prng.h"
 #include "miscadmin.h"
 #include "pgstat.h"
-#include "port/pg_iovec.h"
 #include "portability/mem.h"
 #include "postmaster/startup.h"
 #include "storage/fd.h"
@@ -3738,67 +3737,3 @@ 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 df4d6d240c06f99a650659eb2b18f1126c27802f..eac05a13ed524e125c459f95df45c7cfe60732d0 100644 (file)
@@ -28,6 +28,7 @@
 #ifdef FRONTEND
 #include "common/logging.h"
 #endif
+#include "port/pg_iovec.h"
 
 #ifdef FRONTEND
 
@@ -460,3 +461,69 @@ get_dirent_type(const char *path,
 
    return result;
 }
+
+/*
+ * pg_pwritev_with_retry
+ *
+ * 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 2811744c12f570f1af1b9a9f08422a94bfc4b5d2..2c5dbcb0b1eea59ec2d2f75aa87e6bcd396c48e1 100644 (file)
@@ -24,6 +24,8 @@ typedef enum PGFileType
    PGFILETYPE_LNK
 } PGFileType;
 
+struct iovec;                  /* avoid including port/pg_iovec.h here */
+
 #ifdef FRONTEND
 extern int fsync_fname(const char *fname, bool isdir);
 extern void fsync_pgdata(const char *pg_data, int serverVersion);
@@ -37,4 +39,9 @@ extern PGFileType get_dirent_type(const char *path,
                                  bool look_through_symlinks,
                                  int elevel);
 
+extern ssize_t pg_pwritev_with_retry(int fd,
+                                    const struct iovec *iov,
+                                    int iovcnt,
+                                    off_t offset);
+
 #endif                         /* FILE_UTILS_H */
index 5a48fccd9c203d6e389b759c212e61b294f7593c..c0a212487d92bdb2644a1b338646e104782cce7c 100644 (file)
@@ -51,8 +51,6 @@ typedef enum RecoveryInitSyncMethod
    RECOVERY_INIT_SYNC_METHOD_SYNCFS
 }          RecoveryInitSyncMethod;
 
-struct iovec;                  /* avoid including port/pg_iovec.h here */
-
 typedef int File;
 
 
@@ -178,10 +176,6 @@ extern int pg_fsync_no_writethrough(int fd);
 extern int pg_fsync_writethrough(int fd);
 extern int pg_fdatasync(int fd);
 extern void pg_flush_data(int fd, off_t offset, off_t nbytes);
-extern ssize_t pg_pwritev_with_retry(int fd,
-                                    const struct iovec *iov,
-                                    int iovcnt,
-                                    off_t offset);
 extern int pg_truncate(const char *path, off_t length);
 extern void fsync_fname(const char *fname, bool isdir);
 extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);