diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 7b9b483ed9..b75dab5e10 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -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 .done regardless of whether .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 .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. diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index b4c7f0d22b..c8b04d6969 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 3328a50fab..973c84f4f3 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -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. */