1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

Remove mmap(2) based copying; it is slower

This commit is contained in:
Marko Mäkelä
2026-10-15 13:50:28 +03:00
parent cd96a9ba04
commit 5be90f9246
3 changed files with 73 additions and 176 deletions

View File

@@ -73,48 +73,7 @@ using tpool::pwrite;
# include <sys/types.h>
# include <dirent.h>
# include <sys/mman.h>
/**
Copy a file using a memory mapping.
@tparam stream true=write to a stream, false=pwrite to a file
@param p map to source file
@param out_fd destination
@param o start offset
@param end last offset (exclusive)
@return error code
@retval 0 on success
@retval 1 if a memory mapping failed
*/
template<bool stream>
static ssize_t mmap_copy(const void *p, int out_fd, uint64_t o, uint64_t end)
{
size_t c= size_t(end - o);
ssize_t ret;
for (const char *b= static_cast<const char*>(p) + o;;
b+= ret, o+= uint64_t(ret))
{
const size_t size{std::min(c, size_t(INT_MAX >> 20 << 20))};
if (stream)
{
if ((ret= backup_stream_write(out_fd, b, size)))
break;
ret= size;
}
else if ((ret= pwrite(out_fd, b, size, off_t(o))) < 0)
break;
c-= ret;
if (!c)
{
ret= 0;
break;
}
if (!ret)
{
ret= -1;
break;
}
}
return ret;
}
#endif
/**
@@ -198,20 +157,7 @@ int copy_entire_file(int src, int dst) noexcept
ret= int(copy_file_shortcut(src, dst, 0, end));
if (ret == 1)
# endif
{
# ifdef copy_file_mmap
void *p= mmap(nullptr, size_t{end}, PROT_READ, MAP_SHARED, src, 0);
if (p != MAP_FAILED)
{
ret= int(copy_file_mmap(p, dst, 0, end));
munmap(p, size_t{end});
}
else
# endif
{
ret= backup::copy(src, dst, 0, end);
}
}
ret= backup::copy(src, dst, 0, end);
#ifdef POSIX_FADV_DONTNEED
std::ignore= posix_fadvise(src, 0, 0, POSIX_FADV_DONTNEED);
#endif
@@ -424,9 +370,15 @@ int append(handle src, backup_fd stream, uint64_t start, uint64_t end) noexcept
that the receiving end of the pipe has consumed everything before
our caller re-enables writes to this src region.
On Linux, even for MAP_PRIVATE, the following has been documented:
For Linux mmap(2), even for MAP_PRIVATE, the following is documented:
It is unspecified whether changes made to the file after the
mmap() call are visible in the mapped region.
mmap(2) call are visible in the mapped region.
Similarly, for Linux sendfile(2): If out_fd refers to a socket or
pipe with zero-copy support, callers must ensure the transferred
portions of the file referred to by in_fd remain unmodified until
the reader on the other end of out_fd has consumed the
transferred data.
*/
# ifdef __linux__
const int pipe_size{fcntl(stream, F_GETPIPE_SZ)};
@@ -483,7 +435,7 @@ int backup_stream_zeropad(backup_fd stream, size_t written) noexcept
@param end last offset to copy (exclusive)
@return error code (non-positive)
@retval 0 on success
@retval 1 if a fallback to copy_mmap() or backup::copy() is needed
@retval 1 if a fallback to backup::copy() is needed
*/
int copy_file_range_try(int src, int dst, uint64_t start, uint64_t end)
noexcept
@@ -497,22 +449,6 @@ int copy_file_range_try(int src, int dst, uint64_t start, uint64_t end)
}
#endif
#ifdef copy_file_mmap
/**
Copy from a memory mapping to a file.
@param map source file mapping
@param dst target to append map to
@param start first offset to copy
@param end last offset to copy (exclusive)
@return error code (non-positive)
@retval 0 on success
*/
int copy_mmap(const void *map, int dst, uint64_t start, uint64_t end) noexcept
{
return int(mmap_copy<false>(map, dst, start, end));
}
#endif
/** Append to the configuration file.
@param target backup target directory
@param config the configuration file snippet to append
@@ -1698,15 +1634,6 @@ int backup_stream_append_async(int src, int stream,
# ifdef __linux__
return int(stepwise<send_step,true>(src, stream, off_t(start), off_t(end)));
# else
# if SIZEOF_SIZE_T > 4
void *p= mmap(nullptr, size_t{end}, PROT_READ, MAP_SHARED, src, 0);
if (p != MAP_FAILED)
{
ssize_t ret= mmap_copy<true>(p, stream, start, end);
munmap(p, size_t{end});
return int(ret);
}
# endif
return int(pread_write<true>(src, stream, start, end));
# endif
}

View File

@@ -174,24 +174,7 @@ int append(handle src, backup_fd stream, uint64_t start, uint64_t end)
noexcept;
}
#if defined _WIN32 || defined __FreeBSD__
/* There is no special variant of backup::copy(). */
#else
# if SIZEOF_SIZE_T > 4
/**
Copy from a memory mapping to a file.
@param map source file mapping
@param dst target to append map to
@param start first offset to copy
@param end last offset to copy (exclusive)
@return error code (non-positive)
@retval 0 on success
*/
int copy_mmap(const void *map, int dst, uint64_t start, uint64_t end) noexcept;
# define copy_file_mmap copy_mmap
# endif
# ifdef __linux__
#ifdef __linux__
/**
Try to copy a portion of a file via copy_file_range(2).
@param src source file descriptor
@@ -200,12 +183,11 @@ int copy_mmap(const void *map, int dst, uint64_t start, uint64_t end) noexcept;
@param end last offset to copy (exclusive)
@return error code (non-positive)
@retval 0 on success
@retval 1 if a fallback to copy_mmap() or backup::copy() is needed
@retval 1 if a fallback to backup::copy() is needed
*/
int copy_file_range_try(int src, int dst, uint64_t start, uint64_t end)
noexcept;
# define copy_file_shortcut copy_file_range_try
# endif
# define copy_file_shortcut copy_file_range_try
#endif
/** Append to the configuration file.

View File

@@ -800,6 +800,37 @@ public:
return res;
}
#ifdef HAVE_PMEM
/**
Copy a file using a memory mapping.
@param p map to source file
@param dst destination
@param o start offset
@param end last offset (exclusive)
@return error code (non-positive)
@retval 0 on success
*/
static int mmap_copy(const void *p, int dst, uint64_t o, uint64_t end)
noexcept
{
size_t c= size_t(end - o);
ssize_t ret;
for (const char *b= static_cast<const char*>(p) + o;;
b+= ret, o+= uint64_t(ret))
{
const size_t size{std::min(c, size_t(INT_MAX >> 20 << 20))};
if ((ret= pwrite(dst, b, size, off_t(o))) < 0)
return int(ret);
c-= ret;
if (!c)
break;
if (!ret)
return -1;
}
return 0;
}
#endif
/**
Copy the log in real time.
@return error code (never positive)
@@ -874,7 +905,7 @@ public:
const uint64_t begin{prev - first}, end{lsn - first};
#ifdef HAVE_PMEM
if (log_sys.is_mmap())
err= copy_file_mmap(tracked.buf, ctx.log_dst, begin, end);
err= mmap_copy(tracked.buf, ctx.log_dst, begin, end);
else
#endif
{
@@ -2305,84 +2336,41 @@ int InnoDB_backup::backup(IF_WIN(const char *,int) target, fil_node_t *node,
#endif
{
const uint32_t BACKUP_BATCH_SIZE{innodb_backup.ctx.BACKUP_BATCH_SIZE};
#ifdef copy_file_mmap
const size_t c{size_t{final_limit ? final_limit : limit} * page_size};
void *p= mmap(nullptr, c, PROT_READ, MAP_SHARED, node->handle, 0);
if (p != MAP_FAILED)
for (uint32_t page{0};;)
{
for (uint32_t page{0};;)
while (page < limit)
{
while (page < limit)
start+= BACKUP_BATCH_SIZE;
buf_page_t **end= backup_batch_start(blocks, node->space, start);
if (end)
{
start+= BACKUP_BATCH_SIZE;
buf_page_t **end= backup_batch_start(blocks, node->space, start);
if (end)
{
const uint64_t o{uint64_t{page} * page_size};
page= std::min(limit, page + BACKUP_BATCH_SIZE);
/* TODO: avoid copying freed page ranges, or pages that were
allocated after the backup started */
err= copy_file_mmap(p, f, o, uint64_t{page} * page_size);
}
else
{
end= blocks;
err= 2;
}
backup_batch_stop(node->space, blocks, end);
if (err)
break;
}
if (final_limit != 0 && !err && page == buf_dblwr.begin())
{
/* Copy the rest after the doublewrite buffer. */
ut_ad(start == page);
limit= final_limit;
start= page+= buf_dblwr.size();
const uint64_t o{uint64_t{page} * page_size};
page= std::min(limit, page + BACKUP_BATCH_SIZE);
/* TODO: avoid copying freed page ranges, or pages that were
allocated after the backup started */
err=
backup::copy(node->handle, f, o, uint64_t{page} * page_size);
}
else
{
end= blocks;
err= 2;
}
backup_batch_stop(node->space, blocks, end);
if (err)
break;
}
munmap(p, c);
if (final_limit != 0 && !err && page == buf_dblwr.begin())
{
/* Copy the rest after the doublewrite buffer. */
ut_ad(start == page);
limit= final_limit;
start= page+= buf_dblwr.size();
}
else
break;
}
else
#endif
for (uint32_t page{0};;)
{
while (page < limit)
{
start+= BACKUP_BATCH_SIZE;
buf_page_t **end= backup_batch_start(blocks, node->space, start);
if (end)
{
const uint64_t o{uint64_t{page} * page_size};
page= std::min(limit, page + BACKUP_BATCH_SIZE);
/* TODO: avoid copying freed page ranges, or pages that were
allocated after the backup started */
err=
backup::copy(node->handle, f, o, uint64_t{page} * page_size);
}
else
{
end= blocks;
err= 2;
}
backup_batch_stop(node->space, blocks, end);
if (err)
break;
}
if (final_limit != 0 && !err && page == buf_dblwr.begin())
{
/* Copy the rest after the doublewrite buffer. */
ut_ad(start == page);
limit= final_limit;
start= page+= buf_dblwr.size();
}
else
break;
}
}
if (IF_WIN(!CloseHandle,close)(f) | err)