diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index efd0347..393315f 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -605,7 +605,6 @@ typedef struct xl_restore_point } xl_restore_point; -static void XLogArchiveNotify(const char *xlog); static void XLogArchiveNotifySeg(XLogSegNo segno); static bool XLogArchiveCheckDone(const char *xlog); static bool XLogArchiveIsBusy(const char *xlog); @@ -1280,23 +1279,63 @@ XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites, } /* - * XLogArchiveNotify + * XLogSetArchiveStatus * - * Create an archive notification file + * Create an archive notification file with given archive status * * The name of the notification file is the message that will be picked up * by the archiver, e.g. we write 0000000100000001000000C6.ready * and the archiver then knows to archive XLOGDIR/0000000100000001000000C6, * then when complete, rename it to 0000000100000001000000C6.done */ -static void -XLogArchiveNotify(const char *xlog) +void +XLogSetArchiveStatus(const char *xlog, int archive_status) { char archiveStatusPath[MAXPGPATH]; + struct stat stat_buf; FILE *fd; - /* insert an otherwise empty file called .ready */ - StatusFilePath(archiveStatusPath, xlog, ".ready"); + switch (archive_status) + { + case XLOG_ARCHIVE_STATUS_READY: + + /* If already marked READY then quick exit */ + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY); + if (stat(archiveStatusPath, &stat_buf) == 0) + return; + + break; + + case XLOG_ARCHIVE_STATUS_DONE: + + /* If marked READY then rename to DONE */ + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY); + if (stat(archiveStatusPath, &stat_buf) == 0) + { + char archiveStatusDone[MAXPGPATH]; + + StatusFilePath(archiveStatusDone, xlog, XLOG_ARCHIVE_STATUS_DONE); + + if (rename(archiveStatusPath, archiveStatusDone) < 0) + ereport(WARNING, + (errcode_for_file_access(), + errmsg("could not rename file \"%s\" to \"%s\": %m", + archiveStatusPath, archiveStatusDone))); + return; + } + + /* If already marked DONE then exit */ + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE); + if (stat(archiveStatusPath, &stat_buf) == 0) + return; + + break; + + default: + elog(ERROR, "invalud archive status"); + } + + /* insert an otherwise empty file with prefix that indicates archive_status */ fd = AllocateFile(archiveStatusPath, "w"); if (fd == NULL) { @@ -1315,13 +1354,15 @@ XLogArchiveNotify(const char *xlog) return; } - /* Notify archiver that it's got something to do */ - if (IsUnderPostmaster) + /* Notify archiver that it's got something to do if .ready has been created */ + if (IsUnderPostmaster && archive_status == XLOG_ARCHIVE_STATUS_READY) SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER); } /* * Convenience routine to notify using segment number representation of filename + * + * This always creates XLOG_ARCHIVE_STATUS_READY */ static void XLogArchiveNotifySeg(XLogSegNo segno) @@ -1329,7 +1370,7 @@ XLogArchiveNotifySeg(XLogSegNo segno) char xlog[MAXFNAMELEN]; XLogFileName(xlog, ThisTimeLineID, segno); - XLogArchiveNotify(xlog); + XLogSetArchiveStatus(xlog, XLOG_ARCHIVE_STATUS_READY); } /* @@ -1357,22 +1398,22 @@ XLogArchiveCheckDone(const char *xlog) return true; /* First check for .done --- this means archiver is done with it */ - StatusFilePath(archiveStatusPath, xlog, ".done"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE); if (stat(archiveStatusPath, &stat_buf) == 0) return true; /* check for .ready --- this means archiver is still busy with it */ - StatusFilePath(archiveStatusPath, xlog, ".ready"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY); if (stat(archiveStatusPath, &stat_buf) == 0) return false; /* Race condition --- maybe archiver just finished, so recheck */ - StatusFilePath(archiveStatusPath, xlog, ".done"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE); if (stat(archiveStatusPath, &stat_buf) == 0) return true; /* Retry creation of the .ready file */ - XLogArchiveNotify(xlog); + XLogSetArchiveStatus(xlog, XLOG_ARCHIVE_STATUS_READY); return false; } @@ -1393,17 +1434,17 @@ XLogArchiveIsBusy(const char *xlog) struct stat stat_buf; /* First check for .done --- this means archiver is done with it */ - StatusFilePath(archiveStatusPath, xlog, ".done"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE); if (stat(archiveStatusPath, &stat_buf) == 0) return false; /* check for .ready --- this means archiver is still busy with it */ - StatusFilePath(archiveStatusPath, xlog, ".ready"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY); if (stat(archiveStatusPath, &stat_buf) == 0) return true; /* Race condition --- maybe archiver just finished, so recheck */ - StatusFilePath(archiveStatusPath, xlog, ".done"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE); if (stat(archiveStatusPath, &stat_buf) == 0) return false; @@ -1431,12 +1472,12 @@ XLogArchiveCleanup(const char *xlog) char archiveStatusPath[MAXPGPATH]; /* Remove the .done file */ - StatusFilePath(archiveStatusPath, xlog, ".done"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_DONE); unlink(archiveStatusPath); /* should we complain about failure? */ /* Remove the .ready file if present --- normally it shouldn't be */ - StatusFilePath(archiveStatusPath, xlog, ".ready"); + StatusFilePath(archiveStatusPath, xlog, XLOG_ARCHIVE_STATUS_READY); unlink(archiveStatusPath); /* should we complain about failure? */ } @@ -2806,6 +2847,12 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, path, xlogfpath))); /* + * Create .done file forcibly to prevent the restored segment from + * being archived again later. + */ + XLogSetArchiveStatus(xlogfname, XLOG_ARCHIVE_STATUS_DONE); + + /* * If the existing segment was replaced, since walsenders might have * it open, request them to reload a currently-open segment. */ @@ -3573,7 +3620,7 @@ ValidateXLOGDirectoryStructure(void) /* * Remove previous backup history files. This also retries creation of - * .ready files for any backup history files for which XLogArchiveNotify + * .ready files for any backup history files for which XLogSetArchiveStatus * failed earlier. */ static void @@ -4669,7 +4716,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, /* The history file can be archived immediately. */ TLHistoryFileName(histfname, newTLI); - XLogArchiveNotify(histfname); + XLogSetArchiveStatus(histfname, XLOG_ARCHIVE_STATUS_READY); } /* @@ -5611,7 +5658,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo) if (XLogArchivingActive()) { XLogFileName(xlogpath, endTLI, endLogSegNo); - XLogArchiveNotify(xlogpath); + XLogSetArchiveStatus(xlogpath, XLOG_ARCHIVE_STATUS_READY); } } diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c index d5d8be0..1a51e17 100644 --- a/src/backend/postmaster/pgarch.c +++ b/src/backend/postmaster/pgarch.c @@ -111,7 +111,6 @@ static void pgarch_MainLoop(void); static void pgarch_ArchiverCopyLoop(void); static bool pgarch_archiveXlog(char *xlog); static bool pgarch_readyXlog(char *xlog); -static void pgarch_archiveDone(char *xlog); /* ------------------------------------------------------------ @@ -492,7 +491,7 @@ pgarch_ArchiverCopyLoop(void) if (pgarch_archiveXlog(xlog)) { /* successful */ - pgarch_archiveDone(xlog); + XLogSetArchiveStatus(xlog, XLOG_ARCHIVE_STATUS_DONE); break; /* out of inner retry loop */ } else @@ -730,26 +729,3 @@ pgarch_readyXlog(char *xlog) } return found; } - -/* - * pgarch_archiveDone - * - * Emit notification that an xlog file has been successfully archived. - * We do this by renaming the status file from NNN.ready to NNN.done. - * Eventually, a checkpoint process will notice this and delete both the - * NNN.done file and the xlog file itself. - */ -static void -pgarch_archiveDone(char *xlog) -{ - char rlogready[MAXPGPATH]; - char rlogdone[MAXPGPATH]; - - StatusFilePath(rlogready, xlog, ".ready"); - StatusFilePath(rlogdone, xlog, ".done"); - if (rename(rlogready, rlogdone) < 0) - ereport(WARNING, - (errcode_for_file_access(), - errmsg("could not rename file \"%s\" to \"%s\": %m", - rlogready, rlogdone))); -} diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index b0a8b19..9d689c2 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -505,6 +505,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 restored segment from + * being archived again later. + */ + XLogSetArchiveStatus(XLogFileNameP(recvFileTLI, recvSegNo), + XLOG_ARCHIVE_STATUS_DONE); } recvFile = -1; diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index b5bfb7b..78849ce 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -192,8 +192,14 @@ typedef XLogLongPageHeaderData *XLogLongPageHeader; #define TLHistoryFilePath(path, tli) \ snprintf(path, MAXPGPATH, XLOGDIR "/%08X.history", tli) -#define StatusFilePath(path, xlog, suffix) \ - snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, suffix) +#define XLOG_ARCHIVE_STATUS_INVALID 0 +#define XLOG_ARCHIVE_STATUS_READY 1 +#define XLOG_ARCHIVE_STATUS_DONE 2 + +#define StatusFilePath(path, xlog, archive_status) \ + snprintf(path, MAXPGPATH, XLOGDIR "/archive_status/%s%s", xlog, \ + (archive_status == XLOG_ARCHIVE_STATUS_READY ? ".ready" : ".done")) + #define BackupHistoryFileName(fname, tli, logSegNo, offset) \ snprintf(fname, MAXFNAMELEN, "%08X%08X%08X.%08X.backup", tli, \ @@ -230,6 +236,11 @@ extern pg_time_t GetLastSegSwitchTime(void); extern XLogRecPtr RequestXLogSwitch(void); /* + * Exported to support xlog archive status setting from WALReceiver/Archiver + */ +extern void XLogSetArchiveStatus(const char *xlog, int archive_status); + +/* * These aren't in xlog.h because I'd rather not include fmgr.h there. */ extern Datum pg_start_backup(PG_FUNCTION_ARGS);