0009-Use-copy_file_range-in-pg_upgrade.patch
text/x-patch
Filename: 0009-Use-copy_file_range-in-pg_upgrade.patch
Type: text/x-patch
Part: 8
Message:
Large files for relations
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch 0009
Subject: Use copy_file_range() in pg_upgrade.
| File | + | − |
|---|---|---|
| src/bin/pg_upgrade/file.c | 51 | 14 |
From b435220922d7cd916f1b7acce313c8174738991c Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Sun, 30 Apr 2023 14:45:45 +1200
Subject: [PATCH 09/11] Use copy_file_range() in pg_upgrade.
This gives the kernel the opportunity to copy or clone efficiently.
We watch out for EXDEV and fall back to read/write for old Linux
kernels.
XXX Should we also let the user opt out?
---
src/bin/pg_upgrade/file.c | 65 ++++++++++++++++++++++++++++++---------
1 file changed, 51 insertions(+), 14 deletions(-)
diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index d173602882..836b2bbbd0 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -9,6 +9,7 @@
#include "postgres_fe.h"
+#include <limits.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef HAVE_COPYFILE_H
@@ -98,32 +99,68 @@ copyFile(const char *src, const char *dst,
/* copy in fairly large chunks for best efficiency */
#define COPY_BUF_SIZE (50 * BLCKSZ)
+#ifdef HAVE_COPY_FILE_RANGE
+ buffer = NULL;
+#else
buffer = (char *) pg_malloc(COPY_BUF_SIZE);
+#endif
/* perform data copying i.e read src source, write to destination */
while (true)
{
- ssize_t nbytes = read(src_fd, buffer, COPY_BUF_SIZE);
+ ssize_t nbytes = 0;
- if (nbytes < 0)
- pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s",
- schemaName, relName, src, strerror(errno));
+#ifdef HAVE_COPY_FILE_RANGE
+ if (buffer == NULL)
+ {
+ nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0);
+ if (nbytes < 0)
+ {
+ if (errno == EXDEV)
+ {
+ /* Linux < 5.3 might fail. Fall back to read/write. */
+ buffer = (char *) pg_malloc(COPY_BUF_SIZE);
+ }
+ else
+ {
+ pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s",
- if (nbytes == 0)
- break;
+ schemaName, relName, src, strerror(errno));
+ }
+ }
+ }
+#endif
- errno = 0;
- if (write(dest_fd, buffer, nbytes) != nbytes)
+ if (buffer)
{
- /* if write didn't set errno, assume problem is no disk space */
- if (errno == 0)
- errno = ENOSPC;
- pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %s",
- schemaName, relName, dst, strerror(errno));
+ nbytes = read(src_fd, buffer, COPY_BUF_SIZE);
+
+ if (nbytes < 0)
+ pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %s",
+ schemaName, relName, src, strerror(errno));
+ if (nbytes > 0)
+ {
+ errno = 0;
+ if (write(dest_fd, buffer, nbytes) != nbytes)
+ {
+ /*
+ * If write didn't set errno, assume problem is no disk
+ * space.
+ */
+ if (errno == 0)
+ errno = ENOSPC;
+ pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %s",
+ schemaName, relName, dst, strerror(errno));
+ }
+ }
}
+
+ if (nbytes == 0)
+ break;
}
- pg_free(buffer);
+ if (buffer)
+ pg_free(buffer);
close(src_fd);
close(dest_fd);
--
2.40.1