Skip to content

Commit f07f044

Browse files
committed
Add copy_file_range strategy to create database
1 parent 4b8bb61 commit f07f044

File tree

3 files changed

+84
-10
lines changed

3 files changed

+84
-10
lines changed

src/backend/commands/dbcommands.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ typedef enum CreateDBStrategy
8383
{
8484
CREATEDB_WAL_LOG,
8585
CREATEDB_FILE_COPY,
86+
CREATEDB_COPY_FILE_RANGE,
8687
} CreateDBStrategy;
8788

8889
typedef struct
@@ -136,7 +137,8 @@ static CreateDBRelInfo *ScanSourceDatabasePgClassTuple(HeapTupleData *tuple,
136137
static void CreateDirAndVersionFile(char *dbpath, Oid dbid, Oid tsid,
137138
bool isRedo);
138139
static void CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid,
139-
Oid src_tsid, Oid dst_tsid);
140+
Oid src_tsid, Oid dst_tsid,
141+
bool range_copy);
140142
static void recovery_create_dbdir(char *path, bool only_tblspc);
141143

142144
/*
@@ -548,7 +550,7 @@ CreateDirAndVersionFile(char *dbpath, Oid dbid, Oid tsid, bool isRedo)
548550
*/
549551
static void
550552
CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
551-
Oid dst_tsid)
553+
Oid dst_tsid, bool range_copy)
552554
{
553555
TableScanDesc scan;
554556
Relation rel;
@@ -608,7 +610,7 @@ CreateDatabaseUsingFileCopy(Oid src_dboid, Oid dst_dboid, Oid src_tsid,
608610
*
609611
* We don't need to copy subdirectories
610612
*/
611-
copydir(srcpath, dstpath, false);
613+
copydir(srcpath, dstpath, false, range_copy);
612614

613615
/* Record the filesystem change in XLOG */
614616
{
@@ -1022,6 +1024,8 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
10221024
dbstrategy = CREATEDB_WAL_LOG;
10231025
else if (pg_strcasecmp(strategy, "file_copy") == 0)
10241026
dbstrategy = CREATEDB_FILE_COPY;
1027+
else if (pg_strcasecmp(strategy, "copy_file_range") == 0)
1028+
dbstrategy = CREATEDB_COPY_FILE_RANGE;
10251029
else
10261030
ereport(ERROR,
10271031
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@@ -1508,9 +1512,12 @@ createdb(ParseState *pstate, const CreatedbStmt *stmt)
15081512
if (dbstrategy == CREATEDB_WAL_LOG)
15091513
CreateDatabaseUsingWalLog(src_dboid, dboid, src_deftablespace,
15101514
dst_deftablespace);
1515+
else if (dbstrategy == CREATEDB_COPY_FILE_RANGE)
1516+
CreateDatabaseUsingFileCopy(src_dboid, dboid, src_deftablespace,
1517+
dst_deftablespace, true);
15111518
else
15121519
CreateDatabaseUsingFileCopy(src_dboid, dboid, src_deftablespace,
1513-
dst_deftablespace);
1520+
dst_deftablespace, false);
15141521

15151522
/*
15161523
* Close pg_database, but keep lock till commit.
@@ -2156,7 +2163,7 @@ movedb(const char *dbname, const char *tblspcname)
21562163
/*
21572164
* Copy files from the old tablespace to the new one
21582165
*/
2159-
copydir(src_dbpath, dst_dbpath, false);
2166+
copydir(src_dbpath, dst_dbpath, false, false);
21602167

21612168
/*
21622169
* Record the filesystem change in XLOG
@@ -3341,7 +3348,7 @@ dbase_redo(XLogReaderState *record)
33413348
*
33423349
* We don't need to copy subdirectories
33433350
*/
3344-
copydir(src_path, dst_path, false);
3351+
copydir(src_path, dst_path, false, false);
33453352

33463353
pfree(src_path);
33473354
pfree(dst_path);

src/backend/storage/file/copydir.c

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "pgstat.h"
2727
#include "storage/copydir.h"
2828
#include "storage/fd.h"
29+
#include "pg_config.h"
2930

3031
/*
3132
* copydir: copy a directory
@@ -34,7 +35,7 @@
3435
* a directory or a regular file is ignored.
3536
*/
3637
void
37-
copydir(const char *fromdir, const char *todir, bool recurse)
38+
copydir(const char *fromdir, const char *todir, bool recurse, bool range_copy)
3839
{
3940
DIR *xldir;
4041
struct dirent *xlde;
@@ -68,10 +69,15 @@ copydir(const char *fromdir, const char *todir, bool recurse)
6869
{
6970
/* recurse to handle subdirectories */
7071
if (recurse)
71-
copydir(fromfile, tofile, true);
72+
copydir(fromfile, tofile, true, range_copy);
7273
}
7374
else if (xlde_type == PGFILETYPE_REG)
74-
copy_file(fromfile, tofile);
75+
{
76+
if (range_copy)
77+
copy_file_reflink(fromfile, tofile);
78+
else
79+
copy_file(fromfile, tofile);
80+
}
7581
}
7682
FreeDir(xldir);
7783

@@ -214,3 +220,63 @@ copy_file(const char *fromfile, const char *tofile)
214220

215221
pfree(buffer);
216222
}
223+
224+
/*
225+
* copy one file using copy_file_range to give filesystem a chance to do COW optimization
226+
*/
227+
void
228+
copy_file_reflink(const char *fromfile, const char *tofile)
229+
{
230+
#if defined(HAVE_COPY_FILE_RANGE)
231+
int srcfd;
232+
int dstfd;
233+
ssize_t nbytes;
234+
235+
/*
236+
* Open the files
237+
*/
238+
srcfd = OpenTransientFile(fromfile, O_RDONLY | PG_BINARY);
239+
240+
if (srcfd < 0)
241+
ereport(ERROR,
242+
errcode_for_file_access(),
243+
errmsg("could not open file \"%s\": %m", fromfile));
244+
245+
dstfd = OpenTransientFile(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY);
246+
247+
if (dstfd < 0)
248+
ereport(ERROR,
249+
errcode_for_file_access(),
250+
errmsg("could not create file \"%s\": %m", tofile));
251+
252+
/*
253+
* Do the data copying.
254+
*/
255+
do
256+
{
257+
/* If we got a cancel signal during the copy of the file, quit */
258+
CHECK_FOR_INTERRUPTS();
259+
260+
pgstat_report_wait_start(WAIT_EVENT_COPY_FILE_READ);
261+
nbytes = copy_file_range(srcfd, NULL, dstfd, NULL, SSIZE_MAX, 0);
262+
pgstat_report_wait_end();
263+
if (nbytes < 0)
264+
ereport(ERROR,
265+
errcode_for_file_access(),
266+
errmsg("could not copy file \"%s\": %m", fromfile));
267+
}
268+
while (nbytes > 0);
269+
270+
if (CloseTransientFile(dstfd) != 0)
271+
ereport(ERROR,
272+
errcode_for_file_access(),
273+
errmsg("could not close file \"%s\": %m", tofile));
274+
275+
if (CloseTransientFile(srcfd) != 0)
276+
ereport(ERROR,
277+
errcode_for_file_access(),
278+
errmsg("could not close file \"%s\": %m", fromfile));
279+
#else
280+
pg_fatal("copy_file_range not available on this platform");
281+
#endif
282+
}

src/include/storage/copydir.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
#ifndef COPYDIR_H
1414
#define COPYDIR_H
1515

16-
extern void copydir(const char *fromdir, const char *todir, bool recurse);
16+
extern void copydir(const char *fromdir, const char *todir, bool recurse, bool range_copy);
1717
extern void copy_file(const char *fromfile, const char *tofile);
18+
extern void copy_file_reflink(const char *fromfile, const char *tofile);
1819

1920
#endif /* COPYDIR_H */

0 commit comments

Comments
 (0)