From df840f7ae979d0e849511f74b3b25806b156ada3 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sat, 30 Mar 2024 17:41:27 +0100 Subject: [PATCH v20240330 3/4] extend use of copy_file_range --- src/bin/pg_combinebackup/pg_combinebackup.c | 29 +++++++++ src/bin/pg_combinebackup/reconstruct.c | 66 +++++++++++++-------- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c index 76a63d826a7..4f3d7747ce6 100644 --- a/src/bin/pg_combinebackup/pg_combinebackup.c +++ b/src/bin/pg_combinebackup/pg_combinebackup.c @@ -223,6 +223,35 @@ main(int argc, char *argv[]) if (opt.no_manifest) opt.manifest_checksums = CHECKSUM_TYPE_NONE; + /* Check that the platform supports the requested copy method. */ + if (opt.copy_method == COPY_METHOD_CLONE) + { +#if (defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE)) || \ + (defined(__linux__) && defined(FICLONE)) + + if (opt.dry_run) + pg_log_debug("would use cloning to copy files"); + else + pg_log_debug("will use cloning to copy files"); + +#else + pg_fatal("file cloning not supported on this platform"); +#endif + } + else if (opt.copy_method == COPY_METHOD_COPY_FILE_RANGE) + { +#if defined(HAVE_COPY_FILE_RANGE) + + if (opt.dry_run) + pg_log_debug("would use copy_file_range to copy blocks"); + else + pg_log_debug("will use copy_file_range to copy blocks"); + +#else + pg_fatal("copy_file_range not supported on this platform"); +#endif + } + /* Read the server version from the final backup. */ version = read_pg_version_file(argv[argc - 1]); diff --git a/src/bin/pg_combinebackup/reconstruct.c b/src/bin/pg_combinebackup/reconstruct.c index 2689d65efba..dadf92cbfde 100644 --- a/src/bin/pg_combinebackup/reconstruct.c +++ b/src/bin/pg_combinebackup/reconstruct.c @@ -619,6 +619,9 @@ write_reconstructed_file(char *input_filename, rfile *s = sourcemap[i]; int wb; + bool skip_page_read = false; + bool use_copy_range = false; + /* Update accounting information. */ if (s == NULL) ++zero_blocks; @@ -634,28 +637,23 @@ write_reconstructed_file(char *input_filename, continue; /* - * If requested, copy the block using copy_file_range. + * Do we need to actually read the souce block? * - * We can'd do this if the block needs to be zero-filled or when we - * need to update checksum. + * We only need to read the block if we are to perform plain copy or + * calculate the checksum. If the user requested copy_file_range, we + * may be able to skip reading the block. */ - if ((copy_method == COPY_METHOD_COPY_FILE_RANGE) && - (s != NULL) && (checksum_ctx->type == CHECKSUM_TYPE_NONE)) - { -#if defined(HAVE_COPY_FILE_RANGE) - wb = copy_file_range(s->fd, &offsetmap[i], wfd, NULL, BLCKSZ, 0); + skip_page_read = ((copy_method == COPY_METHOD_COPY_FILE_RANGE) && + (checksum_ctx->type == CHECKSUM_TYPE_NONE)); - if (wb < 0) - pg_fatal("error while copying file range from \"%s\" to \"%s\": %m", - input_filename, output_filename); - else if (wb != BLCKSZ) - pg_fatal("could not write file \"%s\": wrote only %d of %d bytes", - output_filename, wb, BLCKSZ); -#else - pg_fatal("copy_file_range not supported on this platform"); -#endif - continue; - } + /* + * Should we copy the block using copy_file_range? + * + * We can do that if the user requested that, and the block is not + * going to be zero-filled. + */ + use_copy_range = ((copy_method == COPY_METHOD_COPY_FILE_RANGE) && + (s != NULL)); /* Read or zero-fill the block as appropriate. */ if (s == NULL) @@ -666,7 +664,7 @@ write_reconstructed_file(char *input_filename, */ memset(buffer, 0, BLCKSZ); } - else + else if (!skip_page_read) { int rb; @@ -683,14 +681,34 @@ write_reconstructed_file(char *input_filename, } } - /* Write out the block. */ - if ((wb = write(wfd, buffer, BLCKSZ)) != BLCKSZ) + /* + * If possible, copy the block using copy_file_range. If not possible + * (not requested/supported, or the block is zero-filled), fallback to + * the regular write. + */ + if (use_copy_range) { + wb = copy_file_range(s->fd, &offsetmap[i], wfd, NULL, BLCKSZ, 0); + if (wb < 0) - pg_fatal("could not write file \"%s\": %m", output_filename); - else + pg_fatal("error while copying file range from \"%s\" to \"%s\": %m", + input_filename, output_filename); + else if (wb != BLCKSZ) pg_fatal("could not write file \"%s\": wrote only %d of %d bytes", output_filename, wb, BLCKSZ); + continue; + } + else + { + /* Write out the block. */ + if ((wb = write(wfd, buffer, BLCKSZ)) != BLCKSZ) + { + if (wb < 0) + pg_fatal("could not write file \"%s\": %m", output_filename); + else + pg_fatal("could not write file \"%s\": wrote only %d of %d bytes", + output_filename, wb, BLCKSZ); + } } /* Update the checksum computation. */ -- 2.44.0