Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions src/backend/storage/file/copydir.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,19 @@
#include "postgres.h"

#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#include "common/file_utils.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/copydir.h"

#include <limits.h>
#include <common/logging.h>

#include "storage/fd.h"
#include "pg_config.h"

/*
* copydir: copy a directory
Expand Down Expand Up @@ -71,7 +77,11 @@ copydir(const char *fromdir, const char *todir, bool recurse)
copydir(fromfile, tofile, true);
}
else if (xlde_type == PGFILETYPE_REG)
#if defined(HAVE_COPY_FILE_RANGE)
copy_file_reflink(fromfile, tofile);
#else
copy_file(fromfile, tofile);
#endif
}
FreeDir(xldir);

Expand Down Expand Up @@ -214,3 +224,63 @@ copy_file(const char *fromfile, const char *tofile)

pfree(buffer);
}

/*
* copy one file using copy_file_range to give filesystem a chance to do COW optimization
*/
void
copy_file_reflink(const char *fromfile, const char *tofile)
{
#if defined(HAVE_COPY_FILE_RANGE)
int srcfd;
int dstfd;
ssize_t nbytes;

/*
* Open the files
*/
srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);

if (srcfd < 0)
ereport(ERROR,
errcode_for_file_access(),
errmsg("could not open file \"%s\": %m", fromfile));

dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);

if (dstfd < 0)
ereport(ERROR,
errcode_for_file_access(),
errmsg("could not create file \"%s\": %m", tofile));

/*
* Do the data copying.
*/
do
{
/* If we got a cancel signal during the copy of the file, quit */
CHECK_FOR_INTERRUPTS();

pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
nbytes = copy_file_range(srcfd, NULL, dstfd, NULL, SSIZE_MAX, 0);
pgstat_report_wait_end();
if (nbytes < 0)
ereport(ERROR,
errcode_for_file_access(),
errmsg("could not copy file \"%s\": %m", fromfile));
}
while (nbytes > 0);

if (CloseTransientFile(dstfd) != 0)
ereport(ERROR,
errcode_for_file_access(),
errmsg("could not close file \"%s\": %m", tofile));

if (CloseTransientFile(srcfd) != 0)
ereport(ERROR,
errcode_for_file_access(),
errmsg("could not close file \"%s\": %m", fromfile));
#else
pg_fatal("copy_file_range not available on this platform");
#endif
}
1 change: 1 addition & 0 deletions src/include/storage/copydir.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@

extern void copydir(const char *fromdir, const char *todir, bool recurse);
extern void copy_file(const char *fromfile, const char *tofile);
extern void copy_file_reflink(const char *fromfile, const char *tofile);

#endif /* COPYDIR_H */