From 16c5fced3c4d456e5f51e7e84a153770059357a1 Mon Sep 17 00:00:00 2001
From: Amul Sul <amul.sul@enterprisedb.com>
Date: Mon, 20 Sep 2021 05:52:19 -0400
Subject: [PATCH v35 01/10] Store ArchiveRecoveryRequested in shared memory and
 change its scope.

Storing ArchiveRecoveryRequested value in shared memory makes it
accessible to other processes as well. As of now no other process does
care about that but this will help to move code executed when
ArchiveRecoveryRequested set to other processes.

Also, the patch does change the scope of ArchiveRecoveryRequested
global to local, and type to integer. Now it has three values as -1
for the unknown, 1 for the request is made & 0 for no request or
request is completed.
---
 src/backend/access/transam/timeline.c    |   6 +-
 src/backend/access/transam/xlog.c        | 122 ++++++++++++++++-------
 src/backend/access/transam/xlogarchive.c |   2 +-
 src/include/access/xlog.h                |   1 +
 src/include/access/xlog_internal.h       |   1 -
 5 files changed, 93 insertions(+), 39 deletions(-)

diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index 8d0903c1756..0d4951b8255 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -93,7 +93,7 @@ readTimeLineHistory(TimeLineID targetTLI)
 		return list_make1(entry);
 	}
 
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 	{
 		TLHistoryFileName(histfname, targetTLI);
 		fromArchive =
@@ -229,7 +229,7 @@ existsTimeLineHistory(TimeLineID probeTLI)
 	if (probeTLI == 1)
 		return false;
 
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 	{
 		TLHistoryFileName(histfname, probeTLI);
 		RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
@@ -331,7 +331,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 	/*
 	 * If a history file exists for the parent, copy it verbatim
 	 */
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 	{
 		TLHistoryFileName(histfname, parentTLI);
 		RestoreArchivedFile(path, histfname, "RECOVERYHISTORY", 0, false);
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index e51a7a749da..4a6ddfb1872 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -239,17 +239,23 @@ static bool LocalPromoteIsTriggered = false;
 static int	LocalXLogInsertAllowed = -1;
 
 /*
- * When ArchiveRecoveryRequested is set, archive recovery was requested,
- * ie. signal files were present. When InArchiveRecovery is set, we are
- * currently recovering using offline XLOG archives. These variables are only
- * valid in the startup process.
- *
- * When ArchiveRecoveryRequested is true, but InArchiveRecovery is false, we're
- * currently performing crash recovery using only XLOG files in pg_wal, but
- * will switch to using offline XLOG archives as soon as we reach the end of
- * WAL in pg_wal.
-*/
-bool		ArchiveRecoveryRequested = false;
+ * When ArchiveRecoveryRequested is ARCHIVE_RECOVERY_REQUEST_YES, archive
+ * recovery was requested, ie. signal files were present. When InArchiveRecovery
+ * is set, we are currently recovering using offline XLOG archives.
+ *
+ * When ArchiveRecoveryRequested is ARCHIVE_RECOVERY_REQUEST_YES, but
+ * InArchiveRecovery is false, we're currently performing crash recovery using
+ * only XLOG files in pg_wal, but will switch to using offline XLOG archives as
+ * soon as we reach the end of WAL in pg_wal.
+ *
+ * InArchiveRecovery only valid in the startup process. ArchiveRecoveryRequested
+ * can be acccsed through ArchiveRecoveryIsRequested().
+ */
+#define ARCHIVE_RECOVERY_REQUEST_UNKOWN		-1
+#define ARCHIVE_RECOVERY_REQUEST_NO			0
+#define ARCHIVE_RECOVERY_REQUEST_YES		1
+
+static int	ArchiveRecoveryRequested = ARCHIVE_RECOVERY_REQUEST_UNKOWN;
 bool		InArchiveRecovery = false;
 
 static bool standby_signal_file_found = false;
@@ -637,6 +643,12 @@ typedef struct XLogCtlData
 	 */
 	RecoveryState SharedRecoveryState;
 
+	/*
+	 * SharedArchiveRecoveryRequested indicates whether an archive recovery is
+	 * requested. Protected by info_lck.
+	 */
+	bool		SharedArchiveRecoveryRequested;
+
 	/*
 	 * SharedHotStandbyActive indicates if we allow hot standby queries to be
 	 * run.  Protected by info_lck.
@@ -4455,7 +4467,7 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
 			 * we'd have no idea how far we'd have to replay to reach
 			 * consistency.  So err on the safe side and give up.
 			 */
-			if (!InArchiveRecovery && ArchiveRecoveryRequested &&
+			if (!InArchiveRecovery && ArchiveRecoveryIsRequested() &&
 				!fetching_ckpt)
 			{
 				ereport(DEBUG1,
@@ -5223,6 +5235,7 @@ XLOGShmemInit(void)
 	 */
 	XLogCtl->XLogCacheBlck = XLOGbuffers - 1;
 	XLogCtl->SharedRecoveryState = RECOVERY_STATE_CRASH;
+	XLogCtl->SharedArchiveRecoveryRequested = false;
 	XLogCtl->SharedHotStandbyActive = false;
 	XLogCtl->InstallXLogFileSegmentActive = false;
 	XLogCtl->SharedPromoteIsTriggered = false;
@@ -5485,16 +5498,16 @@ readRecoverySignalFile(void)
 	}
 
 	StandbyModeRequested = false;
-	ArchiveRecoveryRequested = false;
+	ArchiveRecoveryRequested = ARCHIVE_RECOVERY_REQUEST_NO;
 	if (standby_signal_file_found)
 	{
 		StandbyModeRequested = true;
-		ArchiveRecoveryRequested = true;
+		ArchiveRecoveryRequested = ARCHIVE_RECOVERY_REQUEST_YES;
 	}
 	else if (recovery_signal_file_found)
 	{
 		StandbyModeRequested = false;
-		ArchiveRecoveryRequested = true;
+		ArchiveRecoveryRequested = ARCHIVE_RECOVERY_REQUEST_YES;
 	}
 	else
 		return;
@@ -5507,12 +5520,18 @@ readRecoverySignalFile(void)
 		ereport(FATAL,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("standby mode is not supported by single-user servers")));
+
+	/*
+	 * Remember archive recovery request in shared memory state.  A lock is not
+	 * needed since we are the only ones who updating this.
+	 */
+	XLogCtl->SharedArchiveRecoveryRequested = (bool) ArchiveRecoveryRequested;
 }
 
 static void
 validateRecoveryParameters(void)
 {
-	if (!ArchiveRecoveryRequested)
+	if (!ArchiveRecoveryIsRequested())
 		return;
 
 	/*
@@ -5750,7 +5769,7 @@ recoveryStopsBefore(XLogReaderState *record)
 	 * Ignore recovery target settings when not in archive recovery (meaning
 	 * we are in crash recovery).
 	 */
-	if (!ArchiveRecoveryRequested)
+	if (!ArchiveRecoveryIsRequested())
 		return false;
 
 	/* Check if we should stop as soon as reaching consistency */
@@ -5897,7 +5916,7 @@ recoveryStopsAfter(XLogReaderState *record)
 	 * Ignore recovery target settings when not in archive recovery (meaning
 	 * we are in crash recovery).
 	 */
-	if (!ArchiveRecoveryRequested)
+	if (!ArchiveRecoveryIsRequested())
 		return false;
 
 	info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
@@ -6211,7 +6230,7 @@ recoveryApplyDelay(XLogReaderState *record)
 		return false;
 
 	/* nothing to do if crash recovery is requested */
-	if (!ArchiveRecoveryRequested)
+	if (!ArchiveRecoveryIsRequested())
 		return false;
 
 	/*
@@ -6455,7 +6474,7 @@ CheckRequiredParameterValues(void)
 	 * For archive recovery, the WAL must be generated with at least 'replica'
 	 * wal_level.
 	 */
-	if (ArchiveRecoveryRequested && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
+	if (ArchiveRecoveryIsRequested() && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
 	{
 		ereport(FATAL,
 				(errmsg("WAL was generated with wal_level=minimal, cannot continue recovering"),
@@ -6467,7 +6486,7 @@ CheckRequiredParameterValues(void)
 	 * For Hot Standby, the WAL must be generated with 'replica' mode, and we
 	 * must have at least as many backend slots as the primary.
 	 */
-	if (ArchiveRecoveryRequested && EnableHotStandby)
+	if (ArchiveRecoveryIsRequested() && EnableHotStandby)
 	{
 		/* We ignore autovacuum_max_workers when we make this test. */
 		RecoveryRequiresIntParameter("max_connections",
@@ -6633,7 +6652,7 @@ StartupXLOG(void)
 	readRecoverySignalFile();
 	validateRecoveryParameters();
 
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 	{
 		if (StandbyModeRequested)
 			ereport(LOG,
@@ -6666,7 +6685,7 @@ StartupXLOG(void)
 	 * Take ownership of the wakeup latch if we're going to sleep during
 	 * recovery.
 	 */
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 		OwnLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/* Set up XLOG reader facility */
@@ -6833,7 +6852,7 @@ StartupXLOG(void)
 		 * to minRecoveryPoint, up to backupEndPoint, or until we see an
 		 * end-of-backup record), and we can enter archive recovery directly.
 		 */
-		if (ArchiveRecoveryRequested &&
+		if (ArchiveRecoveryIsRequested() &&
 			(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
 			 ControlFile->backupEndRequired ||
 			 ControlFile->backupEndPoint != InvalidXLogRecPtr ||
@@ -7063,7 +7082,7 @@ StartupXLOG(void)
 	}
 	else if (ControlFile->state != DB_SHUTDOWNED)
 		InRecovery = true;
-	else if (ArchiveRecoveryRequested)
+	else if (ArchiveRecoveryIsRequested())
 	{
 		/* force recovery due to presence of recovery signal file */
 		InRecovery = true;
@@ -7229,7 +7248,7 @@ StartupXLOG(void)
 		 * control file and we've established a recovery snapshot from a
 		 * running-xacts WAL record.
 		 */
-		if (ArchiveRecoveryRequested && EnableHotStandby)
+		if (ArchiveRecoveryIsRequested() && EnableHotStandby)
 		{
 			TransactionId *xids;
 			int			nxids;
@@ -7646,7 +7665,7 @@ StartupXLOG(void)
 		 * This check is intentionally after the above log messages that
 		 * indicate how far recovery went.
 		 */
-		if (ArchiveRecoveryRequested &&
+		if (ArchiveRecoveryIsRequested() &&
 			recoveryTarget != RECOVERY_TARGET_UNSET &&
 			!reachedRecoveryTarget)
 			ereport(FATAL,
@@ -7674,7 +7693,7 @@ StartupXLOG(void)
 	 * We don't need the latch anymore. It's not strictly necessary to disown
 	 * it, but let's do it for the sake of tidiness.
 	 */
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 		DisownLatch(&XLogCtl->recoveryWakeupLatch);
 
 	/*
@@ -7725,7 +7744,7 @@ StartupXLOG(void)
 		 * crashes while an online backup is in progress. We must not treat
 		 * that as an error, or the database will refuse to start up.
 		 */
-		if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
+		if (ArchiveRecoveryIsRequested() || ControlFile->backupEndRequired)
 		{
 			if (ControlFile->backupEndRequired)
 				ereport(FATAL,
@@ -7771,7 +7790,7 @@ StartupXLOG(void)
 	 * In a normal crash recovery, we can just extend the timeline we were in.
 	 */
 	PrevTimeLineID = ThisTimeLineID;
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 	{
 		char	   *reason;
 		char		recoveryPath[MAXPGPATH];
@@ -7899,7 +7918,7 @@ StartupXLOG(void)
 		 * after we're fully out of recovery mode and already accepting
 		 * queries.
 		 */
-		if (ArchiveRecoveryRequested && IsUnderPostmaster &&
+		if (ArchiveRecoveryIsRequested() && IsUnderPostmaster &&
 			LocalPromoteIsTriggered)
 		{
 			promoted = true;
@@ -7924,7 +7943,7 @@ StartupXLOG(void)
 		}
 	}
 
-	if (ArchiveRecoveryRequested)
+	if (ArchiveRecoveryIsRequested())
 	{
 		/*
 		 * And finally, execute the recovery_end_command, if any.
@@ -8003,6 +8022,15 @@ StartupXLOG(void)
 				XLogArchiveNotify(partialfname);
 			}
 		}
+
+		/*
+		 * Done with archive recovery request, clear the shared memory state
+		 * which no longer needed.
+		 */
+		SpinLockAcquire(&XLogCtl->info_lck);
+		XLogCtl->SharedArchiveRecoveryRequested = false;
+		ArchiveRecoveryRequested = ARCHIVE_RECOVERY_REQUEST_UNKOWN;
+		SpinLockRelease(&XLogCtl->info_lck);
 	}
 
 	/*
@@ -8263,6 +8291,32 @@ RecoveryInProgress(void)
 	}
 }
 
+/*
+ * Is the archive recovery is requested?
+ *
+ * If ArchiveRecoveryRequested is unknown, then it will be updated by checking
+ * shared memory. Like PromoteIsTriggered(), this works in any process that's
+ * connected to shared memory.
+ */
+bool
+ArchiveRecoveryIsRequested(void)
+{
+	/*
+	 * If not UNKNOWN, the ArchiveRecoveryRequested value either
+	 * ARCHIVE_RECOVERY_REQUEST_YES => 1 or ARCHIVE_RECOVERY_REQUEST_NO => 0
+	 * which can be coerced to boolean true or false respectively.
+	 */
+	if (likely(ArchiveRecoveryRequested != ARCHIVE_RECOVERY_REQUEST_UNKOWN))
+		return (bool) ArchiveRecoveryRequested;
+
+	SpinLockAcquire(&XLogCtl->info_lck);
+	ArchiveRecoveryRequested = XLogCtl->SharedArchiveRecoveryRequested ?
+		ARCHIVE_RECOVERY_REQUEST_YES : ARCHIVE_RECOVERY_REQUEST_NO;
+	SpinLockRelease(&XLogCtl->info_lck);
+
+	return (bool) ArchiveRecoveryRequested;
+}
+
 /*
  * Returns current recovery state from shared memory.
  *
@@ -10174,7 +10228,7 @@ xlog_redo(XLogReaderState *record)
 		 * record, the backup was canceled and the end-of-backup record will
 		 * never arrive.
 		 */
-		if (ArchiveRecoveryRequested &&
+		if (ArchiveRecoveryIsRequested() &&
 			!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
 			XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
 			ereport(PANIC,
@@ -12176,7 +12230,7 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
 		 * Request a restartpoint if we've replayed too much xlog since the
 		 * last one.
 		 */
-		if (ArchiveRecoveryRequested && IsUnderPostmaster)
+		if (ArchiveRecoveryIsRequested() && IsUnderPostmaster)
 		{
 			if (XLogCheckpointNeeded(readSegNo))
 			{
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 26b023e754b..756d03adb6f 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -67,7 +67,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
 	 * Ignore restore_command when not in archive recovery (meaning we are in
 	 * crash recovery).
 	 */
-	if (!ArchiveRecoveryRequested)
+	if (!ArchiveRecoveryIsRequested())
 		goto not_available;
 
 	/* In standby mode, restore_command might not be supplied */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index 5e2c94a05ff..8ea4e583980 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -289,6 +289,7 @@ extern RecoveryPauseState GetRecoveryPauseState(void);
 extern void SetRecoveryPause(bool recoveryPause);
 extern TimestampTz GetLatestXTime(void);
 extern TimestampTz GetCurrentChunkReplayStartTime(void);
+extern bool ArchiveRecoveryIsRequested(void);
 
 extern void UpdateControlFile(void);
 extern uint64 GetSystemIdentifier(void);
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 3b5eceff658..2051953d404 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -319,7 +319,6 @@ extern void GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli);
  * Exported for the functions in timeline.c and xlogarchive.c.  Only valid
  * in the startup process.
  */
-extern bool ArchiveRecoveryRequested;
 extern bool InArchiveRecovery;
 extern bool StandbyMode;
 extern char *recoveryRestoreCommand;
-- 
2.18.0

