Hi, When we do archive recovery from the database cluster of which timeline ID is more than 2 pg_wal/RECOVERYHISTORY is remained even after archive recovery completed.
The cause of this seems cbc55da556b that moved exitArchiveRecovery() to before writeTimeLineHistory(). writeTimeLineHIstory() restores the history file from archive directory and therefore creates RECOVERYHISTORY file in pg_wal directory. We used to remove such temporary file by exitArchiveRecovery() but with this commit the order of calling these functions is reversed. Therefore we create RECOVERYHISTORY file after exited from archive recovery mode and remain it. To fix it I think that we can remove RECOVERYHISTORY file before the history file is archived in writeTimeLineHIstory(). The commit cbc55da556b is intended to minimize the window between the moment the file is written and the end-of-recovery record is generated. So I think it's not good to put exitArchiveRecovery() after writeTimeLineHIstory(). This issue seems to exist in all supported version as far as I read the code, although I don't test all of them yet. I've attached the draft patch to fix this issue. Regression test might be required. Feedback and suggestion are very welcome. Regards, -- Masahiko Sawada
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c index c2ba480c70..b0fd1dc5ac 100644 --- a/src/backend/access/transam/timeline.c +++ b/src/backend/access/transam/timeline.c @@ -281,9 +281,9 @@ findNewestTimeLine(TimeLineID startTLI) * switchpoint: WAL location where the system switched to the new timeline * reason: human-readable explanation of why the timeline was switched * - * Currently this is only used at the end recovery, and so there are no locking + * Currently this is only used after the end recovery, and so there are no locking * considerations. But we should be just as tense as XLogFileInit to avoid - * emplacing a bogus file. + * emplacing a bogus file and need to get rid of recovered timeline-history file. */ void writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, @@ -296,6 +296,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, int srcfd; int fd; int nbytes; + bool remove_tmphist = false; Assert(newTLI > parentTLI); /* else bad selection of newTLI */ @@ -319,7 +320,8 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, if (ArchiveRecoveryRequested) { TLHistoryFileName(histfname, parentTLI); - RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false); + remove_tmphist = RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", + 0, false); } else TLHistoryFilePath(path, parentTLI); @@ -375,6 +377,19 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI, ereport(ERROR, (errcode_for_file_access(), errmsg("could not close file \"%s\": %m", path))); + + /* + * Get rid of remaining recovered timeline-history file since we are + * already exited from archive recovery mode and therefore there is no + * cleanup later. + */ + if (remove_tmphist) + { + char histpath[MAXPGPATH]; + + snprintf(histpath, MAXPGPATH, XLOGDIR "/RECOVERYHISTORY"); + unlink(histpath); /* ignore any error */ + } } /*