From ab9a14e903347929d248ac4dabe2614de482350b Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 5 Sep 2012 18:10:15 -0700 Subject: [PATCH] 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. --- src/backend/access/transam/xlog.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 787eda2a61..ff56c26ab4 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2787,7 +2787,33 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, XLogFilePath(xlogfpath, tli, segno); if (stat(xlogfpath, &statbuf) == 0) { - if (unlink(xlogfpath) != 0) + char oldpath[MAXPGPATH]; +#ifdef WIN32 + static unsigned int deletedcounter = 1; + /* + * On Windows, if another process (e.g a walsender process) holds + * the file open in FILE_SHARE_DELETE mode, unlink will succeed, + * but the file will still show up in directory listing until the + * last handle is closed, and we cannot rename the new file in its + * place until that. To avoid that problem, rename the old file to + * a temporary name first. Use a counter to create a unique + * filename, because the same file might be restored from the + * archive multiple times, and a walsender could still be holding + * onto an old deleted version of it. + */ + snprintf(oldpath, MAXPGPATH, "%s.deleted%u", + xlogfpath, deletedcounter++); + if (rename(xlogfpath, oldpath) != 0) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not rename file \"%s\" to \"%s\": %m", + xlogfpath, oldpath))); + } +#else + strncpy(oldpath, xlogfpath, MAXPGPATH); +#endif + if (unlink(oldpath) != 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not remove file \"%s\": %m",