aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Munro <tmunro@postgresql.org>2023-12-12 10:28:46 +1300
committerThomas Munro <tmunro@postgresql.org>2023-12-12 10:57:18 +1300
commit0c6be59f5e34f44b20d9ec3ffb58c1d9a0bf985e (patch)
treec4a8d36502194629edc76f8e4b4561df7ce3673b
parentbaf7c93ed583949d837bc13f24a15a0efbcb1ae7 (diff)
downloadpostgresql-0c6be59f5e34f44b20d9ec3ffb58c1d9a0bf985e.tar.gz
postgresql-0c6be59f5e34f44b20d9ec3ffb58c1d9a0bf985e.zip
Provide helper for retrying partial vectored I/O.
compute_remaining_iovec() is a re-usable routine for retrying after pg_readv() or pg_writev() reports a short transfer. This will gain new users in a later commit, but can already replace the open-coded equivalent code in the existing pg_pwritev_with_retry() function. Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi> Discussion: https://postgr.es/m/CA+hUKGJkOiOCa+mag4BF+zHo7qo=o9CFheB8=g6uT5TUm2gkvA@mail.gmail.com
-rw-r--r--src/common/file_utils.c77
-rw-r--r--src/include/common/file_utils.h5
2 files changed, 57 insertions, 25 deletions
diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index abe5129412d..5380299f35f 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -582,6 +582,52 @@ get_dirent_type(const char *path,
}
/*
+ * Compute what remains to be done after a possibly partial vectored read or
+ * write. The part of 'source' beginning after 'transferred' bytes is copied
+ * to 'destination', and its length is returned. 'source' and 'destination'
+ * may point to the same array, for in-place adjustment. A return value of
+ * zero indicates completion (for callers without a cheaper way to know that).
+ */
+int
+compute_remaining_iovec(struct iovec *destination,
+ const struct iovec *source,
+ int iovcnt,
+ size_t transferred)
+{
+ Assert(iovcnt > 0);
+
+ /* Skip wholly transferred iovecs. */
+ while (source->iov_len <= transferred)
+ {
+ transferred -= source->iov_len;
+ source++;
+ iovcnt--;
+
+ /* All iovecs transferred? */
+ if (iovcnt == 0)
+ {
+ /*
+ * We don't expect the kernel to transfer more than we asked it
+ * to, or something is out of sync.
+ */
+ Assert(transferred == 0);
+ return 0;
+ }
+ }
+
+ /* Copy the remaining iovecs to the front of the array. */
+ if (source != destination)
+ memmove(destination, source, sizeof(*source) * iovcnt);
+
+ /* Adjust leading iovec, which may have been partially transferred. */
+ Assert(destination->iov_len > transferred);
+ destination->iov_base = (char *) destination->iov_base + transferred;
+ destination->iov_len -= transferred;
+
+ return iovcnt;
+}
+
+/*
* pg_pwritev_with_retry
*
* Convenience wrapper for pg_pwritev() that retries on partial write. If an
@@ -601,7 +647,7 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
return -1;
}
- for (;;)
+ do
{
/* Write as much as we can. */
part = pg_pwritev(fd, iov, iovcnt, offset);
@@ -616,33 +662,14 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
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.
+ * See what is left. On the first loop we used the caller's array,
+ * but in later loops we'll use our local copy that we are allowed to
+ * mutate.
*/
- 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;
+ iovcnt = compute_remaining_iovec(iov_copy, iov, iovcnt, part);
iov = iov_copy;
- }
+ } while (iovcnt > 0);
return sum;
}
diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h
index 3bb20170cbd..02a940e3102 100644
--- a/src/include/common/file_utils.h
+++ b/src/include/common/file_utils.h
@@ -46,6 +46,11 @@ extern PGFileType get_dirent_type(const char *path,
bool look_through_symlinks,
int elevel);
+extern int compute_remaining_iovec(struct iovec *destination,
+ const struct iovec *source,
+ int iovcnt,
+ size_t transferred);
+
extern ssize_t pg_pwritev_with_retry(int fd,
const struct iovec *iov,
int iovcnt,