diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c index 432cc1463c352093a9d462fb7f934191a698ef59..d7b7b7721439dcf537e6964237bb21adc0ce9220 100644 --- a/src/backend/access/transam/timeline.c +++ b/src/backend/access/transam/timeline.c @@ -59,6 +59,7 @@ readTimeLineHistory(TimeLineID targetTLI) TimeLineHistoryEntry *entry; TimeLineID lasttli = 0; XLogRecPtr prevend; + bool fromArchive = false; /* Timeline 1 does not have a history file, so no need to check */ if (targetTLI == 1) @@ -72,7 +73,8 @@ readTimeLineHistory(TimeLineID targetTLI) if (InArchiveRecovery) { TLHistoryFileName(histfname, targetTLI); - RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false); + fromArchive = + RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false); } else TLHistoryFilePath(path, targetTLI); @@ -165,6 +167,13 @@ readTimeLineHistory(TimeLineID targetTLI) result = lcons(entry, result); + /* + * If the history file was fetched from archive, save it in pg_xlog for + * future reference. + */ + if (fromArchive) + KeepFileRestoredFromArchive(path, histfname); + return result; } diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 2998f60c5f91770fcc6b956579dac5d5f0acb413..aebdf0b85ab71dd2581e4513ab047b3d9a7d852f 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -2626,68 +2626,12 @@ XLogFileRead(XLogSegNo segno, int emode, TimeLineID tli, */ if (source == XLOG_FROM_ARCHIVE) { - char xlogfpath[MAXPGPATH]; - bool reload = false; - struct stat statbuf; - - XLogFilePath(xlogfpath, tli, segno); - if (stat(xlogfpath, &statbuf) == 0) - { - char oldpath[MAXPGPATH]; -#ifdef WIN32 - static unsigned int deletedcounter = 1; - /* - * On Windows, if another process (e.g a walsender process) holds - * the file open in FILE_SHARE_DELETE mode, unlink will succeed, - * but the file will still show up in directory listing until the - * last handle is closed, and we cannot rename the new file in its - * place until that. To avoid that problem, rename the old file to - * a temporary name first. Use a counter to create a unique - * filename, because the same file might be restored from the - * archive multiple times, and a walsender could still be holding - * onto an old deleted version of it. - */ - snprintf(oldpath, MAXPGPATH, "%s.deleted%u", - xlogfpath, deletedcounter++); - if (rename(xlogfpath, oldpath) != 0) - { - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not rename file \"%s\" to \"%s\": %m", - xlogfpath, oldpath))); - } -#else - strncpy(oldpath, xlogfpath, MAXPGPATH); -#endif - if (unlink(oldpath) != 0) - ereport(FATAL, - (errcode_for_file_access(), - errmsg("could not remove file \"%s\": %m", - xlogfpath))); - reload = true; - } - - if (rename(path, xlogfpath) < 0) - ereport(ERROR, - (errcode_for_file_access(), - errmsg("could not rename file \"%s\" to \"%s\": %m", - path, xlogfpath))); + KeepFileRestoredFromArchive(path, xlogfname); /* * Set path to point at the new file in pg_xlog. */ - strncpy(path, xlogfpath, MAXPGPATH); - - /* - * If the existing segment was replaced, since walsenders might have - * it open, request them to reload a currently-open segment. - */ - if (reload) - WalSndRqstFileReload(); - - /* Signal walsender that new WAL has arrived */ - if (AllowCascadeReplication()) - WalSndWakeup(); + snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname); } fd = BasicOpenFile(path, O_RDONLY | PG_BINARY, 0); diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index 0ef53e7cbf68f470fd6afdab5b757fca0f7a4fa7..95852a5c48f24a5ad02d9eaf8849a2c11de5c9ef 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -24,6 +24,7 @@ #include "access/xlog_internal.h" #include "miscadmin.h" #include "postmaster/startup.h" +#include "replication/walsender.h" #include "storage/fd.h" #include "storage/ipc.h" #include "storage/lwlock.h" @@ -416,6 +417,80 @@ ExecuteRecoveryCommand(char *command, char *commandName, bool failOnSignal) } +/* + * A file was restored from the archive under a temporary filename (path), + * and now we want to keep it. Rename it under the permanent filename in + * in pg_xlog (xlogfname), replacing any existing file with the same name. + */ +void +KeepFileRestoredFromArchive(char *path, char *xlogfname) +{ + char xlogfpath[MAXPGPATH]; + bool reload = false; + struct stat statbuf; + + snprintf(xlogfpath, MAXPGPATH, XLOGDIR "/%s", xlogfname); + + if (stat(xlogfpath, &statbuf) == 0) + { + char oldpath[MAXPGPATH]; +#ifdef WIN32 + static unsigned int deletedcounter = 1; + /* + * On Windows, if another process (e.g a walsender process) holds + * the file open in FILE_SHARE_DELETE mode, unlink will succeed, + * but the file will still show up in directory listing until the + * last handle is closed, and we cannot rename the new file in its + * place until that. To avoid that problem, rename the old file to + * a temporary name first. Use a counter to create a unique + * filename, because the same file might be restored from the + * archive multiple times, and a walsender could still be holding + * onto an old deleted version of it. + */ + snprintf(oldpath, MAXPGPATH, "%s.deleted%u", + xlogfpath, deletedcounter++); + if (rename(xlogfpath, oldpath) != 0) + { + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not rename file \"%s\" to \"%s\": %m", + xlogfpath, oldpath))); + } +#else + strncpy(oldpath, xlogfpath, MAXPGPATH); +#endif + if (unlink(oldpath) != 0) + ereport(FATAL, + (errcode_for_file_access(), + errmsg("could not remove file \"%s\": %m", + xlogfpath))); + reload = true; + } + + if (rename(path, xlogfpath) < 0) + ereport(ERROR, + (errcode_for_file_access(), + errmsg("could not rename file \"%s\" to \"%s\": %m", + path, xlogfpath))); + + /* + * If the existing file was replaced, since walsenders might have it + * open, request them to reload a currently-open segment. This is only + * required for WAL segments, walsenders don't hold other files open, but + * there's no harm in doing this too often, and we don't know what kind + * of a file we're dealing with here. + */ + if (reload) + WalSndRqstFileReload(); + + /* + * Signal walsender that new WAL has arrived. Again, this isn't necessary + * if we restored something other than a WAL segment, but it does no harm + * either. + */ + WalSndWakeup(); +} + /* * XLogArchiveNotify * diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h index 1443f96998f4cc51da1d5511f7b8f66c637bc87b..01898c63be26cf66081a9e14bf3e52d3ffb3b927 100644 --- a/src/include/access/xlog_internal.h +++ b/src/include/access/xlog_internal.h @@ -265,6 +265,7 @@ extern bool RestoreArchivedFile(char *path, const char *xlogfname, bool cleanupEnabled); extern void ExecuteRecoveryCommand(char *command, char *commandName, bool failOnerror); +extern void KeepFileRestoredFromArchive(char *path, char *xlogfname); extern void XLogArchiveNotify(const char *xlog); extern void XLogArchiveNotifySeg(XLogSegNo segno); extern bool XLogArchiveCheckDone(const char *xlog);