413
416
* indicate the OS just doesn't allow/require fsyncing directories.
416
fsync_fname(char *fname, bool isdir)
419
fsync_fname(const char *fname, bool isdir)
421
fsync_fname_ext(fname, isdir, false, ERROR);
425
* durable_rename -- rename(2) wrapper, issuing fsyncs required for durability
427
* This routine ensures that, after returning, the effect of renaming file
428
* persists in case of a crash. A crash while this routine is running will
429
* leave you with either the pre-existing or the moved file in place of the
430
* new file; no mixed state or truncated files are possible.
432
* It does so by using fsync on the old filename and the possibly existing
433
* target filename before the rename, and the target file and directory after.
435
* Note that rename() cannot be used across arbitrary directories, as they
436
* might not be on the same filesystem. Therefore this routine does not
437
* support renaming across directories.
439
* Log errors with the caller specified severity.
441
* Returns 0 if the operation succeeded, -1 otherwise. Note that errno is not
445
durable_rename(const char *oldfile, const char *newfile, int elevel)
422
* Some OSs require directories to be opened read-only whereas other
423
* systems don't allow us to fsync files opened read-only; so we need both
450
* First fsync the old and target path (if it exists), to ensure that they
451
* are properly persistent on disk. Syncing the target file is not
452
* strictly necessary, but it makes it easier to reason about crashes;
453
* because it's then guaranteed that either source or target file exists
427
fd = OpenTransientFile(fname,
456
if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
459
fd = OpenTransientFile((char *) newfile, PG_BINARY | O_RDWR, 0);
465
(errcode_for_file_access(),
466
errmsg("could not open file \"%s\": %m", newfile)));
431
fd = OpenTransientFile(fname,
432
O_RDONLY | PG_BINARY,
436
* Some OSs don't allow us to open directories at all (Windows returns
439
if (fd < 0 && isdir && (errno == EISDIR || errno == EACCES))
444
(errcode_for_file_access(),
445
errmsg("could not open file \"%s\": %m", fname)));
447
returncode = pg_fsync(fd);
449
/* Some OSs don't allow us to fsync directories at all */
450
if (returncode != 0 && isdir && errno == EBADF)
472
if (pg_fsync(fd) != 0)
476
/* close file upon error, might not be in transaction context */
478
CloseTransientFile(fd);
482
(errcode_for_file_access(),
483
errmsg("could not fsync file \"%s\": %m", newfile)));
452
486
CloseTransientFile(fd);
458
(errcode_for_file_access(),
459
errmsg("could not fsync file \"%s\": %m", fname)));
461
CloseTransientFile(fd);
489
/* Time to do the real deal... */
490
if (rename(oldfile, newfile) < 0)
493
(errcode_for_file_access(),
494
errmsg("could not rename file \"%s\" to \"%s\": %m",
500
* To guarantee renaming the file is persistent, fsync the file with its
501
* new name, and its containing directory.
503
if (fsync_fname_ext(newfile, false, false, elevel) != 0)
506
if (fsync_parent_path(newfile, elevel) != 0)
513
* durable_link_or_rename -- rename a file in a durable manner.
515
* Similar to durable_rename(), except that this routine tries (but does not
516
* guarantee) not to overwrite the target file.
518
* Note that a crash in an unfortunate moment can leave you with two links to
521
* Log errors with the caller specified severity.
523
* Returns 0 if the operation succeeded, -1 otherwise. Note that errno is not
527
durable_link_or_rename(const char *oldfile, const char *newfile, int elevel)
530
* Ensure that, if we crash directly after the rename/link, a file with
531
* valid contents is moved into place.
533
if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
536
#if HAVE_WORKING_LINK
537
if (link(oldfile, newfile) < 0)
540
(errcode_for_file_access(),
541
errmsg("could not link file \"%s\" to \"%s\": %m",
547
/* XXX: Add racy file existence check? */
548
if (rename(oldfile, newfile) < 0)
551
(errcode_for_file_access(),
552
errmsg("could not rename file \"%s\" to \"%s\": %m",
559
* Make change persistent in case of an OS crash, both the new entry and
560
* its parent directory need to be flushed.
562
if (fsync_fname_ext(newfile, false, false, elevel) != 0)
565
/* Same for parent directory */
566
if (fsync_parent_path(newfile, elevel) != 0)
466
573
* InitFileAccess --- initialize this module during backend startup
2671
2778
#endif /* PG_FLUSH_DATA_WORKS */
2781
datadir_fsync_fname(const char *fname, bool isdir, int elevel)
2784
* We want to silently ignoring errors about unreadable files. Pass that
2785
* desire on to fsync_fname_ext().
2787
fsync_fname_ext(fname, isdir, true, elevel);
2674
2791
* fsync_fname_ext -- Try to fsync a file or directory
2676
* Ignores errors trying to open unreadable files, or trying to fsync
2677
* directories on systems where that isn't allowed/required, and logs other
2678
* errors at a caller-specified level.
2793
* If ignore_perm is true, ignore errors upon trying to open unreadable
2794
* files. Logs other errors at a caller-specified level.
2796
* Returns 0 if the operation succeeded, -1 otherwise.
2681
fsync_fname_ext(const char *fname, bool isdir, int elevel)
2799
fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel)
2719
2840
* those errors. Anything else needs to be logged.
2721
2842
if (returncode != 0 && !(isdir && errno == EBADF))
2846
/* close file upon error, might not be in transaction context */
2848
(void) CloseTransientFile(fd);
2722
2851
ereport(elevel,
2723
2852
(errcode_for_file_access(),
2724
2853
errmsg("could not fsync file \"%s\": %m", fname)));
2726
2857
(void) CloseTransientFile(fd);
2863
* fsync_parent_path -- fsync the parent path of a file or directory
2865
* This is aimed at making file operations persistent on disk in case of
2866
* an OS crash or power failure.
2869
fsync_parent_path(const char *fname, int elevel)
2871
char parentpath[MAXPGPATH];
2873
strlcpy(parentpath, fname, MAXPGPATH);
2874
get_parent_directory(parentpath);
2877
* get_parent_directory() returns an empty string if the input argument is
2878
* just a file name (see comments in path.c), so handle that as being the
2879
* current directory.
2881
if (strlen(parentpath) == 0)
2882
strlcpy(parentpath, ".", MAXPGPATH);
2884
if (fsync_fname_ext(parentpath, true, false, elevel) != 0)