*** a/doc/src/sgml/backup.sgml --- b/doc/src/sgml/backup.sgml *************** *** 1071,1079 **** restore_command = 'cp /mnt/server/archivedir/%f %p' WAL segments that cannot be found in the archive will be sought in pg_xlog/; this allows use of recent un-archived segments. However, segments that are available from the archive will be used in ! preference to files in pg_xlog/. The system will not ! overwrite the existing contents of pg_xlog/ when retrieving ! archived files. --- 1071,1077 ---- WAL segments that cannot be found in the archive will be sought in pg_xlog/; this allows use of recent un-archived segments. However, segments that are available from the archive will be used in ! preference to files in pg_xlog/. *** a/src/backend/access/transam/xlog.c --- b/src/backend/access/transam/xlog.c *************** *** 610,617 **** typedef struct xl_restore_point } xl_restore_point; ! static void XLogArchiveNotify(const char *xlog); static void XLogArchiveNotifySeg(uint32 log, uint32 seg); static bool XLogArchiveCheckDone(const char *xlog); static bool XLogArchiveIsBusy(const char *xlog); static void XLogArchiveCleanup(const char *xlog); --- 610,618 ---- } xl_restore_point; ! static void XLogArchiveNotify(const char *xlog, bool done); static void XLogArchiveNotifySeg(uint32 log, uint32 seg); + static void XLogArchiveForceDone(const char *xlog); static bool XLogArchiveCheckDone(const char *xlog); static bool XLogArchiveIsBusy(const char *xlog); static void XLogArchiveCleanup(const char *xlog); *************** *** 1291,1305 **** XLogCheckBuffer(XLogRecData *rdata, bool doPageWrites, * 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) { char archiveStatusPath[MAXPGPATH]; FILE *fd; ! /* insert an otherwise empty file called .ready */ ! StatusFilePath(archiveStatusPath, xlog, ".ready"); fd = AllocateFile(archiveStatusPath, "w"); if (fd == NULL) { --- 1292,1308 ---- * 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 + * + * If done is true, create .done file. Otherwise, .ready. */ static void ! XLogArchiveNotify(const char *xlog, bool done) { char archiveStatusPath[MAXPGPATH]; FILE *fd; ! /* insert an otherwise empty file called .ready or .done */ ! StatusFilePath(archiveStatusPath, xlog, done ? ".done" : ".ready"); fd = AllocateFile(archiveStatusPath, "w"); if (fd == NULL) { *************** *** 1318,1330 **** XLogArchiveNotify(const char *xlog) return; } ! /* Notify archiver that it's got something to do */ ! if (IsUnderPostmaster) SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER); } /* * Convenience routine to notify using log/seg representation of filename */ static void XLogArchiveNotifySeg(uint32 log, uint32 seg) --- 1321,1335 ---- return; } ! /* Notify archiver that it's got something to do if .ready has been created */ ! if (IsUnderPostmaster && !done) SendPostmasterSignal(PMSIGNAL_WAKEN_ARCHIVER); } /* * Convenience routine to notify using log/seg representation of filename + * + * This always creates .ready. */ static void XLogArchiveNotifySeg(uint32 log, uint32 seg) *************** *** 1332,1338 **** XLogArchiveNotifySeg(uint32 log, uint32 seg) char xlog[MAXFNAMELEN]; XLogFileName(xlog, ThisTimeLineID, log, seg); ! XLogArchiveNotify(xlog); } /* --- 1337,1379 ---- char xlog[MAXFNAMELEN]; XLogFileName(xlog, ThisTimeLineID, log, seg); ! XLogArchiveNotify(xlog, false); ! } ! ! /* ! * XLogArchiveForceDone ! * ! * Emit notification forcibly that an XLOG segment file has been successfully ! * archived, by creating .done regardless of whether .ready ! * exists or not. ! */ ! static void ! XLogArchiveForceDone(const char *xlog) ! { ! char archiveReady[MAXPGPATH]; ! char archiveDone[MAXPGPATH]; ! struct stat stat_buf; ! ! /* 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; ! } ! ! /* Create .done if neither .ready nor .done exists */ ! XLogArchiveNotify(xlog, true); } /* *************** *** 1375,1381 **** XLogArchiveCheckDone(const char *xlog) return true; /* Retry creation of the .ready file */ ! XLogArchiveNotify(xlog); return false; } --- 1416,1422 ---- return true; /* Retry creation of the .ready file */ ! XLogArchiveNotify(xlog, false); return false; } *************** *** 2810,2815 **** XLogFileRead(uint32 log, uint32 seg, int emode, TimeLineID tli, --- 2851,2862 ---- path, xlogfpath))); /* + * 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. */ *************** *** 4649,4655 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, /* The history file can be archived immediately. */ TLHistoryFileName(histfname, newTLI); ! XLogArchiveNotify(histfname); } /* --- 4696,4702 ---- /* The history file can be archived immediately. */ TLHistoryFileName(histfname, newTLI); ! XLogArchiveNotify(histfname, false); } /* *************** *** 5596,5602 **** exitArchiveRecovery(TimeLineID endTLI, uint32 endLogId, uint32 endLogSeg) if (XLogArchivingActive()) { XLogFileName(xlogpath, endTLI, endLogId, endLogSeg); ! XLogArchiveNotify(xlogpath); } } --- 5643,5649 ---- if (XLogArchivingActive()) { XLogFileName(xlogpath, endTLI, endLogId, endLogSeg); ! XLogArchiveNotify(xlogpath, false); } }