v20240330-0004-allow-cloning-with-checksum-calculation.patch
text/x-patch
Filename: v20240330-0004-allow-cloning-with-checksum-calculation.patch
Type: text/x-patch
Part: 4
Patch
Format: format-patch
Series: patch v20240330-0004
Subject: allow cloning with checksum calculation
| File | + | − |
|---|---|---|
| src/bin/pg_combinebackup/copy_file.c | 67 | 41 |
From 1d8d7eab9873242c1f0d4b5ad8696a8904e5cb98 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@2ndquadrant.com>
Date: Sat, 30 Mar 2024 23:45:35 +0100
Subject: [PATCH v20240330 4/4] allow cloning with checksum calculation
---
src/bin/pg_combinebackup/copy_file.c | 108 +++++++++++++++++----------
1 file changed, 67 insertions(+), 41 deletions(-)
diff --git a/src/bin/pg_combinebackup/copy_file.c b/src/bin/pg_combinebackup/copy_file.c
index be8336f7120..8e8c02e58f8 100644
--- a/src/bin/pg_combinebackup/copy_file.c
+++ b/src/bin/pg_combinebackup/copy_file.c
@@ -25,12 +25,15 @@
static void copy_file_blocks(const char *src, const char *dst,
pg_checksum_context *checksum_ctx);
-static void copy_file_clone(const char *src, const char *dst);
+static void copy_file_clone(const char *src, const char *dst,
+ pg_checksum_context *checksum_ctx);
-static void copy_file_by_range(const char *src, const char *dst);
+static void copy_file_by_range(const char *src, const char *dst,
+ pg_checksum_context *checksum_ctx);
#ifdef WIN32
-static void copy_file_copyfile(const char *src, const char *dst);
+static void copy_file_copyfile(const char *src, const char *dst,
+ pg_checksum_context *checksum_ctx);
#endif
/*
@@ -44,7 +47,8 @@ copy_file(const char *src, const char *dst,
CopyMethod copy_method)
{
char *strategy_name = NULL;
- void (*strategy_implementation) (const char *, const char *) = NULL;
+ void (*strategy_implementation) (const char *, const char *,
+ pg_checksum_context *checksum_ctx) = NULL;
/*
* In dry-run mode, we don't actually copy anything, nor do we read any
@@ -60,29 +64,8 @@ copy_file(const char *src, const char *dst,
pg_fatal("could not close \"%s\": %m", src);
}
- /*
- * If we need to compute a checksum, but the user perhaps requested
- * a special copy method that does not support this, fallback to the
- * default block-by-block copy. We don't want to fail if just one of
- * many files requires checksum, etc.
- *
- * If we don't need to compute a checksum, then we can use any special
- * operating system primitives that we know about to copy the file; this
- * may be quicker than a naive block copy. We only do this for WIN32.
- * On other operating systems the user has to explicitly specify one of
- * the available primitives - there may be multiple, we don't know which
- * are reliable/preferred.
- */
- if (checksum_ctx->type != CHECKSUM_TYPE_NONE)
- {
- /* fallback to block-by-block copy */
- copy_method = COPY_METHOD_COPY;
- }
#ifdef WIN32
- else
- {
- copy_method = COPY_METHOD_COPYFILE;
- }
+ copy_method = COPY_METHOD_COPYFILE;
#endif
/* Determine the name of the copy strategy for use in log messages. */
@@ -94,6 +77,7 @@ copy_file(const char *src, const char *dst,
break;
case COPY_METHOD_COPY:
/* leave NULL for simple block-by-block copy */
+ strategy_implementation = copy_file_blocks;
break;
case COPY_METHOD_COPY_FILE_RANGE:
strategy_name = "copy_file_range";
@@ -119,25 +103,55 @@ copy_file(const char *src, const char *dst,
else
{
if (strategy_name)
- {
pg_log_debug("copying \"%s\" to \"%s\" using strategy %s",
src, dst, strategy_name);
- strategy_implementation(src, dst);
- }
+ else if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
+ pg_log_debug("copying \"%s\" to \"%s\"",
+ src, dst);
else
- {
- if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
- pg_log_debug("copying \"%s\" to \"%s\"",
- src, dst);
- else
- pg_log_debug("copying \"%s\" to \"%s\" and checksumming with %s",
- src, dst, pg_checksum_type_name(checksum_ctx->type));
+ pg_log_debug("copying \"%s\" to \"%s\" and checksumming with %s",
+ src, dst, pg_checksum_type_name(checksum_ctx->type));
- copy_file_blocks(src, dst, checksum_ctx);
- }
+ strategy_implementation(src, dst, checksum_ctx);
}
}
+/*
+ * Calculate checksum for src file.
+ */
+static void
+checksum_file(const char *src, pg_checksum_context *checksum_ctx)
+{
+ int src_fd;
+ uint8 *buffer;
+ const int buffer_size = 50 * BLCKSZ;
+ ssize_t rb;
+ unsigned offset = 0;
+
+ /* bail out if no checksum needed */
+ if (checksum_ctx->type == CHECKSUM_TYPE_NONE)
+ return;
+
+ if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0)
+ pg_fatal("could not open file \"%s\": %m", src);
+
+ buffer = pg_malloc(buffer_size);
+
+ while ((rb = read(src_fd, buffer, buffer_size)) > 0)
+ {
+ if (pg_checksum_update(checksum_ctx, buffer, rb) < 0)
+ pg_fatal("could not update checksum of file \"%s\"", src);
+
+ offset += rb;
+ }
+
+ if (rb < 0)
+ pg_fatal("could not read file \"%s\": %m", src);
+
+ pg_free(buffer);
+ close(src_fd);
+}
+
/*
* Copy a file block by block, and optionally compute a checksum as we go.
*/
@@ -193,7 +207,8 @@ copy_file_blocks(const char *src, const char *dst,
* Clones/reflinks a file from src to dest.
*/
static void
-copy_file_clone(const char *src, const char *dest)
+copy_file_clone(const char *src, const char *dest,
+ pg_checksum_context *checksum_ctx)
{
#if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)
if (copyfile(src, dest, NULL, COPYFILE_CLONE_FORCE) < 0)
@@ -220,6 +235,9 @@ copy_file_clone(const char *src, const char *dest)
#else
pg_fatal("file cloning not supported on this platform");
#endif
+
+ /* if needed, calculate checksum of the file */
+ checksum_file(src, checksum_ctx);
}
/*
@@ -227,7 +245,8 @@ copy_file_clone(const char *src, const char *dest)
* Copies a file from src to dest using copy_file_range system call.
*/
static void
-copy_file_by_range(const char *src, const char *dest)
+copy_file_by_range(const char *src, const char *dest,
+ pg_checksum_context *checksum_ctx)
{
#if defined(HAVE_COPY_FILE_RANGE)
int src_fd;
@@ -254,16 +273,23 @@ copy_file_by_range(const char *src, const char *dest)
#else
pg_fatal("copy_file_range not supported on this platform");
#endif
+
+ /* if needed, calculate checksum of the file */
+ checksum_file(src, checksum_ctx);
}
#ifdef WIN32
static void
-copy_file_copyfile(const char *src, const char *dst)
+copy_file_copyfile(const char *src, const char *dst,
+ pg_checksum_context *checksum_ctx)
{
if (CopyFile(src, dst, true) == 0)
{
_dosmaperr(GetLastError());
pg_fatal("could not copy \"%s\" to \"%s\": %m", src, dst);
}
+
+ /* if needed, calculate checksum of the file */
+ checksum_file(src, checksum_ctx);
}
#endif /* WIN32 */
--
2.44.0