|
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 | #ifdefHAVE_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(constchar*src,constchar*dst, |
| 152 | +constchar*schemaName,constchar*relName) |
| 153 | +{ |
| 154 | +#ifdefHAVE_COPY_FILE_RANGE |
| 155 | +intsrc_fd; |
| 156 | +intdest_fd; |
| 157 | +ssize_tnbytes; |
| 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 | +charexisting_file[MAXPGPATH]; |
| 405 | +charnew_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 | +intsrc_fd; |
| 414 | +intdest_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 | {
|
|