Skip to content

Commit 55b5686

Browse files
committed
Revert recent changes with durable_rename_excl()
This reverts commits 2c902bb and ccfbd92. Per buildfarm members kestrel, rorqual and calliphoridae, the assertions checking that a TLI history file should not exist when created by a WAL receiver have been failing, and switching to durable_rename() over durable_rename_excl() would cause the newest TLI history file to overwrite the existing one. We need to think harder about such cases, so revert the new logic for now. Note that all the failures have been reported in the test 025_stuck_on_old_timeline. Discussion: https://postgr.es/m/511362.1651116498@sss.pgh.pa.us
1 parent e84f82a commit 55b5686

File tree

6 files changed

+91
-13
lines changed

6 files changed

+91
-13
lines changed

contrib/basic_archive/basic_archive.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -281,10 +281,9 @@ basic_archive_file_internal(const char *file, const char *path)
281281

282282
/*
283283
* Sync the temporary file to disk and move it to its final destination.
284-
* Note that this will overwrite any existing file, but this is only
285-
* possible if someone else created the file since the stat() above.
284+
* This will fail if destination already exists.
286285
*/
287-
(void) durable_rename(temp, destination, ERROR);
286+
(void) durable_rename_excl(temp, destination, ERROR);
288287

289288
ereport(DEBUG1,
290289
(errmsg("archived \"%s\" via basic_archive", file)));

src/backend/access/transam/timeline.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -439,11 +439,14 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
439439

440440
/*
441441
* Now move the completed history file into place with its final name.
442-
* The target file should not exist.
443442
*/
444443
TLHistoryFilePath(path, newTLI);
445-
Assert(access(path, F_OK) != 0 && errno == ENOENT);
446-
durable_rename(tmppath, path, ERROR);
444+
445+
/*
446+
* Perform the rename using link if available, paranoidly trying to avoid
447+
* overwriting an existing file (there shouldn't be one).
448+
*/
449+
durable_rename_excl(tmppath, path, ERROR);
447450

448451
/* The history file can be archived immediately. */
449452
if (XLogArchivingActive())
@@ -514,11 +517,14 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
514517

515518
/*
516519
* Now move the completed history file into place with its final name.
517-
* The target file should not exist.
518520
*/
519521
TLHistoryFilePath(path, tli);
520-
Assert(access(path, F_OK) != 0 && errno == ENOENT);
521-
durable_rename(tmppath, path, ERROR);
522+
523+
/*
524+
* Perform the rename using link if available, paranoidly trying to avoid
525+
* overwriting an existing file (there shouldn't be one).
526+
*/
527+
durable_rename_excl(tmppath, path, ERROR);
522528
}
523529

524530
/*

src/backend/access/transam/xlog.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3323,12 +3323,14 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
33233323
}
33243324
}
33253325

3326-
/* The target file should not exist */
3327-
Assert(access(path, F_OK) != 0 && errno == ENOENT);
3328-
if (durable_rename(tmppath, path, LOG) != 0)
3326+
/*
3327+
* Perform the rename using link if available, paranoidly trying to avoid
3328+
* overwriting an existing file (there shouldn't be one).
3329+
*/
3330+
if (durable_rename_excl(tmppath, path, LOG) != 0)
33293331
{
33303332
LWLockRelease(ControlFileLock);
3331-
/* durable_rename already emitted log message */
3333+
/* durable_rename_excl already emitted log message */
33323334
return false;
33333335
}
33343336

src/backend/storage/file/fd.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,69 @@ durable_unlink(const char *fname, int elevel)
807807
return 0;
808808
}
809809

810+
/*
811+
* durable_rename_excl -- rename a file in a durable manner.
812+
*
813+
* Similar to durable_rename(), except that this routine tries (but does not
814+
* guarantee) not to overwrite the target file.
815+
*
816+
* Note that a crash in an unfortunate moment can leave you with two links to
817+
* the target file.
818+
*
819+
* Log errors with the caller specified severity.
820+
*
821+
* On Windows, using a hard link followed by unlink() causes concurrency
822+
* issues, while a simple rename() does not cause that, so be careful when
823+
* changing the logic of this routine.
824+
*
825+
* Returns 0 if the operation succeeded, -1 otherwise. Note that errno is not
826+
* valid upon return.
827+
*/
828+
int
829+
durable_rename_excl(const char *oldfile, const char *newfile, int elevel)
830+
{
831+
/*
832+
* Ensure that, if we crash directly after the rename/link, a file with
833+
* valid contents is moved into place.
834+
*/
835+
if (fsync_fname_ext(oldfile, false, false, elevel) != 0)
836+
return -1;
837+
838+
#ifdef HAVE_WORKING_LINK
839+
if (link(oldfile, newfile) < 0)
840+
{
841+
ereport(elevel,
842+
(errcode_for_file_access(),
843+
errmsg("could not link file \"%s\" to \"%s\": %m",
844+
oldfile, newfile)));
845+
return -1;
846+
}
847+
unlink(oldfile);
848+
#else
849+
if (rename(oldfile, newfile) < 0)
850+
{
851+
ereport(elevel,
852+
(errcode_for_file_access(),
853+
errmsg("could not rename file \"%s\" to \"%s\": %m",
854+
oldfile, newfile)));
855+
return -1;
856+
}
857+
#endif
858+
859+
/*
860+
* Make change persistent in case of an OS crash, both the new entry and
861+
* its parent directory need to be flushed.
862+
*/
863+
if (fsync_fname_ext(newfile, false, false, elevel) != 0)
864+
return -1;
865+
866+
/* Same for parent directory */
867+
if (fsync_parent_path(newfile, elevel) != 0)
868+
return -1;
869+
870+
return 0;
871+
}
872+
810873
/*
811874
* InitFileAccess --- initialize this module during backend startup
812875
*

src/include/pg_config_manual.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,13 @@
163163
#define USE_BARRIER_SMGRRELEASE
164164
#endif
165165

166+
/*
167+
* Define this if your operating system supports link()
168+
*/
169+
#if !defined(WIN32) && !defined(__CYGWIN__)
170+
#define HAVE_WORKING_LINK 1
171+
#endif
172+
166173
/*
167174
* USE_POSIX_FADVISE controls whether Postgres will attempt to use the
168175
* posix_fadvise() kernel call. Usually the automatic configure tests are

src/include/storage/fd.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ extern void fsync_fname(const char *fname, bool isdir);
187187
extern int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel);
188188
extern int durable_rename(const char *oldfile, const char *newfile, int loglevel);
189189
extern int durable_unlink(const char *fname, int loglevel);
190+
extern int durable_rename_excl(const char *oldfile, const char *newfile, int loglevel);
190191
extern void SyncDataDirectory(void);
191192
extern int data_sync_elevel(int elevel);
192193

0 commit comments

Comments
 (0)