*** 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 *************** *** 605,612 **** 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); static void XLogArchiveCleanup(const char *xlog); --- 605,613 ---- } xl_restore_point; ! static void XLogArchiveNotify(const char *xlog, bool done); static void XLogArchiveNotifySeg(XLogSegNo segno); + static void XLogArchiveForceDone(const char *xlog); static bool XLogArchiveCheckDone(const char *xlog); static bool XLogArchiveIsBusy(const char *xlog); static void XLogArchiveCleanup(const char *xlog); *************** *** 1288,1302 **** 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) { --- 1289,1305 ---- * 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) { *************** *** 1315,1327 **** 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 segment number representation of filename */ static void XLogArchiveNotifySeg(XLogSegNo segno) --- 1318,1332 ---- 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 segment number representation of filename + * + * This always creates .ready. */ static void XLogArchiveNotifySeg(XLogSegNo segno) *************** *** 1329,1335 **** XLogArchiveNotifySeg(XLogSegNo segno) char xlog[MAXFNAMELEN]; XLogFileName(xlog, ThisTimeLineID, segno); ! XLogArchiveNotify(xlog); } /* --- 1334,1376 ---- char xlog[MAXFNAMELEN]; XLogFileName(xlog, ThisTimeLineID, segno); ! 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); } /* *************** *** 1372,1378 **** XLogArchiveCheckDone(const char *xlog) return true; /* Retry creation of the .ready file */ ! XLogArchiveNotify(xlog); return false; } --- 1413,1419 ---- return true; /* Retry creation of the .ready file */ ! XLogArchiveNotify(xlog, false); return false; } *************** *** 2806,2811 **** XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, --- 2847,2858 ---- 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. */ *************** *** 4669,4675 **** writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, /* The history file can be archived immediately. */ TLHistoryFileName(histfname, newTLI); ! XLogArchiveNotify(histfname); } /* --- 4716,4722 ---- /* The history file can be archived immediately. */ TLHistoryFileName(histfname, newTLI); ! XLogArchiveNotify(histfname, false); } /* *************** *** 5611,5617 **** exitArchiveRecovery(TimeLineID endTLI, XLogSegNo endLogSegNo) if (XLogArchivingActive()) { XLogFileName(xlogpath, endTLI, endLogSegNo); ! XLogArchiveNotify(xlogpath); } } --- 5658,5664 ---- if (XLogArchivingActive()) { XLogFileName(xlogpath, endTLI, endLogSegNo); ! XLogArchiveNotify(xlogpath, false); } }