From 464aaab4dbbdfaed0b66fb495ff47b75f87c296f Mon Sep 17 00:00:00 2001 From: Oleg Sidorkin Date: Sat, 31 Jan 2026 12:46:13 +0300 Subject: [PATCH] perf: Use copy_file_range to copy files if available (#1680) --- cmake/GenerateConfigurationFile.cmake | 1 + cmake/config.h.in | 3 +++ src/ccache/util/file.cpp | 8 +++++++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/cmake/GenerateConfigurationFile.cmake b/cmake/GenerateConfigurationFile.cmake index 01522ad9..ad8cce6a 100644 --- a/cmake/GenerateConfigurationFile.cmake +++ b/cmake/GenerateConfigurationFile.cmake @@ -25,6 +25,7 @@ endforeach() include(CheckFunctionExists) set(functions + copy_file_range getopt_long getpwuid localtime_r diff --git a/cmake/config.h.in b/cmake/config.h.in index dfd8e4e3..87dd0322 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -113,6 +113,9 @@ // === Functions === +// Define if you have the "copy_file_range" function. +#cmakedefine HAVE_COPY_FILE_RANGE + // Define if you have the "getopt_long" function. #cmakedefine HAVE_GETOPT_LONG diff --git a/src/ccache/util/file.cpp b/src/ccache/util/file.cpp index 4631eb33..4653e247 100644 --- a/src/ccache/util/file.cpp +++ b/src/ccache/util/file.cpp @@ -161,17 +161,23 @@ copy_file_impl(const fs::path& src, FMT("Failed to copy {} to {}: {}", src, dest, strerror(errno))); } return {}; -# elif defined(HAVE_SYS_SENDFILE_H) +# elif defined(HAVE_COPY_FILE_RANGE) || defined(HAVE_SYS_SENDFILE_H) DirEntry dir_entry(src, *src_fd); if (!dir_entry) { return tl::unexpected(FMT("Failed to stat {}: {}", src, strerror(errno))); } ssize_t bytes_left = dir_entry.size(); while (bytes_left > 0) { +# if defined(HAVE_SYS_SENDFILE_H) ssize_t n = sendfile(*dst_fd, *src_fd, nullptr, bytes_left); +# elif defined(HAVE_COPY_FILE_RANGE) + ssize_t n = + copy_file_range(*src_fd, nullptr, *dst_fd, nullptr, bytes_left, 0); +# endif if (n < 0) { switch (errno) { case EINVAL: + case EXDEV: case ENOSYS: return copy_fd(*src_fd, *dst_fd); default: -- 2.47.3