/
githubmirror
/
postgres
Обзор
Документация
Войти
/
githubmirror
/
postgres
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/bin/pg_upgrade/file.c
295 строк
8 KB
Nathan Bossart
Remove pg_upgrade support for upgrading from pre-v10 servers.
02 июл 2026, 21:05
02 июл 2026, 21:05
14d8418
Код
Авторство
О чём код?
/* * file.c * * file system operations * * Copyright (c) 2010-2026, PostgreSQL Global Development Group * src/bin/pg_upgrade/file.c */ #include "postgres_fe.h" #include <sys/stat.h> #include <limits.h> #include <fcntl.h> #ifdef HAVE_COPYFILE_H #include <copyfile.h> #endif #ifdef __linux__ #include <sys/ioctl.h> #include <linux/fs.h> #endif #include "common/file_perm.h" #include "pg_upgrade.h" /* * cloneFile() * * Clones/reflinks a relation file from src to dst. * * schemaName/relName are relation's SQL name (used for error messages only). */ void cloneFile(const char *src, const char *dst, const char *schemaName, const char *relName) { #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE) if (copyfile(src, dst, NULL, COPYFILE_CLONE_FORCE) < 0) pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %m", schemaName, relName, src, dst); #elif defined(__linux__) && defined(FICLONE) int src_fd; int dest_fd; if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("error while cloning relation \"%s.%s\": could not open file \"%s\": %m", schemaName, relName, src); if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, pg_file_create_mode)) < 0) pg_fatal("error while cloning relation \"%s.%s\": could not create file \"%s\": %m", schemaName, relName, dst); if (ioctl(dest_fd, FICLONE, src_fd) < 0) { int save_errno = errno; unlink(dst); pg_fatal("error while cloning relation \"%s.%s\" (\"%s\" to \"%s\"): %s", schemaName, relName, src, dst, strerror(save_errno)); } close(src_fd); close(dest_fd); #endif } /* * copyFile() * * Copies a relation file from src to dst. * schemaName/relName are relation's SQL name (used for error messages only). */ void copyFile(const char *src, const char *dst, const char *schemaName, const char *relName) { #ifndef WIN32 int src_fd; int dest_fd; char *buffer; if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m", schemaName, relName, src); if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, pg_file_create_mode)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m", schemaName, relName, dst); /* copy in fairly large chunks for best efficiency */ #define COPY_BUF_SIZE (50 * BLCKSZ) buffer = (char *) pg_malloc(COPY_BUF_SIZE); /* perform data copying i.e read src source, write to destination */ while (true) { ssize_t nbytes = read(src_fd, buffer, COPY_BUF_SIZE); if (nbytes < 0) pg_fatal("error while copying relation \"%s.%s\": could not read file \"%s\": %m", schemaName, relName, src); if (nbytes == 0) break; errno = 0; if (write(dest_fd, buffer, nbytes) != nbytes) { /* if write didn't set errno, assume problem is no disk space */ if (errno == 0) errno = ENOSPC; pg_fatal("error while copying relation \"%s.%s\": could not write file \"%s\": %m", schemaName, relName, dst); } } pg_free(buffer); close(src_fd); close(dest_fd); #else /* WIN32 */ if (CopyFile(src, dst, true) == 0) { _dosmaperr(GetLastError()); pg_fatal("error while copying relation \"%s.%s\" (\"%s\" to \"%s\"): %m", schemaName, relName, src, dst); } #endif /* WIN32 */ } /* * copyFileByRange() * * Copies a relation file from src to dst. * schemaName/relName are relation's SQL name (used for error messages only). */ void copyFileByRange(const char *src, const char *dst, const char *schemaName, const char *relName) { #ifdef HAVE_COPY_FILE_RANGE int src_fd; int dest_fd; ssize_t nbytes; if ((src_fd = open(src, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not open file \"%s\": %m", schemaName, relName, src); if ((dest_fd = open(dst, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, pg_file_create_mode)) < 0) pg_fatal("error while copying relation \"%s.%s\": could not create file \"%s\": %m", schemaName, relName, dst); do { nbytes = copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0); if (nbytes < 0) pg_fatal("error while copying relation \"%s.%s\": could not copy file range from \"%s\" to \"%s\": %m", schemaName, relName, src, dst); } while (nbytes > 0); close(src_fd); close(dest_fd); #endif } /* * linkFile() * * Hard-links a relation file from src to dst. * schemaName/relName are relation's SQL name (used for error messages only). */ void linkFile(const char *src, const char *dst, const char *schemaName, const char *relName) { if (link(src, dst) < 0) pg_fatal("error while creating link for relation \"%s.%s\" (\"%s\" to \"%s\"): %m", schemaName, relName, src, dst); } void check_file_clone(void) { char existing_file[MAXPGPATH]; char new_link_file[MAXPGPATH]; snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata); snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.clonetest", new_cluster.pgdata); unlink(new_link_file); /* might fail */ #if defined(HAVE_COPYFILE) && defined(COPYFILE_CLONE_FORCE) if (copyfile(existing_file, new_link_file, NULL, COPYFILE_CLONE_FORCE) < 0) pg_fatal("could not clone file between old and new data directories: %m"); #elif defined(__linux__) && defined(FICLONE) { int src_fd; int dest_fd; if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", existing_file); if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, pg_file_create_mode)) < 0) pg_fatal("could not create file \"%s\": %m", new_link_file); if (ioctl(dest_fd, FICLONE, src_fd) < 0) pg_fatal("could not clone file between old and new data directories: %m"); close(src_fd); close(dest_fd); } #else pg_fatal("file cloning not supported on this platform"); #endif unlink(new_link_file); } void check_copy_file_range(void) { char existing_file[MAXPGPATH]; char new_link_file[MAXPGPATH]; snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata); snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.copy_file_range_test", new_cluster.pgdata); unlink(new_link_file); /* might fail */ #if defined(HAVE_COPY_FILE_RANGE) { int src_fd; int dest_fd; if ((src_fd = open(existing_file, O_RDONLY | PG_BINARY, 0)) < 0) pg_fatal("could not open file \"%s\": %m", existing_file); if ((dest_fd = open(new_link_file, O_RDWR | O_CREAT | O_EXCL | PG_BINARY, pg_file_create_mode)) < 0) pg_fatal("could not create file \"%s\": %m", new_link_file); if (copy_file_range(src_fd, NULL, dest_fd, NULL, SSIZE_MAX, 0) < 0) pg_fatal("could not copy file range between old and new data directories: %m"); close(src_fd); close(dest_fd); } #else pg_fatal("copy_file_range not supported on this platform"); #endif unlink(new_link_file); } void check_hard_link(transferMode transfer_mode) { char existing_file[MAXPGPATH]; char new_link_file[MAXPGPATH]; snprintf(existing_file, sizeof(existing_file), "%s/PG_VERSION", old_cluster.pgdata); snprintf(new_link_file, sizeof(new_link_file), "%s/PG_VERSION.linktest", new_cluster.pgdata); unlink(new_link_file); /* might fail */ if (link(existing_file, new_link_file) < 0) { if (transfer_mode == TRANSFER_MODE_LINK) pg_fatal("could not create hard link between old and new data directories: %m\n" "In link mode the old and new data directories must be on the same file system."); else if (transfer_mode == TRANSFER_MODE_SWAP) pg_fatal("could not create hard link between old and new data directories: %m\n" "In swap mode the old and new data directories must be on the same file system."); else pg_fatal("unrecognized transfer mode"); } unlink(new_link_file); }