From 04063a995759c9f32bd87b0155c68a2c5fb346ed Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Wed, 26 Feb 2025 11:44:36 -0600 Subject: [PATCH v3 3/4] Add new frontend functions for durable file operations. This commit exports the existing pre_sync_fname() function and adds durable_mkdir_p() and durable_rename_dir() for use in frontend programs. A follow-up commit will use this to help optimize pg_upgrade's file transfer step. Discussion: https://postgr.es/m/Zyvop-LxLXBLrZil%40nathan --- src/common/file_utils.c | 55 +++++++++++++++++++++++++++------ src/include/common/file_utils.h | 3 ++ 2 files changed, 49 insertions(+), 9 deletions(-) diff --git a/src/common/file_utils.c b/src/common/file_utils.c index 78e272916f5..a5a03abd7ca 100644 --- a/src/common/file_utils.c +++ b/src/common/file_utils.c @@ -26,6 +26,7 @@ #include "common/file_utils.h" #ifdef FRONTEND +#include "common/file_perm.h" #include "common/logging.h" #endif #include "common/relpath.h" @@ -45,9 +46,6 @@ */ #define MINIMUM_VERSION_FOR_PG_WAL 100000 -#ifdef PG_FLUSH_DATA_WORKS -static int pre_sync_fname(const char *fname, bool isdir); -#endif static void walkdir(const char *path, int (*action) (const char *fname, bool isdir), bool process_symlinks, @@ -352,16 +350,16 @@ walkdir(const char *path, } /* - * Hint to the OS that it should get ready to fsync() this file. + * Hint to the OS that it should get ready to fsync() this file, if supported + * by the platform. * * Ignores errors trying to open unreadable files, and reports other errors * non-fatally. */ -#ifdef PG_FLUSH_DATA_WORKS - -static int +int pre_sync_fname(const char *fname, bool isdir) { +#ifdef PG_FLUSH_DATA_WORKS int fd; fd = open(fname, O_RDONLY | PG_BINARY, 0); @@ -388,11 +386,10 @@ pre_sync_fname(const char *fname, bool isdir) #endif (void) close(fd); +#endif /* PG_FLUSH_DATA_WORKS */ return 0; } -#endif /* PG_FLUSH_DATA_WORKS */ - /* * fsync_fname -- Try to fsync a file or directory * @@ -539,6 +536,46 @@ durable_rename(const char *oldfile, const char *newfile) return 0; } +/* + * durable_rename_dir: rename(2) wrapper for directories, issuing fsyncs + * required for durability. + */ +int +durable_rename_dir(const char *olddir, const char *newdir) +{ + if (fsync_fname(olddir, true) != 0 || + fsync_parent_path(olddir) != 0 || + fsync_parent_path(newdir) != 0) + return -1; + + if (rename(olddir, newdir) != 0) + return -1; + + if (fsync_fname(newdir, true) != 0 || + fsync_parent_path(olddir) != 0 || + fsync_parent_path(newdir) != 0) + return -1; + + return 0; +} + +/* + * durable_mkdir_p: pg_mkdir_p() wrapper, issuing fsyncs required for + * durability. + */ +int +durable_mkdir_p(char *newdir) +{ + if (pg_mkdir_p(newdir, pg_dir_create_mode) && errno != EEXIST) + return -1; + + if (fsync_fname(newdir, true) != 0 || + fsync_parent_path(newdir) != 0) + return -1; + + return 0; +} + #endif /* FRONTEND */ /* diff --git a/src/include/common/file_utils.h b/src/include/common/file_utils.h index 8274bc877ab..7d253a4cb51 100644 --- a/src/include/common/file_utils.h +++ b/src/include/common/file_utils.h @@ -33,11 +33,14 @@ typedef enum DataDirSyncMethod struct iovec; /* avoid including port/pg_iovec.h here */ #ifdef FRONTEND +extern int pre_sync_fname(const char *fname, bool isdir); extern int fsync_fname(const char *fname, bool isdir); extern void sync_pgdata(const char *pg_data, int serverVersion, DataDirSyncMethod sync_method, bool sync_data_files); extern void sync_dir_recurse(const char *dir, DataDirSyncMethod sync_method); extern int durable_rename(const char *oldfile, const char *newfile); +extern int durable_rename_dir(const char *olddir, const char *newdir); +extern int durable_mkdir_p(char *newdir); extern int fsync_parent_path(const char *fname); #endif -- 2.39.5 (Apple Git-154)