]> granicus.if.org Git - postgresql/commitdiff
Force archive_status of .done for xlogs created by dearchival/replication.
authorSimon Riggs <simon@2ndQuadrant.com>
Wed, 8 Aug 2012 22:58:49 +0000 (23:58 +0100)
committerSimon Riggs <simon@2ndQuadrant.com>
Wed, 8 Aug 2012 22:58:49 +0000 (23:58 +0100)
This prevents spurious attempts to archive xlog files after promotion of
standby, a bug introduced by cascading replication patch in 9.2.

Fujii Masao, simplified and extended to cover streaming by Simon Riggs

src/backend/access/transam/xlog.c
src/backend/replication/walreceiver.c
src/include/access/xlog_internal.h

index 7b9b483ed9700d24794610611181400ed681208f..b75dab5e10fe5694ae90051f5426acddae900605 100644 (file)
@@ -1335,6 +1335,59 @@ XLogArchiveNotifySeg(uint32 log, uint32 seg)
        XLogArchiveNotify(xlog);
 }
 
+/*
+ * XLogArchiveForceDone
+ *
+ * Emit notification forcibly that an XLOG segment file has been successfully
+ * archived, by creating <XLOG>.done regardless of whether <XLOG>.ready
+ * exists or not.
+ */
+void
+XLogArchiveForceDone(const char *xlog)
+{
+       char            archiveReady[MAXPGPATH];
+       char            archiveDone[MAXPGPATH];
+       struct stat stat_buf;
+       FILE       *fd;
+
+       /* Exit if already known done */
+       StatusFilePath(archiveDone, xlog, ".done");
+       if (stat(archiveDone, &stat_buf) == 0)
+               return;
+
+       /* If .ready exists, rename it to .done */
+       StatusFilePath(archiveReady, xlog, ".ready");
+       if (stat(archiveReady, &stat_buf) == 0)
+       {
+               if (rename(archiveReady, archiveDone) < 0)
+                       ereport(WARNING,
+                                       (errcode_for_file_access(),
+                                        errmsg("could not rename file \"%s\" to \"%s\": %m",
+                                                       archiveReady, archiveDone)));
+
+               return;
+       }
+
+       /* insert an otherwise empty file called <XLOG>.done */
+       fd = AllocateFile(archiveDone, "w");
+       if (fd == NULL)
+       {
+               ereport(LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not create archive status file \"%s\": %m",
+                                               archiveDone)));
+               return;
+       }
+       if (FreeFile(fd))
+       {
+               ereport(LOG,
+                               (errcode_for_file_access(),
+                                errmsg("could not write archive status file \"%s\": %m",
+                                               archiveDone)));
+               return;
+       }
+}
+
 /*
  * XLogArchiveCheckDone
  *
@@ -2814,6 +2867,12 @@ XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli,
                 */
                strncpy(path, xlogfpath, MAXPGPATH);
 
+               /*
+                * Create .done file forcibly to prevent the restored segment from
+                * being archived again later.
+                */
+               XLogArchiveForceDone(xlogfname);
+
                /*
                 * If the existing segment was replaced, since walsenders might have
                 * it open, request them to reload a currently-open segment.
index b4c7f0d22b632e76342edfa1aa0cb2543d06003d..c8b04d69691792277571cca493da7f7a0614bfaa 100644 (file)
@@ -66,10 +66,12 @@ walrcv_disconnect_type walrcv_disconnect = NULL;
 #define NAPTIME_PER_CYCLE 100  /* max sleep time between cycles (100ms) */
 
 /*
- * These variables are used similarly to openLogFile/Id/Seg/Off,
- * but for walreceiver to write the XLOG.
+ * These variables are used similarly to openLogFile/SegNo/Off,
+ * but for walreceiver to write the XLOG. recvFileTLI is the TimeLineID
+ * corresponding the filename of recvFile.
  */
 static int     recvFile = -1;
+static TimeLineID      recvFileTLI = 0;
 static uint32 recvId = 0;
 static uint32 recvSeg = 0;
 static uint32 recvOff = 0;
@@ -492,6 +494,8 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                         */
                        if (recvFile >= 0)
                        {
+                               char            xlogfname[MAXFNAMELEN];
+
                                XLogWalRcvFlush(false);
 
                                /*
@@ -504,6 +508,13 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                                                        (errcode_for_file_access(),
                                                errmsg("could not close log file %u, segment %u: %m",
                                                           recvId, recvSeg)));
+
+                               /*
+                                * Create .done file forcibly to prevent the restored segment from
+                                * being archived again later.
+                                */
+                               XLogFileName(xlogfname, recvFileTLI, recvId, recvSeg);
+                               XLogArchiveForceDone(xlogfname);
                        }
                        recvFile = -1;
 
@@ -511,6 +522,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr)
                        XLByteToSeg(recptr, recvId, recvSeg);
                        use_existent = true;
                        recvFile = XLogFileInit(recvId, recvSeg, &use_existent, true);
+                       recvFileTLI = ThisTimeLineID;
                        recvOff = 0;
                }
 
index 3328a50faba0064a58a58ad8ff9dfd445f13e5fb..973c84f4f3b5f2c5ea75cc4e15d44dd73d05155f 100644 (file)
@@ -263,6 +263,11 @@ extern const RmgrData RmgrTable[];
 extern pg_time_t GetLastSegSwitchTime(void);
 extern XLogRecPtr RequestXLogSwitch(void);
 
+/*
+ * Exported to support xlog archive status setting from WALReceiver
+ */
+extern void XLogArchiveForceDone(const char *xlog);
+
 /*
  * These aren't in xlog.h because I'd rather not include fmgr.h there.
  */