Skip to content

Commit 4b8dacf

Browse files
committed
Fix WAL file replacement during cascading replication on Windows.
When the startup process restores a WAL file from the archive, it deletes any old file with the same name and renames the new file in its place. On Windows, however, when a file is deleted, it still lingers as long as a process holds a file handle open on it. With cascading replication, a walsender process can hold the old file open, so the rename() in the startup process would fail. To fix that, rename the old file to a temporary name, to make the original file name available for reuse, before deleting the old file.
1 parent 308d4ec commit 4b8dacf

File tree

1 file changed

+27
-1
lines changed
  • src/backend/access/transam

1 file changed

+27
-1
lines changed

src/backend/access/transam/xlog.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2844,7 +2844,33 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
28442844
XLogFilePath(xlogfpath, tli, log, seg);
28452845
if (stat(xlogfpath, &statbuf) == 0)
28462846
{
2847-
if (unlink(xlogfpath) != 0)
2847+
char oldpath[MAXPGPATH];
2848+
#ifdef WIN32
2849+
static unsigned int deletedcounter = 1;
2850+
/*
2851+
* On Windows, if another process (e.g a walsender process) holds
2852+
* the file open in FILE_SHARE_DELETE mode, unlink will succeed,
2853+
* but the file will still show up in directory listing until the
2854+
* last handle is closed, and we cannot rename the new file in its
2855+
* place until that. To avoid that problem, rename the old file to
2856+
* a temporary name first. Use a counter to create a unique
2857+
* filename, because the same file might be restored from the
2858+
* archive multiple times, and a walsender could still be holding
2859+
* onto an old deleted version of it.
2860+
*/
2861+
snprintf(oldpath, MAXPGPATH, "%s.deleted%u",
2862+
xlogfpath, deletedcounter++);
2863+
if (rename(xlogfpath, oldpath) != 0)
2864+
{
2865+
ereport(ERROR,
2866+
(errcode_for_file_access(),
2867+
errmsg("could not rename file \"%s\" to \"%s\": %m",
2868+
xlogfpath, oldpath)));
2869+
}
2870+
#else
2871+
strncpy(oldpath, xlogfpath, MAXPGPATH);
2872+
#endif
2873+
if (unlink(oldpath) != 0)
28482874
ereport(FATAL,
28492875
(errcode_for_file_access(),
28502876
errmsg("could not remove file \"%s\": %m",

0 commit comments

Comments
 (0)