aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSimon Riggs <simon@2ndQuadrant.com>2012-08-08 23:58:49 +0100
committerSimon Riggs <simon@2ndQuadrant.com>2012-08-08 23:58:49 +0100
commit6f4b8a4f4f7a2d683ff79ab59d3693714b965e3d (patch)
tree32f13502ec48c0fd6c07af0b182eb372b95ded7c /src
parent7c055d64a6c541f8480abd5833321e1661e10bce (diff)
downloadpostgresql-6f4b8a4f4f7a2d683ff79ab59d3693714b965e3d.tar.gz
postgresql-6f4b8a4f4f7a2d683ff79ab59d3693714b965e3d.zip
Force archive_status of .done for xlogs created by dearchival/replication.
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/transam/xlog.c59
-rw-r--r--src/backend/replication/walreceiver.c16
-rw-r--r--src/include/access/xlog_internal.h5
3 files changed, 78 insertions, 2 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 7b9b483ed97..b75dab5e10f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -1336,6 +1336,59 @@ XLogArchiveNotifySeg(uint32 log, uint32 seg)
}
/*
+ * 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
*
* This is called when we are ready to delete or recycle an old XLOG segment
@@ -2815,6 +2868,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.
*/
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index b4c7f0d22b6..c8b04d69691 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -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;
}
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 3328a50faba..973c84f4f3b 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -264,6 +264,11 @@ 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.
*/
extern Datum pg_start_backup(PG_FUNCTION_ARGS);