|
10 | 10 | #include "postgres_fe.h"
|
11 | 11 |
|
12 | 12 | #include <sys/stat.h>
|
| 13 | +#include <limits.h> |
13 | 14 | #include <fcntl.h>
|
14 | 15 | #ifdef HAVE_COPYFILE_H
|
15 | 16 | #include <copyfile.h>
|
@@ -140,6 +141,45 @@ copyFile(const char *src, const char *dst,
|
140 | 141 | }
|
141 | 142 |
|
142 | 143 |
|
| 144 | +/* |
| 145 | + * copyFileByRange() |
| 146 | + * |
| 147 | + * Copies a relation file from src to dst. |
| 148 | + * schemaName/relName are relation's SQL name (used for error messages only). |
| 149 | + */ |
| 150 | +void |
| 151 | +copyFileByRange(const char *src, const char *dst, |
| 152 | + const char *schemaName, const char *relName) |
| 153 | +{ |
| 154 | +#ifdef HAVE_COPY_FILE_RANGE |
| 155 | + int src_fd; |
| 156 | + int dest_fd; |
| 157 | + ssize_t nbytes; |
| 158 | + |
| 159 | + if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) |
| 160 | + pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %s", |
| 161 | + schemaName, relName, src, strerror(errno)); |
| 162 | + |
| 163 | + if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, |
| 164 | + pg_file_create_mode)) < 0) |
| 165 | + pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %s", |
| 166 | + schemaName, relName, dst, strerror(errno)); |
| 167 | + |
| 168 | + do |
| 169 | + { |
| 170 | + nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0); |
| 171 | + if (nbytes < 0) |
| 172 | + pg_fatal("error while copying relation \"%s.%s\": could not copy file range from \"%s\" to \"%s\": %s", |
| 173 | + schemaName, relName, src, dst, strerror(errno)); |
| 174 | + } |
| 175 | + while (nbytes > 0); |
| 176 | + |
| 177 | + close(src_fd); |
| 178 | + close(dest_fd); |
| 179 | +#endif |
| 180 | +} |
| 181 | + |
| 182 | + |
143 | 183 | /*
|
144 | 184 | * linkFile()
|
145 | 185 | *
|
@@ -358,6 +398,44 @@ check_file_clone(void)
|
358 | 398 | unlink(new_link_file);
|
359 | 399 | }
|
360 | 400 |
|
| 401 | +void |
| 402 | +check_copy_file_range(void) |
| 403 | +{ |
| 404 | + char existing_file[MAXPGPATH]; |
| 405 | + char new_link_file[MAXPGPATH]; |
| 406 | + |
| 407 | + snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata); |
| 408 | + snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.copy_file_range_test", new_cluster.pgdata); |
| 409 | + unlink(new_link_file); /* might fail */ |
| 410 | + |
| 411 | +#if defined(HAVE_COPY_FILE_RANGE) |
| 412 | + { |
| 413 | + int src_fd; |
| 414 | + int dest_fd; |
| 415 | + |
| 416 | + if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) |
| 417 | + pg_fatal("could not open file \"%s\": %s", |
| 418 | + existing_file, strerror(errno)); |
| 419 | + |
| 420 | + if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, |
| 421 | + pg_file_create_mode)) < 0) |
| 422 | + pg_fatal("could not create file \"%s\": %s", |
| 423 | + new_link_file, strerror(errno)); |
| 424 | + |
| 425 | + if (copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0) < 0) |
| 426 | + pg_fatal("could not copy file range between old and new data directories: %s", |
| 427 | + strerror(errno)); |
| 428 | + |
| 429 | + close(src_fd); |
| 430 | + close(dest_fd); |
| 431 | + } |
| 432 | +#else |
| 433 | + pg_fatal("copy_file_range not supported on this platform"); |
| 434 | +#endif |
| 435 | + |
| 436 | + unlink(new_link_file); |
| 437 | +} |
| 438 | + |
361 | 439 | void
|
362 | 440 | check_hard_link(void)
|
363 | 441 | {
|
|
0 commit comments