Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Fix WAL file replacement during cascading replication on Windows.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 6 Sep 2012 01:10:15 +0000 (18:10 -0700)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Thu, 6 Sep 2012 01:52:12 +0000 (18:52 -0700)
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

index 787eda2a61ec793b947469b1303d476c27d30430..ff56c26ab4c0edd26bf0a494715efabfa86976b2 100644 (file)
@@ -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",