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 */
+		}
 	}
 
 	/*

Reply via email to