PostgreSQL Source Code git master
xlogrecovery.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <math.h>
#include <time.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/timeline.h"
#include "access/transam.h"
#include "access/xact.h"
#include "access/xlog_internal.h"
#include "access/xlogarchive.h"
#include "access/xlogprefetcher.h"
#include "access/xlogreader.h"
#include "access/xlogrecovery.h"
#include "access/xlogutils.h"
#include "access/xlogwait.h"
#include "backup/basebackup.h"
#include "catalog/pg_control.h"
#include "commands/tablespace.h"
#include "common/file_utils.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "pgstat.h"
#include "postmaster/bgwriter.h"
#include "postmaster/startup.h"
#include "replication/slot.h"
#include "replication/slotsync.h"
#include "replication/walreceiver.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/procarray.h"
#include "storage/spin.h"
#include "utils/datetime.h"
#include "utils/fmgrprotos.h"
#include "utils/guc_hooks.h"
#include "utils/pgstat_internal.h"
#include "utils/pg_lsn.h"
#include "utils/ps_status.h"
#include "utils/pg_rusage.h"
Include dependency graph for xlogrecovery.c:

Go to the source code of this file.

Data Structures

struct  XLogPageReadPrivate
 
struct  XLogRecoveryCtlData
 

Macros

#define RECOVERY_COMMAND_FILE   "recovery.conf"
 
#define RECOVERY_COMMAND_DONE   "recovery.done"
 

Typedefs

typedef struct XLogPageReadPrivate XLogPageReadPrivate
 
typedef struct XLogRecoveryCtlData XLogRecoveryCtlData
 

Enumerations

enum  XLogSource { XLOG_FROM_ANY = 0 , XLOG_FROM_ARCHIVE , XLOG_FROM_PG_WAL , XLOG_FROM_STREAM }
 

Functions

static void ApplyWalRecord (XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *replayTLI)
 
static void EnableStandbyMode (void)
 
static void readRecoverySignalFile (void)
 
static void validateRecoveryParameters (void)
 
static bool read_backup_label (XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, bool *backupEndRequired, bool *backupFromStandby)
 
static bool read_tablespace_map (List **tablespaces)
 
static void xlogrecovery_redo (XLogReaderState *record, TimeLineID replayTLI)
 
static void CheckRecoveryConsistency (void)
 
static void rm_redo_error_callback (void *arg)
 
static void xlog_block_info (StringInfo buf, XLogReaderState *record)
 
static void checkTimeLineSwitch (XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI, TimeLineID replayTLI)
 
static bool getRecordTimestamp (XLogReaderState *record, TimestampTz *recordXtime)
 
static void verifyBackupPageConsistency (XLogReaderState *record)
 
static bool recoveryStopsBefore (XLogReaderState *record)
 
static bool recoveryStopsAfter (XLogReaderState *record)
 
static char * getRecoveryStopReason (void)
 
static void recoveryPausesHere (bool endOfRecovery)
 
static bool recoveryApplyDelay (XLogReaderState *record)
 
static void ConfirmRecoveryPaused (void)
 
static XLogRecordReadRecord (XLogPrefetcher *xlogprefetcher, int emode, bool fetching_ckpt, TimeLineID replayTLI)
 
static int XLogPageRead (XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf)
 
static XLogPageReadResult WaitForWALToBecomeAvailable (XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr, TimeLineID replayTLI, XLogRecPtr replayLSN, bool nonblocking)
 
static int emode_for_corrupt_record (int emode, XLogRecPtr RecPtr)
 
static XLogRecordReadCheckpointRecord (XLogPrefetcher *xlogprefetcher, XLogRecPtr RecPtr, TimeLineID replayTLI)
 
static bool rescanLatestTimeLine (TimeLineID replayTLI, XLogRecPtr replayLSN)
 
static int XLogFileRead (XLogSegNo segno, TimeLineID tli, XLogSource source, bool notfoundOk)
 
static int XLogFileReadAnyTLI (XLogSegNo segno, XLogSource source)
 
static bool CheckForStandbyTrigger (void)
 
static void SetPromoteIsTriggered (void)
 
static bool HotStandbyActiveInReplay (void)
 
static void SetCurrentChunkStartTime (TimestampTz xtime)
 
static void SetLatestXTime (TimestampTz xtime)
 
Size XLogRecoveryShmemSize (void)
 
void XLogRecoveryShmemInit (void)
 
void InitWalRecovery (ControlFileData *ControlFile, bool *wasShutdown_ptr, bool *haveBackupLabel_ptr, bool *haveTblspcMap_ptr)
 
EndOfWalRecoveryInfoFinishWalRecovery (void)
 
void ShutdownWalRecovery (void)
 
void PerformWalRecovery (void)
 
static void CheckTablespaceDirectory (void)
 
void xlog_outdesc (StringInfo buf, XLogReaderState *record)
 
RecoveryPauseState GetRecoveryPauseState (void)
 
void SetRecoveryPause (bool recoveryPause)
 
void StartupRequestWalReceiverRestart (void)
 
bool PromoteIsTriggered (void)
 
void RemovePromoteSignalFiles (void)
 
bool CheckPromoteSignal (void)
 
void WakeupRecovery (void)
 
void XLogRequestWalReceiverReply (void)
 
bool HotStandbyActive (void)
 
XLogRecPtr GetXLogReplayRecPtr (TimeLineID *replayTLI)
 
XLogRecPtr GetCurrentReplayRecPtr (TimeLineID *replayEndTLI)
 
TimestampTz GetLatestXTime (void)
 
TimestampTz GetCurrentChunkReplayStartTime (void)
 
void GetXLogReceiptTime (TimestampTz *rtime, bool *fromStream)
 
void RecoveryRequiresIntParameter (const char *param_name, int currValue, int minValue)
 
bool check_primary_slot_name (char **newval, void **extra, GucSource source)
 
static pg_noreturn void error_multiple_recovery_targets (void)
 
bool check_recovery_target (char **newval, void **extra, GucSource source)
 
void assign_recovery_target (const char *newval, void *extra)
 
bool check_recovery_target_lsn (char **newval, void **extra, GucSource source)
 
void assign_recovery_target_lsn (const char *newval, void *extra)
 
bool check_recovery_target_name (char **newval, void **extra, GucSource source)
 
void assign_recovery_target_name (const char *newval, void *extra)
 
bool check_recovery_target_time (char **newval, void **extra, GucSource source)
 
void assign_recovery_target_time (const char *newval, void *extra)
 
bool check_recovery_target_timeline (char **newval, void **extra, GucSource source)
 
void assign_recovery_target_timeline (const char *newval, void *extra)
 
bool check_recovery_target_xid (char **newval, void **extra, GucSource source)
 
void assign_recovery_target_xid (const char *newval, void *extra)
 

Variables

const struct config_enum_entry recovery_target_action_options []
 
char * recoveryRestoreCommand = NULL
 
char * recoveryEndCommand = NULL
 
char * archiveCleanupCommand = NULL
 
RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET
 
bool recoveryTargetInclusive = true
 
int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE
 
TransactionId recoveryTargetXid
 
char * recovery_target_time_string
 
TimestampTz recoveryTargetTime
 
const char * recoveryTargetName
 
XLogRecPtr recoveryTargetLSN
 
int recovery_min_apply_delay = 0
 
char * PrimaryConnInfo = NULL
 
char * PrimarySlotName = NULL
 
bool wal_receiver_create_temp_slot = false
 
RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal = RECOVERY_TARGET_TIMELINE_LATEST
 
TimeLineID recoveryTargetTLIRequested = 0
 
TimeLineID recoveryTargetTLI = 0
 
static ListexpectedTLEs
 
static TimeLineID curFileTLI
 
bool ArchiveRecoveryRequested = false
 
bool InArchiveRecovery = false
 
static bool StandbyModeRequested = false
 
bool StandbyMode = false
 
static bool standby_signal_file_found = false
 
static bool recovery_signal_file_found = false
 
static XLogRecPtr CheckPointLoc = InvalidXLogRecPtr
 
static TimeLineID CheckPointTLI = 0
 
static XLogRecPtr RedoStartLSN = InvalidXLogRecPtr
 
static TimeLineID RedoStartTLI = 0
 
static bool LocalHotStandbyActive = false
 
static bool LocalPromoteIsTriggered = false
 
static bool doRequestWalReceiverReply
 
static XLogReaderStatexlogreader = NULL
 
static XLogPrefetcherxlogprefetcher = NULL
 
static bool InRedo = false
 
static const char *const xlogSourceNames [] = {"any", "archive", "pg_wal", "stream"}
 
static int readFile = -1
 
static XLogSegNo readSegNo = 0
 
static uint32 readOff = 0
 
static uint32 readLen = 0
 
static XLogSource readSource = XLOG_FROM_ANY
 
static XLogSource currentSource = XLOG_FROM_ANY
 
static bool lastSourceFailed = false
 
static bool pendingWalRcvRestart = false
 
static TimestampTz XLogReceiptTime = 0
 
static XLogSource XLogReceiptSource = XLOG_FROM_ANY
 
static XLogRecPtr flushedUpto = 0
 
static TimeLineID receiveTLI = 0
 
static XLogRecPtr minRecoveryPoint
 
static TimeLineID minRecoveryPointTLI
 
static XLogRecPtr backupStartPoint
 
static XLogRecPtr backupEndPoint
 
static bool backupEndRequired = false
 
bool reachedConsistency = false
 
static char * replay_image_masked = NULL
 
static char * primary_image_masked = NULL
 
static XLogRecoveryCtlDataXLogRecoveryCtl = NULL
 
static XLogRecPtr abortedRecPtr
 
static XLogRecPtr missingContrecPtr
 
static TransactionId recoveryStopXid
 
static TimestampTz recoveryStopTime
 
static XLogRecPtr recoveryStopLSN
 
static char recoveryStopName [MAXFNAMELEN]
 
static bool recoveryStopAfter
 

Macro Definition Documentation

◆ RECOVERY_COMMAND_DONE

#define RECOVERY_COMMAND_DONE   "recovery.done"

Definition at line 72 of file xlogrecovery.c.

◆ RECOVERY_COMMAND_FILE

#define RECOVERY_COMMAND_FILE   "recovery.conf"

Definition at line 71 of file xlogrecovery.c.

Typedef Documentation

◆ XLogPageReadPrivate

◆ XLogRecoveryCtlData

Enumeration Type Documentation

◆ XLogSource

enum XLogSource
Enumerator
XLOG_FROM_ANY 
XLOG_FROM_ARCHIVE 
XLOG_FROM_PG_WAL 
XLOG_FROM_STREAM 

Definition at line 212 of file xlogrecovery.c.

213{
214 XLOG_FROM_ANY = 0, /* request to read WAL from any source */
215 XLOG_FROM_ARCHIVE, /* restored using restore_command */
216 XLOG_FROM_PG_WAL, /* existing file in pg_wal */
217 XLOG_FROM_STREAM, /* streamed from primary */
218} XLogSource;
XLogSource
Definition: xlogrecovery.c:213
@ XLOG_FROM_PG_WAL
Definition: xlogrecovery.c:216
@ XLOG_FROM_STREAM
Definition: xlogrecovery.c:217
@ XLOG_FROM_ARCHIVE
Definition: xlogrecovery.c:215
@ XLOG_FROM_ANY
Definition: xlogrecovery.c:214

Function Documentation

◆ ApplyWalRecord()

static void ApplyWalRecord ( XLogReaderState xlogreader,
XLogRecord record,
TimeLineID replayTLI 
)
static

Definition at line 1930 of file xlogrecovery.c.

1931{
1932 ErrorContextCallback errcallback;
1933 bool switchedTLI = false;
1934
1935 /* Setup error traceback support for ereport() */
1936 errcallback.callback = rm_redo_error_callback;
1937 errcallback.arg = xlogreader;
1938 errcallback.previous = error_context_stack;
1939 error_context_stack = &errcallback;
1940
1941 /*
1942 * TransamVariables->nextXid must be beyond record's xid.
1943 */
1945
1946 /*
1947 * Before replaying this record, check if this record causes the current
1948 * timeline to change. The record is already considered to be part of the
1949 * new timeline, so we update replayTLI before replaying it. That's
1950 * important so that replayEndTLI, which is recorded as the minimum
1951 * recovery point's TLI if recovery stops after this record, is set
1952 * correctly.
1953 */
1954 if (record->xl_rmid == RM_XLOG_ID)
1955 {
1956 TimeLineID newReplayTLI = *replayTLI;
1957 TimeLineID prevReplayTLI = *replayTLI;
1958 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1959
1960 if (info == XLOG_CHECKPOINT_SHUTDOWN)
1961 {
1962 CheckPoint checkPoint;
1963
1964 memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
1965 newReplayTLI = checkPoint.ThisTimeLineID;
1966 prevReplayTLI = checkPoint.PrevTimeLineID;
1967 }
1968 else if (info == XLOG_END_OF_RECOVERY)
1969 {
1970 xl_end_of_recovery xlrec;
1971
1972 memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
1973 newReplayTLI = xlrec.ThisTimeLineID;
1974 prevReplayTLI = xlrec.PrevTimeLineID;
1975 }
1976
1977 if (newReplayTLI != *replayTLI)
1978 {
1979 /* Check that it's OK to switch to this TLI */
1981 newReplayTLI, prevReplayTLI, *replayTLI);
1982
1983 /* Following WAL records should be run with new TLI */
1984 *replayTLI = newReplayTLI;
1985 switchedTLI = true;
1986 }
1987 }
1988
1989 /*
1990 * Update shared replayEndRecPtr before replaying this record, so that
1991 * XLogFlush will update minRecoveryPoint correctly.
1992 */
1995 XLogRecoveryCtl->replayEndTLI = *replayTLI;
1997
1998 /*
1999 * If we are attempting to enter Hot Standby mode, process XIDs we see
2000 */
2004
2005 /*
2006 * Some XLOG record types that are related to recovery are processed
2007 * directly here, rather than in xlog_redo()
2008 */
2009 if (record->xl_rmid == RM_XLOG_ID)
2010 xlogrecovery_redo(xlogreader, *replayTLI);
2011
2012 /* Now apply the WAL record itself */
2014
2015 /*
2016 * After redo, check whether the backup pages associated with the WAL
2017 * record are consistent with the existing pages. This check is done only
2018 * if consistency check is enabled for this record.
2019 */
2020 if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
2022
2023 /* Pop the error context stack */
2024 error_context_stack = errcallback.previous;
2025
2026 /*
2027 * Update lastReplayedEndRecPtr after this record has been successfully
2028 * replayed.
2029 */
2033 XLogRecoveryCtl->lastReplayedTLI = *replayTLI;
2035
2036 /* ------
2037 * Wakeup walsenders:
2038 *
2039 * On the standby, the WAL is flushed first (which will only wake up
2040 * physical walsenders) and then applied, which will only wake up logical
2041 * walsenders.
2042 *
2043 * Indeed, logical walsenders on standby can't decode and send data until
2044 * it's been applied.
2045 *
2046 * Physical walsenders don't need to be woken up during replay unless
2047 * cascading replication is allowed and time line change occurred (so that
2048 * they can notice that they are on a new time line).
2049 *
2050 * That's why the wake up conditions are for:
2051 *
2052 * - physical walsenders in case of new time line and cascade
2053 * replication is allowed
2054 * - logical walsenders in case cascade replication is allowed (could not
2055 * be created otherwise)
2056 * ------
2057 */
2059 WalSndWakeup(switchedTLI, true);
2060
2061 /*
2062 * If rm_redo called XLogRequestWalReceiverReply, then we wake up the
2063 * receiver so that it notices the updated lastReplayedEndRecPtr and sends
2064 * a reply to the primary.
2065 */
2067 {
2070 }
2071
2072 /* Allow read-only connections if we're consistent now */
2074
2075 /* Is this a timeline switch? */
2076 if (switchedTLI)
2077 {
2078 /*
2079 * Before we continue on the new timeline, clean up any (possibly
2080 * bogus) future WAL segments on the old timeline.
2081 */
2083
2084 /* Reset the prefetcher. */
2086 }
2087}
uint8_t uint8
Definition: c.h:539
ErrorContextCallback * error_context_stack
Definition: elog.c:95
#define XLOG_CHECKPOINT_SHUTDOWN
Definition: pg_control.h:68
#define XLOG_END_OF_RECOVERY
Definition: pg_control.h:77
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4365
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
TimeLineID PrevTimeLineID
Definition: pg_control.h:40
TimeLineID ThisTimeLineID
Definition: pg_control.h:39
struct ErrorContextCallback * previous
Definition: elog.h:297
void(* callback)(void *arg)
Definition: elog.h:298
void(* rm_redo)(XLogReaderState *record)
XLogRecPtr EndRecPtr
Definition: xlogreader.h:206
XLogRecPtr ReadRecPtr
Definition: xlogreader.h:205
uint8 xl_info
Definition: xlogrecord.h:46
TransactionId xl_xid
Definition: xlogrecord.h:44
RmgrId xl_rmid
Definition: xlogrecord.h:47
XLogRecPtr lastReplayedEndRecPtr
Definition: xlogrecovery.c:347
TimeLineID replayEndTLI
Definition: xlogrecovery.c:356
TimeLineID lastReplayedTLI
Definition: xlogrecovery.c:348
XLogRecPtr replayEndRecPtr
Definition: xlogrecovery.c:355
XLogRecPtr lastReplayedReadRecPtr
Definition: xlogrecovery.c:346
TimeLineID PrevTimeLineID
TimeLineID ThisTimeLineID
#define TransactionIdIsValid(xid)
Definition: transam.h:41
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:304
void WalRcvForceReply(void)
Definition: walreceiver.c:1350
#define AllowCascadeReplication()
Definition: walreceiver.h:40
void WalSndWakeup(bool physical, bool logical)
Definition: walsender.c:3793
void RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
Definition: xlog.c:3959
static RmgrData GetRmgr(RmgrId rmid)
uint32 TimeLineID
Definition: xlogdefs.h:63
void XLogPrefetchReconfigure(void)
#define XLogRecGetData(decoder)
Definition: xlogreader.h:414
#define XLR_CHECK_CONSISTENCY
Definition: xlogrecord.h:91
static void rm_redo_error_callback(void *arg)
static void xlogrecovery_redo(XLogReaderState *record, TimeLineID replayTLI)
static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI, TimeLineID replayTLI)
static void CheckRecoveryConsistency(void)
static void verifyBackupPageConsistency(XLogReaderState *record)
static XLogRecoveryCtlData * XLogRecoveryCtl
Definition: xlogrecovery.c:372
static bool doRequestWalReceiverReply
Definition: xlogrecovery.c:188
static XLogReaderState * xlogreader
Definition: xlogrecovery.c:191
HotStandbyState standbyState
Definition: xlogutils.c:53
@ STANDBY_INITIALIZED
Definition: xlogutils.h:53

References AdvanceNextFullTransactionIdPastXid(), AllowCascadeReplication, ErrorContextCallback::arg, ErrorContextCallback::callback, CheckRecoveryConsistency(), checkTimeLineSwitch(), doRequestWalReceiverReply, XLogReaderState::EndRecPtr, error_context_stack, GetRmgr(), XLogRecoveryCtlData::info_lck, XLogRecoveryCtlData::lastReplayedEndRecPtr, XLogRecoveryCtlData::lastReplayedReadRecPtr, XLogRecoveryCtlData::lastReplayedTLI, ErrorContextCallback::previous, xl_end_of_recovery::PrevTimeLineID, CheckPoint::PrevTimeLineID, XLogReaderState::ReadRecPtr, RecordKnownAssignedTransactionIds(), RemoveNonParentXlogFiles(), XLogRecoveryCtlData::replayEndRecPtr, XLogRecoveryCtlData::replayEndTLI, RmgrData::rm_redo, rm_redo_error_callback(), SpinLockAcquire, SpinLockRelease, STANDBY_INITIALIZED, standbyState, xl_end_of_recovery::ThisTimeLineID, CheckPoint::ThisTimeLineID, TransactionIdIsValid, verifyBackupPageConsistency(), WalRcvForceReply(), WalSndWakeup(), XLogRecord::xl_info, XLogRecord::xl_rmid, XLogRecord::xl_xid, XLOG_CHECKPOINT_SHUTDOWN, XLOG_END_OF_RECOVERY, XLogPrefetchReconfigure(), xlogreader, XLogRecGetData, xlogrecovery_redo(), XLogRecoveryCtl, and XLR_CHECK_CONSISTENCY.

Referenced by PerformWalRecovery().

◆ assign_recovery_target()

void assign_recovery_target ( const char *  newval,
void *  extra 
)

Definition at line 4861 of file xlogrecovery.c.

4862{
4866
4867 if (newval && strcmp(newval, "") != 0)
4869 else
4871}
#define newval
RecoveryTargetType recoveryTarget
Definition: xlogrecovery.c:88
static pg_noreturn void error_multiple_recovery_targets(void)
@ RECOVERY_TARGET_IMMEDIATE
Definition: xlogrecovery.h:30
@ RECOVERY_TARGET_UNSET
Definition: xlogrecovery.h:25

References error_multiple_recovery_targets(), newval, RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_UNSET, and recoveryTarget.

◆ assign_recovery_target_lsn()

void assign_recovery_target_lsn ( const char *  newval,
void *  extra 
)

Definition at line 4902 of file xlogrecovery.c.

4903{
4907
4908 if (newval && strcmp(newval, "") != 0)
4909 {
4911 recoveryTargetLSN = *((XLogRecPtr *) extra);
4912 }
4913 else
4915}
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr recoveryTargetLSN
Definition: xlogrecovery.c:95
@ RECOVERY_TARGET_LSN
Definition: xlogrecovery.h:29

References error_multiple_recovery_targets(), newval, RECOVERY_TARGET_LSN, RECOVERY_TARGET_UNSET, recoveryTarget, and recoveryTargetLSN.

◆ assign_recovery_target_name()

void assign_recovery_target_name ( const char *  newval,
void *  extra 
)

Definition at line 4937 of file xlogrecovery.c.

4938{
4942
4943 if (newval && strcmp(newval, "") != 0)
4944 {
4947 }
4948 else
4950}
const char * recoveryTargetName
Definition: xlogrecovery.c:94
@ RECOVERY_TARGET_NAME
Definition: xlogrecovery.h:28

References error_multiple_recovery_targets(), newval, RECOVERY_TARGET_NAME, RECOVERY_TARGET_UNSET, recoveryTarget, and recoveryTargetName.

◆ assign_recovery_target_time()

void assign_recovery_target_time ( const char *  newval,
void *  extra 
)

◆ assign_recovery_target_timeline()

void assign_recovery_target_timeline ( const char *  newval,
void *  extra 
)

Definition at line 5080 of file xlogrecovery.c.

5081{
5084 recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
5085 else
5087}
RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal
Definition: xlogrecovery.c:123
TimeLineID recoveryTargetTLIRequested
Definition: xlogrecovery.c:124
RecoveryTargetTimeLineGoal
Definition: xlogrecovery.h:37
@ RECOVERY_TARGET_TIMELINE_NUMERIC
Definition: xlogrecovery.h:40

References newval, RECOVERY_TARGET_TIMELINE_NUMERIC, recoveryTargetTimeLineGoal, and recoveryTargetTLIRequested.

◆ assign_recovery_target_xid()

void assign_recovery_target_xid ( const char *  newval,
void *  extra 
)

Definition at line 5118 of file xlogrecovery.c.

5119{
5123
5124 if (newval && strcmp(newval, "") != 0)
5125 {
5127 recoveryTargetXid = *((TransactionId *) extra);
5128 }
5129 else
5131}
uint32 TransactionId
Definition: c.h:660
TransactionId recoveryTargetXid
Definition: xlogrecovery.c:91
@ RECOVERY_TARGET_XID
Definition: xlogrecovery.h:26

References error_multiple_recovery_targets(), newval, RECOVERY_TARGET_UNSET, RECOVERY_TARGET_XID, recoveryTarget, and recoveryTargetXid.

◆ check_primary_slot_name()

bool check_primary_slot_name ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 4796 of file xlogrecovery.c.

4797{
4798 int err_code;
4799 char *err_msg = NULL;
4800 char *err_hint = NULL;
4801
4802 if (*newval && strcmp(*newval, "") != 0 &&
4803 !ReplicationSlotValidateNameInternal(*newval, false, &err_code,
4804 &err_msg, &err_hint))
4805 {
4806 GUC_check_errcode(err_code);
4807 GUC_check_errdetail("%s", err_msg);
4808 if (err_hint != NULL)
4809 GUC_check_errhint("%s", err_hint);
4810 return false;
4811 }
4812
4813 return true;
4814}
void GUC_check_errcode(int sqlerrcode)
Definition: guc.c:6628
#define GUC_check_errdetail
Definition: guc.h:505
#define GUC_check_errhint
Definition: guc.h:509
bool ReplicationSlotValidateNameInternal(const char *name, bool allow_reserved_name, int *err_code, char **err_msg, char **err_hint)
Definition: slot.c:311

References GUC_check_errcode(), GUC_check_errdetail, GUC_check_errhint, newval, and ReplicationSlotValidateNameInternal().

◆ check_recovery_target()

bool check_recovery_target ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 4847 of file xlogrecovery.c.

4848{
4849 if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
4850 {
4851 GUC_check_errdetail("The only allowed value is \"immediate\".");
4852 return false;
4853 }
4854 return true;
4855}

References GUC_check_errdetail, and newval.

◆ check_recovery_target_lsn()

bool check_recovery_target_lsn ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 4877 of file xlogrecovery.c.

4878{
4879 if (strcmp(*newval, "") != 0)
4880 {
4881 XLogRecPtr lsn;
4882 XLogRecPtr *myextra;
4883 ErrorSaveContext escontext = {T_ErrorSaveContext};
4884
4885 lsn = pg_lsn_in_safe(*newval, (Node *) &escontext);
4886 if (escontext.error_occurred)
4887 return false;
4888
4889 myextra = (XLogRecPtr *) guc_malloc(LOG, sizeof(XLogRecPtr));
4890 if (!myextra)
4891 return false;
4892 *myextra = lsn;
4893 *extra = myextra;
4894 }
4895 return true;
4896}
#define LOG
Definition: elog.h:31
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:636
XLogRecPtr pg_lsn_in_safe(const char *str, Node *escontext)
Definition: pg_lsn.c:32
bool error_occurred
Definition: miscnodes.h:47
Definition: nodes.h:135

References ErrorSaveContext::error_occurred, guc_malloc(), LOG, newval, and pg_lsn_in_safe().

◆ check_recovery_target_name()

bool check_recovery_target_name ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 4921 of file xlogrecovery.c.

4922{
4923 /* Use the value of newval directly */
4924 if (strlen(*newval) >= MAXFNAMELEN)
4925 {
4926 GUC_check_errdetail("\"%s\" is too long (maximum %d characters).",
4927 "recovery_target_name", MAXFNAMELEN - 1);
4928 return false;
4929 }
4930 return true;
4931}
#define MAXFNAMELEN

References GUC_check_errdetail, MAXFNAMELEN, and newval.

◆ check_recovery_target_time()

bool check_recovery_target_time ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 4962 of file xlogrecovery.c.

4963{
4964 if (strcmp(*newval, "") != 0)
4965 {
4966 /* reject some special values */
4967 if (strcmp(*newval, "now") == 0 ||
4968 strcmp(*newval, "today") == 0 ||
4969 strcmp(*newval, "tomorrow") == 0 ||
4970 strcmp(*newval, "yesterday") == 0)
4971 {
4972 return false;
4973 }
4974
4975 /*
4976 * parse timestamp value (see also timestamptz_in())
4977 */
4978 {
4979 char *str = *newval;
4980 fsec_t fsec;
4981 struct pg_tm tt,
4982 *tm = &tt;
4983 int tz;
4984 int dtype;
4985 int nf;
4986 int dterr;
4987 char *field[MAXDATEFIELDS];
4988 int ftype[MAXDATEFIELDS];
4989 char workbuf[MAXDATELEN + MAXDATEFIELDS];
4990 DateTimeErrorExtra dtextra;
4992
4993 dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
4994 field, ftype, MAXDATEFIELDS, &nf);
4995 if (dterr == 0)
4996 dterr = DecodeDateTime(field, ftype, nf,
4997 &dtype, tm, &fsec, &tz, &dtextra);
4998 if (dterr != 0)
4999 return false;
5000 if (dtype != DTK_DATE)
5001 return false;
5002
5003 if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
5004 {
5005 GUC_check_errdetail("Timestamp out of range: \"%s\".", str);
5006 return false;
5007 }
5008 }
5009 }
5010 return true;
5011}
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:773
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, DateTimeErrorExtra *extra)
Definition: datetime.c:997
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:2006
int64 TimestampTz
Definition: timestamp.h:39
int32 fsec_t
Definition: timestamp.h:41
const char * str
#define MAXDATEFIELDS
Definition: datetime.h:202
#define DTK_DATE
Definition: datetime.h:144
#define MAXDATELEN
Definition: datetime.h:200
static struct pg_tm tm
Definition: localtime.c:104
int64 timestamp
Definition: pgtime.h:35

References DecodeDateTime(), DTK_DATE, GUC_check_errdetail, MAXDATEFIELDS, MAXDATELEN, newval, ParseDateTime(), str, tm, and tm2timestamp().

◆ check_recovery_target_timeline()

bool check_recovery_target_timeline ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 5033 of file xlogrecovery.c.

5034{
5037
5038 if (strcmp(*newval, "current") == 0)
5040 else if (strcmp(*newval, "latest") == 0)
5042 else
5043 {
5044 char *endp;
5045 uint64 timeline;
5046
5048
5049 errno = 0;
5050 timeline = strtou64(*newval, &endp, 0);
5051
5052 if (*endp != '\0' || errno == EINVAL || errno == ERANGE)
5053 {
5054 GUC_check_errdetail("\"%s\" is not a valid number.",
5055 "recovery_target_timeline");
5056 return false;
5057 }
5058
5059 if (timeline < 1 || timeline > PG_UINT32_MAX)
5060 {
5061 GUC_check_errdetail("\"%s\" must be between %u and %u.",
5062 "recovery_target_timeline", 1, UINT_MAX);
5063 return false;
5064 }
5065 }
5066
5068 if (!myextra)
5069 return false;
5070 *myextra = rttg;
5071 *extra = myextra;
5072
5073 return true;
5074}
#define PG_UINT32_MAX
Definition: c.h:598
uint64_t uint64
Definition: c.h:542
@ RECOVERY_TARGET_TIMELINE_CONTROLFILE
Definition: xlogrecovery.h:38
@ RECOVERY_TARGET_TIMELINE_LATEST
Definition: xlogrecovery.h:39

References GUC_check_errdetail, guc_malloc(), LOG, newval, PG_UINT32_MAX, RECOVERY_TARGET_TIMELINE_CONTROLFILE, RECOVERY_TARGET_TIMELINE_LATEST, and RECOVERY_TARGET_TIMELINE_NUMERIC.

◆ check_recovery_target_xid()

bool check_recovery_target_xid ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 5093 of file xlogrecovery.c.

5094{
5095 if (strcmp(*newval, "") != 0)
5096 {
5097 TransactionId xid;
5098 TransactionId *myextra;
5099
5100 errno = 0;
5101 xid = (TransactionId) strtou64(*newval, NULL, 0);
5102 if (errno == EINVAL || errno == ERANGE)
5103 return false;
5104
5105 myextra = (TransactionId *) guc_malloc(LOG, sizeof(TransactionId));
5106 if (!myextra)
5107 return false;
5108 *myextra = xid;
5109 *extra = myextra;
5110 }
5111 return true;
5112}

References guc_malloc(), LOG, and newval.

◆ CheckForStandbyTrigger()

static bool CheckForStandbyTrigger ( void  )
static

Definition at line 4489 of file xlogrecovery.c.

4490{
4492 return true;
4493
4495 {
4496 ereport(LOG, (errmsg("received promote request")));
4500 return true;
4501 }
4502
4503 return false;
4504}
bool IsPromoteSignaled(void)
Definition: startup.c:288
void ResetPromoteSignaled(void)
Definition: startup.c:294
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ereport(elevel,...)
Definition: elog.h:150
bool CheckPromoteSignal(void)
static bool LocalPromoteIsTriggered
Definition: xlogrecovery.c:185
static void SetPromoteIsTriggered(void)
void RemovePromoteSignalFiles(void)

References CheckPromoteSignal(), ereport, errmsg(), IsPromoteSignaled(), LocalPromoteIsTriggered, LOG, RemovePromoteSignalFiles(), ResetPromoteSignaled(), and SetPromoteIsTriggered().

Referenced by ReadRecord(), recoveryApplyDelay(), recoveryPausesHere(), RecoveryRequiresIntParameter(), and WaitForWALToBecomeAvailable().

◆ CheckPromoteSignal()

bool CheckPromoteSignal ( void  )

Definition at line 4519 of file xlogrecovery.c.

4520{
4521 struct stat stat_buf;
4522
4523 if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
4524 return true;
4525
4526 return false;
4527}
#define stat
Definition: win32_port.h:274
#define PROMOTE_SIGNAL_FILE
Definition: xlog.h:312

References PROMOTE_SIGNAL_FILE, and stat.

Referenced by CheckForStandbyTrigger(), and process_pm_pmsignal().

◆ CheckRecoveryConsistency()

static void CheckRecoveryConsistency ( void  )
static

Definition at line 2198 of file xlogrecovery.c.

2199{
2200 XLogRecPtr lastReplayedEndRecPtr;
2201 TimeLineID lastReplayedTLI;
2202
2203 /*
2204 * During crash recovery, we don't reach a consistent state until we've
2205 * replayed all the WAL.
2206 */
2208 return;
2209
2211
2212 /*
2213 * assume that we are called in the startup process, and hence don't need
2214 * a lock to read lastReplayedEndRecPtr
2215 */
2216 lastReplayedEndRecPtr = XLogRecoveryCtl->lastReplayedEndRecPtr;
2217 lastReplayedTLI = XLogRecoveryCtl->lastReplayedTLI;
2218
2219 /*
2220 * Have we reached the point where our base backup was completed?
2221 */
2223 backupEndPoint <= lastReplayedEndRecPtr)
2224 {
2225 XLogRecPtr saveBackupStartPoint = backupStartPoint;
2226 XLogRecPtr saveBackupEndPoint = backupEndPoint;
2227
2228 elog(DEBUG1, "end of backup reached");
2229
2230 /*
2231 * We have reached the end of base backup, as indicated by pg_control.
2232 * Update the control file accordingly.
2233 */
2234 ReachedEndOfBackup(lastReplayedEndRecPtr, lastReplayedTLI);
2237 backupEndRequired = false;
2238
2239 ereport(LOG,
2240 errmsg("completed backup recovery with redo LSN %X/%08X and end LSN %X/%08X",
2241 LSN_FORMAT_ARGS(saveBackupStartPoint),
2242 LSN_FORMAT_ARGS(saveBackupEndPoint)));
2243 }
2244
2245 /*
2246 * Have we passed our safe starting point? Note that minRecoveryPoint is
2247 * known to be incorrectly set if recovering from a backup, until the
2248 * XLOG_BACKUP_END arrives to advise us of the correct minRecoveryPoint.
2249 * All we know prior to that is that we're not consistent yet.
2250 */
2252 minRecoveryPoint <= lastReplayedEndRecPtr)
2253 {
2254 /*
2255 * Check to see if the XLOG sequence contained any unresolved
2256 * references to uninitialized pages.
2257 */
2259
2260 /*
2261 * Check that pg_tblspc doesn't contain any real directories. Replay
2262 * of Database/CREATE_* records may have created fictitious tablespace
2263 * directories that should have been removed by the time consistency
2264 * was reached.
2265 */
2267
2268 reachedConsistency = true;
2270 ereport(LOG,
2271 errmsg("consistent recovery state reached at %X/%08X",
2272 LSN_FORMAT_ARGS(lastReplayedEndRecPtr)));
2273 }
2274
2275 /*
2276 * Have we got a valid starting snapshot that will allow queries to be
2277 * run? If so, we can tell postmaster that the database is consistent now,
2278 * enabling connections.
2279 */
2284 {
2288
2289 LocalHotStandbyActive = true;
2290
2292 }
2293}
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:226
bool IsUnderPostmaster
Definition: globals.c:120
Assert(PointerIsAligned(start, uint64))
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:165
@ PMSIGNAL_BEGIN_HOT_STANDBY
Definition: pmsignal.h:37
@ PMSIGNAL_RECOVERY_CONSISTENT
Definition: pmsignal.h:36
void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli)
Definition: xlog.c:6319
#define XLogRecPtrIsValid(r)
Definition: xlogdefs.h:29
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:47
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
bool reachedConsistency
Definition: xlogrecovery.c:302
static bool backupEndRequired
Definition: xlogrecovery.c:286
static XLogRecPtr minRecoveryPoint
Definition: xlogrecovery.c:281
static XLogRecPtr backupEndPoint
Definition: xlogrecovery.c:285
bool InArchiveRecovery
Definition: xlogrecovery.c:141
static bool LocalHotStandbyActive
Definition: xlogrecovery.c:179
static void CheckTablespaceDirectory(void)
static XLogRecPtr backupStartPoint
Definition: xlogrecovery.c:284
void XLogCheckInvalidPages(void)
Definition: xlogutils.c:234
@ STANDBY_SNAPSHOT_READY
Definition: xlogutils.h:55

References Assert(), backupEndPoint, backupEndRequired, backupStartPoint, CheckTablespaceDirectory(), DEBUG1, elog, ereport, errmsg(), InArchiveRecovery, XLogRecoveryCtlData::info_lck, InvalidXLogRecPtr, IsUnderPostmaster, XLogRecoveryCtlData::lastReplayedEndRecPtr, XLogRecoveryCtlData::lastReplayedTLI, LocalHotStandbyActive, LOG, LSN_FORMAT_ARGS, minRecoveryPoint, PMSIGNAL_BEGIN_HOT_STANDBY, PMSIGNAL_RECOVERY_CONSISTENT, reachedConsistency, ReachedEndOfBackup(), SendPostmasterSignal(), XLogRecoveryCtlData::SharedHotStandbyActive, SpinLockAcquire, SpinLockRelease, STANDBY_SNAPSHOT_READY, standbyState, XLogCheckInvalidPages(), XLogRecoveryCtl, and XLogRecPtrIsValid.

Referenced by ApplyWalRecord(), PerformWalRecovery(), and ReadRecord().

◆ CheckTablespaceDirectory()

static void CheckTablespaceDirectory ( void  )
static

Definition at line 2165 of file xlogrecovery.c.

2166{
2167 DIR *dir;
2168 struct dirent *de;
2169
2171 while ((de = ReadDir(dir, PG_TBLSPC_DIR)) != NULL)
2172 {
2173 char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR)];
2174
2175 /* Skip entries of non-oid names */
2176 if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
2177 continue;
2178
2179 snprintf(path, sizeof(path), "%s/%s", PG_TBLSPC_DIR, de->d_name);
2180
2181 if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
2184 errmsg("unexpected directory entry \"%s\" found in %s",
2185 de->d_name, PG_TBLSPC_DIR),
2186 errdetail("All directory entries in %s/ should be symbolic links.",
2188 errhint("Remove those directories, or set \"allow_in_place_tablespaces\" to ON transiently to let recovery complete.")));
2189 }
2190}
bool allow_in_place_tablespaces
Definition: tablespace.c:85
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errhint(const char *fmt,...)
Definition: elog.c:1330
int errcode(int sqlerrcode)
Definition: elog.c:863
#define WARNING
Definition: elog.h:36
#define PANIC
Definition: elog.h:42
#define ERROR
Definition: elog.h:39
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2904
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2970
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:547
@ PGFILETYPE_LNK
Definition: file_utils.h:24
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:42
#define MAXPGPATH
#define snprintf
Definition: port.h:260
#define PG_TBLSPC_DIR
Definition: relpath.h:41
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References AllocateDir(), allow_in_place_tablespaces, dirent::d_name, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errdetail(), errhint(), errmsg(), ERROR, get_dirent_type(), MAXPGPATH, PANIC, PG_TBLSPC_DIR, PGFILETYPE_LNK, ReadDir(), snprintf, and WARNING.

Referenced by CheckRecoveryConsistency().

◆ checkTimeLineSwitch()

static void checkTimeLineSwitch ( XLogRecPtr  lsn,
TimeLineID  newTLI,
TimeLineID  prevTLI,
TimeLineID  replayTLI 
)
static

Definition at line 2401 of file xlogrecovery.c.

2403{
2404 /* Check that the record agrees on what the current (old) timeline is */
2405 if (prevTLI != replayTLI)
2406 ereport(PANIC,
2407 (errmsg("unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record",
2408 prevTLI, replayTLI)));
2409
2410 /*
2411 * The new timeline better be in the list of timelines we expect to see,
2412 * according to the timeline history. It should also not decrease.
2413 */
2414 if (newTLI < replayTLI || !tliInHistory(newTLI, expectedTLEs))
2415 ereport(PANIC,
2416 (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
2417 newTLI, replayTLI)));
2418
2419 /*
2420 * If we have not yet reached min recovery point, and we're about to
2421 * switch to a timeline greater than the timeline of the min recovery
2422 * point: trouble. After switching to the new timeline, we could not
2423 * possibly visit the min recovery point on the correct timeline anymore.
2424 * This can happen if there is a newer timeline in the archive that
2425 * branched before the timeline the min recovery point is on, and you
2426 * attempt to do PITR to the new timeline.
2427 */
2429 lsn < minRecoveryPoint &&
2430 newTLI > minRecoveryPointTLI)
2431 ereport(PANIC,
2432 errmsg("unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%08X on timeline %u",
2433 newTLI,
2436
2437 /* Looks good */
2438}
bool tliInHistory(TimeLineID tli, List *expectedTLEs)
Definition: timeline.c:526
static List * expectedTLEs
Definition: xlogrecovery.c:126
static TimeLineID minRecoveryPointTLI
Definition: xlogrecovery.c:282

References ereport, errmsg(), expectedTLEs, LSN_FORMAT_ARGS, minRecoveryPoint, minRecoveryPointTLI, PANIC, tliInHistory(), and XLogRecPtrIsValid.

Referenced by ApplyWalRecord().

◆ ConfirmRecoveryPaused()

static void ConfirmRecoveryPaused ( void  )
static

◆ emode_for_corrupt_record()

static int emode_for_corrupt_record ( int  emode,
XLogRecPtr  RecPtr 
)
static

Definition at line 4088 of file xlogrecovery.c.

4089{
4090 static XLogRecPtr lastComplaint = 0;
4091
4092 if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
4093 {
4094 if (RecPtr == lastComplaint)
4095 emode = DEBUG1;
4096 else
4097 lastComplaint = RecPtr;
4098 }
4099 return emode;
4100}
static XLogSource readSource
Definition: xlogrecovery.c:237

References DEBUG1, LOG, readSource, and XLOG_FROM_PG_WAL.

Referenced by ReadRecord(), and XLogPageRead().

◆ EnableStandbyMode()

static void EnableStandbyMode ( void  )
static

Definition at line 486 of file xlogrecovery.c.

487{
488 StandbyMode = true;
489
490 /*
491 * To avoid server log bloat, we don't report recovery progress in a
492 * standby as it will always be in recovery unless promoted. We disable
493 * startup progress timeout in standby mode to avoid calling
494 * startup_progress_timeout_handler() unnecessarily.
495 */
497}
void disable_startup_progress_timeout(void)
Definition: startup.c:309
bool StandbyMode
Definition: xlogrecovery.c:150

References disable_startup_progress_timeout(), and StandbyMode.

Referenced by InitWalRecovery(), and ReadRecord().

◆ error_multiple_recovery_targets()

static pg_noreturn void error_multiple_recovery_targets ( void  )
static

Definition at line 4835 of file xlogrecovery.c.

4836{
4837 ereport(ERROR,
4838 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4839 errmsg("multiple recovery targets specified"),
4840 errdetail("At most one of \"recovery_target\", \"recovery_target_lsn\", \"recovery_target_name\", \"recovery_target_time\", \"recovery_target_xid\" may be set.")));
4841}

References ereport, errcode(), errdetail(), errmsg(), and ERROR.

Referenced by assign_recovery_target(), assign_recovery_target_lsn(), assign_recovery_target_name(), assign_recovery_target_time(), and assign_recovery_target_xid().

◆ FinishWalRecovery()

EndOfWalRecoveryInfo * FinishWalRecovery ( void  )

Definition at line 1468 of file xlogrecovery.c.

1469{
1471 XLogRecPtr lastRec;
1472 TimeLineID lastRecTLI;
1473 XLogRecPtr endOfLog;
1474
1475 /*
1476 * Kill WAL receiver, if it's still running, before we continue to write
1477 * the startup checkpoint and aborted-contrecord records. It will trump
1478 * over these records and subsequent ones if it's still alive when we
1479 * start writing WAL.
1480 */
1482
1483 /*
1484 * Shutdown the slot sync worker to drop any temporary slots acquired by
1485 * it and to prevent it from keep trying to fetch the failover slots.
1486 *
1487 * We do not update the 'synced' column in 'pg_replication_slots' system
1488 * view from true to false here, as any failed update could leave 'synced'
1489 * column false for some slots. This could cause issues during slot sync
1490 * after restarting the server as a standby. While updating the 'synced'
1491 * column after switching to the new timeline is an option, it does not
1492 * simplify the handling for the 'synced' column. Therefore, we retain the
1493 * 'synced' column as true after promotion as it may provide useful
1494 * information about the slot origin.
1495 */
1497
1498 /*
1499 * We are now done reading the xlog from stream. Turn off streaming
1500 * recovery to force fetching the files (which would be required at end of
1501 * recovery, e.g., timeline history file) from archive or pg_wal.
1502 *
1503 * Note that standby mode must be turned off after killing WAL receiver,
1504 * i.e., calling XLogShutdownWalRcv().
1505 */
1507 StandbyMode = false;
1508
1509 /*
1510 * Determine where to start writing WAL next.
1511 *
1512 * Re-fetch the last valid or last applied record, so we can identify the
1513 * exact endpoint of what we consider the valid portion of WAL. There may
1514 * be an incomplete continuation record after that, in which case
1515 * 'abortedRecPtr' and 'missingContrecPtr' are set and the caller will
1516 * write a special OVERWRITE_CONTRECORD message to mark that the rest of
1517 * it is intentionally missing. See CreateOverwriteContrecordRecord().
1518 *
1519 * An important side-effect of this is to load the last page into
1520 * xlogreader. The caller uses it to initialize the WAL for writing.
1521 */
1522 if (!InRecovery)
1523 {
1524 lastRec = CheckPointLoc;
1525 lastRecTLI = CheckPointTLI;
1526 }
1527 else
1528 {
1530 lastRecTLI = XLogRecoveryCtl->lastReplayedTLI;
1531 }
1533 (void) ReadRecord(xlogprefetcher, PANIC, false, lastRecTLI);
1534 endOfLog = xlogreader->EndRecPtr;
1535
1536 /*
1537 * Remember the TLI in the filename of the XLOG segment containing the
1538 * end-of-log. It could be different from the timeline that endOfLog
1539 * nominally belongs to, if there was a timeline switch in that segment,
1540 * and we were reading the old WAL from a segment belonging to a higher
1541 * timeline.
1542 */
1543 result->endOfLogTLI = xlogreader->seg.ws_tli;
1544
1546 {
1547 /*
1548 * We are no longer in archive recovery state.
1549 *
1550 * We are now done reading the old WAL. Turn off archive fetching if
1551 * it was active.
1552 */
1554 InArchiveRecovery = false;
1555
1556 /*
1557 * If the ending log segment is still open, close it (to avoid
1558 * problems on Windows with trying to rename or delete an open file).
1559 */
1560 if (readFile >= 0)
1561 {
1562 close(readFile);
1563 readFile = -1;
1564 }
1565 }
1566
1567 /*
1568 * Copy the last partial block to the caller, for initializing the WAL
1569 * buffer for appending new WAL.
1570 */
1571 if (endOfLog % XLOG_BLCKSZ != 0)
1572 {
1573 char *page;
1574 int len;
1575 XLogRecPtr pageBeginPtr;
1576
1577 pageBeginPtr = endOfLog - (endOfLog % XLOG_BLCKSZ);
1579
1580 /* Copy the valid part of the last block */
1581 len = endOfLog % XLOG_BLCKSZ;
1582 page = palloc(len);
1583 memcpy(page, xlogreader->readBuf, len);
1584
1585 result->lastPageBeginPtr = pageBeginPtr;
1586 result->lastPage = page;
1587 }
1588 else
1589 {
1590 /* There is no partial block to copy. */
1591 result->lastPageBeginPtr = endOfLog;
1592 result->lastPage = NULL;
1593 }
1594
1595 /*
1596 * Create a comment for the history file to explain why and where timeline
1597 * changed.
1598 */
1600
1601 result->lastRec = lastRec;
1602 result->lastRecTLI = lastRecTLI;
1603 result->endOfLog = endOfLog;
1604
1605 result->abortedRecPtr = abortedRecPtr;
1607
1610
1611 return result;
1612}
#define close(a)
Definition: win32.h:12
void * palloc(Size size)
Definition: mcxt.c:1365
const void size_t len
void ShutDownSlotSync(void)
Definition: slotsync.c:1660
XLogRecPtr lastPageBeginPtr
Definition: xlogrecovery.h:121
XLogRecPtr abortedRecPtr
Definition: xlogrecovery.h:130
XLogRecPtr missingContrecPtr
Definition: xlogrecovery.h:131
TimeLineID endOfLogTLI
Definition: xlogrecovery.h:119
TimeLineID ws_tli
Definition: xlogreader.h:49
WALOpenSegment seg
Definition: xlogreader.h:271
bool WalRcvStreaming(void)
int wal_segment_size
Definition: xlog.c:145
void XLogShutdownWalRcv(void)
Definition: xlog.c:9537
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
void XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
static char * getRecoveryStopReason(void)
bool ArchiveRecoveryRequested
Definition: xlogrecovery.c:140
static XLogRecPtr missingContrecPtr
Definition: xlogrecovery.c:381
static uint32 readOff
Definition: xlogrecovery.c:235
static bool standby_signal_file_found
Definition: xlogrecovery.c:153
static int readFile
Definition: xlogrecovery.c:233
static XLogRecPtr abortedRecPtr
Definition: xlogrecovery.c:380
static XLogRecord * ReadRecord(XLogPrefetcher *xlogprefetcher, int emode, bool fetching_ckpt, TimeLineID replayTLI)
static XLogRecPtr CheckPointLoc
Definition: xlogrecovery.c:170
static bool recovery_signal_file_found
Definition: xlogrecovery.c:154
static XLogPrefetcher * xlogprefetcher
Definition: xlogrecovery.c:194
static TimeLineID CheckPointTLI
Definition: xlogrecovery.c:171
bool InRecovery
Definition: xlogutils.c:50

References abortedRecPtr, EndOfWalRecoveryInfo::abortedRecPtr, ArchiveRecoveryRequested, Assert(), CheckPointLoc, CheckPointTLI, close, EndOfWalRecoveryInfo::endOfLog, EndOfWalRecoveryInfo::endOfLogTLI, XLogReaderState::EndRecPtr, getRecoveryStopReason(), InArchiveRecovery, InRecovery, EndOfWalRecoveryInfo::lastPage, EndOfWalRecoveryInfo::lastPageBeginPtr, EndOfWalRecoveryInfo::lastRec, EndOfWalRecoveryInfo::lastRecTLI, XLogRecoveryCtlData::lastReplayedReadRecPtr, XLogRecoveryCtlData::lastReplayedTLI, len, missingContrecPtr, EndOfWalRecoveryInfo::missingContrecPtr, palloc(), PANIC, XLogReaderState::readBuf, readFile, readOff, ReadRecord(), recovery_signal_file_found, EndOfWalRecoveryInfo::recovery_signal_file_found, EndOfWalRecoveryInfo::recoveryStopReason, XLogReaderState::seg, ShutDownSlotSync(), standby_signal_file_found, EndOfWalRecoveryInfo::standby_signal_file_found, StandbyMode, wal_segment_size, WalRcvStreaming(), WALOpenSegment::ws_tli, xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, XLogRecoveryCtl, XLogSegmentOffset, and XLogShutdownWalRcv().

Referenced by StartupXLOG().

◆ GetCurrentChunkReplayStartTime()

TimestampTz GetCurrentChunkReplayStartTime ( void  )

◆ GetCurrentReplayRecPtr()

XLogRecPtr GetCurrentReplayRecPtr ( TimeLineID replayEndTLI)

Definition at line 4618 of file xlogrecovery.c.

4619{
4620 XLogRecPtr recptr;
4621 TimeLineID tli;
4622
4627
4628 if (replayEndTLI)
4629 *replayEndTLI = tli;
4630 return recptr;
4631}

References XLogRecoveryCtlData::info_lck, XLogRecoveryCtlData::replayEndRecPtr, XLogRecoveryCtlData::replayEndTLI, SpinLockAcquire, SpinLockRelease, and XLogRecoveryCtl.

Referenced by UpdateMinRecoveryPoint(), and xlog_redo().

◆ GetLatestXTime()

◆ getRecordTimestamp()

static bool getRecordTimestamp ( XLogReaderState record,
TimestampTz recordXtime 
)
static

Definition at line 2450 of file xlogrecovery.c.

2451{
2452 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2453 uint8 xact_info = info & XLOG_XACT_OPMASK;
2454 uint8 rmid = XLogRecGetRmid(record);
2455
2456 if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2457 {
2458 *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
2459 return true;
2460 }
2461 if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
2462 xact_info == XLOG_XACT_COMMIT_PREPARED))
2463 {
2464 *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
2465 return true;
2466 }
2467 if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
2468 xact_info == XLOG_XACT_ABORT_PREPARED))
2469 {
2470 *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
2471 return true;
2472 }
2473 return false;
2474}
#define XLOG_RESTORE_POINT
Definition: pg_control.h:75
#define XLOG_XACT_COMMIT_PREPARED
Definition: xact.h:173
#define XLOG_XACT_COMMIT
Definition: xact.h:170
#define XLOG_XACT_OPMASK
Definition: xact.h:180
#define XLOG_XACT_ABORT
Definition: xact.h:172
#define XLOG_XACT_ABORT_PREPARED
Definition: xact.h:174
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:409
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:410

References XLOG_RESTORE_POINT, XLOG_XACT_ABORT, XLOG_XACT_ABORT_PREPARED, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_PREPARED, XLOG_XACT_OPMASK, XLogRecGetData, XLogRecGetInfo, and XLogRecGetRmid.

Referenced by recoveryApplyDelay(), recoveryStopsAfter(), and recoveryStopsBefore().

◆ GetRecoveryPauseState()

◆ getRecoveryStopReason()

static char * getRecoveryStopReason ( void  )
static

Definition at line 2910 of file xlogrecovery.c.

2911{
2912 char reason[200];
2913
2915 snprintf(reason, sizeof(reason),
2916 "%s transaction %u",
2917 recoveryStopAfter ? "after" : "before",
2920 snprintf(reason, sizeof(reason),
2921 "%s %s\n",
2922 recoveryStopAfter ? "after" : "before",
2925 snprintf(reason, sizeof(reason),
2926 "%s LSN %X/%08X\n",
2927 recoveryStopAfter ? "after" : "before",
2930 snprintf(reason, sizeof(reason),
2931 "at restore point \"%s\"",
2934 snprintf(reason, sizeof(reason), "reached consistency");
2935 else
2936 snprintf(reason, sizeof(reason), "no recovery target specified");
2937
2938 return pstrdup(reason);
2939}
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1862
char * pstrdup(const char *in)
Definition: mcxt.c:1759
static XLogRecPtr recoveryStopLSN
Definition: xlogrecovery.c:389
static TimestampTz recoveryStopTime
Definition: xlogrecovery.c:388
static char recoveryStopName[MAXFNAMELEN]
Definition: xlogrecovery.c:390
static bool recoveryStopAfter
Definition: xlogrecovery.c:391
static TransactionId recoveryStopXid
Definition: xlogrecovery.c:387

References LSN_FORMAT_ARGS, pstrdup(), RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_LSN, RECOVERY_TARGET_NAME, RECOVERY_TARGET_TIME, RECOVERY_TARGET_XID, recoveryStopAfter, recoveryStopLSN, recoveryStopName, recoveryStopTime, recoveryStopXid, recoveryTarget, snprintf, and timestamptz_to_str().

Referenced by FinishWalRecovery().

◆ GetXLogReceiptTime()

void GetXLogReceiptTime ( TimestampTz rtime,
bool *  fromStream 
)

Definition at line 4698 of file xlogrecovery.c.

4699{
4700 /*
4701 * This must be executed in the startup process, since we don't export the
4702 * relevant state to shared memory.
4703 */
4705
4706 *rtime = XLogReceiptTime;
4707 *fromStream = (XLogReceiptSource == XLOG_FROM_STREAM);
4708}
static XLogSource XLogReceiptSource
Definition: xlogrecovery.c:262
static TimestampTz XLogReceiptTime
Definition: xlogrecovery.c:261

References Assert(), InRecovery, XLOG_FROM_STREAM, XLogReceiptSource, and XLogReceiptTime.

Referenced by GetStandbyLimitTime().

◆ GetXLogReplayRecPtr()

◆ HotStandbyActive()

bool HotStandbyActive ( void  )

Definition at line 4558 of file xlogrecovery.c.

4559{
4560 /*
4561 * We check shared state each time only until Hot Standby is active. We
4562 * can't de-activate Hot Standby, so there's no need to keep checking
4563 * after the shared variable has once been seen true.
4564 */
4566 return true;
4567 else
4568 {
4569 /* spinlock is essential on machines with weak memory ordering! */
4573
4574 return LocalHotStandbyActive;
4575 }
4576}

References XLogRecoveryCtlData::info_lck, LocalHotStandbyActive, XLogRecoveryCtlData::SharedHotStandbyActive, SpinLockAcquire, SpinLockRelease, and XLogRecoveryCtl.

Referenced by XLogWalRcvSendHSFeedback().

◆ HotStandbyActiveInReplay()

static bool HotStandbyActiveInReplay ( void  )
static

Definition at line 4583 of file xlogrecovery.c.

4584{
4586 return LocalHotStandbyActive;
4587}
bool IsPostmasterEnvironment
Definition: globals.c:119
#define AmStartupProcess()
Definition: miscadmin.h:390

References AmStartupProcess, Assert(), IsPostmasterEnvironment, and LocalHotStandbyActive.

Referenced by RecoveryRequiresIntParameter().

◆ InitWalRecovery()

void InitWalRecovery ( ControlFileData ControlFile,
bool *  wasShutdown_ptr,
bool *  haveBackupLabel_ptr,
bool *  haveTblspcMap_ptr 
)

Definition at line 520 of file xlogrecovery.c.

522{
523 XLogPageReadPrivate *private;
524 struct stat st;
525 bool wasShutdown;
526 XLogRecord *record;
527 DBState dbstate_at_startup;
528 bool haveTblspcMap = false;
529 bool haveBackupLabel = false;
530 CheckPoint checkPoint;
531 bool backupFromStandby = false;
532
533 dbstate_at_startup = ControlFile->state;
534
535 /*
536 * Initialize on the assumption we want to recover to the latest timeline
537 * that's active according to pg_control.
538 */
542 else
544
545 /*
546 * Check for signal files, and if so set up state for offline recovery
547 */
550
551 /*
552 * Take ownership of the wakeup latch if we're going to sleep during
553 * recovery, if required.
554 */
557
558 /*
559 * Set the WAL reading processor now, as it will be needed when reading
560 * the checkpoint record required (backup_label or not).
561 */
562 private = palloc0(sizeof(XLogPageReadPrivate));
563 xlogreader =
565 XL_ROUTINE(.page_read = &XLogPageRead,
566 .segment_open = NULL,
567 .segment_close = wal_segment_close),
568 private);
569 if (!xlogreader)
571 (errcode(ERRCODE_OUT_OF_MEMORY),
572 errmsg("out of memory"),
573 errdetail("Failed while allocating a WAL reading processor.")));
575
576 /*
577 * Set the WAL decode buffer size. This limits how far ahead we can read
578 * in the WAL.
579 */
581
582 /* Create a WAL prefetcher. */
584
585 /*
586 * Allocate two page buffers dedicated to WAL consistency checks. We do
587 * it this way, rather than just making static arrays, for two reasons:
588 * (1) no need to waste the storage in most instantiations of the backend;
589 * (2) a static char array isn't guaranteed to have any particular
590 * alignment, whereas palloc() will provide MAXALIGN'd storage.
591 */
592 replay_image_masked = (char *) palloc(BLCKSZ);
593 primary_image_masked = (char *) palloc(BLCKSZ);
594
595 /*
596 * Read the backup_label file. We want to run this part of the recovery
597 * process after checking for signal files and after performing validation
598 * of the recovery parameters.
599 */
601 &backupFromStandby))
602 {
603 List *tablespaces = NIL;
604
605 /*
606 * Archive recovery was requested, and thanks to the backup label
607 * file, we know how far we need to replay to reach consistency. Enter
608 * archive recovery directly.
609 */
610 InArchiveRecovery = true;
613
614 /*
615 * Omitting backup_label when creating a new replica, PITR node etc.
616 * unfortunately is a common cause of corruption. Logging that
617 * backup_label was used makes it a bit easier to exclude that as the
618 * cause of observed corruption.
619 *
620 * Do so before we try to read the checkpoint record (which can fail),
621 * as otherwise it can be hard to understand why a checkpoint other
622 * than ControlFile->checkPoint is used.
623 */
624 ereport(LOG,
625 errmsg("starting backup recovery with redo LSN %X/%08X, checkpoint LSN %X/%08X, on timeline ID %u",
629
630 /*
631 * When a backup_label file is present, we want to roll forward from
632 * the checkpoint it identifies, rather than using pg_control.
633 */
636 if (record != NULL)
637 {
638 memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
639 wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
641 errmsg_internal("checkpoint record is at %X/%08X",
643 InRecovery = true; /* force recovery even if SHUTDOWNED */
644
645 /*
646 * Make sure that REDO location exists. This may not be the case
647 * if there was a crash during an online backup, which left a
648 * backup_label around that references a WAL segment that's
649 * already been archived.
650 */
651 if (checkPoint.redo < CheckPointLoc)
652 {
654 if (!ReadRecord(xlogprefetcher, LOG, false,
655 checkPoint.ThisTimeLineID))
657 errmsg("could not find redo location %X/%08X referenced by checkpoint record at %X/%08X",
659 errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
660 "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
661 "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
663 }
664 }
665 else
666 {
668 errmsg("could not locate required checkpoint record at %X/%08X",
670 errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
671 "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
672 "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
674 wasShutdown = false; /* keep compiler quiet */
675 }
676
677 /* Read the tablespace_map file if present and create symlinks. */
678 if (read_tablespace_map(&tablespaces))
679 {
680 ListCell *lc;
681
682 foreach(lc, tablespaces)
683 {
684 tablespaceinfo *ti = lfirst(lc);
685 char *linkloc;
686
687 linkloc = psprintf("%s/%u", PG_TBLSPC_DIR, ti->oid);
688
689 /*
690 * Remove the existing symlink if any and Create the symlink
691 * under PGDATA.
692 */
694
695 if (symlink(ti->path, linkloc) < 0)
698 errmsg("could not create symbolic link \"%s\": %m",
699 linkloc)));
700
701 pfree(ti->path);
702 pfree(ti);
703 }
704
705 /* tell the caller to delete it later */
706 haveTblspcMap = true;
707 }
708
709 /* tell the caller to delete it later */
710 haveBackupLabel = true;
711 }
712 else
713 {
714 /* No backup_label file has been found if we are here. */
715
716 /*
717 * If tablespace_map file is present without backup_label file, there
718 * is no use of such file. There is no harm in retaining it, but it
719 * is better to get rid of the map file so that we don't have any
720 * redundant file in data directory and it will avoid any sort of
721 * confusion. It seems prudent though to just rename the file out of
722 * the way rather than delete it completely, also we ignore any error
723 * that occurs in rename operation as even if map file is present
724 * without backup_label file, it is harmless.
725 */
726 if (stat(TABLESPACE_MAP, &st) == 0)
727 {
728 unlink(TABLESPACE_MAP_OLD);
730 ereport(LOG,
731 (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
733 errdetail("File \"%s\" was renamed to \"%s\".",
735 else
736 ereport(LOG,
737 (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
739 errdetail("Could not rename file \"%s\" to \"%s\": %m.",
741 }
742
743 /*
744 * It's possible that archive recovery was requested, but we don't
745 * know how far we need to replay the WAL before we reach consistency.
746 * This can happen for example if a base backup is taken from a
747 * running server using an atomic filesystem snapshot, without calling
748 * pg_backup_start/stop. Or if you just kill a running primary server
749 * and put it into archive recovery by creating a recovery signal
750 * file.
751 *
752 * Our strategy in that case is to perform crash recovery first,
753 * replaying all the WAL present in pg_wal, and only enter archive
754 * recovery after that.
755 *
756 * But usually we already know how far we need to replay the WAL (up
757 * to minRecoveryPoint, up to backupEndPoint, or until we see an
758 * end-of-backup record), and we can enter archive recovery directly.
759 */
765 {
766 InArchiveRecovery = true;
769 }
770
771 /*
772 * For the same reason as when starting up with backup_label present,
773 * emit a log message when we continue initializing from a base
774 * backup.
775 */
777 ereport(LOG,
778 errmsg("restarting backup recovery with redo LSN %X/%08X",
780
781 /* Get the last valid checkpoint record. */
788 if (record != NULL)
789 {
791 errmsg_internal("checkpoint record is at %X/%08X",
793 }
794 else
795 {
796 /*
797 * We used to attempt to go back to a secondary checkpoint record
798 * here, but only when not in standby mode. We now just fail if we
799 * can't read the last checkpoint because this allows us to
800 * simplify processing around checkpoints.
801 */
803 errmsg("could not locate a valid checkpoint record at %X/%08X",
805 }
806 memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
807 wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
808 }
809
811 {
813 ereport(LOG,
814 (errmsg("entering standby mode")));
816 ereport(LOG,
817 (errmsg("starting point-in-time recovery to XID %u",
820 ereport(LOG,
821 (errmsg("starting point-in-time recovery to %s",
824 ereport(LOG,
825 (errmsg("starting point-in-time recovery to \"%s\"",
828 ereport(LOG,
829 errmsg("starting point-in-time recovery to WAL location (LSN) \"%X/%08X\"",
832 ereport(LOG,
833 (errmsg("starting point-in-time recovery to earliest consistent point")));
834 else
835 ereport(LOG,
836 (errmsg("starting archive recovery")));
837 }
838
839 /*
840 * If the location of the checkpoint record is not on the expected
841 * timeline in the history of the requested timeline, we cannot proceed:
842 * the backup is not part of the history of the requested timeline.
843 */
844 Assert(expectedTLEs); /* was initialized by reading checkpoint
845 * record */
848 {
849 XLogRecPtr switchpoint;
850
851 /*
852 * tliSwitchPoint will throw an error if the checkpoint's timeline is
853 * not in expectedTLEs at all.
854 */
855 switchpoint = tliSwitchPoint(CheckPointTLI, expectedTLEs, NULL);
857 (errmsg("requested timeline %u is not a child of this server's history",
859 /* translator: %s is a backup_label file or a pg_control file */
860 errdetail("Latest checkpoint in file \"%s\" is at %X/%08X on timeline %u, but in the history of the requested timeline, the server forked off from that timeline at %X/%08X.",
861 haveBackupLabel ? "backup_label" : "pg_control",
864 LSN_FORMAT_ARGS(switchpoint))));
865 }
866
867 /*
868 * The min recovery point should be part of the requested timeline's
869 * history, too.
870 */
875 errmsg("requested timeline %u does not contain minimum recovery point %X/%08X on timeline %u",
879
881 errmsg_internal("redo record is at %X/%08X; shutdown %s",
882 LSN_FORMAT_ARGS(checkPoint.redo),
883 wasShutdown ? "true" : "false"));
885 (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: %u",
887 checkPoint.nextOid)));
889 (errmsg_internal("next MultiXactId: %u; next MultiXactOffset: %u",
890 checkPoint.nextMulti, checkPoint.nextMultiOffset)));
892 (errmsg_internal("oldest unfrozen transaction ID: %u, in database %u",
893 checkPoint.oldestXid, checkPoint.oldestXidDB)));
895 (errmsg_internal("oldest MultiXactId: %u, in database %u",
896 checkPoint.oldestMulti, checkPoint.oldestMultiDB)));
898 (errmsg_internal("commit timestamp Xid oldest/newest: %u/%u",
899 checkPoint.oldestCommitTsXid,
900 checkPoint.newestCommitTsXid)));
903 (errmsg("invalid next transaction ID")));
904
905 /* sanity check */
906 if (checkPoint.redo > CheckPointLoc)
908 (errmsg("invalid redo in checkpoint record")));
909
910 /*
911 * Check whether we need to force recovery from WAL. If it appears to
912 * have been a clean shutdown and we did not have a recovery signal file,
913 * then assume no recovery needed.
914 */
915 if (checkPoint.redo < CheckPointLoc)
916 {
917 if (wasShutdown)
919 (errmsg("invalid redo record in shutdown checkpoint")));
920 InRecovery = true;
921 }
922 else if (ControlFile->state != DB_SHUTDOWNED)
923 InRecovery = true;
925 {
926 /* force recovery due to presence of recovery signal file */
927 InRecovery = true;
928 }
929
930 /*
931 * If recovery is needed, update our in-memory copy of pg_control to show
932 * that we are recovering and to show the selected checkpoint as the place
933 * we are starting from. We also mark pg_control with any minimum recovery
934 * stop point obtained from a backup history file.
935 *
936 * We don't write the changes to disk yet, though. Only do that after
937 * initializing various subsystems.
938 */
939 if (InRecovery)
940 {
942 {
944 }
945 else
946 {
947 ereport(LOG,
948 (errmsg("database system was not properly shut down; "
949 "automatic recovery in progress")));
951 ereport(LOG,
952 (errmsg("crash recovery starts in timeline %u "
953 "and has target timeline %u",
957 }
959 ControlFile->checkPointCopy = checkPoint;
961 {
962 /* initialize minRecoveryPoint if not set yet */
963 if (ControlFile->minRecoveryPoint < checkPoint.redo)
964 {
965 ControlFile->minRecoveryPoint = checkPoint.redo;
967 }
968 }
969
970 /*
971 * Set backupStartPoint if we're starting recovery from a base backup.
972 *
973 * Also set backupEndPoint and use minRecoveryPoint as the backup end
974 * location if we're starting recovery from a base backup which was
975 * taken from a standby. In this case, the database system status in
976 * pg_control must indicate that the database was already in recovery.
977 * Usually that will be DB_IN_ARCHIVE_RECOVERY but also can be
978 * DB_SHUTDOWNED_IN_RECOVERY if recovery previously was interrupted
979 * before reaching this point; e.g. because restore_command or
980 * primary_conninfo were faulty.
981 *
982 * Any other state indicates that the backup somehow became corrupted
983 * and we can't sensibly continue with recovery.
984 */
985 if (haveBackupLabel)
986 {
987 ControlFile->backupStartPoint = checkPoint.redo;
989
990 if (backupFromStandby)
991 {
992 if (dbstate_at_startup != DB_IN_ARCHIVE_RECOVERY &&
993 dbstate_at_startup != DB_SHUTDOWNED_IN_RECOVERY)
995 (errmsg("backup_label contains data inconsistent with control file"),
996 errhint("This means that the backup is corrupted and you will "
997 "have to use another backup for recovery.")));
999 }
1000 }
1001 }
1002
1003 /* remember these, so that we know when we have reached consistency */
1008 {
1011 }
1012 else
1013 {
1016 }
1017
1018 /*
1019 * Start recovery assuming that the final record isn't lost.
1020 */
1023
1024 *wasShutdown_ptr = wasShutdown;
1025 *haveBackupLabel_ptr = haveBackupLabel;
1026 *haveTblspcMap_ptr = haveTblspcMap;
1027}
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition: timeline.c:544
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition: timeline.c:572
void remove_tablespace_symlink(const char *linkloc)
Definition: tablespace.c:883
#define UINT64_FORMAT
Definition: c.h:560
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1170
int errcode_for_file_access(void)
Definition: elog.c:886
#define FATAL
Definition: elog.h:41
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:779
char * DataDir
Definition: globals.c:71
void OwnLatch(Latch *latch)
Definition: latch.c:126
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc0(Size size)
Definition: mcxt.c:1395
DBState
Definition: pg_control.h:90
@ DB_IN_ARCHIVE_RECOVERY
Definition: pg_control.h:96
@ DB_SHUTDOWNED_IN_RECOVERY
Definition: pg_control.h:93
@ DB_SHUTDOWNED
Definition: pg_control.h:92
@ DB_IN_CRASH_RECOVERY
Definition: pg_control.h:95
#define lfirst(lc)
Definition: pg_list.h:172
#define NIL
Definition: pg_list.h:68
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
Oid oldestMultiDB
Definition: pg_control.h:51
MultiXactId oldestMulti
Definition: pg_control.h:50
MultiXactOffset nextMultiOffset
Definition: pg_control.h:47
TransactionId newestCommitTsXid
Definition: pg_control.h:55
TransactionId oldestXid
Definition: pg_control.h:48
Oid nextOid
Definition: pg_control.h:45
MultiXactId nextMulti
Definition: pg_control.h:46
FullTransactionId nextXid
Definition: pg_control.h:44
TransactionId oldestCommitTsXid
Definition: pg_control.h:53
XLogRecPtr redo
Definition: pg_control.h:37
Oid oldestXidDB
Definition: pg_control.h:49
XLogRecPtr backupStartPoint
Definition: pg_control.h:170
bool backupEndRequired
Definition: pg_control.h:172
CheckPoint checkPointCopy
Definition: pg_control.h:135
XLogRecPtr backupEndPoint
Definition: pg_control.h:171
XLogRecPtr minRecoveryPoint
Definition: pg_control.h:168
XLogRecPtr checkPoint
Definition: pg_control.h:133
uint64 system_identifier
Definition: pg_control.h:110
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:169
Definition: pg_list.h:54
uint64 system_identifier
Definition: xlogreader.h:190
#define U64FromFullTransactionId(x)
Definition: transam.h:49
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
#define symlink(oldpath, newpath)
Definition: win32_port.h:225
int wal_decode_buffer_size
Definition: xlog.c:138
static ControlFileData * ControlFile
Definition: xlog.c:575
#define TABLESPACE_MAP_OLD
Definition: xlog.h:309
#define TABLESPACE_MAP
Definition: xlog.h:308
#define BACKUP_LABEL_FILE
Definition: xlog.h:305
XLogPrefetcher * XLogPrefetcherAllocate(XLogReaderState *reader)
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:107
void XLogReaderSetDecodeBuffer(XLogReaderState *state, void *buffer, size_t size)
Definition: xlogreader.c:91
#define XL_ROUTINE(...)
Definition: xlogreader.h:117
static int XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf)
static void validateRecoveryParameters(void)
static XLogRecord * ReadCheckpointRecord(XLogPrefetcher *xlogprefetcher, XLogRecPtr RecPtr, TimeLineID replayTLI)
static TimeLineID RedoStartTLI
Definition: xlogrecovery.c:173
static void readRecoverySignalFile(void)
static bool read_tablespace_map(List **tablespaces)
static bool read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, bool *backupEndRequired, bool *backupFromStandby)
static char * primary_image_masked
Definition: xlogrecovery.c:306
static char * replay_image_masked
Definition: xlogrecovery.c:305
TimeLineID recoveryTargetTLI
Definition: xlogrecovery.c:125
static XLogRecPtr RedoStartLSN
Definition: xlogrecovery.c:172
static void EnableStandbyMode(void)
Definition: xlogrecovery.c:486
TimestampTz recoveryTargetTime
Definition: xlogrecovery.c:93
static bool StandbyModeRequested
Definition: xlogrecovery.c:149
void wal_segment_close(XLogReaderState *state)
Definition: xlogutils.c:831

References abortedRecPtr, ArchiveRecoveryRequested, Assert(), BACKUP_LABEL_FILE, backupEndPoint, ControlFileData::backupEndPoint, backupEndRequired, ControlFileData::backupEndRequired, backupStartPoint, ControlFileData::backupStartPoint, ControlFileData::checkPoint, ControlFileData::checkPointCopy, CheckPointLoc, CheckPointTLI, ControlFile, DataDir, DB_IN_ARCHIVE_RECOVERY, DB_IN_CRASH_RECOVERY, DB_SHUTDOWNED, DB_SHUTDOWNED_IN_RECOVERY, DEBUG1, durable_rename(), EnableStandbyMode(), ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), errmsg_internal(), ERROR, expectedTLEs, FATAL, InArchiveRecovery, InRecovery, InvalidXLogRecPtr, lfirst, LOG, LSN_FORMAT_ARGS, minRecoveryPoint, ControlFileData::minRecoveryPoint, minRecoveryPointTLI, ControlFileData::minRecoveryPointTLI, missingContrecPtr, CheckPoint::newestCommitTsXid, CheckPoint::nextMulti, CheckPoint::nextMultiOffset, CheckPoint::nextOid, CheckPoint::nextXid, NIL, tablespaceinfo::oid, CheckPoint::oldestCommitTsXid, CheckPoint::oldestMulti, CheckPoint::oldestMultiDB, CheckPoint::oldestXid, CheckPoint::oldestXidDB, OwnLatch(), palloc(), palloc0(), PANIC, tablespaceinfo::path, pfree(), PG_TBLSPC_DIR, primary_image_masked, psprintf(), read_backup_label(), read_tablespace_map(), ReadCheckpointRecord(), ReadRecord(), readRecoverySignalFile(), RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_LSN, RECOVERY_TARGET_NAME, RECOVERY_TARGET_TIME, RECOVERY_TARGET_XID, recoveryTarget, recoveryTargetLSN, recoveryTargetName, recoveryTargetTime, recoveryTargetTLI, recoveryTargetXid, XLogRecoveryCtlData::recoveryWakeupLatch, CheckPoint::redo, RedoStartLSN, RedoStartTLI, remove_tablespace_symlink(), replay_image_masked, StandbyModeRequested, stat, ControlFileData::state, symlink, XLogReaderState::system_identifier, ControlFileData::system_identifier, TABLESPACE_MAP, TABLESPACE_MAP_OLD, CheckPoint::ThisTimeLineID, timestamptz_to_str(), tliOfPointInHistory(), tliSwitchPoint(), TransactionIdIsNormal, U64FromFullTransactionId, UINT64_FORMAT, validateRecoveryParameters(), wal_decode_buffer_size, wal_segment_close(), wal_segment_size, XidFromFullTransactionId, XLogRecord::xl_info, XL_ROUTINE, XLOG_CHECKPOINT_SHUTDOWN, XLogPageRead(), xlogprefetcher, XLogPrefetcherAllocate(), XLogPrefetcherBeginRead(), xlogreader, XLogReaderAllocate(), XLogReaderSetDecodeBuffer(), XLogRecGetData, XLogRecoveryCtl, and XLogRecPtrIsValid.

Referenced by StartupXLOG().

◆ PerformWalRecovery()

void PerformWalRecovery ( void  )

Definition at line 1663 of file xlogrecovery.c.

1664{
1665 XLogRecord *record;
1666 bool reachedRecoveryTarget = false;
1667 TimeLineID replayTLI;
1668
1669 /*
1670 * Initialize shared variables for tracking progress of WAL replay, as if
1671 * we had just replayed the record before the REDO location (or the
1672 * checkpoint record itself, if it's a shutdown checkpoint).
1673 */
1676 {
1680 }
1681 else
1682 {
1686 }
1693
1694 /* Also ensure XLogReceiptTime has a sane value */
1696
1697 /*
1698 * Let postmaster know we've started redo now, so that it can launch the
1699 * archiver if necessary.
1700 */
1703
1704 /*
1705 * Allow read-only connections immediately if we're consistent already.
1706 */
1708
1709 /*
1710 * Find the first record that logically follows the checkpoint --- it
1711 * might physically precede it, though.
1712 */
1714 {
1715 /* back up to find the record */
1716 replayTLI = RedoStartTLI;
1718 record = ReadRecord(xlogprefetcher, PANIC, false, replayTLI);
1719
1720 /*
1721 * If a checkpoint record's redo pointer points back to an earlier
1722 * LSN, the record at that LSN should be an XLOG_CHECKPOINT_REDO
1723 * record.
1724 */
1725 if (record->xl_rmid != RM_XLOG_ID ||
1727 ereport(FATAL,
1728 errmsg("unexpected record type found at redo point %X/%08X",
1730 }
1731 else
1732 {
1733 /* just have to read next record after CheckPoint */
1735 replayTLI = CheckPointTLI;
1736 record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1737 }
1738
1739 if (record != NULL)
1740 {
1741 TimestampTz xtime;
1742 PGRUsage ru0;
1743
1744 pg_rusage_init(&ru0);
1745
1746 InRedo = true;
1747
1748 RmgrStartup();
1749
1750 ereport(LOG,
1751 errmsg("redo starts at %X/%08X",
1753
1754 /* Prepare to report progress of the redo phase. */
1755 if (!StandbyMode)
1757
1758 /*
1759 * main redo apply loop
1760 */
1761 do
1762 {
1763 if (!StandbyMode)
1764 ereport_startup_progress("redo in progress, elapsed time: %ld.%02d s, current LSN: %X/%08X",
1766
1767#ifdef WAL_DEBUG
1768 if (XLOG_DEBUG)
1769 {
1771
1773 appendStringInfo(&buf, "REDO @ %X/%08X; LSN %X/%08X: ",
1776 xlog_outrec(&buf, xlogreader);
1777 appendStringInfoString(&buf, " - ");
1779 elog(LOG, "%s", buf.data);
1780 pfree(buf.data);
1781 }
1782#endif
1783
1784 /* Handle interrupt signals of startup process */
1786
1787 /*
1788 * Pause WAL replay, if requested by a hot-standby session via
1789 * SetRecoveryPause().
1790 *
1791 * Note that we intentionally don't take the info_lck spinlock
1792 * here. We might therefore read a slightly stale value of the
1793 * recoveryPause flag, but it can't be very stale (no worse than
1794 * the last spinlock we did acquire). Since a pause request is a
1795 * pretty asynchronous thing anyway, possibly responding to it one
1796 * WAL record later than we otherwise would is a minor issue, so
1797 * it doesn't seem worth adding another spinlock cycle to prevent
1798 * that.
1799 */
1800 if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1802 recoveryPausesHere(false);
1803
1804 /*
1805 * Have we reached our recovery target?
1806 */
1808 {
1809 reachedRecoveryTarget = true;
1810 break;
1811 }
1812
1813 /*
1814 * If we've been asked to lag the primary, wait on latch until
1815 * enough time has passed.
1816 */
1818 {
1819 /*
1820 * We test for paused recovery again here. If user sets
1821 * delayed apply, it may be because they expect to pause
1822 * recovery in case of problems, so we must test again here
1823 * otherwise pausing during the delay-wait wouldn't work.
1824 */
1825 if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1827 recoveryPausesHere(false);
1828 }
1829
1830 /*
1831 * Apply the record
1832 */
1833 ApplyWalRecord(xlogreader, record, &replayTLI);
1834
1835 /* Exit loop if we reached inclusive recovery target */
1837 {
1838 reachedRecoveryTarget = true;
1839 break;
1840 }
1841
1842 /*
1843 * If we replayed an LSN that someone was waiting for then walk
1844 * over the shared memory array and set latches to notify the
1845 * waiters.
1846 */
1847 if (waitLSNState &&
1851
1852 /* Else, try to fetch the next WAL record */
1853 record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1854 } while (record != NULL);
1855
1856 /*
1857 * end of main redo apply loop
1858 */
1859
1860 if (reachedRecoveryTarget)
1861 {
1862 if (!reachedConsistency)
1863 ereport(FATAL,
1864 (errmsg("requested recovery stop point is before consistent recovery point")));
1865
1866 /*
1867 * This is the last point where we can restart recovery with a new
1868 * recovery target, if we shutdown and begin again. After this,
1869 * Resource Managers may choose to do permanent corrective actions
1870 * at end of recovery.
1871 */
1872 switch (recoveryTargetAction)
1873 {
1875
1876 /*
1877 * exit with special return code to request shutdown of
1878 * postmaster. Log messages issued from postmaster.
1879 */
1880 proc_exit(3);
1881
1883 SetRecoveryPause(true);
1884 recoveryPausesHere(true);
1885
1886 /* drop into promote */
1887
1889 break;
1890 }
1891 }
1892
1893 RmgrCleanup();
1894
1895 ereport(LOG,
1896 errmsg("redo done at %X/%08X system usage: %s",
1898 pg_rusage_show(&ru0)));
1899 xtime = GetLatestXTime();
1900 if (xtime)
1901 ereport(LOG,
1902 (errmsg("last completed transaction was at log time %s",
1903 timestamptz_to_str(xtime))));
1904
1905 InRedo = false;
1906 }
1907 else
1908 {
1909 /* there are no WAL records following the checkpoint */
1910 ereport(LOG,
1911 (errmsg("redo is not required")));
1912 }
1913
1914 /*
1915 * This check is intentionally after the above log messages that indicate
1916 * how far recovery went.
1917 */
1920 !reachedRecoveryTarget)
1921 ereport(FATAL,
1922 (errcode(ERRCODE_CONFIG_FILE_ERROR),
1923 errmsg("recovery ended before configured recovery target was reached")));
1924}
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:465
void begin_startup_progress_phase(void)
Definition: startup.c:343
void ProcessStartupProcInterrupts(void)
Definition: startup.c:154
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
void proc_exit(int code)
Definition: ipc.c:104
#define XLOG_CHECKPOINT_REDO
Definition: pg_control.h:82
const char * pg_rusage_show(const PGRUsage *ru0)
Definition: pg_rusage.c:40
void pg_rusage_init(PGRUsage *ru0)
Definition: pg_rusage.c:27
static char * buf
Definition: pg_test_fsync.c:72
@ PMSIGNAL_RECOVERY_STARTED
Definition: pmsignal.h:35
void RmgrStartup(void)
Definition: rmgr.c:58
void RmgrCleanup(void)
Definition: rmgr.c:74
#define ereport_startup_progress(msg,...)
Definition: startup.h:18
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97
pg_atomic_uint64 minWaitedLSN[WAIT_LSN_TYPE_COUNT]
Definition: xlogwait.h:79
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
static bool recoveryStopsBefore(XLogReaderState *record)
int recoveryTargetAction
Definition: xlogrecovery.c:90
static bool recoveryApplyDelay(XLogReaderState *record)
static bool recoveryStopsAfter(XLogReaderState *record)
void SetRecoveryPause(bool recoveryPause)
void xlog_outdesc(StringInfo buf, XLogReaderState *record)
static bool InRedo
Definition: xlogrecovery.c:206
static void ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *replayTLI)
static void recoveryPausesHere(bool endOfRecovery)
TimestampTz GetLatestXTime(void)
@ RECOVERY_TARGET_ACTION_PAUSE
Definition: xlogrecovery.h:48
@ RECOVERY_TARGET_ACTION_PROMOTE
Definition: xlogrecovery.h:49
@ RECOVERY_TARGET_ACTION_SHUTDOWN
Definition: xlogrecovery.h:50
@ RECOVERY_NOT_PAUSED
Definition: xlogrecovery.h:56
struct WaitLSNState * waitLSNState
Definition: xlogwait.c:63
void WaitLSNWakeup(WaitLSNType lsnType, XLogRecPtr currentLSN)
Definition: xlogwait.c:269
@ WAIT_LSN_TYPE_REPLAY
Definition: xlogwait.h:38

References appendStringInfo(), appendStringInfoString(), ApplyWalRecord(), ArchiveRecoveryRequested, Assert(), begin_startup_progress_phase(), buf, CheckPointLoc, CheckPointTLI, CheckRecoveryConsistency(), XLogRecoveryCtlData::currentChunkStartTime, elog, XLogReaderState::EndRecPtr, ereport, ereport_startup_progress, errcode(), errmsg(), FATAL, GetCurrentTimestamp(), GetLatestXTime(), XLogRecoveryCtlData::info_lck, initStringInfo(), InRedo, InvalidXLogRecPtr, IsUnderPostmaster, XLogRecoveryCtlData::lastReplayedEndRecPtr, XLogRecoveryCtlData::lastReplayedReadRecPtr, XLogRecoveryCtlData::lastReplayedTLI, LOG, LSN_FORMAT_ARGS, WaitLSNState::minWaitedLSN, PANIC, pfree(), pg_atomic_read_u64(), pg_rusage_init(), pg_rusage_show(), PMSIGNAL_RECOVERY_STARTED, proc_exit(), ProcessStartupProcInterrupts(), reachedConsistency, ReadRecord(), XLogReaderState::ReadRecPtr, RECOVERY_NOT_PAUSED, RECOVERY_TARGET_ACTION_PAUSE, RECOVERY_TARGET_ACTION_PROMOTE, RECOVERY_TARGET_ACTION_SHUTDOWN, RECOVERY_TARGET_UNSET, recoveryApplyDelay(), XLogRecoveryCtlData::recoveryLastXTime, recoveryPausesHere(), XLogRecoveryCtlData::recoveryPauseState, recoveryStopsAfter(), recoveryStopsBefore(), recoveryTarget, recoveryTargetAction, RedoStartLSN, RedoStartTLI, XLogRecoveryCtlData::replayEndRecPtr, XLogRecoveryCtlData::replayEndTLI, RmgrCleanup(), RmgrStartup(), SendPostmasterSignal(), SetRecoveryPause(), SpinLockAcquire, SpinLockRelease, StandbyMode, timestamptz_to_str(), WAIT_LSN_TYPE_REPLAY, waitLSNState, WaitLSNWakeup(), XLogRecord::xl_info, XLogRecord::xl_rmid, XLOG_CHECKPOINT_REDO, xlog_outdesc(), xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, XLogReceiptTime, XLogRecoveryCtl, and XLR_INFO_MASK.

Referenced by StartupXLOG().

◆ PromoteIsTriggered()

bool PromoteIsTriggered ( void  )

Definition at line 4450 of file xlogrecovery.c.

4451{
4452 /*
4453 * We check shared state each time only until a standby promotion is
4454 * triggered. We can't trigger a promotion again, so there's no need to
4455 * keep checking after the shared variable has once been seen true.
4456 */
4458 return true;
4459
4463
4465}

References XLogRecoveryCtlData::info_lck, LocalPromoteIsTriggered, XLogRecoveryCtlData::SharedPromoteIsTriggered, SpinLockAcquire, SpinLockRelease, and XLogRecoveryCtl.

Referenced by ExecWaitStmt(), PerformRecoveryXLogAction(), pg_wal_replay_pause(), pg_wal_replay_resume(), and WaitForLSN().

◆ read_backup_label()

static bool read_backup_label ( XLogRecPtr checkPointLoc,
TimeLineID backupLabelTLI,
bool *  backupEndRequired,
bool *  backupFromStandby 
)
static

Definition at line 1218 of file xlogrecovery.c.

1220{
1221 char startxlogfilename[MAXFNAMELEN];
1222 TimeLineID tli_from_walseg,
1223 tli_from_file;
1224 FILE *lfp;
1225 char ch;
1226 char backuptype[20];
1227 char backupfrom[20];
1228 char backuplabel[MAXPGPATH];
1229 char backuptime[128];
1230 uint32 hi,
1231 lo;
1232
1233 /* suppress possible uninitialized-variable warnings */
1234 *checkPointLoc = InvalidXLogRecPtr;
1235 *backupLabelTLI = 0;
1236 *backupEndRequired = false;
1237 *backupFromStandby = false;
1238
1239 /*
1240 * See if label file is present
1241 */
1242 lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
1243 if (!lfp)
1244 {
1245 if (errno != ENOENT)
1246 ereport(FATAL,
1248 errmsg("could not read file \"%s\": %m",
1250 return false; /* it's not there, all is fine */
1251 }
1252
1253 /*
1254 * Read and parse the START WAL LOCATION and CHECKPOINT lines (this code
1255 * is pretty crude, but we are not expecting any variability in the file
1256 * format).
1257 */
1258 if (fscanf(lfp, "START WAL LOCATION: %X/%08X (file %08X%16s)%c",
1259 &hi, &lo, &tli_from_walseg, startxlogfilename, &ch) != 5 || ch != '\n')
1260 ereport(FATAL,
1261 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1262 errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
1263 RedoStartLSN = ((uint64) hi) << 32 | lo;
1264 RedoStartTLI = tli_from_walseg;
1265 if (fscanf(lfp, "CHECKPOINT LOCATION: %X/%08X%c",
1266 &hi, &lo, &ch) != 3 || ch != '\n')
1267 ereport(FATAL,
1268 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1269 errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
1270 *checkPointLoc = ((uint64) hi) << 32 | lo;
1271 *backupLabelTLI = tli_from_walseg;
1272
1273 /*
1274 * BACKUP METHOD lets us know if this was a typical backup ("streamed",
1275 * which could mean either pg_basebackup or the pg_backup_start/stop
1276 * method was used) or if this label came from somewhere else (the only
1277 * other option today being from pg_rewind). If this was a streamed
1278 * backup then we know that we need to play through until we get to the
1279 * end of the WAL which was generated during the backup (at which point we
1280 * will have reached consistency and backupEndRequired will be reset to be
1281 * false).
1282 */
1283 if (fscanf(lfp, "BACKUP METHOD: %19s\n", backuptype) == 1)
1284 {
1285 if (strcmp(backuptype, "streamed") == 0)
1286 *backupEndRequired = true;
1287 }
1288
1289 /*
1290 * BACKUP FROM lets us know if this was from a primary or a standby. If
1291 * it was from a standby, we'll double-check that the control file state
1292 * matches that of a standby.
1293 */
1294 if (fscanf(lfp, "BACKUP FROM: %19s\n", backupfrom) == 1)
1295 {
1296 if (strcmp(backupfrom, "standby") == 0)
1297 *backupFromStandby = true;
1298 }
1299
1300 /*
1301 * Parse START TIME and LABEL. Those are not mandatory fields for recovery
1302 * but checking for their presence is useful for debugging and the next
1303 * sanity checks. Cope also with the fact that the result buffers have a
1304 * pre-allocated size, hence if the backup_label file has been generated
1305 * with strings longer than the maximum assumed here an incorrect parsing
1306 * happens. That's fine as only minor consistency checks are done
1307 * afterwards.
1308 */
1309 if (fscanf(lfp, "START TIME: %127[^\n]\n", backuptime) == 1)
1311 (errmsg_internal("backup time %s in file \"%s\"",
1312 backuptime, BACKUP_LABEL_FILE)));
1313
1314 if (fscanf(lfp, "LABEL: %1023[^\n]\n", backuplabel) == 1)
1316 (errmsg_internal("backup label %s in file \"%s\"",
1317 backuplabel, BACKUP_LABEL_FILE)));
1318
1319 /*
1320 * START TIMELINE is new as of 11. Its parsing is not mandatory, still use
1321 * it as a sanity check if present.
1322 */
1323 if (fscanf(lfp, "START TIMELINE: %u\n", &tli_from_file) == 1)
1324 {
1325 if (tli_from_walseg != tli_from_file)
1326 ereport(FATAL,
1327 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1328 errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE),
1329 errdetail("Timeline ID parsed is %u, but expected %u.",
1330 tli_from_file, tli_from_walseg)));
1331
1333 (errmsg_internal("backup timeline %u in file \"%s\"",
1334 tli_from_file, BACKUP_LABEL_FILE)));
1335 }
1336
1337 if (fscanf(lfp, "INCREMENTAL FROM LSN: %X/%08X\n", &hi, &lo) > 0)
1338 ereport(FATAL,
1339 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1340 errmsg("this is an incremental backup, not a data directory"),
1341 errhint("Use pg_combinebackup to reconstruct a valid data directory.")));
1342
1343 if (ferror(lfp) || FreeFile(lfp))
1344 ereport(FATAL,
1346 errmsg("could not read file \"%s\": %m",
1348
1349 return true;
1350}
uint32_t uint32
Definition: c.h:541
int FreeFile(FILE *file)
Definition: fd.c:2840
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2641

References AllocateFile(), BACKUP_LABEL_FILE, backupEndRequired, DEBUG1, ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), errmsg_internal(), FATAL, FreeFile(), InvalidXLogRecPtr, MAXFNAMELEN, MAXPGPATH, RedoStartLSN, and RedoStartTLI.

Referenced by InitWalRecovery().

◆ read_tablespace_map()

static bool read_tablespace_map ( List **  tablespaces)
static

Definition at line 1364 of file xlogrecovery.c.

1365{
1366 tablespaceinfo *ti;
1367 FILE *lfp;
1368 char str[MAXPGPATH];
1369 int ch,
1370 i,
1371 n;
1372 bool was_backslash;
1373
1374 /*
1375 * See if tablespace_map file is present
1376 */
1377 lfp = AllocateFile(TABLESPACE_MAP, "r");
1378 if (!lfp)
1379 {
1380 if (errno != ENOENT)
1381 ereport(FATAL,
1383 errmsg("could not read file \"%s\": %m",
1384 TABLESPACE_MAP)));
1385 return false; /* it's not there, all is fine */
1386 }
1387
1388 /*
1389 * Read and parse the link name and path lines from tablespace_map file
1390 * (this code is pretty crude, but we are not expecting any variability in
1391 * the file format). De-escape any backslashes that were inserted.
1392 */
1393 i = 0;
1394 was_backslash = false;
1395 while ((ch = fgetc(lfp)) != EOF)
1396 {
1397 if (!was_backslash && (ch == '\n' || ch == '\r'))
1398 {
1399 char *endp;
1400
1401 if (i == 0)
1402 continue; /* \r immediately followed by \n */
1403
1404 /*
1405 * The de-escaped line should contain an OID followed by exactly
1406 * one space followed by a path. The path might start with
1407 * spaces, so don't be too liberal about parsing.
1408 */
1409 str[i] = '\0';
1410 n = 0;
1411 while (str[n] && str[n] != ' ')
1412 n++;
1413 if (n < 1 || n >= i - 1)
1414 ereport(FATAL,
1415 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1416 errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
1417 str[n++] = '\0';
1418
1419 ti = palloc0(sizeof(tablespaceinfo));
1420 errno = 0;
1421 ti->oid = strtoul(str, &endp, 10);
1422 if (*endp != '\0' || errno == EINVAL || errno == ERANGE)
1423 ereport(FATAL,
1424 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1425 errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
1426 ti->path = pstrdup(str + n);
1427 *tablespaces = lappend(*tablespaces, ti);
1428
1429 i = 0;
1430 continue;
1431 }
1432 else if (!was_backslash && ch == '\\')
1433 was_backslash = true;
1434 else
1435 {
1436 if (i < sizeof(str) - 1)
1437 str[i++] = ch;
1438 was_backslash = false;
1439 }
1440 }
1441
1442 if (i != 0 || was_backslash) /* last line not terminated? */
1443 ereport(FATAL,
1444 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1445 errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
1446
1447 if (ferror(lfp) || FreeFile(lfp))
1448 ereport(FATAL,
1450 errmsg("could not read file \"%s\": %m",
1451 TABLESPACE_MAP)));
1452
1453 return true;
1454}
int i
Definition: isn.c:77
List * lappend(List *list, void *datum)
Definition: list.c:339

References AllocateFile(), ereport, errcode(), errcode_for_file_access(), errmsg(), FATAL, FreeFile(), i, lappend(), MAXPGPATH, tablespaceinfo::oid, palloc0(), tablespaceinfo::path, pstrdup(), str, and TABLESPACE_MAP.

Referenced by InitWalRecovery().

◆ ReadCheckpointRecord()

static XLogRecord * ReadCheckpointRecord ( XLogPrefetcher xlogprefetcher,
XLogRecPtr  RecPtr,
TimeLineID  replayTLI 
)
static

Definition at line 4107 of file xlogrecovery.c.

4109{
4110 XLogRecord *record;
4111 uint8 info;
4112
4113 Assert(xlogreader != NULL);
4114
4115 if (!XRecOffIsValid(RecPtr))
4116 {
4117 ereport(LOG,
4118 (errmsg("invalid checkpoint location")));
4119 return NULL;
4120 }
4121
4123 record = ReadRecord(xlogprefetcher, LOG, true, replayTLI);
4124
4125 if (record == NULL)
4126 {
4127 ereport(LOG,
4128 (errmsg("invalid checkpoint record")));
4129 return NULL;
4130 }
4131 if (record->xl_rmid != RM_XLOG_ID)
4132 {
4133 ereport(LOG,
4134 (errmsg("invalid resource manager ID in checkpoint record")));
4135 return NULL;
4136 }
4137 info = record->xl_info & ~XLR_INFO_MASK;
4138 if (info != XLOG_CHECKPOINT_SHUTDOWN &&
4139 info != XLOG_CHECKPOINT_ONLINE)
4140 {
4141 ereport(LOG,
4142 (errmsg("invalid xl_info in checkpoint record")));
4143 return NULL;
4144 }
4146 {
4147 ereport(LOG,
4148 (errmsg("invalid length of checkpoint record")));
4149 return NULL;
4150 }
4151 return record;
4152}
#define XLOG_CHECKPOINT_ONLINE
Definition: pg_control.h:69
uint32 xl_tot_len
Definition: xlogrecord.h:43
#define XRecOffIsValid(xlrp)
#define SizeOfXLogRecordDataHeaderShort
Definition: xlogrecord.h:217
#define SizeOfXLogRecord
Definition: xlogrecord.h:55

References Assert(), ereport, errmsg(), LOG, ReadRecord(), SizeOfXLogRecord, SizeOfXLogRecordDataHeaderShort, XLogRecord::xl_info, XLogRecord::xl_rmid, XLogRecord::xl_tot_len, XLOG_CHECKPOINT_ONLINE, XLOG_CHECKPOINT_SHUTDOWN, xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, and XRecOffIsValid.

Referenced by InitWalRecovery().

◆ ReadRecord()

static XLogRecord * ReadRecord ( XLogPrefetcher xlogprefetcher,
int  emode,
bool  fetching_ckpt,
TimeLineID  replayTLI 
)
static

Definition at line 3155 of file xlogrecovery.c.

3157{
3158 XLogRecord *record;
3161
3163
3164 /* Pass through parameters to XLogPageRead */
3165 private->fetching_ckpt = fetching_ckpt;
3166 private->emode = emode;
3167 private->randAccess = !XLogRecPtrIsValid(xlogreader->ReadRecPtr);
3168 private->replayTLI = replayTLI;
3169
3170 /* This is the first attempt to read this page. */
3171 lastSourceFailed = false;
3172
3173 for (;;)
3174 {
3175 char *errormsg;
3176
3177 record = XLogPrefetcherReadRecord(xlogprefetcher, &errormsg);
3178 if (record == NULL)
3179 {
3180 /*
3181 * When we find that WAL ends in an incomplete record, keep track
3182 * of that record. After recovery is done, we'll write a record
3183 * to indicate to downstream WAL readers that that portion is to
3184 * be ignored.
3185 *
3186 * However, when ArchiveRecoveryRequested = true, we're going to
3187 * switch to a new timeline at the end of recovery. We will only
3188 * copy WAL over to the new timeline up to the end of the last
3189 * complete record, so if we did this, we would later create an
3190 * overwrite contrecord in the wrong place, breaking everything.
3191 */
3194 {
3197 }
3198
3199 if (readFile >= 0)
3200 {
3201 close(readFile);
3202 readFile = -1;
3203 }
3204
3205 /*
3206 * We only end up here without a message when XLogPageRead()
3207 * failed - in that case we already logged something. In
3208 * StandbyMode that only happens if we have been triggered, so we
3209 * shouldn't loop anymore in that case.
3210 */
3211 if (errormsg)
3213 (errmsg_internal("%s", errormsg) /* already translated */ ));
3214 }
3215
3216 /*
3217 * Check page TLI is one of the expected values.
3218 */
3220 {
3221 char fname[MAXFNAMELEN];
3222 XLogSegNo segno;
3223 int32 offset;
3224
3228 XLogFileName(fname, xlogreader->seg.ws_tli, segno,
3231 errmsg("unexpected timeline ID %u in WAL segment %s, LSN %X/%08X, offset %u",
3233 fname,
3235 offset));
3236 record = NULL;
3237 }
3238
3239 if (record)
3240 {
3241 /* Great, got a record */
3242 return record;
3243 }
3244 else
3245 {
3246 /* No valid record available from this source */
3247 lastSourceFailed = true;
3248
3249 /*
3250 * If archive recovery was requested, but we were still doing
3251 * crash recovery, switch to archive recovery and retry using the
3252 * offline archive. We have now replayed all the valid WAL in
3253 * pg_wal, so we are presumably now consistent.
3254 *
3255 * We require that there's at least some valid WAL present in
3256 * pg_wal, however (!fetching_ckpt). We could recover using the
3257 * WAL from the archive, even if pg_wal is completely empty, but
3258 * we'd have no idea how far we'd have to replay to reach
3259 * consistency. So err on the safe side and give up.
3260 */
3262 !fetching_ckpt)
3263 {
3265 (errmsg_internal("reached end of WAL in pg_wal, entering archive recovery")));
3266 InArchiveRecovery = true;
3269
3272 minRecoveryPointTLI = replayTLI;
3273
3275
3276 /*
3277 * Before we retry, reset lastSourceFailed and currentSource
3278 * so that we will check the archive next.
3279 */
3280 lastSourceFailed = false;
3282
3283 continue;
3284 }
3285
3286 /* In standby mode, loop back to retry. Otherwise, give up. */
3288 continue;
3289 else
3290 return NULL;
3291 }
3292 }
3293}
int32_t int32
Definition: c.h:537
XLogRecPtr missingContrecPtr
Definition: xlogreader.h:214
XLogRecPtr abortedRecPtr
Definition: xlogreader.h:213
TimeLineID latestPageTLI
Definition: xlogreader.h:279
XLogRecPtr latestPagePtr
Definition: xlogreader.h:278
void * private_data
Definition: xlogreader.h:195
void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI)
Definition: xlog.c:6281
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
uint64 XLogSegNo
Definition: xlogdefs.h:52
XLogRecord * XLogPrefetcherReadRecord(XLogPrefetcher *prefetcher, char **errmsg)
XLogReaderState * XLogPrefetcherGetReader(XLogPrefetcher *prefetcher)
static bool CheckForStandbyTrigger(void)
static bool lastSourceFailed
Definition: xlogrecovery.c:250
static XLogSource currentSource
Definition: xlogrecovery.c:249
static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)

References abortedRecPtr, XLogReaderState::abortedRecPtr, AmStartupProcess, ArchiveRecoveryRequested, Assert(), CheckForStandbyTrigger(), CheckRecoveryConsistency(), close, currentSource, DEBUG1, emode_for_corrupt_record(), EnableStandbyMode(), XLogReaderState::EndRecPtr, ereport, errmsg(), errmsg_internal(), expectedTLEs, InArchiveRecovery, IsUnderPostmaster, lastSourceFailed, XLogReaderState::latestPagePtr, XLogReaderState::latestPageTLI, LSN_FORMAT_ARGS, MAXFNAMELEN, minRecoveryPoint, minRecoveryPointTLI, missingContrecPtr, XLogReaderState::missingContrecPtr, XLogReaderState::private_data, readFile, XLogReaderState::ReadRecPtr, XLogReaderState::seg, StandbyMode, StandbyModeRequested, SwitchIntoArchiveRecovery(), tliInHistory(), wal_segment_size, WALOpenSegment::ws_tli, XLByteToSeg, XLOG_FROM_ANY, XLogFileName(), xlogprefetcher, XLogPrefetcherGetReader(), XLogPrefetcherReadRecord(), xlogreader, XLogRecPtrIsValid, and XLogSegmentOffset.

Referenced by FinishWalRecovery(), InitWalRecovery(), PerformWalRecovery(), and ReadCheckpointRecord().

◆ readRecoverySignalFile()

static void readRecoverySignalFile ( void  )
static

Definition at line 1037 of file xlogrecovery.c.

1038{
1039 struct stat stat_buf;
1040
1042 return;
1043
1044 /*
1045 * Check for old recovery API file: recovery.conf
1046 */
1047 if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
1048 ereport(FATAL,
1050 errmsg("using recovery command file \"%s\" is not supported",
1052
1053 /*
1054 * Remove unused .done file, if present. Ignore if absent.
1055 */
1056 unlink(RECOVERY_COMMAND_DONE);
1057
1058 /*
1059 * Check for recovery signal files and if found, fsync them since they
1060 * represent server state information. We don't sweat too much about the
1061 * possibility of fsync failure, however.
1062 *
1063 * If present, standby signal file takes precedence. If neither is present
1064 * then we won't enter archive recovery.
1065 */
1066 if (stat(STANDBY_SIGNAL_FILE, &stat_buf) == 0)
1067 {
1068 int fd;
1069
1071 S_IRUSR | S_IWUSR);
1072 if (fd >= 0)
1073 {
1074 (void) pg_fsync(fd);
1075 close(fd);
1076 }
1078 }
1079 else if (stat(RECOVERY_SIGNAL_FILE, &stat_buf) == 0)
1080 {
1081 int fd;
1082
1084 S_IRUSR | S_IWUSR);
1085 if (fd >= 0)
1086 {
1087 (void) pg_fsync(fd);
1088 close(fd);
1089 }
1091 }
1092
1093 StandbyModeRequested = false;
1096 {
1097 StandbyModeRequested = true;
1099 }
1101 {
1102 StandbyModeRequested = false;
1104 }
1105 else
1106 return;
1107
1108 /*
1109 * We don't support standby mode in standalone backends; that requires
1110 * other processes such as the WAL receiver to be alive.
1111 */
1113 ereport(FATAL,
1114 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1115 errmsg("standby mode is not supported by single-user servers")));
1116}
#define PG_BINARY
Definition: c.h:1261
int BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition: fd.c:1108
int pg_fsync(int fd)
Definition: fd.c:386
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:477
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define S_IRUSR
Definition: win32_port.h:279
#define S_IWUSR
Definition: win32_port.h:282
#define STANDBY_SIGNAL_FILE
Definition: xlog.h:304
#define RECOVERY_SIGNAL_FILE
Definition: xlog.h:303
#define RECOVERY_COMMAND_FILE
Definition: xlogrecovery.c:71
#define RECOVERY_COMMAND_DONE
Definition: xlogrecovery.c:72

References ArchiveRecoveryRequested, BasicOpenFilePerm(), close, ereport, errcode(), errcode_for_file_access(), errmsg(), FATAL, fd(), IsBootstrapProcessingMode, IsUnderPostmaster, PG_BINARY, pg_fsync(), RECOVERY_COMMAND_DONE, RECOVERY_COMMAND_FILE, RECOVERY_SIGNAL_FILE, recovery_signal_file_found, S_IRUSR, S_IWUSR, STANDBY_SIGNAL_FILE, standby_signal_file_found, StandbyModeRequested, and stat.

Referenced by InitWalRecovery().

◆ recoveryApplyDelay()

static bool recoveryApplyDelay ( XLogReaderState record)
static

Definition at line 3006 of file xlogrecovery.c.

3007{
3008 uint8 xact_info;
3009 TimestampTz xtime;
3010 TimestampTz delayUntil;
3011 long msecs;
3012
3013 /* nothing to do if no delay configured */
3014 if (recovery_min_apply_delay <= 0)
3015 return false;
3016
3017 /* no delay is applied on a database not yet consistent */
3018 if (!reachedConsistency)
3019 return false;
3020
3021 /* nothing to do if crash recovery is requested */
3023 return false;
3024
3025 /*
3026 * Is it a COMMIT record?
3027 *
3028 * We deliberately choose not to delay aborts since they have no effect on
3029 * MVCC. We already allow replay of records that don't have a timestamp,
3030 * so there is already opportunity for issues caused by early conflicts on
3031 * standbys.
3032 */
3033 if (XLogRecGetRmid(record) != RM_XACT_ID)
3034 return false;
3035
3036 xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
3037
3038 if (xact_info != XLOG_XACT_COMMIT &&
3039 xact_info != XLOG_XACT_COMMIT_PREPARED)
3040 return false;
3041
3042 if (!getRecordTimestamp(record, &xtime))
3043 return false;
3044
3046
3047 /*
3048 * Exit without arming the latch if it's already past time to apply this
3049 * record
3050 */
3052 if (msecs <= 0)
3053 return false;
3054
3055 while (true)
3056 {
3058
3059 /* This might change recovery_min_apply_delay. */
3061
3063 break;
3064
3065 /*
3066 * Recalculate delayUntil as recovery_min_apply_delay could have
3067 * changed while waiting in this loop.
3068 */
3070
3071 /*
3072 * Wait for difference between GetCurrentTimestamp() and delayUntil.
3073 */
3075 delayUntil);
3076
3077 if (msecs <= 0)
3078 break;
3079
3080 elog(DEBUG2, "recovery apply delay %ld milliseconds", msecs);
3081
3084 msecs,
3085 WAIT_EVENT_RECOVERY_APPLY_DELAY);
3086 }
3087 return true;
3088}
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1757
#define DEBUG2
Definition: elog.h:29
void ResetLatch(Latch *latch)
Definition: latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:172
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:85
#define WL_TIMEOUT
Definition: waiteventset.h:37
#define WL_EXIT_ON_PM_DEATH
Definition: waiteventset.h:39
#define WL_LATCH_SET
Definition: waiteventset.h:34
static bool getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
int recovery_min_apply_delay
Definition: xlogrecovery.c:96

References ArchiveRecoveryRequested, CheckForStandbyTrigger(), DEBUG2, elog, GetCurrentTimestamp(), getRecordTimestamp(), ProcessStartupProcInterrupts(), reachedConsistency, recovery_min_apply_delay, XLogRecoveryCtlData::recoveryWakeupLatch, ResetLatch(), TimestampDifferenceMilliseconds(), TimestampTzPlusMilliseconds, WaitLatch(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, WL_TIMEOUT, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_PREPARED, XLOG_XACT_OPMASK, XLogRecGetInfo, XLogRecGetRmid, and XLogRecoveryCtl.

Referenced by PerformWalRecovery().

◆ recoveryPausesHere()

static void recoveryPausesHere ( bool  endOfRecovery)
static

Definition at line 2949 of file xlogrecovery.c.

2950{
2951 /* Don't pause unless users can connect! */
2953 return;
2954
2955 /* Don't pause after standby promotion has been triggered */
2957 return;
2958
2959 if (endOfRecovery)
2960 ereport(LOG,
2961 (errmsg("pausing at the end of recovery"),
2962 errhint("Execute pg_wal_replay_resume() to promote.")));
2963 else
2964 ereport(LOG,
2965 (errmsg("recovery has paused"),
2966 errhint("Execute pg_wal_replay_resume() to continue.")));
2967
2968 /* loop until recoveryPauseState is set to RECOVERY_NOT_PAUSED */
2970 {
2973 return;
2974
2975 /*
2976 * If recovery pause is requested then set it paused. While we are in
2977 * the loop, user might resume and pause again so set this every time.
2978 */
2980
2981 /*
2982 * We wait on a condition variable that will wake us as soon as the
2983 * pause ends, but we use a timeout so we can check the above exit
2984 * condition periodically too.
2985 */
2987 WAIT_EVENT_RECOVERY_PAUSE);
2988 }
2990}
bool ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
ConditionVariable recoveryNotPausedCV
Definition: xlogrecovery.c:367
static void ConfirmRecoveryPaused(void)
RecoveryPauseState GetRecoveryPauseState(void)

References CheckForStandbyTrigger(), ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), ConfirmRecoveryPaused(), ereport, errhint(), errmsg(), GetRecoveryPauseState(), LocalHotStandbyActive, LocalPromoteIsTriggered, LOG, ProcessStartupProcInterrupts(), RECOVERY_NOT_PAUSED, XLogRecoveryCtlData::recoveryNotPausedCV, and XLogRecoveryCtl.

Referenced by PerformWalRecovery(), and WaitForWALToBecomeAvailable().

◆ RecoveryRequiresIntParameter()

void RecoveryRequiresIntParameter ( const char *  param_name,
int  currValue,
int  minValue 
)

Definition at line 4715 of file xlogrecovery.c.

4716{
4717 if (currValue < minValue)
4718 {
4720 {
4721 bool warned_for_promote = false;
4722
4724 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4725 errmsg("hot standby is not possible because of insufficient parameter settings"),
4726 errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4727 param_name,
4728 currValue,
4729 minValue)));
4730
4731 SetRecoveryPause(true);
4732
4733 ereport(LOG,
4734 (errmsg("recovery has paused"),
4735 errdetail("If recovery is unpaused, the server will shut down."),
4736 errhint("You can then restart the server after making the necessary configuration changes.")));
4737
4739 {
4741
4743 {
4744 if (!warned_for_promote)
4746 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4747 errmsg("promotion is not possible because of insufficient parameter settings"),
4748
4749 /*
4750 * Repeat the detail from above so it's easy to find
4751 * in the log.
4752 */
4753 errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4754 param_name,
4755 currValue,
4756 minValue),
4757 errhint("Restart the server after making the necessary configuration changes.")));
4758 warned_for_promote = true;
4759 }
4760
4761 /*
4762 * If recovery pause is requested then set it paused. While
4763 * we are in the loop, user might resume and pause again so
4764 * set this every time.
4765 */
4767
4768 /*
4769 * We wait on a condition variable that will wake us as soon
4770 * as the pause ends, but we use a timeout so we can check the
4771 * above conditions periodically too.
4772 */
4774 WAIT_EVENT_RECOVERY_PAUSE);
4775 }
4777 }
4778
4779 ereport(FATAL,
4780 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4781 errmsg("recovery aborted because of insufficient parameter settings"),
4782 /* Repeat the detail from above so it's easy to find in the log. */
4783 errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4784 param_name,
4785 currValue,
4786 minValue),
4787 errhint("You can restart the server after making the necessary configuration changes.")));
4788 }
4789}
static bool HotStandbyActiveInReplay(void)

References CheckForStandbyTrigger(), ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), ConfirmRecoveryPaused(), ereport, errcode(), errdetail(), errhint(), errmsg(), FATAL, GetRecoveryPauseState(), HotStandbyActiveInReplay(), LOG, ProcessStartupProcInterrupts(), RECOVERY_NOT_PAUSED, XLogRecoveryCtlData::recoveryNotPausedCV, SetRecoveryPause(), WARNING, and XLogRecoveryCtl.

Referenced by CheckRequiredParameterValues().

◆ recoveryStopsAfter()

static bool recoveryStopsAfter ( XLogReaderState record)
static

Definition at line 2750 of file xlogrecovery.c.

2751{
2752 uint8 info;
2753 uint8 xact_info;
2754 uint8 rmid;
2755 TimestampTz recordXtime = 0;
2756
2757 /*
2758 * Ignore recovery target settings when not in archive recovery (meaning
2759 * we are in crash recovery).
2760 */
2762 return false;
2763
2764 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2765 rmid = XLogRecGetRmid(record);
2766
2767 /*
2768 * There can be many restore points that share the same name; we stop at
2769 * the first one.
2770 */
2772 rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2773 {
2774 xl_restore_point *recordRestorePointData;
2775
2776 recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
2777
2778 if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
2779 {
2780 recoveryStopAfter = true;
2783 (void) getRecordTimestamp(record, &recoveryStopTime);
2784 strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN);
2785
2786 ereport(LOG,
2787 (errmsg("recovery stopping at restore point \"%s\", time %s",
2790 return true;
2791 }
2792 }
2793
2794 /* Check if the target LSN has been reached */
2797 record->ReadRecPtr >= recoveryTargetLSN)
2798 {
2799 recoveryStopAfter = true;
2801 recoveryStopLSN = record->ReadRecPtr;
2802 recoveryStopTime = 0;
2803 recoveryStopName[0] = '\0';
2804 ereport(LOG,
2805 errmsg("recovery stopping after WAL location (LSN) \"%X/%08X\"",
2807 return true;
2808 }
2809
2810 if (rmid != RM_XACT_ID)
2811 return false;
2812
2813 xact_info = info & XLOG_XACT_OPMASK;
2814
2815 if (xact_info == XLOG_XACT_COMMIT ||
2816 xact_info == XLOG_XACT_COMMIT_PREPARED ||
2817 xact_info == XLOG_XACT_ABORT ||
2818 xact_info == XLOG_XACT_ABORT_PREPARED)
2819 {
2820 TransactionId recordXid;
2821
2822 /* Update the last applied transaction timestamp */
2823 if (getRecordTimestamp(record, &recordXtime))
2824 SetLatestXTime(recordXtime);
2825
2826 /* Extract the XID of the committed/aborted transaction */
2827 if (xact_info == XLOG_XACT_COMMIT_PREPARED)
2828 {
2829 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
2830 xl_xact_parsed_commit parsed;
2831
2833 xlrec,
2834 &parsed);
2835 recordXid = parsed.twophase_xid;
2836 }
2837 else if (xact_info == XLOG_XACT_ABORT_PREPARED)
2838 {
2839 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
2840 xl_xact_parsed_abort parsed;
2841
2843 xlrec,
2844 &parsed);
2845 recordXid = parsed.twophase_xid;
2846 }
2847 else
2848 recordXid = XLogRecGetXid(record);
2849
2850 /*
2851 * There can be only one transaction end record with this exact
2852 * transactionid
2853 *
2854 * when testing for an xid, we MUST test for equality only, since
2855 * transactions are numbered in the order they start, not the order
2856 * they complete. A higher numbered xid will complete before you about
2857 * 50% of the time...
2858 */
2860 recordXid == recoveryTargetXid)
2861 {
2862 recoveryStopAfter = true;
2863 recoveryStopXid = recordXid;
2864 recoveryStopTime = recordXtime;
2866 recoveryStopName[0] = '\0';
2867
2868 if (xact_info == XLOG_XACT_COMMIT ||
2869 xact_info == XLOG_XACT_COMMIT_PREPARED)
2870 {
2871 ereport(LOG,
2872 (errmsg("recovery stopping after commit of transaction %u, time %s",
2875 }
2876 else if (xact_info == XLOG_XACT_ABORT ||
2877 xact_info == XLOG_XACT_ABORT_PREPARED)
2878 {
2879 ereport(LOG,
2880 (errmsg("recovery stopping after abort of transaction %u, time %s",
2883 }
2884 return true;
2885 }
2886 }
2887
2888 /* Check if we should stop as soon as reaching consistency */
2890 {
2891 ereport(LOG,
2892 (errmsg("recovery stopping after reaching consistency")));
2893
2894 recoveryStopAfter = true;
2896 recoveryStopTime = 0;
2898 recoveryStopName[0] = '\0';
2899 return true;
2900 }
2901
2902 return false;
2903}
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char rp_name[MAXFNAMELEN]
TransactionId twophase_xid
Definition: xact.h:428
TransactionId twophase_xid
Definition: xact.h:398
#define InvalidTransactionId
Definition: transam.h:31
void ParseCommitRecord(uint8 info, xl_xact_commit *xlrec, xl_xact_parsed_commit *parsed)
Definition: xactdesc.c:35
void ParseAbortRecord(uint8 info, xl_xact_abort *xlrec, xl_xact_parsed_abort *parsed)
Definition: xactdesc.c:141
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:411
bool recoveryTargetInclusive
Definition: xlogrecovery.c:89
static void SetLatestXTime(TimestampTz xtime)

References ArchiveRecoveryRequested, ereport, errmsg(), getRecordTimestamp(), InvalidTransactionId, InvalidXLogRecPtr, LOG, LSN_FORMAT_ARGS, MAXFNAMELEN, ParseAbortRecord(), ParseCommitRecord(), reachedConsistency, XLogReaderState::ReadRecPtr, RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_LSN, RECOVERY_TARGET_NAME, RECOVERY_TARGET_XID, recoveryStopAfter, recoveryStopLSN, recoveryStopName, recoveryStopTime, recoveryStopXid, recoveryTarget, recoveryTargetInclusive, recoveryTargetLSN, recoveryTargetName, recoveryTargetXid, xl_restore_point::rp_name, SetLatestXTime(), strlcpy(), timestamptz_to_str(), xl_xact_parsed_commit::twophase_xid, xl_xact_parsed_abort::twophase_xid, XLOG_RESTORE_POINT, XLOG_XACT_ABORT, XLOG_XACT_ABORT_PREPARED, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_PREPARED, XLOG_XACT_OPMASK, XLogRecGetData, XLogRecGetInfo, XLogRecGetRmid, and XLogRecGetXid.

Referenced by PerformWalRecovery().

◆ recoveryStopsBefore()

static bool recoveryStopsBefore ( XLogReaderState record)
static

Definition at line 2597 of file xlogrecovery.c.

2598{
2599 bool stopsHere = false;
2600 uint8 xact_info;
2601 bool isCommit;
2602 TimestampTz recordXtime = 0;
2603 TransactionId recordXid;
2604
2605 /*
2606 * Ignore recovery target settings when not in archive recovery (meaning
2607 * we are in crash recovery).
2608 */
2610 return false;
2611
2612 /* Check if we should stop as soon as reaching consistency */
2614 {
2615 ereport(LOG,
2616 (errmsg("recovery stopping after reaching consistency")));
2617
2618 recoveryStopAfter = false;
2621 recoveryStopTime = 0;
2622 recoveryStopName[0] = '\0';
2623 return true;
2624 }
2625
2626 /* Check if target LSN has been reached */
2629 record->ReadRecPtr >= recoveryTargetLSN)
2630 {
2631 recoveryStopAfter = false;
2633 recoveryStopLSN = record->ReadRecPtr;
2634 recoveryStopTime = 0;
2635 recoveryStopName[0] = '\0';
2636 ereport(LOG,
2637 errmsg("recovery stopping before WAL location (LSN) \"%X/%08X\"",
2639 return true;
2640 }
2641
2642 /* Otherwise we only consider stopping before COMMIT or ABORT records. */
2643 if (XLogRecGetRmid(record) != RM_XACT_ID)
2644 return false;
2645
2646 xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
2647
2648 if (xact_info == XLOG_XACT_COMMIT)
2649 {
2650 isCommit = true;
2651 recordXid = XLogRecGetXid(record);
2652 }
2653 else if (xact_info == XLOG_XACT_COMMIT_PREPARED)
2654 {
2655 xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
2656 xl_xact_parsed_commit parsed;
2657
2658 isCommit = true;
2660 xlrec,
2661 &parsed);
2662 recordXid = parsed.twophase_xid;
2663 }
2664 else if (xact_info == XLOG_XACT_ABORT)
2665 {
2666 isCommit = false;
2667 recordXid = XLogRecGetXid(record);
2668 }
2669 else if (xact_info == XLOG_XACT_ABORT_PREPARED)
2670 {
2671 xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
2672 xl_xact_parsed_abort parsed;
2673
2674 isCommit = false;
2676 xlrec,
2677 &parsed);
2678 recordXid = parsed.twophase_xid;
2679 }
2680 else
2681 return false;
2682
2684 {
2685 /*
2686 * There can be only one transaction end record with this exact
2687 * transactionid
2688 *
2689 * when testing for an xid, we MUST test for equality only, since
2690 * transactions are numbered in the order they start, not the order
2691 * they complete. A higher numbered xid will complete before you about
2692 * 50% of the time...
2693 */
2694 stopsHere = (recordXid == recoveryTargetXid);
2695 }
2696
2697 /*
2698 * Note: we must fetch recordXtime regardless of recoveryTarget setting.
2699 * We don't expect getRecordTimestamp ever to fail, since we already know
2700 * this is a commit or abort record; but test its result anyway.
2701 */
2702 if (getRecordTimestamp(record, &recordXtime) &&
2704 {
2705 /*
2706 * There can be many transactions that share the same commit time, so
2707 * we stop after the last one, if we are inclusive, or stop at the
2708 * first one if we are exclusive
2709 */
2711 stopsHere = (recordXtime > recoveryTargetTime);
2712 else
2713 stopsHere = (recordXtime >= recoveryTargetTime);
2714 }
2715
2716 if (stopsHere)
2717 {
2718 recoveryStopAfter = false;
2719 recoveryStopXid = recordXid;
2720 recoveryStopTime = recordXtime;
2722 recoveryStopName[0] = '\0';
2723
2724 if (isCommit)
2725 {
2726 ereport(LOG,
2727 (errmsg("recovery stopping before commit of transaction %u, time %s",
2730 }
2731 else
2732 {
2733 ereport(LOG,
2734 (errmsg("recovery stopping before abort of transaction %u, time %s",
2737 }
2738 }
2739
2740 return stopsHere;
2741}

References ArchiveRecoveryRequested, ereport, errmsg(), getRecordTimestamp(), InvalidTransactionId, InvalidXLogRecPtr, LOG, LSN_FORMAT_ARGS, ParseAbortRecord(), ParseCommitRecord(), reachedConsistency, XLogReaderState::ReadRecPtr, RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_LSN, RECOVERY_TARGET_TIME, RECOVERY_TARGET_XID, recoveryStopAfter, recoveryStopLSN, recoveryStopName, recoveryStopTime, recoveryStopXid, recoveryTarget, recoveryTargetInclusive, recoveryTargetLSN, recoveryTargetTime, recoveryTargetXid, timestamptz_to_str(), xl_xact_parsed_commit::twophase_xid, xl_xact_parsed_abort::twophase_xid, XLOG_XACT_ABORT, XLOG_XACT_ABORT_PREPARED, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_PREPARED, XLOG_XACT_OPMASK, XLogRecGetData, XLogRecGetInfo, XLogRecGetRmid, and XLogRecGetXid.

Referenced by PerformWalRecovery().

◆ RemovePromoteSignalFiles()

void RemovePromoteSignalFiles ( void  )

Definition at line 4510 of file xlogrecovery.c.

4511{
4512 unlink(PROMOTE_SIGNAL_FILE);
4513}

References PROMOTE_SIGNAL_FILE.

Referenced by CheckForStandbyTrigger(), and PostmasterMain().

◆ rescanLatestTimeLine()

static bool rescanLatestTimeLine ( TimeLineID  replayTLI,
XLogRecPtr  replayLSN 
)
static

Definition at line 4162 of file xlogrecovery.c.

4163{
4164 List *newExpectedTLEs;
4165 bool found;
4166 ListCell *cell;
4167 TimeLineID newtarget;
4168 TimeLineID oldtarget = recoveryTargetTLI;
4169 TimeLineHistoryEntry *currentTle = NULL;
4170
4172 if (newtarget == recoveryTargetTLI)
4173 {
4174 /* No new timelines found */
4175 return false;
4176 }
4177
4178 /*
4179 * Determine the list of expected TLIs for the new TLI
4180 */
4181
4182 newExpectedTLEs = readTimeLineHistory(newtarget);
4183
4184 /*
4185 * If the current timeline is not part of the history of the new timeline,
4186 * we cannot proceed to it.
4187 */
4188 found = false;
4189 foreach(cell, newExpectedTLEs)
4190 {
4191 currentTle = (TimeLineHistoryEntry *) lfirst(cell);
4192
4193 if (currentTle->tli == recoveryTargetTLI)
4194 {
4195 found = true;
4196 break;
4197 }
4198 }
4199 if (!found)
4200 {
4201 ereport(LOG,
4202 (errmsg("new timeline %u is not a child of database system timeline %u",
4203 newtarget,
4204 replayTLI)));
4205 return false;
4206 }
4207
4208 /*
4209 * The current timeline was found in the history file, but check that the
4210 * next timeline was forked off from it *after* the current recovery
4211 * location.
4212 */
4213 if (currentTle->end < replayLSN)
4214 {
4215 ereport(LOG,
4216 errmsg("new timeline %u forked off current database system timeline %u before current recovery point %X/%08X",
4217 newtarget,
4218 replayTLI,
4219 LSN_FORMAT_ARGS(replayLSN)));
4220 return false;
4221 }
4222
4223 /* The new timeline history seems valid. Switch target */
4224 recoveryTargetTLI = newtarget;
4226 expectedTLEs = newExpectedTLEs;
4227
4228 /*
4229 * As in StartupXLOG(), try to ensure we have all the history files
4230 * between the old target and new target in pg_wal.
4231 */
4232 restoreTimeLineHistoryFiles(oldtarget + 1, newtarget);
4233
4234 ereport(LOG,
4235 (errmsg("new target timeline is %u",
4237
4238 return true;
4239}
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:76
TimeLineID findNewestTimeLine(TimeLineID startTLI)
Definition: timeline.c:264
void restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
Definition: timeline.c:50
void list_free_deep(List *list)
Definition: list.c:1560
TimeLineID tli
Definition: timeline.h:27
XLogRecPtr end
Definition: timeline.h:29

References TimeLineHistoryEntry::end, ereport, errmsg(), expectedTLEs, findNewestTimeLine(), lfirst, list_free_deep(), LOG, LSN_FORMAT_ARGS, readTimeLineHistory(), recoveryTargetTLI, restoreTimeLineHistoryFiles(), and TimeLineHistoryEntry::tli.

Referenced by WaitForWALToBecomeAvailable().

◆ rm_redo_error_callback()

static void rm_redo_error_callback ( void *  arg)
static

Definition at line 2299 of file xlogrecovery.c.

2300{
2301 XLogReaderState *record = (XLogReaderState *) arg;
2303
2305 xlog_outdesc(&buf, record);
2306 xlog_block_info(&buf, record);
2307
2308 /* translator: %s is a WAL record description */
2309 errcontext("WAL redo at %X/%08X for %s",
2310 LSN_FORMAT_ARGS(record->ReadRecPtr),
2311 buf.data);
2312
2313 pfree(buf.data);
2314}
#define errcontext
Definition: elog.h:198
void * arg
static void xlog_block_info(StringInfo buf, XLogReaderState *record)

References arg, buf, errcontext, initStringInfo(), LSN_FORMAT_ARGS, pfree(), XLogReaderState::ReadRecPtr, xlog_block_info(), and xlog_outdesc().

Referenced by ApplyWalRecord().

◆ SetCurrentChunkStartTime()

◆ SetLatestXTime()

◆ SetPromoteIsTriggered()

static void SetPromoteIsTriggered ( void  )
static

Definition at line 4468 of file xlogrecovery.c.

4469{
4473
4474 /*
4475 * Mark the recovery pause state as 'not paused' because the paused state
4476 * ends and promotion continues if a promotion is triggered while recovery
4477 * is paused. Otherwise pg_get_wal_replay_pause_state() can mistakenly
4478 * return 'paused' while a promotion is ongoing.
4479 */
4480 SetRecoveryPause(false);
4481
4483}

References XLogRecoveryCtlData::info_lck, LocalPromoteIsTriggered, SetRecoveryPause(), XLogRecoveryCtlData::SharedPromoteIsTriggered, SpinLockAcquire, SpinLockRelease, and XLogRecoveryCtl.

Referenced by CheckForStandbyTrigger().

◆ SetRecoveryPause()

◆ ShutdownWalRecovery()

void ShutdownWalRecovery ( void  )

Definition at line 1618 of file xlogrecovery.c.

1619{
1620 char recoveryPath[MAXPGPATH];
1621
1622 /* Final update of pg_stat_recovery_prefetch. */
1624
1625 /* Shut down xlogreader */
1626 if (readFile >= 0)
1627 {
1628 close(readFile);
1629 readFile = -1;
1630 }
1634
1636 {
1637 /*
1638 * Since there might be a partial WAL segment named RECOVERYXLOG, get
1639 * rid of it.
1640 */
1641 snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYXLOG");
1642 unlink(recoveryPath); /* ignore any error */
1643
1644 /* Get rid of any remaining recovered timeline-history file, too */
1645 snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYHISTORY");
1646 unlink(recoveryPath); /* ignore any error */
1647 }
1648
1649 /*
1650 * We don't need the latch anymore. It's not strictly necessary to disown
1651 * it, but let's do it for the sake of tidiness.
1652 */
1655}
void DisownLatch(Latch *latch)
Definition: latch.c:144
#define XLOGDIR
void XLogPrefetcherComputeStats(XLogPrefetcher *prefetcher)
void XLogPrefetcherFree(XLogPrefetcher *prefetcher)
void XLogReaderFree(XLogReaderState *state)
Definition: xlogreader.c:162

References ArchiveRecoveryRequested, close, DisownLatch(), MAXPGPATH, pfree(), XLogReaderState::private_data, readFile, XLogRecoveryCtlData::recoveryWakeupLatch, snprintf, XLOGDIR, xlogprefetcher, XLogPrefetcherComputeStats(), XLogPrefetcherFree(), xlogreader, XLogReaderFree(), and XLogRecoveryCtl.

Referenced by StartupXLOG().

◆ StartupRequestWalReceiverRestart()

void StartupRequestWalReceiverRestart ( void  )

Definition at line 4431 of file xlogrecovery.c.

4432{
4434 {
4435 ereport(LOG,
4436 (errmsg("WAL receiver process shutdown requested")));
4437
4438 pendingWalRcvRestart = true;
4439 }
4440}
bool WalRcvRunning(void)
static bool pendingWalRcvRestart
Definition: xlogrecovery.c:251

References currentSource, ereport, errmsg(), LOG, pendingWalRcvRestart, WalRcvRunning(), and XLOG_FROM_STREAM.

Referenced by StartupRereadConfig().

◆ validateRecoveryParameters()

static void validateRecoveryParameters ( void  )
static

Definition at line 1119 of file xlogrecovery.c.

1120{
1122 return;
1123
1124 /*
1125 * Check for compulsory parameters
1126 */
1128 {
1129 if ((PrimaryConnInfo == NULL || strcmp(PrimaryConnInfo, "") == 0) &&
1130 (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0))
1132 (errmsg("specified neither \"primary_conninfo\" nor \"restore_command\""),
1133 errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
1134 }
1135 else
1136 {
1137 if (recoveryRestoreCommand == NULL ||
1138 strcmp(recoveryRestoreCommand, "") == 0)
1139 ereport(FATAL,
1140 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1141 errmsg("must specify \"restore_command\" when standby mode is not enabled")));
1142 }
1143
1144 /*
1145 * Override any inconsistent requests. Note that this is a change of
1146 * behaviour in 9.5; prior to this we simply ignored a request to pause if
1147 * hot_standby = off, which was surprising behaviour.
1148 */
1152
1153 /*
1154 * Final parsing of recovery_target_time string; see also
1155 * check_recovery_target_time().
1156 */
1158 {
1162 Int32GetDatum(-1)));
1163 }
1164
1165 /*
1166 * If user specified recovery_target_timeline, validate it or compute the
1167 * "latest" value. We can't do this until after we've gotten the restore
1168 * command and set InArchiveRecovery, because we need to fetch timeline
1169 * history files from the archive.
1170 */
1172 {
1174
1175 /* Timeline 1 does not have a history file, all else should */
1176 if (rtli != 1 && !existsTimeLineHistory(rtli))
1177 ereport(FATAL,
1178 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1179 errmsg("recovery target timeline %u does not exist",
1180 rtli)));
1181 recoveryTargetTLI = rtli;
1182 }
1184 {
1185 /* We start the "latest" search from pg_control's timeline */
1187 }
1188 else
1189 {
1190 /*
1191 * else we just use the recoveryTargetTLI as already read from
1192 * ControlFile
1193 */
1195 }
1196}
bool existsTimeLineHistory(TimeLineID probeTLI)
Definition: timeline.c:222
Datum timestamptz_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:418
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:686
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
#define InvalidOid
Definition: postgres_ext.h:37
static TimestampTz DatumGetTimestampTz(Datum X)
Definition: timestamp.h:34
bool EnableHotStandby
Definition: xlog.c:123
char * recoveryRestoreCommand
Definition: xlogrecovery.c:85
char * recovery_target_time_string
Definition: xlogrecovery.c:92
char * PrimaryConnInfo
Definition: xlogrecovery.c:99

References ArchiveRecoveryRequested, Assert(), CStringGetDatum(), DatumGetTimestampTz(), DirectFunctionCall3, EnableHotStandby, ereport, errcode(), errhint(), errmsg(), existsTimeLineHistory(), FATAL, findNewestTimeLine(), Int32GetDatum(), InvalidOid, ObjectIdGetDatum(), PrimaryConnInfo, RECOVERY_TARGET_ACTION_PAUSE, RECOVERY_TARGET_ACTION_SHUTDOWN, RECOVERY_TARGET_TIME, recovery_target_time_string, RECOVERY_TARGET_TIMELINE_CONTROLFILE, RECOVERY_TARGET_TIMELINE_LATEST, RECOVERY_TARGET_TIMELINE_NUMERIC, recoveryRestoreCommand, recoveryTarget, recoveryTargetAction, recoveryTargetTime, recoveryTargetTimeLineGoal, recoveryTargetTLI, recoveryTargetTLIRequested, StandbyModeRequested, timestamptz_in(), and WARNING.

Referenced by InitWalRecovery().

◆ verifyBackupPageConsistency()

static void verifyBackupPageConsistency ( XLogReaderState record)
static

Definition at line 2485 of file xlogrecovery.c.

2486{
2487 RmgrData rmgr = GetRmgr(XLogRecGetRmid(record));
2488 RelFileLocator rlocator;
2489 ForkNumber forknum;
2490 BlockNumber blkno;
2491 int block_id;
2492
2493 /* Records with no backup blocks have no need for consistency checks. */
2494 if (!XLogRecHasAnyBlockRefs(record))
2495 return;
2496
2498
2499 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
2500 {
2501 Buffer buf;
2502 Page page;
2503
2504 if (!XLogRecGetBlockTagExtended(record, block_id,
2505 &rlocator, &forknum, &blkno, NULL))
2506 {
2507 /*
2508 * WAL record doesn't contain a block reference with the given id.
2509 * Do nothing.
2510 */
2511 continue;
2512 }
2513
2514 Assert(XLogRecHasBlockImage(record, block_id));
2515
2516 if (XLogRecBlockImageApply(record, block_id))
2517 {
2518 /*
2519 * WAL record has already applied the page, so bypass the
2520 * consistency check as that would result in comparing the full
2521 * page stored in the record with itself.
2522 */
2523 continue;
2524 }
2525
2526 /*
2527 * Read the contents from the current buffer and store it in a
2528 * temporary page.
2529 */
2530 buf = XLogReadBufferExtended(rlocator, forknum, blkno,
2533 if (!BufferIsValid(buf))
2534 continue;
2535
2537 page = BufferGetPage(buf);
2538
2539 /*
2540 * Take a copy of the local page where WAL has been applied to have a
2541 * comparison base before masking it...
2542 */
2543 memcpy(replay_image_masked, page, BLCKSZ);
2544
2545 /* No need for this page anymore now that a copy is in. */
2547
2548 /*
2549 * If the block LSN is already ahead of this WAL record, we can't
2550 * expect contents to match. This can happen if recovery is
2551 * restarted.
2552 */
2554 continue;
2555
2556 /*
2557 * Read the contents from the backup copy, stored in WAL record and
2558 * store it in a temporary page. There is no need to allocate a new
2559 * page here, a local buffer is fine to hold its contents and a mask
2560 * can be directly applied on it.
2561 */
2562 if (!RestoreBlockImage(record, block_id, primary_image_masked))
2563 ereport(ERROR,
2564 (errcode(ERRCODE_INTERNAL_ERROR),
2565 errmsg_internal("%s", record->errormsg_buf)));
2566
2567 /*
2568 * If masking function is defined, mask both the primary and replay
2569 * images
2570 */
2571 if (rmgr.rm_mask != NULL)
2572 {
2573 rmgr.rm_mask(replay_image_masked, blkno);
2574 rmgr.rm_mask(primary_image_masked, blkno);
2575 }
2576
2577 /* Time to compare the primary and replay images. */
2578 if (memcmp(replay_image_masked, primary_image_masked, BLCKSZ) != 0)
2579 {
2580 elog(FATAL,
2581 "inconsistent page found, rel %u/%u/%u, forknum %u, blkno %u",
2582 rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
2583 forknum, blkno);
2584 }
2585 }
2586}
uint32 BlockNumber
Definition: block.h:31
int Buffer
Definition: buf.h:23
#define InvalidBuffer
Definition: buf.h:25
void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition: bufmgr.c:5604
void UnlockReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:5383
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:436
@ BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:207
@ RBM_NORMAL_NO_LOG
Definition: bufmgr.h:52
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:387
PageData * Page
Definition: bufpage.h:81
static XLogRecPtr PageGetLSN(const PageData *page)
Definition: bufpage.h:385
ForkNumber
Definition: relpath.h:56
RelFileNumber relNumber
void(* rm_mask)(char *pagedata, BlockNumber blkno)
char * errormsg_buf
Definition: xlogreader.h:310
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
Definition: xlogreader.c:2017
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
Definition: xlogreader.c:2076
#define XLogRecBlockImageApply(decoder, block_id)
Definition: xlogreader.h:424
#define XLogRecMaxBlockId(decoder)
Definition: xlogreader.h:417
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:422
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:416
Buffer XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum, BlockNumber blkno, ReadBufferMode mode, Buffer recent_buffer)
Definition: xlogutils.c:460

References Assert(), buf, BUFFER_LOCK_EXCLUSIVE, BufferGetPage(), BufferIsValid(), RelFileLocator::dbOid, elog, XLogReaderState::EndRecPtr, ereport, errcode(), errmsg_internal(), ERROR, XLogReaderState::errormsg_buf, FATAL, GetRmgr(), InvalidBuffer, LockBuffer(), PageGetLSN(), primary_image_masked, RBM_NORMAL_NO_LOG, RelFileLocator::relNumber, replay_image_masked, RestoreBlockImage(), RmgrData::rm_mask, RelFileLocator::spcOid, UnlockReleaseBuffer(), XLogReadBufferExtended(), XLogRecBlockImageApply, XLogRecGetBlockTagExtended(), XLogRecGetInfo, XLogRecGetRmid, XLogRecHasAnyBlockRefs, XLogRecHasBlockImage, XLogRecMaxBlockId, and XLR_CHECK_CONSISTENCY.

Referenced by ApplyWalRecord().

◆ WaitForWALToBecomeAvailable()

static XLogPageReadResult WaitForWALToBecomeAvailable ( XLogRecPtr  RecPtr,
bool  randAccess,
bool  fetching_ckpt,
XLogRecPtr  tliRecPtr,
TimeLineID  replayTLI,
XLogRecPtr  replayLSN,
bool  nonblocking 
)
static

Definition at line 3581 of file xlogrecovery.c.

3585{
3586 static TimestampTz last_fail_time = 0;
3588 bool streaming_reply_sent = false;
3589
3590 /*-------
3591 * Standby mode is implemented by a state machine:
3592 *
3593 * 1. Read from either archive or pg_wal (XLOG_FROM_ARCHIVE), or just
3594 * pg_wal (XLOG_FROM_PG_WAL)
3595 * 2. Check for promotion trigger request
3596 * 3. Read from primary server via walreceiver (XLOG_FROM_STREAM)
3597 * 4. Rescan timelines
3598 * 5. Sleep wal_retrieve_retry_interval milliseconds, and loop back to 1.
3599 *
3600 * Failure to read from the current source advances the state machine to
3601 * the next state.
3602 *
3603 * 'currentSource' indicates the current state. There are no currentSource
3604 * values for "check trigger", "rescan timelines", and "sleep" states,
3605 * those actions are taken when reading from the previous source fails, as
3606 * part of advancing to the next state.
3607 *
3608 * If standby mode is turned off while reading WAL from stream, we move
3609 * to XLOG_FROM_ARCHIVE and reset lastSourceFailed, to force fetching
3610 * the files (which would be required at end of recovery, e.g., timeline
3611 * history file) from archive or pg_wal. We don't need to kill WAL receiver
3612 * here because it's already stopped when standby mode is turned off at
3613 * the end of recovery.
3614 *-------
3615 */
3616 if (!InArchiveRecovery)
3618 else if (currentSource == XLOG_FROM_ANY ||
3620 {
3621 lastSourceFailed = false;
3623 }
3624
3625 for (;;)
3626 {
3627 XLogSource oldSource = currentSource;
3628 bool startWalReceiver = false;
3629
3630 /*
3631 * First check if we failed to read from the current source, and
3632 * advance the state machine if so. The failure to read might've
3633 * happened outside this function, e.g when a CRC check fails on a
3634 * record, or within this loop.
3635 */
3636 if (lastSourceFailed)
3637 {
3638 /*
3639 * Don't allow any retry loops to occur during nonblocking
3640 * readahead. Let the caller process everything that has been
3641 * decoded already first.
3642 */
3643 if (nonblocking)
3644 return XLREAD_WOULDBLOCK;
3645
3646 switch (currentSource)
3647 {
3648 case XLOG_FROM_ARCHIVE:
3649 case XLOG_FROM_PG_WAL:
3650
3651 /*
3652 * Check to see if promotion is requested. Note that we do
3653 * this only after failure, so when you promote, we still
3654 * finish replaying as much as we can from archive and
3655 * pg_wal before failover.
3656 */
3658 {
3660 return XLREAD_FAIL;
3661 }
3662
3663 /*
3664 * Not in standby mode, and we've now tried the archive
3665 * and pg_wal.
3666 */
3667 if (!StandbyMode)
3668 return XLREAD_FAIL;
3669
3670 /*
3671 * Move to XLOG_FROM_STREAM state, and set to start a
3672 * walreceiver if necessary.
3673 */
3675 startWalReceiver = true;
3676 break;
3677
3678 case XLOG_FROM_STREAM:
3679
3680 /*
3681 * Failure while streaming. Most likely, we got here
3682 * because streaming replication was terminated, or
3683 * promotion was triggered. But we also get here if we
3684 * find an invalid record in the WAL streamed from the
3685 * primary, in which case something is seriously wrong.
3686 * There's little chance that the problem will just go
3687 * away, but PANIC is not good for availability either,
3688 * especially in hot standby mode. So, we treat that the
3689 * same as disconnection, and retry from archive/pg_wal
3690 * again. The WAL in the archive should be identical to
3691 * what was streamed, so it's unlikely that it helps, but
3692 * one can hope...
3693 */
3694
3695 /*
3696 * We should be able to move to XLOG_FROM_STREAM only in
3697 * standby mode.
3698 */
3700
3701 /*
3702 * Before we leave XLOG_FROM_STREAM state, make sure that
3703 * walreceiver is not active, so that it won't overwrite
3704 * WAL that we restore from archive.
3705 *
3706 * If walreceiver is actively streaming (or attempting to
3707 * connect), we must shut it down. However, if it's
3708 * already in WAITING state (e.g., due to timeline
3709 * divergence), we only need to reset the install flag to
3710 * allow archive restoration.
3711 */
3712 if (WalRcvStreaming())
3714 else
3715 {
3716 /*
3717 * WALRCV_STOPPING state is a transient state while
3718 * the startup process is in ShutdownWalRcv(). It
3719 * should never appear here since we would be waiting
3720 * for the walreceiver to reach WALRCV_STOPPED in that
3721 * case.
3722 */
3725 }
3726
3727 /*
3728 * Before we sleep, re-scan for possible new timelines if
3729 * we were requested to recover to the latest timeline.
3730 */
3732 {
3733 if (rescanLatestTimeLine(replayTLI, replayLSN))
3734 {
3736 break;
3737 }
3738 }
3739
3740 /*
3741 * XLOG_FROM_STREAM is the last state in our state
3742 * machine, so we've exhausted all the options for
3743 * obtaining the requested WAL. We're going to loop back
3744 * and retry from the archive, but if it hasn't been long
3745 * since last attempt, sleep wal_retrieve_retry_interval
3746 * milliseconds to avoid busy-waiting.
3747 */
3749 if (!TimestampDifferenceExceeds(last_fail_time, now,
3751 {
3752 long wait_time;
3753
3754 wait_time = wal_retrieve_retry_interval -
3755 TimestampDifferenceMilliseconds(last_fail_time, now);
3756
3757 elog(LOG, "waiting for WAL to become available at %X/%08X",
3758 LSN_FORMAT_ARGS(RecPtr));
3759
3760 /* Do background tasks that might benefit us later. */
3762
3766 wait_time,
3767 WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL);
3770
3771 /* Handle interrupt signals of startup process */
3773 }
3774 last_fail_time = now;
3776 break;
3777
3778 default:
3779 elog(ERROR, "unexpected WAL source %d", currentSource);
3780 }
3781 }
3782 else if (currentSource == XLOG_FROM_PG_WAL)
3783 {
3784 /*
3785 * We just successfully read a file in pg_wal. We prefer files in
3786 * the archive over ones in pg_wal, so try the next file again
3787 * from the archive first.
3788 */
3791 }
3792
3793 if (currentSource != oldSource)
3794 elog(DEBUG2, "switched WAL source from %s to %s after %s",
3796 lastSourceFailed ? "failure" : "success");
3797
3798 /*
3799 * We've now handled possible failure. Try to read from the chosen
3800 * source.
3801 */
3802 lastSourceFailed = false;
3803
3804 switch (currentSource)
3805 {
3806 case XLOG_FROM_ARCHIVE:
3807 case XLOG_FROM_PG_WAL:
3808
3809 /*
3810 * WAL receiver must not be running when reading WAL from
3811 * archive or pg_wal.
3812 */
3814
3815 /* Close any old file we might have open. */
3816 if (readFile >= 0)
3817 {
3818 close(readFile);
3819 readFile = -1;
3820 }
3821 /* Reset curFileTLI if random fetch. */
3822 if (randAccess)
3823 curFileTLI = 0;
3824
3825 /*
3826 * Try to restore the file from archive, or read an existing
3827 * file from pg_wal.
3828 */
3832 if (readFile >= 0)
3833 return XLREAD_SUCCESS; /* success! */
3834
3835 /*
3836 * Nope, not found in archive or pg_wal.
3837 */
3838 lastSourceFailed = true;
3839 break;
3840
3841 case XLOG_FROM_STREAM:
3842 {
3843 bool havedata;
3844
3845 /*
3846 * We should be able to move to XLOG_FROM_STREAM only in
3847 * standby mode.
3848 */
3850
3851 /*
3852 * First, shutdown walreceiver if its restart has been
3853 * requested -- but no point if we're already slated for
3854 * starting it.
3855 */
3856 if (pendingWalRcvRestart && !startWalReceiver)
3857 {
3859
3860 /*
3861 * Re-scan for possible new timelines if we were
3862 * requested to recover to the latest timeline.
3863 */
3866 rescanLatestTimeLine(replayTLI, replayLSN);
3867
3868 startWalReceiver = true;
3869 }
3870 pendingWalRcvRestart = false;
3871
3872 /*
3873 * Launch walreceiver if needed.
3874 *
3875 * If fetching_ckpt is true, RecPtr points to the initial
3876 * checkpoint location. In that case, we use RedoStartLSN
3877 * as the streaming start position instead of RecPtr, so
3878 * that when we later jump backwards to start redo at
3879 * RedoStartLSN, we will have the logs streamed already.
3880 */
3881 if (startWalReceiver &&
3882 PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0)
3883 {
3884 XLogRecPtr ptr;
3885 TimeLineID tli;
3886
3887 if (fetching_ckpt)
3888 {
3889 ptr = RedoStartLSN;
3890 tli = RedoStartTLI;
3891 }
3892 else
3893 {
3894 ptr = RecPtr;
3895
3896 /*
3897 * Use the record begin position to determine the
3898 * TLI, rather than the position we're reading.
3899 */
3900 tli = tliOfPointInHistory(tliRecPtr, expectedTLEs);
3901
3902 if (curFileTLI > 0 && tli < curFileTLI)
3903 elog(ERROR, "according to history file, WAL location %X/%08X belongs to timeline %u, but previous recovered WAL file came from timeline %u",
3904 LSN_FORMAT_ARGS(tliRecPtr),
3905 tli, curFileTLI);
3906 }
3907 curFileTLI = tli;
3912 flushedUpto = 0;
3913 }
3914
3915 /*
3916 * Check if WAL receiver is active or wait to start up.
3917 */
3918 if (!WalRcvStreaming())
3919 {
3920 lastSourceFailed = true;
3921 break;
3922 }
3923
3924 /*
3925 * Walreceiver is active, so see if new data has arrived.
3926 *
3927 * We only advance XLogReceiptTime when we obtain fresh
3928 * WAL from walreceiver and observe that we had already
3929 * processed everything before the most recent "chunk"
3930 * that it flushed to disk. In steady state where we are
3931 * keeping up with the incoming data, XLogReceiptTime will
3932 * be updated on each cycle. When we are behind,
3933 * XLogReceiptTime will not advance, so the grace time
3934 * allotted to conflicting queries will decrease.
3935 */
3936 if (RecPtr < flushedUpto)
3937 havedata = true;
3938 else
3939 {
3940 XLogRecPtr latestChunkStart;
3941
3942 flushedUpto = GetWalRcvFlushRecPtr(&latestChunkStart, &receiveTLI);
3943 if (RecPtr < flushedUpto && receiveTLI == curFileTLI)
3944 {
3945 havedata = true;
3946 if (latestChunkStart <= RecPtr)
3947 {
3950 }
3951 }
3952 else
3953 havedata = false;
3954 }
3955 if (havedata)
3956 {
3957 /*
3958 * Great, streamed far enough. Open the file if it's
3959 * not open already. Also read the timeline history
3960 * file if we haven't initialized timeline history
3961 * yet; it should be streamed over and present in
3962 * pg_wal by now. Use XLOG_FROM_STREAM so that source
3963 * info is set correctly and XLogReceiptTime isn't
3964 * changed.
3965 *
3966 * NB: We must set readTimeLineHistory based on
3967 * recoveryTargetTLI, not receiveTLI. Normally they'll
3968 * be the same, but if recovery_target_timeline is
3969 * 'latest' and archiving is configured, then it's
3970 * possible that we managed to retrieve one or more
3971 * new timeline history files from the archive,
3972 * updating recoveryTargetTLI.
3973 */
3974 if (readFile < 0)
3975 {
3976 if (!expectedTLEs)
3979 XLOG_FROM_STREAM, false);
3980 Assert(readFile >= 0);
3981 }
3982 else
3983 {
3984 /* just make sure source info is correct... */
3987 return XLREAD_SUCCESS;
3988 }
3989 break;
3990 }
3991
3992 /* In nonblocking mode, return rather than sleeping. */
3993 if (nonblocking)
3994 return XLREAD_WOULDBLOCK;
3995
3996 /*
3997 * Data not here yet. Check for trigger, then wait for
3998 * walreceiver to wake us up when new WAL arrives.
3999 */
4001 {
4002 /*
4003 * Note that we don't return XLREAD_FAIL immediately
4004 * here. After being triggered, we still want to
4005 * replay all the WAL that was already streamed. It's
4006 * in pg_wal now, so we just treat this as a failure,
4007 * and the state machine will move on to replay the
4008 * streamed WAL from pg_wal, and then recheck the
4009 * trigger and exit replay.
4010 */
4011 lastSourceFailed = true;
4012 break;
4013 }
4014
4015 /*
4016 * Since we have replayed everything we have received so
4017 * far and are about to start waiting for more WAL, let's
4018 * tell the upstream server our replay location now so
4019 * that pg_stat_replication doesn't show stale
4020 * information.
4021 */
4022 if (!streaming_reply_sent)
4023 {
4025 streaming_reply_sent = true;
4026 }
4027
4028 /* Do any background tasks that might benefit us later. */
4030
4031 /* Update pg_stat_recovery_prefetch before sleeping. */
4033
4034 /*
4035 * Wait for more WAL to arrive, when we will be woken
4036 * immediately by the WAL receiver.
4037 */
4040 -1L,
4041 WAIT_EVENT_RECOVERY_WAL_STREAM);
4043 break;
4044 }
4045
4046 default:
4047 elog(ERROR, "unexpected WAL source %d", currentSource);
4048 }
4049
4050 /*
4051 * Check for recovery pause here so that we can confirm more quickly
4052 * that a requested pause has actually taken effect.
4053 */
4054 if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
4056 recoveryPausesHere(false);
4057
4058 /*
4059 * This possibly-long loop needs to handle interrupts of startup
4060 * process.
4061 */
4063 }
4064
4065 return XLREAD_FAIL; /* not reached */
4066}
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1781
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
void KnownAssignedTransactionIdsIdleMaintenance(void)
Definition: procarray.c:4526
@ WALRCV_STOPPING
Definition: walreceiver.h:53
XLogRecPtr GetWalRcvFlushRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI)
void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, const char *slotname, bool create_temp_slot)
WalRcvState WalRcvGetState(void)
void SetInstallXLogFileSegmentActive(void)
Definition: xlog.c:9547
void ResetInstallXLogFileSegmentActive(void)
Definition: xlog.c:9556
int wal_retrieve_retry_interval
Definition: xlog.c:136
@ XLREAD_WOULDBLOCK
Definition: xlogreader.h:352
@ XLREAD_SUCCESS
Definition: xlogreader.h:350
@ XLREAD_FAIL
Definition: xlogreader.h:351
char * PrimarySlotName
Definition: xlogrecovery.c:100
static TimeLineID curFileTLI
Definition: xlogrecovery.c:127
static const char *const xlogSourceNames[]
Definition: xlogrecovery.c:221
static int XLogFileReadAnyTLI(XLogSegNo segno, XLogSource source)
static TimeLineID receiveTLI
Definition: xlogrecovery.c:266
static int XLogFileRead(XLogSegNo segno, TimeLineID tli, XLogSource source, bool notfoundOk)
static XLogSegNo readSegNo
Definition: xlogrecovery.c:234
static void SetCurrentChunkStartTime(TimestampTz xtime)
bool wal_receiver_create_temp_slot
Definition: xlogrecovery.c:101
static XLogRecPtr flushedUpto
Definition: xlogrecovery.c:265
static bool rescanLatestTimeLine(TimeLineID replayTLI, XLogRecPtr replayLSN)

References Assert(), CheckForStandbyTrigger(), close, curFileTLI, currentSource, DEBUG2, elog, ERROR, expectedTLEs, flushedUpto, GetCurrentTimestamp(), GetWalRcvFlushRecPtr(), InArchiveRecovery, KnownAssignedTransactionIdsIdleMaintenance(), lastSourceFailed, LOG, LSN_FORMAT_ARGS, now(), pendingWalRcvRestart, PrimaryConnInfo, PrimarySlotName, ProcessStartupProcInterrupts(), readFile, readSegNo, readSource, readTimeLineHistory(), receiveTLI, RECOVERY_NOT_PAUSED, RECOVERY_TARGET_TIMELINE_LATEST, recoveryPausesHere(), recoveryTargetTimeLineGoal, recoveryTargetTLI, XLogRecoveryCtlData::recoveryWakeupLatch, RedoStartLSN, RedoStartTLI, RequestXLogStreaming(), rescanLatestTimeLine(), ResetInstallXLogFileSegmentActive(), ResetLatch(), SetCurrentChunkStartTime(), SetInstallXLogFileSegmentActive(), StandbyMode, TimestampDifferenceExceeds(), TimestampDifferenceMilliseconds(), tliOfPointInHistory(), WaitLatch(), wal_receiver_create_temp_slot, wal_retrieve_retry_interval, WALRCV_STOPPING, WalRcvForceReply(), WalRcvGetState(), WalRcvStreaming(), WL_EXIT_ON_PM_DEATH, WL_LATCH_SET, WL_TIMEOUT, XLOG_FROM_ANY, XLOG_FROM_ARCHIVE, XLOG_FROM_PG_WAL, XLOG_FROM_STREAM, XLogFileRead(), XLogFileReadAnyTLI(), xlogprefetcher, XLogPrefetcherComputeStats(), XLogReceiptSource, XLogReceiptTime, XLogRecoveryCtl, XLogShutdownWalRcv(), xlogSourceNames, XLREAD_FAIL, XLREAD_SUCCESS, and XLREAD_WOULDBLOCK.

Referenced by XLogPageRead().

◆ WakeupRecovery()

◆ xlog_block_info()

static void xlog_block_info ( StringInfo  buf,
XLogReaderState record 
)
static

Definition at line 2360 of file xlogrecovery.c.

2361{
2362 int block_id;
2363
2364 /* decode block references */
2365 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
2366 {
2367 RelFileLocator rlocator;
2368 ForkNumber forknum;
2369 BlockNumber blk;
2370
2371 if (!XLogRecGetBlockTagExtended(record, block_id,
2372 &rlocator, &forknum, &blk, NULL))
2373 continue;
2374
2375 if (forknum != MAIN_FORKNUM)
2376 appendStringInfo(buf, "; blkref #%d: rel %u/%u/%u, fork %u, blk %u",
2377 block_id,
2378 rlocator.spcOid, rlocator.dbOid,
2379 rlocator.relNumber,
2380 forknum,
2381 blk);
2382 else
2383 appendStringInfo(buf, "; blkref #%d: rel %u/%u/%u, blk %u",
2384 block_id,
2385 rlocator.spcOid, rlocator.dbOid,
2386 rlocator.relNumber,
2387 blk);
2388 if (XLogRecHasBlockImage(record, block_id))
2389 appendStringInfoString(buf, " FPW");
2390 }
2391}
@ MAIN_FORKNUM
Definition: relpath.h:58

References appendStringInfo(), appendStringInfoString(), buf, RelFileLocator::dbOid, MAIN_FORKNUM, RelFileLocator::relNumber, RelFileLocator::spcOid, XLogRecGetBlockTagExtended(), XLogRecHasBlockImage, and XLogRecMaxBlockId.

Referenced by rm_redo_error_callback().

◆ xlog_outdesc()

void xlog_outdesc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 2321 of file xlogrecovery.c.

2322{
2323 RmgrData rmgr = GetRmgr(XLogRecGetRmid(record));
2324 uint8 info = XLogRecGetInfo(record);
2325 const char *id;
2326
2329
2330 id = rmgr.rm_identify(info);
2331 if (id == NULL)
2332 appendStringInfo(buf, "UNKNOWN (%X): ", info & ~XLR_INFO_MASK);
2333 else
2334 appendStringInfo(buf, "%s: ", id);
2335
2336 rmgr.rm_desc(buf, record);
2337}
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
const char *(* rm_identify)(uint8 info)
const char * rm_name
void(* rm_desc)(StringInfo buf, XLogReaderState *record)

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, GetRmgr(), RmgrData::rm_desc, RmgrData::rm_identify, RmgrData::rm_name, XLogRecGetInfo, XLogRecGetRmid, and XLR_INFO_MASK.

Referenced by PerformWalRecovery(), rm_redo_error_callback(), and XLogInsertRecord().

◆ XLogFileRead()

static int XLogFileRead ( XLogSegNo  segno,
TimeLineID  tli,
XLogSource  source,
bool  notfoundOk 
)
static

Definition at line 4249 of file xlogrecovery.c.

4251{
4252 char xlogfname[MAXFNAMELEN];
4253 char activitymsg[MAXFNAMELEN + 16];
4254 char path[MAXPGPATH];
4255 int fd;
4256
4257 XLogFileName(xlogfname, tli, segno, wal_segment_size);
4258
4259 switch (source)
4260 {
4261 case XLOG_FROM_ARCHIVE:
4262 /* Report recovery progress in PS display */
4263 snprintf(activitymsg, sizeof(activitymsg), "waiting for %s",
4264 xlogfname);
4265 set_ps_display(activitymsg);
4266
4267 if (!RestoreArchivedFile(path, xlogfname,
4268 "RECOVERYXLOG",
4270 InRedo))
4271 return -1;
4272 break;
4273
4274 case XLOG_FROM_PG_WAL:
4275 case XLOG_FROM_STREAM:
4276 XLogFilePath(path, tli, segno, wal_segment_size);
4277 break;
4278
4279 default:
4280 elog(ERROR, "invalid XLogFileRead source %d", source);
4281 }
4282
4283 /*
4284 * If the segment was fetched from archival storage, replace the existing
4285 * xlog segment (if any) with the archival version.
4286 */
4288 {
4290 KeepFileRestoredFromArchive(path, xlogfname);
4291
4292 /*
4293 * Set path to point at the new file in pg_wal.
4294 */
4295 snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
4296 }
4297
4298 fd = BasicOpenFile(path, O_RDONLY | PG_BINARY);
4299 if (fd >= 0)
4300 {
4301 /* Success! */
4302 curFileTLI = tli;
4303
4304 /* Report recovery progress in PS display */
4305 snprintf(activitymsg, sizeof(activitymsg), "recovering %s",
4306 xlogfname);
4307 set_ps_display(activitymsg);
4308
4309 /* Track source of data in assorted state variables */
4312 /* In FROM_STREAM case, caller tracks receipt time, not me */
4313 if (source != XLOG_FROM_STREAM)
4315
4316 return fd;
4317 }
4318 if (errno != ENOENT || !notfoundOk) /* unexpected failure? */
4319 ereport(PANIC,
4321 errmsg("could not open file \"%s\": %m", path)));
4322 return -1;
4323}
int BasicOpenFile(const char *fileName, int fileFlags)
Definition: fd.c:1086
static rewind_source * source
Definition: pg_rewind.c:89
static void set_ps_display(const char *activity)
Definition: ps_status.h:40
bool IsInstallXLogFileSegmentActive(void)
Definition: xlog.c:9564
static void XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
bool RestoreArchivedFile(char *path, const char *xlogfname, const char *recovername, off_t expectedSize, bool cleanupEnabled)
Definition: xlogarchive.c:54
void KeepFileRestoredFromArchive(const char *path, const char *xlogfname)
Definition: xlogarchive.c:358

References Assert(), BasicOpenFile(), curFileTLI, elog, ereport, errcode_for_file_access(), errmsg(), ERROR, fd(), GetCurrentTimestamp(), InRedo, IsInstallXLogFileSegmentActive(), KeepFileRestoredFromArchive(), MAXFNAMELEN, MAXPGPATH, PANIC, PG_BINARY, readSource, RestoreArchivedFile(), set_ps_display(), snprintf, source, wal_segment_size, XLOG_FROM_ARCHIVE, XLOG_FROM_PG_WAL, XLOG_FROM_STREAM, XLOGDIR, XLogFileName(), XLogFilePath(), XLogReceiptSource, and XLogReceiptTime.

Referenced by WaitForWALToBecomeAvailable(), and XLogFileReadAnyTLI().

◆ XLogFileReadAnyTLI()

static int XLogFileReadAnyTLI ( XLogSegNo  segno,
XLogSource  source 
)
static

Definition at line 4331 of file xlogrecovery.c.

4332{
4333 char path[MAXPGPATH];
4334 ListCell *cell;
4335 int fd;
4336 List *tles;
4337
4338 /*
4339 * Loop looking for a suitable timeline ID: we might need to read any of
4340 * the timelines listed in expectedTLEs.
4341 *
4342 * We expect curFileTLI on entry to be the TLI of the preceding file in
4343 * sequence, or 0 if there was no predecessor. We do not allow curFileTLI
4344 * to go backwards; this prevents us from picking up the wrong file when a
4345 * parent timeline extends to higher segment numbers than the child we
4346 * want to read.
4347 *
4348 * If we haven't read the timeline history file yet, read it now, so that
4349 * we know which TLIs to scan. We don't save the list in expectedTLEs,
4350 * however, unless we actually find a valid segment. That way if there is
4351 * neither a timeline history file nor a WAL segment in the archive, and
4352 * streaming replication is set up, we'll read the timeline history file
4353 * streamed from the primary when we start streaming, instead of
4354 * recovering with a dummy history generated here.
4355 */
4356 if (expectedTLEs)
4357 tles = expectedTLEs;
4358 else
4360
4361 foreach(cell, tles)
4362 {
4364 TimeLineID tli = hent->tli;
4365
4366 if (tli < curFileTLI)
4367 break; /* don't bother looking at too-old TLIs */
4368
4369 /*
4370 * Skip scanning the timeline ID that the logfile segment to read
4371 * doesn't belong to
4372 */
4373 if (XLogRecPtrIsValid(hent->begin))
4374 {
4375 XLogSegNo beginseg = 0;
4376
4377 XLByteToSeg(hent->begin, beginseg, wal_segment_size);
4378
4379 /*
4380 * The logfile segment that doesn't belong to the timeline is
4381 * older or newer than the segment that the timeline started or
4382 * ended at, respectively. It's sufficient to check only the
4383 * starting segment of the timeline here. Since the timelines are
4384 * scanned in descending order in this loop, any segments newer
4385 * than the ending segment should belong to newer timeline and
4386 * have already been read before. So it's not necessary to check
4387 * the ending segment of the timeline here.
4388 */
4389 if (segno < beginseg)
4390 continue;
4391 }
4392
4394 {
4395 fd = XLogFileRead(segno, tli, XLOG_FROM_ARCHIVE, true);
4396 if (fd != -1)
4397 {
4398 elog(DEBUG1, "got WAL segment from archive");
4399 if (!expectedTLEs)
4400 expectedTLEs = tles;
4401 return fd;
4402 }
4403 }
4404
4406 {
4407 fd = XLogFileRead(segno, tli, XLOG_FROM_PG_WAL, true);
4408 if (fd != -1)
4409 {
4410 if (!expectedTLEs)
4411 expectedTLEs = tles;
4412 return fd;
4413 }
4414 }
4415 }
4416
4417 /* Couldn't find it. For simplicity, complain about front timeline */
4419 errno = ENOENT;
4422 errmsg("could not open file \"%s\": %m", path)));
4423 return -1;
4424}
XLogRecPtr begin
Definition: timeline.h:28

References TimeLineHistoryEntry::begin, curFileTLI, DEBUG1, DEBUG2, elog, ereport, errcode_for_file_access(), errmsg(), expectedTLEs, fd(), lfirst, MAXPGPATH, readTimeLineHistory(), recoveryTargetTLI, source, TimeLineHistoryEntry::tli, wal_segment_size, XLByteToSeg, XLOG_FROM_ANY, XLOG_FROM_ARCHIVE, XLOG_FROM_PG_WAL, XLogFilePath(), XLogFileRead(), and XLogRecPtrIsValid.

Referenced by WaitForWALToBecomeAvailable().

◆ XLogPageRead()

static int XLogPageRead ( XLogReaderState xlogreader,
XLogRecPtr  targetPagePtr,
int  reqLen,
XLogRecPtr  targetRecPtr,
char *  readBuf 
)
static

Definition at line 3324 of file xlogrecovery.c.

3326{
3327 XLogPageReadPrivate *private =
3329 int emode = private->emode;
3330 uint32 targetPageOff;
3332 int r;
3333 instr_time io_start;
3334
3336
3337 XLByteToSeg(targetPagePtr, targetSegNo, wal_segment_size);
3338 targetPageOff = XLogSegmentOffset(targetPagePtr, wal_segment_size);
3339
3340 /*
3341 * See if we need to switch to a new segment because the requested record
3342 * is not in the currently open one.
3343 */
3344 if (readFile >= 0 &&
3345 !XLByteInSeg(targetPagePtr, readSegNo, wal_segment_size))
3346 {
3347 /*
3348 * Request a restartpoint if we've replayed too much xlog since the
3349 * last one.
3350 */
3352 {
3354 {
3355 (void) GetRedoRecPtr();
3358 }
3359 }
3360
3361 close(readFile);
3362 readFile = -1;
3364 }
3365
3366 XLByteToSeg(targetPagePtr, readSegNo, wal_segment_size);
3367
3368retry:
3369 /* See if we need to retrieve more data */
3370 if (readFile < 0 ||
3372 flushedUpto < targetPagePtr + reqLen))
3373 {
3374 if (readFile >= 0 &&
3377 flushedUpto < targetPagePtr + reqLen)
3378 return XLREAD_WOULDBLOCK;
3379
3380 switch (WaitForWALToBecomeAvailable(targetPagePtr + reqLen,
3381 private->randAccess,
3382 private->fetching_ckpt,
3383 targetRecPtr,
3384 private->replayTLI,
3387 {
3388 case XLREAD_WOULDBLOCK:
3389 return XLREAD_WOULDBLOCK;
3390 case XLREAD_FAIL:
3391 if (readFile >= 0)
3392 close(readFile);
3393 readFile = -1;
3394 readLen = 0;
3396 return XLREAD_FAIL;
3397 case XLREAD_SUCCESS:
3398 break;
3399 }
3400 }
3401
3402 /*
3403 * At this point, we have the right segment open and if we're streaming we
3404 * know the requested record is in it.
3405 */
3406 Assert(readFile != -1);
3407
3408 /*
3409 * If the current segment is being streamed from the primary, calculate
3410 * how much of the current page we have received already. We know the
3411 * requested record has been received, but this is for the benefit of
3412 * future calls, to allow quick exit at the top of this function.
3413 */
3415 {
3416 if (((targetPagePtr) / XLOG_BLCKSZ) != (flushedUpto / XLOG_BLCKSZ))
3417 readLen = XLOG_BLCKSZ;
3418 else
3420 targetPageOff;
3421 }
3422 else
3423 readLen = XLOG_BLCKSZ;
3424
3425 /* Read the requested page */
3426 readOff = targetPageOff;
3427
3428 /* Measure I/O timing when reading segment */
3430
3431 pgstat_report_wait_start(WAIT_EVENT_WAL_READ);
3432 r = pg_pread(readFile, readBuf, XLOG_BLCKSZ, (pgoff_t) readOff);
3433 if (r != XLOG_BLCKSZ)
3434 {
3435 char fname[MAXFNAMELEN];
3436 int save_errno = errno;
3437
3439
3441 io_start, 1, r);
3442
3444 if (r < 0)
3445 {
3446 errno = save_errno;
3447 ereport(emode_for_corrupt_record(emode, targetPagePtr + reqLen),
3449 errmsg("could not read from WAL segment %s, LSN %X/%08X, offset %u: %m",
3450 fname, LSN_FORMAT_ARGS(targetPagePtr),
3451 readOff)));
3452 }
3453 else
3454 ereport(emode_for_corrupt_record(emode, targetPagePtr + reqLen),
3456 errmsg("could not read from WAL segment %s, LSN %X/%08X, offset %u: read %d of %zu",
3457 fname, LSN_FORMAT_ARGS(targetPagePtr),
3458 readOff, r, (Size) XLOG_BLCKSZ)));
3459 goto next_record_is_invalid;
3460 }
3462
3464 io_start, 1, r);
3465
3466 Assert(targetSegNo == readSegNo);
3467 Assert(targetPageOff == readOff);
3468 Assert(reqLen <= readLen);
3469
3471
3472 /*
3473 * Check the page header immediately, so that we can retry immediately if
3474 * it's not valid. This may seem unnecessary, because ReadPageInternal()
3475 * validates the page header anyway, and would propagate the failure up to
3476 * ReadRecord(), which would retry. However, there's a corner case with
3477 * continuation records, if a record is split across two pages such that
3478 * we would need to read the two pages from different sources across two
3479 * WAL segments.
3480 *
3481 * The first page is only available locally, in pg_wal, because it's
3482 * already been recycled on the primary. The second page, however, is not
3483 * present in pg_wal, and we should stream it from the primary. There is a
3484 * recycled WAL segment present in pg_wal, with garbage contents, however.
3485 * We would read the first page from the local WAL segment, but when
3486 * reading the second page, we would read the bogus, recycled, WAL
3487 * segment. If we didn't catch that case here, we would never recover,
3488 * because ReadRecord() would retry reading the whole record from the
3489 * beginning.
3490 *
3491 * Of course, this only catches errors in the page header, which is what
3492 * happens in the case of a recycled WAL segment. Other kinds of errors or
3493 * corruption still has the same problem. But this at least fixes the
3494 * common case, which can happen as part of normal operation.
3495 *
3496 * Validating the page header is cheap enough that doing it twice
3497 * shouldn't be a big deal from a performance point of view.
3498 *
3499 * When not in standby mode, an invalid page header should cause recovery
3500 * to end, not retry reading the page, so we don't need to validate the
3501 * page header here for the retry. Instead, ReadPageInternal() is
3502 * responsible for the validation.
3503 */
3504 if (StandbyMode &&
3505 (targetPagePtr % wal_segment_size) == 0 &&
3506 !XLogReaderValidatePageHeader(xlogreader, targetPagePtr, readBuf))
3507 {
3508 /*
3509 * Emit this error right now then retry this page immediately. Use
3510 * errmsg_internal() because the message was already translated.
3511 */
3512 if (xlogreader->errormsg_buf[0])
3515
3516 /* reset any error XLogReaderValidatePageHeader() might have set */
3518 goto next_record_is_invalid;
3519 }
3520
3521 return readLen;
3522
3523next_record_is_invalid:
3524
3525 /*
3526 * If we're reading ahead, give up fast. Retries and error reporting will
3527 * be handled by a later read when recovery catches up to this point.
3528 */
3530 return XLREAD_WOULDBLOCK;
3531
3532 lastSourceFailed = true;
3533
3534 if (readFile >= 0)
3535 close(readFile);
3536 readFile = -1;
3537 readLen = 0;
3539
3540 /* In standby-mode, keep trying */
3541 if (StandbyMode)
3542 goto retry;
3543 else
3544 return XLREAD_FAIL;
3545}
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:228
size_t Size
Definition: c.h:613
void RequestCheckpoint(int flags)
@ IOOBJECT_WAL
Definition: pgstat.h:279
@ IOCONTEXT_NORMAL
Definition: pgstat.h:289
@ IOOP_READ
Definition: pgstat.h:315
instr_time pgstat_prepare_io_time(bool track_io_guc)
Definition: pgstat_io.c:91
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt, uint64 bytes)
Definition: pgstat_io.c:122
#define pg_pread
Definition: port.h:247
#define pgoff_t
Definition: port.h:422
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:69
static void pgstat_report_wait_end(void)
Definition: wait_event.h:85
XLogRecPtr GetRedoRecPtr(void)
Definition: xlog.c:6509
bool track_wal_io_timing
Definition: xlog.c:139
bool XLogCheckpointNeeded(XLogSegNo new_segno)
Definition: xlog.c:2283
#define CHECKPOINT_CAUSE_XLOG
Definition: xlog.h:148
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
void XLogReaderResetError(XLogReaderState *state)
Definition: xlogreader.c:1376
bool XLogReaderValidatePageHeader(XLogReaderState *state, XLogRecPtr recptr, char *phdr)
Definition: xlogreader.c:1235
static XLogPageReadResult WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr, TimeLineID replayTLI, XLogRecPtr replayLSN, bool nonblocking)
static uint32 readLen
Definition: xlogrecovery.c:236

References AmStartupProcess, ArchiveRecoveryRequested, Assert(), CHECKPOINT_CAUSE_XLOG, close, curFileTLI, emode_for_corrupt_record(), XLogReaderState::EndRecPtr, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errcode_for_file_access(), errmsg(), errmsg_internal(), XLogReaderState::errormsg_buf, flushedUpto, GetRedoRecPtr(), IOCONTEXT_NORMAL, IOOBJECT_WAL, IOOP_READ, IsUnderPostmaster, lastSourceFailed, LSN_FORMAT_ARGS, MAXFNAMELEN, XLogReaderState::nonblocking, pg_pread, PG_USED_FOR_ASSERTS_ONLY, pgoff_t, pgstat_count_io_op_time(), pgstat_prepare_io_time(), pgstat_report_wait_end(), pgstat_report_wait_start(), XLogReaderState::private_data, readFile, readLen, readOff, readSegNo, readSource, RequestCheckpoint(), XLogReaderState::seg, StandbyMode, track_wal_io_timing, WaitForWALToBecomeAvailable(), wal_segment_size, WALOpenSegment::ws_tli, XLByteInSeg, XLByteToSeg, XLOG_FROM_ANY, XLOG_FROM_STREAM, XLogCheckpointNeeded(), XLogFileName(), xlogreader, XLogReaderResetError(), XLogReaderValidatePageHeader(), XLogSegmentOffset, XLREAD_FAIL, XLREAD_SUCCESS, and XLREAD_WOULDBLOCK.

Referenced by InitWalRecovery().

◆ xlogrecovery_redo()

static void xlogrecovery_redo ( XLogReaderState record,
TimeLineID  replayTLI 
)
static

Definition at line 2094 of file xlogrecovery.c.

2095{
2096 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2097 XLogRecPtr lsn = record->EndRecPtr;
2098
2099 Assert(XLogRecGetRmid(record) == RM_XLOG_ID);
2100
2101 if (info == XLOG_OVERWRITE_CONTRECORD)
2102 {
2103 /* Verify the payload of a XLOG_OVERWRITE_CONTRECORD record. */
2105
2106 memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_overwrite_contrecord));
2107 if (xlrec.overwritten_lsn != record->overwrittenRecPtr)
2108 elog(FATAL, "mismatching overwritten LSN %X/%08X -> %X/%08X",
2111
2112 /* We have safely skipped the aborted record */
2115
2116 ereport(LOG,
2117 errmsg("successfully skipped missing contrecord at %X/%08X, overwritten at %s",
2120
2121 /* Verifying the record should only happen once */
2123 }
2124 else if (info == XLOG_BACKUP_END)
2125 {
2126 XLogRecPtr startpoint;
2127
2128 memcpy(&startpoint, XLogRecGetData(record), sizeof(startpoint));
2129
2130 if (backupStartPoint == startpoint)
2131 {
2132 /*
2133 * We have reached the end of base backup, the point where
2134 * pg_backup_stop() was done. The data on disk is now consistent
2135 * (assuming we have also reached minRecoveryPoint). Set
2136 * backupEndPoint to the current LSN, so that the next call to
2137 * CheckRecoveryConsistency() will notice it and do the
2138 * end-of-backup processing.
2139 */
2140 elog(DEBUG1, "end of backup record reached");
2141
2142 backupEndPoint = lsn;
2143 }
2144 else
2145 elog(DEBUG1, "saw end-of-backup record for backup starting at %X/%08X, waiting for %X/%08X",
2147 }
2148}
#define XLOG_OVERWRITE_CONTRECORD
Definition: pg_control.h:81
#define XLOG_BACKUP_END
Definition: pg_control.h:73
XLogRecPtr overwrittenRecPtr
Definition: xlogreader.h:216

References abortedRecPtr, Assert(), backupEndPoint, backupStartPoint, DEBUG1, elog, XLogReaderState::EndRecPtr, ereport, errmsg(), FATAL, InvalidXLogRecPtr, LOG, LSN_FORMAT_ARGS, missingContrecPtr, xl_overwrite_contrecord::overwrite_time, xl_overwrite_contrecord::overwritten_lsn, XLogReaderState::overwrittenRecPtr, timestamptz_to_str(), XLOG_BACKUP_END, XLOG_OVERWRITE_CONTRECORD, XLogRecGetData, XLogRecGetInfo, and XLogRecGetRmid.

Referenced by ApplyWalRecord().

◆ XLogRecoveryShmemInit()

void XLogRecoveryShmemInit ( void  )

Definition at line 466 of file xlogrecovery.c.

467{
468 bool found;
469
471 ShmemInitStruct("XLOG Recovery Ctl", XLogRecoveryShmemSize(), &found);
472 if (found)
473 return;
474 memset(XLogRecoveryCtl, 0, sizeof(XLogRecoveryCtlData));
475
479}
void ConditionVariableInit(ConditionVariable *cv)
void InitSharedLatch(Latch *latch)
Definition: latch.c:93
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:389
#define SpinLockInit(lock)
Definition: spin.h:57
Size XLogRecoveryShmemSize(void)
Definition: xlogrecovery.c:455

References ConditionVariableInit(), XLogRecoveryCtlData::info_lck, InitSharedLatch(), XLogRecoveryCtlData::recoveryNotPausedCV, XLogRecoveryCtlData::recoveryWakeupLatch, ShmemInitStruct(), SpinLockInit, XLogRecoveryCtl, and XLogRecoveryShmemSize().

Referenced by CreateOrAttachShmemStructs().

◆ XLogRecoveryShmemSize()

Size XLogRecoveryShmemSize ( void  )

Definition at line 455 of file xlogrecovery.c.

456{
457 Size size;
458
459 /* XLogRecoveryCtl */
460 size = sizeof(XLogRecoveryCtlData);
461
462 return size;
463}
struct XLogRecoveryCtlData XLogRecoveryCtlData

Referenced by CalculateShmemSize(), and XLogRecoveryShmemInit().

◆ XLogRequestWalReceiverReply()

void XLogRequestWalReceiverReply ( void  )

Definition at line 4543 of file xlogrecovery.c.

4544{
4546}

References doRequestWalReceiverReply.

Referenced by xact_redo_commit().

Variable Documentation

◆ abortedRecPtr

XLogRecPtr abortedRecPtr
static

◆ archiveCleanupCommand

char* archiveCleanupCommand = NULL

Definition at line 87 of file xlogrecovery.c.

Referenced by CreateRestartPoint().

◆ ArchiveRecoveryRequested

◆ backupEndPoint

XLogRecPtr backupEndPoint
static

Definition at line 285 of file xlogrecovery.c.

Referenced by CheckRecoveryConsistency(), InitWalRecovery(), and xlogrecovery_redo().

◆ backupEndRequired

bool backupEndRequired = false
static

Definition at line 286 of file xlogrecovery.c.

Referenced by CheckRecoveryConsistency(), InitWalRecovery(), and read_backup_label().

◆ backupStartPoint

XLogRecPtr backupStartPoint
static

Definition at line 284 of file xlogrecovery.c.

Referenced by CheckRecoveryConsistency(), InitWalRecovery(), and xlogrecovery_redo().

◆ CheckPointLoc

XLogRecPtr CheckPointLoc = InvalidXLogRecPtr
static

Definition at line 170 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), InitWalRecovery(), and PerformWalRecovery().

◆ CheckPointTLI

TimeLineID CheckPointTLI = 0
static

Definition at line 171 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), InitWalRecovery(), and PerformWalRecovery().

◆ curFileTLI

TimeLineID curFileTLI
static

◆ currentSource

XLogSource currentSource = XLOG_FROM_ANY
static

◆ doRequestWalReceiverReply

bool doRequestWalReceiverReply
static

Definition at line 188 of file xlogrecovery.c.

Referenced by ApplyWalRecord(), and XLogRequestWalReceiverReply().

◆ expectedTLEs

◆ flushedUpto

XLogRecPtr flushedUpto = 0
static

Definition at line 265 of file xlogrecovery.c.

Referenced by WaitForWALToBecomeAvailable(), and XLogPageRead().

◆ InArchiveRecovery

◆ InRedo

bool InRedo = false
static

Definition at line 206 of file xlogrecovery.c.

Referenced by PerformWalRecovery(), and XLogFileRead().

◆ lastSourceFailed

bool lastSourceFailed = false
static

Definition at line 250 of file xlogrecovery.c.

Referenced by ReadRecord(), WaitForWALToBecomeAvailable(), and XLogPageRead().

◆ LocalHotStandbyActive

bool LocalHotStandbyActive = false
static

◆ LocalPromoteIsTriggered

bool LocalPromoteIsTriggered = false
static

◆ minRecoveryPoint

XLogRecPtr minRecoveryPoint
static

◆ minRecoveryPointTLI

TimeLineID minRecoveryPointTLI
static

Definition at line 282 of file xlogrecovery.c.

Referenced by checkTimeLineSwitch(), InitWalRecovery(), and ReadRecord().

◆ missingContrecPtr

XLogRecPtr missingContrecPtr
static

◆ pendingWalRcvRestart

bool pendingWalRcvRestart = false
static

◆ primary_image_masked

char* primary_image_masked = NULL
static

Definition at line 306 of file xlogrecovery.c.

Referenced by InitWalRecovery(), and verifyBackupPageConsistency().

◆ PrimaryConnInfo

◆ PrimarySlotName

◆ reachedConsistency

◆ readFile

int readFile = -1
static

◆ readLen

uint32 readLen = 0
static

Definition at line 236 of file xlogrecovery.c.

Referenced by ReadPageInternal(), XLogFindNextRecord(), and XLogPageRead().

◆ readOff

uint32 readOff = 0
static

Definition at line 235 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), XLogDecodeNextRecord(), and XLogPageRead().

◆ readSegNo

XLogSegNo readSegNo = 0
static

Definition at line 234 of file xlogrecovery.c.

Referenced by WaitForWALToBecomeAvailable(), and XLogPageRead().

◆ readSource

◆ receiveTLI

TimeLineID receiveTLI = 0
static

◆ recovery_min_apply_delay

int recovery_min_apply_delay = 0

Definition at line 96 of file xlogrecovery.c.

Referenced by recoveryApplyDelay().

◆ recovery_signal_file_found

bool recovery_signal_file_found = false
static

Definition at line 154 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), and readRecoverySignalFile().

◆ recovery_target_action_options

const struct config_enum_entry recovery_target_action_options[]
Initial value:
= {
{"pause", RECOVERY_TARGET_ACTION_PAUSE, false},
{"promote", RECOVERY_TARGET_ACTION_PROMOTE, false},
{"shutdown", RECOVERY_TARGET_ACTION_SHUTDOWN, false},
{NULL, 0, false}
}

Definition at line 77 of file xlogrecovery.c.

◆ recovery_target_time_string

char* recovery_target_time_string

Definition at line 92 of file xlogrecovery.c.

Referenced by validateRecoveryParameters().

◆ recoveryEndCommand

char* recoveryEndCommand = NULL

Definition at line 86 of file xlogrecovery.c.

Referenced by CleanupAfterArchiveRecovery().

◆ recoveryRestoreCommand

char* recoveryRestoreCommand = NULL

Definition at line 85 of file xlogrecovery.c.

Referenced by RestoreArchivedFile(), and validateRecoveryParameters().

◆ recoveryStopAfter

bool recoveryStopAfter
static

Definition at line 391 of file xlogrecovery.c.

Referenced by getRecoveryStopReason(), recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryStopLSN

XLogRecPtr recoveryStopLSN
static

Definition at line 389 of file xlogrecovery.c.

Referenced by getRecoveryStopReason(), recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryStopName

char recoveryStopName[MAXFNAMELEN]
static

Definition at line 390 of file xlogrecovery.c.

Referenced by getRecoveryStopReason(), recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryStopTime

TimestampTz recoveryStopTime
static

Definition at line 388 of file xlogrecovery.c.

Referenced by getRecoveryStopReason(), recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryStopXid

TransactionId recoveryStopXid
static

Definition at line 387 of file xlogrecovery.c.

Referenced by getRecoveryStopReason(), recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryTarget

◆ recoveryTargetAction

int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE

Definition at line 90 of file xlogrecovery.c.

Referenced by PerformWalRecovery(), and validateRecoveryParameters().

◆ recoveryTargetInclusive

bool recoveryTargetInclusive = true

Definition at line 89 of file xlogrecovery.c.

Referenced by recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryTargetLSN

XLogRecPtr recoveryTargetLSN

◆ recoveryTargetName

const char* recoveryTargetName

Definition at line 94 of file xlogrecovery.c.

Referenced by assign_recovery_target_name(), InitWalRecovery(), and recoveryStopsAfter().

◆ recoveryTargetTime

TimestampTz recoveryTargetTime

Definition at line 93 of file xlogrecovery.c.

Referenced by InitWalRecovery(), recoveryStopsBefore(), and validateRecoveryParameters().

◆ recoveryTargetTimeLineGoal

◆ recoveryTargetTLI

◆ recoveryTargetTLIRequested

TimeLineID recoveryTargetTLIRequested = 0

Definition at line 124 of file xlogrecovery.c.

Referenced by assign_recovery_target_timeline(), and validateRecoveryParameters().

◆ recoveryTargetXid

◆ RedoStartLSN

◆ RedoStartTLI

TimeLineID RedoStartTLI = 0
static

◆ replay_image_masked

char* replay_image_masked = NULL
static

Definition at line 305 of file xlogrecovery.c.

Referenced by InitWalRecovery(), and verifyBackupPageConsistency().

◆ standby_signal_file_found

bool standby_signal_file_found = false
static

Definition at line 153 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), and readRecoverySignalFile().

◆ StandbyMode

◆ StandbyModeRequested

bool StandbyModeRequested = false
static

◆ wal_receiver_create_temp_slot

bool wal_receiver_create_temp_slot = false

Definition at line 101 of file xlogrecovery.c.

Referenced by StartupRereadConfig(), and WaitForWALToBecomeAvailable().

◆ xlogprefetcher

◆ xlogreader

◆ XLogReceiptSource

XLogSource XLogReceiptSource = XLOG_FROM_ANY
static

Definition at line 262 of file xlogrecovery.c.

Referenced by GetXLogReceiptTime(), WaitForWALToBecomeAvailable(), and XLogFileRead().

◆ XLogReceiptTime

TimestampTz XLogReceiptTime = 0
static

◆ XLogRecoveryCtl

◆ xlogSourceNames

const char* const xlogSourceNames[] = {"any", "archive", "pg_wal", "stream"}
static

Definition at line 221 of file xlogrecovery.c.

Referenced by WaitForWALToBecomeAvailable().