diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index 52922dae4ec34d8b4a112438084dce26fff164cb..0c178c55c87247f651373bdc80a0f739a6f3c128 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -473,6 +473,12 @@ KeepFileRestoredFromArchive(char *path, char *xlogfname) errmsg("could not rename file \"%s\" to \"%s\": %m", path, xlogfpath))); + /* + * Create .done file forcibly to prevent the restored segment from + * being archived again later. + */ + XLogArchiveForceDone(xlogfname); + /* * If the existing file was replaced, since walsenders might have it * open, request them to reload a currently-open segment. This is only @@ -544,6 +550,59 @@ XLogArchiveNotifySeg(XLogSegNo segno) 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 * diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 37d5e0821edaed476272d44fe96caf88bd613e33..911a66ba887973721e0cf98e92c42637c8baf16b 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -83,7 +83,7 @@ walrcv_disconnect_type walrcv_disconnect = NULL; /* * 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, used for error messages. + * corresponding the filename of recvFile. */ static int recvFile = -1; static TimeLineID recvFileTLI = 0; @@ -528,12 +528,21 @@ WalReceiverMain(void) */ if (recvFile >= 0) { + char xlogfname[MAXFNAMELEN]; + XLogWalRcvFlush(false); if (close(recvFile) != 0) ereport(PANIC, (errcode_for_file_access(), errmsg("could not close log segment %s: %m", XLogFileNameP(recvFileTLI, recvSegNo)))); + + /* + * Create .done file forcibly to prevent the streamed segment from + * being archived later. + */ + XLogFileName(xlogfname, recvFileTLI, recvSegNo); + XLogArchiveForceDone(xlogfname); } recvFile = -1; @@ -865,6 +874,8 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) */ if (recvFile >= 0) { + char xlogfname[MAXFNAMELEN]; + XLogWalRcvFlush(false); /* @@ -877,6 +888,13 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) (errcode_for_file_access(), errmsg("could not close log segment %s: %m", XLogFileNameP(recvFileTLI, recvSegNo)))); + + /* + * Create .done file forcibly to prevent the streamed segment from + * being archived later. + */ + XLogFileName(xlogfname, recvFileTLI, recvSegNo); + XLogArchiveForceDone(xlogfname); } recvFile = -1; diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 16b53e37260b8abe2ec0ef4266bd71150a253f7a..c996c3c3ad867b8678a6971d4bfbc0d00231764f 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -278,6 +278,7 @@ extern void ExecuteRecoveryCommand(char *command, char *commandName, extern void KeepFileRestoredFromArchive(char *path, char *xlogfname); extern void XLogArchiveNotify(const char *xlog); extern void XLogArchiveNotifySeg(XLogSegNo segno); +extern void XLogArchiveForceDone(const char *xlog); extern bool XLogArchiveCheckDone(const char *xlog); extern bool XLogArchiveIsBusy(const char *xlog); extern void XLogArchiveCleanup(const char *xlog);