v4-0001-Refactor-pg_pwrite_zeros.patch
application/x-patch
Filename: v4-0001-Refactor-pg_pwrite_zeros.patch
Type: application/x-patch
Part: 0
Patch
Format: format-patch
Series: patch v4-0001
Subject: Refactor pg_pwrite_zeros()
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlog.c | 1 | 1 |
| src/bin/pg_basebackup/walmethods.c | 1 | 1 |
| src/common/file_utils.c | 52 | 50 |
| src/include/common/file_utils.h | 1 | 1 |
From a941ea3de79cbe890196fa16f60d1e0797a9b119 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 15 Feb 2023 05:17:22 +0000
Subject: [PATCH v4] Refactor pg_pwrite_zeros()
This commit refactors pg_pwrite_zeros() as follows:
- add offset parameter
- avoid memset() of zerobuf on every call
- don't initialize the whole IOV array unnecessarily
- don't handle the smaller trailing write in a separate write call
Suggested-by: Andres Freund
Author: Bharath Rupireddy
Discussion: https://www.postgresql.org/message-id/20230211224424.r25uw4rsv6taukxk%40awork3.anarazel.d
---
src/backend/access/transam/xlog.c | 2 +-
src/bin/pg_basebackup/walmethods.c | 2 +-
src/common/file_utils.c | 102 +++++++++++++++--------------
src/include/common/file_utils.h | 2 +-
4 files changed, 55 insertions(+), 53 deletions(-)
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f9f0f6db8d..786b26054c 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2981,7 +2981,7 @@ XLogFileInitInternal(XLogSegNo logsegno, TimeLineID logtli,
* indirect blocks are down on disk. Therefore, fdatasync(2) or
* O_DSYNC will be sufficient to sync future writes to the log file.
*/
- rc = pg_pwrite_zeros(fd, wal_segment_size);
+ rc = pg_pwrite_zeros(fd, wal_segment_size, 0);
if (rc < 0)
save_errno = errno;
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 54014e2b84..6d14b988cb 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -222,7 +222,7 @@ dir_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
{
ssize_t rc;
- rc = pg_pwrite_zeros(fd, pad_to_size);
+ rc = pg_pwrite_zeros(fd, pad_to_size, 0);
if (rc < 0)
{
diff --git a/src/common/file_utils.c b/src/common/file_utils.c
index 4dae534152..303bb07543 100644
--- a/src/common/file_utils.c
+++ b/src/common/file_utils.c
@@ -531,72 +531,74 @@ pg_pwritev_with_retry(int fd, const struct iovec *iov, int iovcnt, off_t offset)
/*
* pg_pwrite_zeros
*
- * Writes zeros to file worth "size" bytes, using vectored I/O.
+ * Writes zeros to file worth "size" bytes from starting file offset 'offset',
+ * using vectored I/O.
*
* Returns the total amount of data written. On failure, a negative value
* is returned with errno set.
+ *
+ * Note that pg_pwrite(), which gets called from this function, may change the
+ * file position (see win32pwrite.c). If needed, callers must deal with it.
*/
ssize_t
-pg_pwrite_zeros(int fd, size_t size)
+pg_pwrite_zeros(int fd, size_t size, off_t offset)
{
- PGAlignedBlock zbuffer; /* worth BLCKSZ */
- size_t zbuffer_sz;
- struct iovec iov[PG_IOV_MAX];
- int blocks;
- size_t remaining_size = 0;
- int i;
- ssize_t written;
- ssize_t total_written = 0;
-
- zbuffer_sz = sizeof(zbuffer.data);
-
- /* Zero-fill the buffer. */
- memset(zbuffer.data, 0, zbuffer_sz);
-
- /* Prepare to write out a lot of copies of our zero buffer at once. */
- for (i = 0; i < lengthof(iov); ++i)
+ /*
+ * Zero-filled buffer worth BLCKSZ. We use static variable to avoid zeroing
+ * the buffer on every call. Also, with the const qualifier, it is ensured
+ * that the buffer is placed in read-only section of the process's memory.
+ */
+ static const PGAlignedBlock zbuf = {0};
+ static size_t zbuf_sz = BLCKSZ;
+ struct iovec iov[PG_IOV_MAX];
+ int blocks;
+ int init_upto;
+ int i;
+ ssize_t ntotalwritten = 0;
+ size_t nremaining;
+ size_t nlast;
+
+ blocks = size / zbuf_sz;
+ nremaining = size;
+ nlast = size % zbuf_sz;
+
+ /* Initialize only the needed iovec elements with zero buffer. */
+ init_upto = (blocks == 0) ? 1 : ((blocks >= lengthof(iov)) ? lengthof(iov) : blocks);
+ for (i = 0; i < init_upto; ++i)
{
- iov[i].iov_base = zbuffer.data;
- iov[i].iov_len = zbuffer_sz;
+ iov[i].iov_base = (void *) (unconstify(PGAlignedBlock *, &zbuf)->data);
+ iov[i].iov_len = zbuf_sz;
}
- /* Loop, writing as many blocks as we can for each system call. */
- blocks = size / zbuffer_sz;
- remaining_size = size % zbuffer_sz;
- for (i = 0; i < blocks;)
- {
- int iovcnt = Min(blocks - i, lengthof(iov));
- off_t offset = i * zbuffer_sz;
-
- written = pg_pwritev_with_retry(fd, iov, iovcnt, offset);
-
- if (written < 0)
- return written;
-
- i += iovcnt;
- total_written += written;
- }
+ i = 0;
- /* Now, write the remaining size, if any, of the file with zeros. */
- if (remaining_size > 0)
+ /* Loop, writing as many blocks as we can for each system call. */
+ while (nremaining > 0)
{
- /* We'll never write more than one block here */
- int iovcnt = 1;
-
- /* Jump on to the end of previously written blocks */
- off_t offset = i * zbuffer_sz;
+ int iovcnt;
+ ssize_t nwritten;
- iov[0].iov_len = remaining_size;
+ /* Determine if we need to write last bytes (< zbuf_sz) */
+ if (nlast != 0 && nlast == nremaining)
+ {
+ iov[0].iov_len = nlast;
+ iovcnt = 1; /* We will write not more than one block */
+ }
+ else
+ iovcnt = Min(blocks - i, lengthof(iov));
- written = pg_pwritev_with_retry(fd, iov, iovcnt, offset);
+ nwritten = pg_pwritev_with_retry(fd, iov, iovcnt, offset);
- if (written < 0)
- return written;
+ if (nwritten < 0)
+ return nwritten;
- total_written += written;
+ i += iovcnt;
+ ntotalwritten += nwritten;
+ nremaining -= nwritten;
+ offset += nwritten;
}
- Assert(total_written == size);
+ Assert(ntotalwritten == size);
- return total_written;
+ return ntotalwritten;
}
diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h
index bda6d3a541..b7efa1226d 100644
--- a/src/include/common/file_utils.h
+++ b/src/include/common/file_utils.h
@@ -44,6 +44,6 @@ extern ssize_t pg_pwritev_with_retry(int fd,
int iovcnt,
off_t offset);
-extern ssize_t pg_pwrite_zeros(int fd, size_t size);
+extern ssize_t pg_pwrite_zeros(int fd, size_t size, off_t offset);
#endif /* FILE_UTILS_H */
--
2.34.1