Hi!
I felt you might have missed attaching the test patches added at [1].
Well, the tests were written for the initial proposal which (after
Michael's review and advices) has been fixed and updated. The original
tests became not relevant actually. That is why I dropped them.
This change is not required:
Placed back the empty line. The v7 patch is attached.
Currently we have the following commitfest entries for this thread:
[1] - https://commitfest.postgresql.org/patch/5611/
[2] - https://commitfest.postgresql.org/patch/5513/
I have closed the second entry at [2].
I mistakenly pushed the patch twice. Thank you for managing that.
Respectfully,
Mikhail Litsarev,
Postgres Professional: https://postgrespro.com
From 0e7f61589c282a2e9b82cdbf8eadc2159301c3e8 Mon Sep 17 00:00:00 2001
From: Mikhail Litsarev <m.litsa...@postgrespro.ru>
Date: Tue, 25 Mar 2025 23:02:23 +0300
Subject: [PATCH v7 2/2] Wrapper function to extract whole text array from
recovery flags bitset.
It returns SX_PROMOTE_IS_TRIGGERED, SX_STANDBY_MODE_REQUESTED flags for recovery states.
---
src/backend/access/transam/xlogfuncs.c | 31 +++++++++++++++++++++++
src/backend/access/transam/xlogrecovery.c | 16 ++++++++++++
src/include/access/xlogrecovery.h | 1 +
src/include/catalog/pg_proc.dat | 5 ++++
4 files changed, 53 insertions(+)
diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c
index 8c3090165f0..9b71ff7583c 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -30,6 +30,7 @@
#include "storage/fd.h"
#include "storage/latch.h"
#include "storage/standby.h"
+#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/pg_lsn.h"
@@ -748,3 +749,33 @@ pg_promote(PG_FUNCTION_ARGS)
wait_seconds)));
PG_RETURN_BOOL(false);
}
+
+Datum
+pg_get_recovery_flags(PG_FUNCTION_ARGS)
+{
+/*
+ * Currently supported number of recovery flags is equal to two:
+ * {SX_PROMOTE_IS_TRIGGERED, SX_STANDBY_MODE_REQUESTED}.
+ * The SX_STANDBY_MODE_REQUESTED is valid only in the startup process.
+ */
+#define MAX_RECOVERY_FLAGS 2
+
+ bits32 recovery_flags;
+ int cnt = 0;
+ Datum flags[MAX_RECOVERY_FLAGS];
+ ArrayType *txt_arr;
+
+ recovery_flags = GetXLogRecoveryFlags();
+
+ if (recovery_flags & SX_PROMOTE_IS_TRIGGERED)
+ flags[cnt++] = CStringGetTextDatum("PROMOTE_IS_TRIGGERED");
+
+ if (recovery_flags & SX_STANDBY_MODE_REQUESTED)
+ flags[cnt++] = CStringGetTextDatum("STANDBY_MODE_REQUESTED");
+
+ Assert(cnt <= MAX_RECOVERY_FLAGS);
+
+ /* Returns bit array as Datum */
+ txt_arr = construct_array_builtin(flags, cnt, TEXTOID);
+ PG_RETURN_ARRAYTYPE_P(txt_arr);
+}
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 9d8c1cdde43..bd5bdeb5db8 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -4370,6 +4370,22 @@ StartupRequestWalReceiverRestart(void)
}
}
+/*
+ * Return SX_PROMOTE_IS_TRIGGERED, SX_STANDBY_MODE_REQUESTED flags for
+ * recovery states.
+ */
+bits32 GetXLogRecoveryFlags(void)
+{
+ bits32 flags = 0;
+
+ SpinLockAcquire(&XLogRecoveryCtl->info_lck);
+ flags = XLogRecoveryCtl->sharedRecoveryFlags;
+ SpinLockRelease(&XLogRecoveryCtl->info_lck);
+
+ flags |= (localRecoveryFlags & SX_STANDBY_MODE_REQUESTED);
+
+ return flags;
+}
/*
* Has a standby promotion already been triggered?
diff --git a/src/include/access/xlogrecovery.h b/src/include/access/xlogrecovery.h
index 2d44905ea36..faa6c666ede 100644
--- a/src/include/access/xlogrecovery.h
+++ b/src/include/access/xlogrecovery.h
@@ -172,6 +172,7 @@ extern TimestampTz GetLatestXTime(void);
extern TimestampTz GetCurrentChunkReplayStartTime(void);
extern XLogRecPtr GetCurrentReplayRecPtr(TimeLineID *replayEndTLI);
+extern bits32 GetXLogRecoveryFlags(void);
extern bool PromoteIsTriggered(void);
extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3f7b82e02bb..8b775f0bbd9 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -6714,6 +6714,11 @@
proname => 'pg_is_in_recovery', provolatile => 'v', prorettype => 'bool',
proargtypes => '', prosrc => 'pg_is_in_recovery' },
+{ oid => '8439',
+ descr => 'return flags for recovery states',
+ proname => 'pg_get_recovery_flags', provolatile => 'v', prorettype => '_text',
+ proargtypes => '', prosrc => 'pg_get_recovery_flags' },
+
{ oid => '3820', descr => 'current wal flush location',
proname => 'pg_last_wal_receive_lsn', provolatile => 'v',
prorettype => 'pg_lsn', proargtypes => '',
--
2.34.1
From 1667c30af357943036359139c1f3442f576413d4 Mon Sep 17 00:00:00 2001
From: Mikhail Litsarev <m.litsa...@postgrespro.ru>
Date: Tue, 25 Mar 2025 22:56:09 +0300
Subject: [PATCH v7 1/2] Replace recovery boolean flags with a bits32 set.
Move local booleans ArchiveRecoveryRequested, InArchiveRecovery,
StandbyModeRequested, StandbyMode, LocalHotStandbyActive,
LocalPromoteIsTriggered into localRecoveryFlags bitset.
Move SharedHotStandbyActive, SharedPromoteIsTriggered members of
XLogRecoveryCtlData into sharedRecoveryFlags bitset.
Refactor the code according to the changes.
---
src/backend/access/transam/timeline.c | 6 +-
src/backend/access/transam/xlog.c | 26 +--
src/backend/access/transam/xlogarchive.c | 4 +-
src/backend/access/transam/xlogrecovery.c | 221 ++++++++++-----------
src/backend/replication/logical/slotsync.c | 2 +-
src/backend/replication/slot.c | 2 +-
src/include/access/xlog_internal.h | 6 +-
src/include/access/xlogrecovery.h | 34 +++-
8 files changed, 162 insertions(+), 139 deletions(-)
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index a27f27cc037..c9f53c4b667 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 (ArchiveRecoveryRequested())
{
TLHistoryFileName(histfname, targetTLI);
fromArchive =
@@ -229,7 +229,7 @@ existsTimeLineHistory(TimeLineID probeTLI)
if (probeTLI == 1)
return false;
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
{
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 (ArchiveRecoveryRequested())
{
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 4b6c694a3f7..6fb13a8a769 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5434,7 +5434,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 (ArchiveRecoveryRequested() && ControlFile->wal_level == WAL_LEVEL_MINIMAL)
{
ereport(FATAL,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@@ -5447,7 +5447,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 (ArchiveRecoveryRequested() && EnableHotStandby)
{
/* We ignore autovacuum_worker_slots when we make this test. */
RecoveryRequiresIntParameter("max_connections",
@@ -5607,8 +5607,8 @@ StartupXLOG(void)
*
* InitWalRecovery analyzes the control file and the backup label file, if
* any. It updates the in-memory ControlFile buffer according to the
- * starting checkpoint, and sets InRecovery and ArchiveRecoveryRequested.
- * It also applies the tablespace map file, if any.
+ * starting checkpoint, and sets SX_ARCHIVE_RECOVERY_REQUESTED and
+ * InRecovery. It also applies the tablespace map file, if any.
*/
InitWalRecovery(ControlFile, &wasShutdown,
&haveBackupLabel, &haveTblspcMap);
@@ -5740,7 +5740,7 @@ StartupXLOG(void)
{
/* Initialize state for RecoveryInProgress() */
SpinLockAcquire(&XLogCtl->info_lck);
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
XLogCtl->SharedRecoveryState = RECOVERY_STATE_ARCHIVE;
else
XLogCtl->SharedRecoveryState = RECOVERY_STATE_CRASH;
@@ -5793,7 +5793,7 @@ StartupXLOG(void)
* startup process to think that there are still invalid page
* references when checking for data consistency.
*/
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
{
LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
@@ -5827,7 +5827,7 @@ StartupXLOG(void)
* control file and we've established a recovery snapshot from a
* running-xacts WAL record.
*/
- if (ArchiveRecoveryRequested && EnableHotStandby)
+ if (ArchiveRecoveryRequested() && EnableHotStandby)
{
TransactionId *xids;
int nxids;
@@ -5940,7 +5940,7 @@ StartupXLOG(void)
* recover from an online backup but never called pg_backup_stop(), or
* you didn't archive all the WAL needed.
*/
- if (ArchiveRecoveryRequested || ControlFile->backupEndRequired)
+ if (ArchiveRecoveryRequested() || ControlFile->backupEndRequired)
{
if (!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) || ControlFile->backupEndRequired)
ereport(FATAL,
@@ -5992,7 +5992,7 @@ StartupXLOG(void)
* In a normal crash recovery, we can just extend the timeline we were in.
*/
newTLI = endOfRecoveryInfo->lastRecTLI;
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
{
newTLI = findNewestTimeLine(recoveryTargetTLI) + 1;
ereport(LOG,
@@ -6185,7 +6185,7 @@ StartupXLOG(void)
XLogReportParameters();
/* If this is archive recovery, perform post-recovery cleanup actions. */
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
CleanupAfterArchiveRecovery(EndOfLogTLI, EndOfLog, newTLI);
/*
@@ -6344,7 +6344,7 @@ PerformRecoveryXLogAction(void)
* of a full checkpoint. A checkpoint is requested later, after we're
* fully out of recovery mode and already accepting queries.
*/
- if (ArchiveRecoveryRequested && IsUnderPostmaster &&
+ if (ArchiveRecoveryRequested() && IsUnderPostmaster &&
PromoteIsTriggered())
{
promoted = true;
@@ -8338,7 +8338,7 @@ xlog_redo(XLogReaderState *record)
* record, the backup was canceled and the end-of-backup record will
* never arrive.
*/
- if (ArchiveRecoveryRequested &&
+ if (ArchiveRecoveryRequested() &&
!XLogRecPtrIsInvalid(ControlFile->backupStartPoint) &&
XLogRecPtrIsInvalid(ControlFile->backupEndPoint))
ereport(PANIC,
@@ -8579,7 +8579,7 @@ xlog_redo(XLogReaderState *record)
* local copies cannot be updated as long as crash recovery is
* happening and we expect all the WAL to be replayed.
*/
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
{
LocalMinRecoveryPoint = ControlFile->minRecoveryPoint;
LocalMinRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c
index 1ef1713c91a..ad379acc30a 100644
--- a/src/backend/access/transam/xlogarchive.c
+++ b/src/backend/access/transam/xlogarchive.c
@@ -68,7 +68,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
* Ignore restore_command when not in archive recovery (meaning we are in
* crash recovery).
*/
- if (!ArchiveRecoveryRequested)
+ if (!ArchiveRecoveryRequested())
goto not_available;
/* In standby mode, restore_command might not be supplied */
@@ -205,7 +205,7 @@ RestoreArchivedFile(char *path, const char *xlogfname,
* incorrectly conclude we've reached the end of WAL and we're
* done recovering ...
*/
- if (StandbyMode && stat_buf.st_size < expectedSize)
+ if (InStandbyMode() && stat_buf.st_size < expectedSize)
elevel = DEBUG1;
else
elevel = FATAL;
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 2c19013c98b..9d8c1cdde43 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -124,30 +124,7 @@ TimeLineID recoveryTargetTLI = 0;
static List *expectedTLEs;
static TimeLineID curFileTLI;
-/*
- * 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;
-bool InArchiveRecovery = false;
-
-/*
- * When StandbyModeRequested is set, standby mode was requested, i.e.
- * standby.signal file was present. When StandbyMode is set, we are currently
- * in standby mode. These variables are only valid in the startup process.
- * They work similarly to ArchiveRecoveryRequested and InArchiveRecovery.
- */
-static bool StandbyModeRequested = false;
-bool StandbyMode = false;
-
-/* was a signal file present at startup? */
+/* Was a signal file present at startup? */
static bool standby_signal_file_found = false;
static bool recovery_signal_file_found = false;
@@ -171,16 +148,19 @@ static XLogRecPtr RedoStartLSN = InvalidXLogRecPtr;
static TimeLineID RedoStartTLI = 0;
/*
- * Local copy of SharedHotStandbyActive variable. False actually means "not
- * known, need to check the shared state".
- */
-static bool LocalHotStandbyActive = false;
-
-/*
- * Local copy of SharedPromoteIsTriggered variable. False actually means "not
- * known, need to check the shared state".
+ * Local flags:
+ * SX_ARCHIVE_RECOVERY_REQUESTED
+ * SX_IN_ARCHIVE_RECOVERY
+ * SX_STANDBY_MODE_REQUESTED
+ * SX_IN_STANDBY_MODE
+ *
+ * and local copies of sharedRecoveryFlags:
+ * SX_HOT_STANDBY_ACTIVE,
+ * SX_PROMOTE_IS_TRIGGERED.
+ * If some flag is not set, that actually means "not known, need to check
+ * the shared state".
*/
-static bool LocalPromoteIsTriggered = false;
+static bits32 localRecoveryFlags = 0;
/* Has the recovery code requested a walreceiver wakeup? */
static bool doRequestWalReceiverReply;
@@ -298,23 +278,16 @@ bool reachedConsistency = false;
static char *replay_image_masked = NULL;
static char *primary_image_masked = NULL;
-
/*
* Shared-memory state for WAL recovery.
*/
typedef struct XLogRecoveryCtlData
{
/*
- * SharedHotStandbyActive indicates if we allow hot standby queries to be
- * run. Protected by info_lck.
+ * The bit array stores the following states
+ * SX_HOT_STANDBY_ACTIVE, SX_PROMOTE_IS_TRIGGERED. Protected by info_lck.
*/
- bool SharedHotStandbyActive;
-
- /*
- * SharedPromoteIsTriggered indicates if a standby promotion has been
- * triggered. Protected by info_lck.
- */
- bool SharedPromoteIsTriggered;
+ bits32 sharedRecoveryFlags;
/*
* recoveryWakeupLatch is used to wake up the startup process to continue
@@ -441,6 +414,7 @@ static bool HotStandbyActiveInReplay(void);
static void SetCurrentChunkStartTime(TimestampTz xtime);
static void SetLatestXTime(TimestampTz xtime);
+static bool StandbyModeRequested(void);
/*
* Initialization of shared memory for WAL recovery
*/
@@ -478,7 +452,7 @@ XLogRecoveryShmemInit(void)
static void
EnableStandbyMode(void)
{
- StandbyMode = true;
+ localRecoveryFlags |= SX_IN_STANDBY_MODE;
/*
* To avoid server log bloat, we don't report recovery progress in a
@@ -506,8 +480,8 @@ EnableStandbyMode(void)
* disk does after initializing other subsystems, but before calling
* PerformWalRecovery().
*
- * This initializes some global variables like ArchiveRecoveryRequested, and
- * StandbyModeRequested and InRecovery.
+ * This initializes some flags like SX_ARCHIVE_RECOVERY_REQUESTED and
+ * SX_STABDBY_MODE_REQUESTED and global variable InRecovery.
*/
void
InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
@@ -545,7 +519,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
* Take ownership of the wakeup latch if we're going to sleep during
* recovery, if required.
*/
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
OwnLatch(&XLogRecoveryCtl->recoveryWakeupLatch);
/*
@@ -600,8 +574,8 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
* file, we know how far we need to replay to reach consistency. Enter
* archive recovery directly.
*/
- InArchiveRecovery = true;
- if (StandbyModeRequested)
+ localRecoveryFlags |= SX_IN_ARCHIVE_RECOVERY;
+ if (StandbyModeRequested())
EnableStandbyMode();
/*
@@ -750,14 +724,14 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
* to minRecoveryPoint, up to backupEndPoint, or until we see an
* end-of-backup record), and we can enter archive recovery directly.
*/
- if (ArchiveRecoveryRequested &&
+ if (ArchiveRecoveryRequested() &&
(ControlFile->minRecoveryPoint != InvalidXLogRecPtr ||
ControlFile->backupEndRequired ||
ControlFile->backupEndPoint != InvalidXLogRecPtr ||
ControlFile->state == DB_SHUTDOWNED))
{
- InArchiveRecovery = true;
- if (StandbyModeRequested)
+ localRecoveryFlags |= SX_IN_ARCHIVE_RECOVERY;
+ if (StandbyModeRequested())
EnableStandbyMode();
}
@@ -800,9 +774,9 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
}
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
{
- if (StandbyModeRequested)
+ if (StandbyModeRequested())
ereport(LOG,
(errmsg("entering standby mode")));
else if (recoveryTarget == RECOVERY_TARGET_XID)
@@ -914,7 +888,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
}
else if (ControlFile->state != DB_SHUTDOWNED)
InRecovery = true;
- else if (ArchiveRecoveryRequested)
+ else if (ArchiveRecoveryRequested())
{
/* force recovery due to presence of recovery signal file */
InRecovery = true;
@@ -931,7 +905,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
*/
if (InRecovery)
{
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
{
ControlFile->state = DB_IN_ARCHIVE_RECOVERY;
}
@@ -950,7 +924,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
}
ControlFile->checkPoint = CheckPointLoc;
ControlFile->checkPointCopy = checkPoint;
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
{
/* initialize minRecoveryPoint if not set yet */
if (ControlFile->minRecoveryPoint < checkPoint.redo)
@@ -997,7 +971,7 @@ InitWalRecovery(ControlFileData *ControlFile, bool *wasShutdown_ptr,
backupStartPoint = ControlFile->backupStartPoint;
backupEndRequired = ControlFile->backupEndRequired;
backupEndPoint = ControlFile->backupEndPoint;
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
{
minRecoveryPoint = ControlFile->minRecoveryPoint;
minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
@@ -1083,17 +1057,16 @@ readRecoverySignalFile(void)
recovery_signal_file_found = true;
}
- StandbyModeRequested = false;
- ArchiveRecoveryRequested = false;
+ localRecoveryFlags &= ~SX_STANDBY_MODE_REQUESTED;
+ localRecoveryFlags &= ~SX_ARCHIVE_RECOVERY_REQUESTED;
if (standby_signal_file_found)
{
- StandbyModeRequested = true;
- ArchiveRecoveryRequested = true;
+ localRecoveryFlags |= SX_STANDBY_MODE_REQUESTED;
+ localRecoveryFlags |= SX_ARCHIVE_RECOVERY_REQUESTED;
}
else if (recovery_signal_file_found)
{
- StandbyModeRequested = false;
- ArchiveRecoveryRequested = true;
+ localRecoveryFlags |= SX_ARCHIVE_RECOVERY_REQUESTED;
}
else
return;
@@ -1102,7 +1075,7 @@ readRecoverySignalFile(void)
* We don't support standby mode in standalone backends; that requires
* other processes such as the WAL receiver to be alive.
*/
- if (StandbyModeRequested && !IsUnderPostmaster)
+ if (StandbyModeRequested() && !IsUnderPostmaster)
ereport(FATAL,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("standby mode is not supported by single-user servers")));
@@ -1111,13 +1084,13 @@ readRecoverySignalFile(void)
static void
validateRecoveryParameters(void)
{
- if (!ArchiveRecoveryRequested)
+ if (!ArchiveRecoveryRequested())
return;
/*
* Check for compulsory parameters
*/
- if (StandbyModeRequested)
+ if (StandbyModeRequested())
{
if ((PrimaryConnInfo == NULL || strcmp(PrimaryConnInfo, "") == 0) &&
(recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0))
@@ -1158,8 +1131,8 @@ validateRecoveryParameters(void)
/*
* If user specified recovery_target_timeline, validate it or compute the
* "latest" value. We can't do this until after we've gotten the restore
- * command and set InArchiveRecovery, because we need to fetch timeline
- * history files from the archive.
+ * command and set SX_IN_ARCHIVE_RECOVERY, because we need to fetch
+ * timeline history files from the archive.
*/
if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_NUMERIC)
{
@@ -1497,7 +1470,7 @@ FinishWalRecovery(void)
* i.e., calling XLogShutdownWalRcv().
*/
Assert(!WalRcvStreaming());
- StandbyMode = false;
+ localRecoveryFlags &= ~SX_IN_STANDBY_MODE;
/*
* Determine where to start writing WAL next.
@@ -1535,7 +1508,7 @@ FinishWalRecovery(void)
*/
result->endOfLogTLI = xlogreader->seg.ws_tli;
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
{
/*
* We are no longer in archive recovery state.
@@ -1543,8 +1516,8 @@ FinishWalRecovery(void)
* We are now done reading the old WAL. Turn off archive fetching if
* it was active.
*/
- Assert(InArchiveRecovery);
- InArchiveRecovery = false;
+ Assert(InArchiveRecovery());
+ localRecoveryFlags &= ~SX_IN_ARCHIVE_RECOVERY;
/*
* If the ending log segment is still open, close it (to avoid
@@ -1624,7 +1597,7 @@ ShutdownWalRecovery(void)
XLogReaderFree(xlogreader);
XLogPrefetcherFree(xlogprefetcher);
- if (ArchiveRecoveryRequested)
+ if (ArchiveRecoveryRequested())
{
/*
* Since there might be a partial WAL segment named RECOVERYXLOG, get
@@ -1642,7 +1615,7 @@ ShutdownWalRecovery(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 (ArchiveRecoveryRequested())
DisownLatch(&XLogRecoveryCtl->recoveryWakeupLatch);
}
@@ -1744,7 +1717,7 @@ PerformWalRecovery(void)
LSN_FORMAT_ARGS(xlogreader->ReadRecPtr))));
/* Prepare to report progress of the redo phase. */
- if (!StandbyMode)
+ if (!InStandbyMode())
begin_startup_progress_phase();
/*
@@ -1752,7 +1725,7 @@ PerformWalRecovery(void)
*/
do
{
- if (!StandbyMode)
+ if (!InStandbyMode())
ereport_startup_progress("redo in progress, elapsed time: %ld.%02d s, current LSN: %X/%X",
LSN_FORMAT_ARGS(xlogreader->ReadRecPtr));
@@ -1897,7 +1870,7 @@ PerformWalRecovery(void)
* This check is intentionally after the above log messages that indicate
* how far recovery went.
*/
- if (ArchiveRecoveryRequested &&
+ if (ArchiveRecoveryRequested() &&
recoveryTarget != RECOVERY_TARGET_UNSET &&
!reachedRecoveryTarget)
ereport(FATAL,
@@ -2189,7 +2162,7 @@ CheckRecoveryConsistency(void)
if (XLogRecPtrIsInvalid(minRecoveryPoint))
return;
- Assert(InArchiveRecovery);
+ Assert(InArchiveRecovery());
/*
* assume that we are called in the startup process, and hence don't need
@@ -2259,15 +2232,15 @@ CheckRecoveryConsistency(void)
* enabling connections.
*/
if (standbyState == STANDBY_SNAPSHOT_READY &&
- !LocalHotStandbyActive &&
+ !(localRecoveryFlags & SX_HOT_STANDBY_ACTIVE) &&
reachedConsistency &&
IsUnderPostmaster)
{
SpinLockAcquire(&XLogRecoveryCtl->info_lck);
- XLogRecoveryCtl->SharedHotStandbyActive = true;
+ XLogRecoveryCtl->sharedRecoveryFlags |= SX_HOT_STANDBY_ACTIVE;
SpinLockRelease(&XLogRecoveryCtl->info_lck);
- LocalHotStandbyActive = true;
+ localRecoveryFlags |= SX_HOT_STANDBY_ACTIVE;
SendPostmasterSignal(PMSIGNAL_BEGIN_HOT_STANDBY);
}
@@ -2587,7 +2560,7 @@ recoveryStopsBefore(XLogReaderState *record)
* Ignore recovery target settings when not in archive recovery (meaning
* we are in crash recovery).
*/
- if (!ArchiveRecoveryRequested)
+ if (!ArchiveRecoveryRequested())
return false;
/* Check if we should stop as soon as reaching consistency */
@@ -2739,7 +2712,7 @@ recoveryStopsAfter(XLogReaderState *record)
* Ignore recovery target settings when not in archive recovery (meaning
* we are in crash recovery).
*/
- if (!ArchiveRecoveryRequested)
+ if (!ArchiveRecoveryRequested())
return false;
info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
@@ -2930,11 +2903,11 @@ static void
recoveryPausesHere(bool endOfRecovery)
{
/* Don't pause unless users can connect! */
- if (!LocalHotStandbyActive)
+ if (!(localRecoveryFlags & SX_HOT_STANDBY_ACTIVE))
return;
/* Don't pause after standby promotion has been triggered */
- if (LocalPromoteIsTriggered)
+ if (localRecoveryFlags & SX_PROMOTE_IS_TRIGGERED)
return;
if (endOfRecovery)
@@ -3000,7 +2973,7 @@ recoveryApplyDelay(XLogReaderState *record)
return false;
/* nothing to do if crash recovery is requested */
- if (!ArchiveRecoveryRequested)
+ if (!ArchiveRecoveryRequested())
return false;
/*
@@ -3162,13 +3135,13 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
* to indicate to downstream WAL readers that that portion is to
* be ignored.
*
- * However, when ArchiveRecoveryRequested = true, we're going to
+ * However, when ArchiveRecoveryRequested() = true, we're going to
* switch to a new timeline at the end of recovery. We will only
* copy WAL over to the new timeline up to the end of the last
* complete record, so if we did this, we would later create an
* overwrite contrecord in the wrong place, breaking everything.
*/
- if (!ArchiveRecoveryRequested &&
+ if (!ArchiveRecoveryRequested() &&
!XLogRecPtrIsInvalid(xlogreader->abortedRecPtr))
{
abortedRecPtr = xlogreader->abortedRecPtr;
@@ -3237,13 +3210,13 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, 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() && ArchiveRecoveryRequested() &&
!fetching_ckpt)
{
ereport(DEBUG1,
(errmsg_internal("reached end of WAL in pg_wal, entering archive recovery")));
- InArchiveRecovery = true;
- if (StandbyModeRequested)
+ localRecoveryFlags |= SX_IN_ARCHIVE_RECOVERY;
+ if (StandbyModeRequested())
EnableStandbyMode();
SwitchIntoArchiveRecovery(xlogreader->EndRecPtr, replayTLI);
@@ -3263,7 +3236,7 @@ ReadRecord(XLogPrefetcher *xlogprefetcher, int emode,
}
/* In standby mode, loop back to retry. Otherwise, give up. */
- if (StandbyMode && !CheckForStandbyTrigger())
+ if (InStandbyMode() && !CheckForStandbyTrigger())
continue;
else
return NULL;
@@ -3325,7 +3298,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 (ArchiveRecoveryRequested() && IsUnderPostmaster)
{
if (XLogCheckpointNeeded(readSegNo))
{
@@ -3478,7 +3451,7 @@ retry:
* page header here for the retry. Instead, ReadPageInternal() is
* responsible for the validation.
*/
- if (StandbyMode &&
+ if (InStandbyMode() &&
(targetPagePtr % wal_segment_size) == 0 &&
!XLogReaderValidatePageHeader(xlogreader, targetPagePtr, readBuf))
{
@@ -3515,7 +3488,7 @@ next_record_is_invalid:
readSource = XLOG_FROM_ANY;
/* In standby-mode, keep trying */
- if (StandbyMode)
+ if (InStandbyMode())
goto retry;
else
return XLREAD_FAIL;
@@ -3590,10 +3563,10 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* the end of recovery.
*-------
*/
- if (!InArchiveRecovery)
+ if (!InArchiveRecovery())
currentSource = XLOG_FROM_PG_WAL;
else if (currentSource == XLOG_FROM_ANY ||
- (!StandbyMode && currentSource == XLOG_FROM_STREAM))
+ (!InStandbyMode() && currentSource == XLOG_FROM_STREAM))
{
lastSourceFailed = false;
currentSource = XLOG_FROM_ARCHIVE;
@@ -3631,7 +3604,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* finish replaying as much as we can from archive and
* pg_wal before failover.
*/
- if (StandbyMode && CheckForStandbyTrigger())
+ if (InStandbyMode() && CheckForStandbyTrigger())
{
XLogShutdownWalRcv();
return XLREAD_FAIL;
@@ -3641,7 +3614,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* Not in standby mode, and we've now tried the archive
* and pg_wal.
*/
- if (!StandbyMode)
+ if (!InStandbyMode())
return XLREAD_FAIL;
/*
@@ -3673,7 +3646,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* We should be able to move to XLOG_FROM_STREAM only in
* standby mode.
*/
- Assert(StandbyMode);
+ Assert(InStandbyMode());
/*
* Before we leave XLOG_FROM_STREAM state, make sure that
@@ -3744,7 +3717,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* the archive over ones in pg_wal, so try the next file again
* from the archive first.
*/
- if (InArchiveRecovery)
+ if (InArchiveRecovery())
currentSource = XLOG_FROM_ARCHIVE;
}
@@ -3804,7 +3777,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
* We should be able to move to XLOG_FROM_STREAM only in
* standby mode.
*/
- Assert(StandbyMode);
+ Assert(InStandbyMode());
/*
* First, shutdown walreceiver if its restart has been
@@ -4412,21 +4385,22 @@ PromoteIsTriggered(void)
* triggered. We can't trigger a promotion again, so there's no need to
* keep checking after the shared variable has once been seen true.
*/
- if (LocalPromoteIsTriggered)
+ if (localRecoveryFlags & SX_PROMOTE_IS_TRIGGERED)
return true;
SpinLockAcquire(&XLogRecoveryCtl->info_lck);
- LocalPromoteIsTriggered = XLogRecoveryCtl->SharedPromoteIsTriggered;
+ localRecoveryFlags |=
+ (XLogRecoveryCtl->sharedRecoveryFlags & SX_PROMOTE_IS_TRIGGERED);
SpinLockRelease(&XLogRecoveryCtl->info_lck);
- return LocalPromoteIsTriggered;
+ return localRecoveryFlags & SX_PROMOTE_IS_TRIGGERED;
}
static void
SetPromoteIsTriggered(void)
{
SpinLockAcquire(&XLogRecoveryCtl->info_lck);
- XLogRecoveryCtl->SharedPromoteIsTriggered = true;
+ XLogRecoveryCtl->sharedRecoveryFlags |= SX_PROMOTE_IS_TRIGGERED;
SpinLockRelease(&XLogRecoveryCtl->info_lck);
/*
@@ -4437,7 +4411,7 @@ SetPromoteIsTriggered(void)
*/
SetRecoveryPause(false);
- LocalPromoteIsTriggered = true;
+ localRecoveryFlags |= SX_PROMOTE_IS_TRIGGERED;
}
/*
@@ -4446,7 +4420,7 @@ SetPromoteIsTriggered(void)
static bool
CheckForStandbyTrigger(void)
{
- if (LocalPromoteIsTriggered)
+ if (localRecoveryFlags & SX_PROMOTE_IS_TRIGGERED)
return true;
if (IsPromoteSignaled() && CheckPromoteSignal())
@@ -4520,16 +4494,17 @@ HotStandbyActive(void)
* can't de-activate Hot Standby, so there's no need to keep checking
* after the shared variable has once been seen true.
*/
- if (LocalHotStandbyActive)
+ if (localRecoveryFlags & SX_HOT_STANDBY_ACTIVE)
return true;
else
{
/* spinlock is essential on machines with weak memory ordering! */
SpinLockAcquire(&XLogRecoveryCtl->info_lck);
- LocalHotStandbyActive = XLogRecoveryCtl->SharedHotStandbyActive;
+ localRecoveryFlags |=
+ (XLogRecoveryCtl->sharedRecoveryFlags & SX_HOT_STANDBY_ACTIVE);
SpinLockRelease(&XLogRecoveryCtl->info_lck);
- return LocalHotStandbyActive;
+ return localRecoveryFlags & SX_HOT_STANDBY_ACTIVE;
}
}
@@ -4541,7 +4516,7 @@ static bool
HotStandbyActiveInReplay(void)
{
Assert(AmStartupProcess() || !IsPostmasterEnvironment);
- return LocalHotStandbyActive;
+ return localRecoveryFlags & SX_HOT_STANDBY_ACTIVE;
}
/*
@@ -5058,3 +5033,23 @@ assign_recovery_target_xid(const char *newval, void *extra)
else
recoveryTarget = RECOVERY_TARGET_UNSET;
}
+
+bool StandbyModeRequested(void)
+{
+ return localRecoveryFlags & SX_STANDBY_MODE_REQUESTED;
+}
+
+bool ArchiveRecoveryRequested(void)
+{
+ return localRecoveryFlags & SX_ARCHIVE_RECOVERY_REQUESTED;
+}
+
+bool InArchiveRecovery(void)
+{
+ return localRecoveryFlags & SX_IN_ARCHIVE_RECOVERY;
+}
+
+bool InStandbyMode(void)
+{
+ return localRecoveryFlags & SX_IN_STANDBY_MODE;
+}
diff --git a/src/backend/replication/logical/slotsync.c b/src/backend/replication/logical/slotsync.c
index 2c0a7439be4..920040f3bcd 100644
--- a/src/backend/replication/logical/slotsync.c
+++ b/src/backend/replication/logical/slotsync.c
@@ -1517,7 +1517,7 @@ update_synced_slots_inactive_since(void)
* long time after promotion if they haven't been synchronized recently.
* Whoever acquires the slot, i.e., makes the slot active, will reset it.
*/
- if (!StandbyMode)
+ if (!InStandbyMode())
return;
/* The slot sync worker or SQL function mustn't be running by now */
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 719e531eb90..e4b82304d18 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -2537,7 +2537,7 @@ RestoreSlotFromDisk(const char *name)
* primary reduces wal_level < logical while hot standby is disabled,
* logical slots would remain valid even after promotion.
*/
- if (StandbyMode && !EnableHotStandby)
+ if (InStandbyMode() && !EnableHotStandby)
ereport(FATAL,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("logical replication slot \"%s\" exists on the standby, but \"hot_standby\" = \"off\"",
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 2cf8d55d706..2fdf03e33cb 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -397,9 +397,9 @@ extern void XLogRecGetBlockRefInfo(XLogReaderState *record, bool pretty,
* Exported for the functions in timeline.c and xlogarchive.c. Only valid
* in the startup process.
*/
-extern PGDLLIMPORT bool ArchiveRecoveryRequested;
-extern PGDLLIMPORT bool InArchiveRecovery;
-extern PGDLLIMPORT bool StandbyMode;
+extern PGDLLIMPORT bool ArchiveRecoveryRequested(void);
+extern PGDLLIMPORT bool InArchiveRecovery(void);
+extern PGDLLIMPORT bool InStandbyMode(void);
extern PGDLLIMPORT char *recoveryRestoreCommand;
#endif /* XLOG_INTERNAL_H */
diff --git a/src/include/access/xlogrecovery.h b/src/include/access/xlogrecovery.h
index 91446303024..2d44905ea36 100644
--- a/src/include/access/xlogrecovery.h
+++ b/src/include/access/xlogrecovery.h
@@ -16,6 +16,37 @@
#include "lib/stringinfo.h"
#include "utils/timestamp.h"
+/*
+ * The flag indicates if we allow hot standby queries to be run.
+ */
+#define SX_HOT_STANDBY_ACTIVE 0x01 /* SX: Startup Xlog */
+/*
+ * The flag indicates if a standby promotion has been triggered.
+ */
+#define SX_PROMOTE_IS_TRIGGERED 0x02
+/*
+ * When SX_ARCHIVE_RECOVERY_REQUESTED is set, archive recovery was requested,
+ * i.e. signal files were present. When SX_IN_ARCHIVE_RECOVERY is set, we are
+ * currently recovering using offline XLOG archives. These variables are only
+ * valid in the startup process.
+ *
+ * When SX_ARCHIVE_RECOVERY_REQUESTED is set, but SX_IN_ARCHIVE_RECOVERY is
+ * not, 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.
+ */
+#define SX_ARCHIVE_RECOVERY_REQUESTED 0x04
+#define SX_IN_ARCHIVE_RECOVERY 0x08
+/*
+ * When SX_STANDBY_MODE_REQUESTED is set, standby mode was requested, i.e.
+ * standby.signal file was present. When SX_IN_STANDBY_MODE is set, we are
+ * currently in standby mode. These variables are only valid in the startup
+ * process. They work similarly to SX_ARCHIVE_RECOVERY_REQUESTED and
+ * SX_IN_ARCHIVE_RECOVERY.
+ */
+#define SX_STANDBY_MODE_REQUESTED 0x10
+#define SX_IN_STANDBY_MODE 0x20
+
/*
* Recovery target type.
* Only set during a Point in Time recovery, not when in standby mode.
@@ -73,9 +104,6 @@ extern PGDLLIMPORT TimeLineID recoveryTargetTLI;
/* Have we already reached a consistent database state? */
extern PGDLLIMPORT bool reachedConsistency;
-/* Are we currently in standby mode? */
-extern PGDLLIMPORT bool StandbyMode;
-
extern Size XLogRecoveryShmemSize(void);
extern void XLogRecoveryShmemInit(void);
--
2.34.1