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 "backup/basebackup.h"
#include "catalog/pg_control.h"
#include "commands/tablespace.h"
#include "commands/waitlsn.h"
#include "common/file_utils.h"
#include "miscadmin.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/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 void pg_attribute_noreturn () 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 70 of file xlogrecovery.c.

◆ RECOVERY_COMMAND_FILE

#define RECOVERY_COMMAND_FILE   "recovery.conf"

Definition at line 69 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 210 of file xlogrecovery.c.

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

Function Documentation

◆ ApplyWalRecord()

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

Definition at line 1920 of file xlogrecovery.c.

1921 {
1922  ErrorContextCallback errcallback;
1923  bool switchedTLI = false;
1924 
1925  /* Setup error traceback support for ereport() */
1926  errcallback.callback = rm_redo_error_callback;
1927  errcallback.arg = (void *) xlogreader;
1928  errcallback.previous = error_context_stack;
1929  error_context_stack = &errcallback;
1930 
1931  /*
1932  * TransamVariables->nextXid must be beyond record's xid.
1933  */
1935 
1936  /*
1937  * Before replaying this record, check if this record causes the current
1938  * timeline to change. The record is already considered to be part of the
1939  * new timeline, so we update replayTLI before replaying it. That's
1940  * important so that replayEndTLI, which is recorded as the minimum
1941  * recovery point's TLI if recovery stops after this record, is set
1942  * correctly.
1943  */
1944  if (record->xl_rmid == RM_XLOG_ID)
1945  {
1946  TimeLineID newReplayTLI = *replayTLI;
1947  TimeLineID prevReplayTLI = *replayTLI;
1948  uint8 info = record->xl_info & ~XLR_INFO_MASK;
1949 
1950  if (info == XLOG_CHECKPOINT_SHUTDOWN)
1951  {
1952  CheckPoint checkPoint;
1953 
1954  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
1955  newReplayTLI = checkPoint.ThisTimeLineID;
1956  prevReplayTLI = checkPoint.PrevTimeLineID;
1957  }
1958  else if (info == XLOG_END_OF_RECOVERY)
1959  {
1960  xl_end_of_recovery xlrec;
1961 
1962  memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
1963  newReplayTLI = xlrec.ThisTimeLineID;
1964  prevReplayTLI = xlrec.PrevTimeLineID;
1965  }
1966 
1967  if (newReplayTLI != *replayTLI)
1968  {
1969  /* Check that it's OK to switch to this TLI */
1971  newReplayTLI, prevReplayTLI, *replayTLI);
1972 
1973  /* Following WAL records should be run with new TLI */
1974  *replayTLI = newReplayTLI;
1975  switchedTLI = true;
1976  }
1977  }
1978 
1979  /*
1980  * Update shared replayEndRecPtr before replaying this record, so that
1981  * XLogFlush will update minRecoveryPoint correctly.
1982  */
1985  XLogRecoveryCtl->replayEndTLI = *replayTLI;
1987 
1988  /*
1989  * If we are attempting to enter Hot Standby mode, process XIDs we see
1990  */
1992  TransactionIdIsValid(record->xl_xid))
1994 
1995  /*
1996  * Some XLOG record types that are related to recovery are processed
1997  * directly here, rather than in xlog_redo()
1998  */
1999  if (record->xl_rmid == RM_XLOG_ID)
2000  xlogrecovery_redo(xlogreader, *replayTLI);
2001 
2002  /* Now apply the WAL record itself */
2003  GetRmgr(record->xl_rmid).rm_redo(xlogreader);
2004 
2005  /*
2006  * After redo, check whether the backup pages associated with the WAL
2007  * record are consistent with the existing pages. This check is done only
2008  * if consistency check is enabled for this record.
2009  */
2010  if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
2012 
2013  /* Pop the error context stack */
2014  error_context_stack = errcallback.previous;
2015 
2016  /*
2017  * Update lastReplayedEndRecPtr after this record has been successfully
2018  * replayed.
2019  */
2023  XLogRecoveryCtl->lastReplayedTLI = *replayTLI;
2025 
2026  /* ------
2027  * Wakeup walsenders:
2028  *
2029  * On the standby, the WAL is flushed first (which will only wake up
2030  * physical walsenders) and then applied, which will only wake up logical
2031  * walsenders.
2032  *
2033  * Indeed, logical walsenders on standby can't decode and send data until
2034  * it's been applied.
2035  *
2036  * Physical walsenders don't need to be woken up during replay unless
2037  * cascading replication is allowed and time line change occurred (so that
2038  * they can notice that they are on a new time line).
2039  *
2040  * That's why the wake up conditions are for:
2041  *
2042  * - physical walsenders in case of new time line and cascade
2043  * replication is allowed
2044  * - logical walsenders in case cascade replication is allowed (could not
2045  * be created otherwise)
2046  * ------
2047  */
2049  WalSndWakeup(switchedTLI, true);
2050 
2051  /*
2052  * If rm_redo called XLogRequestWalReceiverReply, then we wake up the
2053  * receiver so that it notices the updated lastReplayedEndRecPtr and sends
2054  * a reply to the primary.
2055  */
2057  {
2058  doRequestWalReceiverReply = false;
2059  WalRcvForceReply();
2060  }
2061 
2062  /* Allow read-only connections if we're consistent now */
2064 
2065  /* Is this a timeline switch? */
2066  if (switchedTLI)
2067  {
2068  /*
2069  * Before we continue on the new timeline, clean up any (possibly
2070  * bogus) future WAL segments on the old timeline.
2071  */
2073 
2074  /* Reset the prefetcher. */
2076  }
2077 }
unsigned char uint8
Definition: c.h:504
ErrorContextCallback * error_context_stack
Definition: elog.c:94
#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:4407
#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:296
void(* callback)(void *arg)
Definition: elog.h:297
void(* rm_redo)(XLogReaderState *record)
XLogRecPtr EndRecPtr
Definition: xlogreader.h:207
XLogRecPtr ReadRecPtr
Definition: xlogreader.h:206
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:340
TimeLineID replayEndTLI
Definition: xlogrecovery.c:349
TimeLineID lastReplayedTLI
Definition: xlogrecovery.c:341
XLogRecPtr replayEndRecPtr
Definition: xlogrecovery.c:348
XLogRecPtr lastReplayedReadRecPtr
Definition: xlogrecovery.c:339
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:1359
#define AllowCascadeReplication()
Definition: walreceiver.h:41
void WalSndWakeup(bool physical, bool logical)
Definition: walsender.c:3669
void RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
Definition: xlog.c:3933
static RmgrData GetRmgr(RmgrId rmid)
uint32 TimeLineID
Definition: xlogdefs.h:59
void XLogPrefetchReconfigure(void)
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#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:365
static bool doRequestWalReceiverReply
Definition: xlogrecovery.c:186
static XLogReaderState * xlogreader
Definition: xlogrecovery.c:189
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, XLR_CHECK_CONSISTENCY, and XLR_INFO_MASK.

Referenced by PerformWalRecovery().

◆ assign_recovery_target()

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

Definition at line 4805 of file xlogrecovery.c.

4806 {
4809  error_multiple_recovery_targets();
4810 
4811  if (newval && strcmp(newval, "") != 0)
4813  else
4815 }
#define newval
RecoveryTargetType recoveryTarget
Definition: xlogrecovery.c:86
@ RECOVERY_TARGET_IMMEDIATE
Definition: xlogrecovery.h:30
@ RECOVERY_TARGET_UNSET
Definition: xlogrecovery.h:25

References 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 4844 of file xlogrecovery.c.

4845 {
4848  error_multiple_recovery_targets();
4849 
4850  if (newval && strcmp(newval, "") != 0)
4851  {
4853  recoveryTargetLSN = *((XLogRecPtr *) extra);
4854  }
4855  else
4857 }
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr recoveryTargetLSN
Definition: xlogrecovery.c:93
@ RECOVERY_TARGET_LSN
Definition: xlogrecovery.h:29

References 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 4879 of file xlogrecovery.c.

4880 {
4883  error_multiple_recovery_targets();
4884 
4885  if (newval && strcmp(newval, "") != 0)
4886  {
4889  }
4890  else
4892 }
const char * recoveryTargetName
Definition: xlogrecovery.c:92
@ RECOVERY_TARGET_NAME
Definition: xlogrecovery.h:28

References newval, RECOVERY_TARGET_NAME, RECOVERY_TARGET_UNSET, recoveryTarget, and recoveryTargetName.

◆ assign_recovery_target_time()

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

Definition at line 4959 of file xlogrecovery.c.

4960 {
4963  error_multiple_recovery_targets();
4964 
4965  if (newval && strcmp(newval, "") != 0)
4967  else
4969 }
@ RECOVERY_TARGET_TIME
Definition: xlogrecovery.h:27

References newval, RECOVERY_TARGET_TIME, RECOVERY_TARGET_UNSET, and recoveryTarget.

◆ assign_recovery_target_timeline()

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

Definition at line 5008 of file xlogrecovery.c.

5009 {
5012  recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
5013  else
5015 }
RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal
Definition: xlogrecovery.c:121
TimeLineID recoveryTargetTLIRequested
Definition: xlogrecovery.c:122
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 5044 of file xlogrecovery.c.

5045 {
5048  error_multiple_recovery_targets();
5049 
5050  if (newval && strcmp(newval, "") != 0)
5051  {
5053  recoveryTargetXid = *((TransactionId *) extra);
5054  }
5055  else
5057 }
uint32 TransactionId
Definition: c.h:652
TransactionId recoveryTargetXid
Definition: xlogrecovery.c:89
@ RECOVERY_TARGET_XID
Definition: xlogrecovery.h:26

References 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 4750 of file xlogrecovery.c.

4751 {
4752  if (*newval && strcmp(*newval, "") != 0 &&
4754  return false;
4755 
4756  return true;
4757 }
#define WARNING
Definition: elog.h:36
bool ReplicationSlotValidateName(const char *name, int elevel)
Definition: slot.c:252

References newval, ReplicationSlotValidateName(), and WARNING.

◆ check_recovery_target()

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

Definition at line 4791 of file xlogrecovery.c.

4792 {
4793  if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
4794  {
4795  GUC_check_errdetail("The only allowed value is \"immediate\".");
4796  return false;
4797  }
4798  return true;
4799 }
#define GUC_check_errdetail
Definition: guc.h:476

References GUC_check_errdetail, and newval.

◆ check_recovery_target_lsn()

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

Definition at line 4821 of file xlogrecovery.c.

4822 {
4823  if (strcmp(*newval, "") != 0)
4824  {
4825  XLogRecPtr lsn;
4826  XLogRecPtr *myextra;
4827  bool have_error = false;
4828 
4829  lsn = pg_lsn_in_internal(*newval, &have_error);
4830  if (have_error)
4831  return false;
4832 
4833  myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
4834  *myextra = lsn;
4835  *extra = (void *) myextra;
4836  }
4837  return true;
4838 }
#define ERROR
Definition: elog.h:39
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:637
XLogRecPtr pg_lsn_in_internal(const char *str, bool *have_error)
Definition: pg_lsn.c:29

References ERROR, guc_malloc(), newval, and pg_lsn_in_internal().

◆ check_recovery_target_name()

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

Definition at line 4863 of file xlogrecovery.c.

4864 {
4865  /* Use the value of newval directly */
4866  if (strlen(*newval) >= MAXFNAMELEN)
4867  {
4868  GUC_check_errdetail("\"%s\" is too long (maximum %d characters).",
4869  "recovery_target_name", MAXFNAMELEN - 1);
4870  return false;
4871  }
4872  return true;
4873 }
#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 4904 of file xlogrecovery.c.

4905 {
4906  if (strcmp(*newval, "") != 0)
4907  {
4908  /* reject some special values */
4909  if (strcmp(*newval, "now") == 0 ||
4910  strcmp(*newval, "today") == 0 ||
4911  strcmp(*newval, "tomorrow") == 0 ||
4912  strcmp(*newval, "yesterday") == 0)
4913  {
4914  return false;
4915  }
4916 
4917  /*
4918  * parse timestamp value (see also timestamptz_in())
4919  */
4920  {
4921  char *str = *newval;
4922  fsec_t fsec;
4923  struct pg_tm tt,
4924  *tm = &tt;
4925  int tz;
4926  int dtype;
4927  int nf;
4928  int dterr;
4929  char *field[MAXDATEFIELDS];
4930  int ftype[MAXDATEFIELDS];
4931  char workbuf[MAXDATELEN + MAXDATEFIELDS];
4932  DateTimeErrorExtra dtextra;
4934 
4935  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
4936  field, ftype, MAXDATEFIELDS, &nf);
4937  if (dterr == 0)
4938  dterr = DecodeDateTime(field, ftype, nf,
4939  &dtype, tm, &fsec, &tz, &dtextra);
4940  if (dterr != 0)
4941  return false;
4942  if (dtype != DTK_DATE)
4943  return false;
4944 
4945  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
4946  {
4947  GUC_check_errdetail("timestamp out of range: \"%s\"", str);
4948  return false;
4949  }
4950  }
4951  }
4952  return true;
4953 }
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:754
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, DateTimeErrorExtra *extra)
Definition: datetime.c:978
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:1987
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 4975 of file xlogrecovery.c.

4976 {
4978  RecoveryTargetTimeLineGoal *myextra;
4979 
4980  if (strcmp(*newval, "current") == 0)
4982  else if (strcmp(*newval, "latest") == 0)
4984  else
4985  {
4987 
4988  errno = 0;
4989  strtoul(*newval, NULL, 0);
4990  if (errno == EINVAL || errno == ERANGE)
4991  {
4992  GUC_check_errdetail("\"recovery_target_timeline\" is not a valid number.");
4993  return false;
4994  }
4995  }
4996 
4998  *myextra = rttg;
4999  *extra = (void *) myextra;
5000 
5001  return true;
5002 }
@ RECOVERY_TARGET_TIMELINE_CONTROLFILE
Definition: xlogrecovery.h:38
@ RECOVERY_TARGET_TIMELINE_LATEST
Definition: xlogrecovery.h:39

References ERROR, GUC_check_errdetail, guc_malloc(), newval, 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 5021 of file xlogrecovery.c.

5022 {
5023  if (strcmp(*newval, "") != 0)
5024  {
5025  TransactionId xid;
5026  TransactionId *myextra;
5027 
5028  errno = 0;
5029  xid = (TransactionId) strtou64(*newval, NULL, 0);
5030  if (errno == EINVAL || errno == ERANGE)
5031  return false;
5032 
5033  myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
5034  *myextra = xid;
5035  *extra = (void *) myextra;
5036  }
5037  return true;
5038 }
#define strtou64(str, endptr, base)
Definition: c.h:1298

References ERROR, guc_malloc(), newval, and strtou64.

◆ CheckForStandbyTrigger()

static bool CheckForStandbyTrigger ( void  )
static

Definition at line 4443 of file xlogrecovery.c.

4444 {
4446  return true;
4447 
4449  {
4450  ereport(LOG, (errmsg("received promote request")));
4454  return true;
4455  }
4456 
4457  return false;
4458 }
bool IsPromoteSignaled(void)
Definition: startup.c:288
void ResetPromoteSignaled(void)
Definition: startup.c:294
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
bool CheckPromoteSignal(void)
static bool LocalPromoteIsTriggered
Definition: xlogrecovery.c:183
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 4473 of file xlogrecovery.c.

4474 {
4475  struct stat stat_buf;
4476 
4477  if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
4478  return true;
4479 
4480  return false;
4481 }
#define stat
Definition: win32_port.h:284
#define PROMOTE_SIGNAL_FILE
Definition: xlog.h:308

References PROMOTE_SIGNAL_FILE, and stat.

Referenced by CheckForStandbyTrigger(), and process_pm_pmsignal().

◆ CheckRecoveryConsistency()

static void CheckRecoveryConsistency ( void  )
static

Definition at line 2188 of file xlogrecovery.c.

2189 {
2190  XLogRecPtr lastReplayedEndRecPtr;
2191  TimeLineID lastReplayedTLI;
2192 
2193  /*
2194  * During crash recovery, we don't reach a consistent state until we've
2195  * replayed all the WAL.
2196  */
2198  return;
2199 
2201 
2202  /*
2203  * assume that we are called in the startup process, and hence don't need
2204  * a lock to read lastReplayedEndRecPtr
2205  */
2206  lastReplayedEndRecPtr = XLogRecoveryCtl->lastReplayedEndRecPtr;
2207  lastReplayedTLI = XLogRecoveryCtl->lastReplayedTLI;
2208 
2209  /*
2210  * Have we reached the point where our base backup was completed?
2211  */
2213  backupEndPoint <= lastReplayedEndRecPtr)
2214  {
2215  XLogRecPtr saveBackupStartPoint = backupStartPoint;
2216  XLogRecPtr saveBackupEndPoint = backupEndPoint;
2217 
2218  elog(DEBUG1, "end of backup reached");
2219 
2220  /*
2221  * We have reached the end of base backup, as indicated by pg_control.
2222  * Update the control file accordingly.
2223  */
2224  ReachedEndOfBackup(lastReplayedEndRecPtr, lastReplayedTLI);
2227  backupEndRequired = false;
2228 
2229  ereport(LOG,
2230  (errmsg("completed backup recovery with redo LSN %X/%X and end LSN %X/%X",
2231  LSN_FORMAT_ARGS(saveBackupStartPoint),
2232  LSN_FORMAT_ARGS(saveBackupEndPoint))));
2233  }
2234 
2235  /*
2236  * Have we passed our safe starting point? Note that minRecoveryPoint is
2237  * known to be incorrectly set if recovering from a backup, until the
2238  * XLOG_BACKUP_END arrives to advise us of the correct minRecoveryPoint.
2239  * All we know prior to that is that we're not consistent yet.
2240  */
2242  minRecoveryPoint <= lastReplayedEndRecPtr)
2243  {
2244  /*
2245  * Check to see if the XLOG sequence contained any unresolved
2246  * references to uninitialized pages.
2247  */
2249 
2250  /*
2251  * Check that pg_tblspc doesn't contain any real directories. Replay
2252  * of Database/CREATE_* records may have created fictitious tablespace
2253  * directories that should have been removed by the time consistency
2254  * was reached.
2255  */
2257 
2258  reachedConsistency = true;
2259  ereport(LOG,
2260  (errmsg("consistent recovery state reached at %X/%X",
2261  LSN_FORMAT_ARGS(lastReplayedEndRecPtr))));
2262  }
2263 
2264  /*
2265  * Have we got a valid starting snapshot that will allow queries to be
2266  * run? If so, we can tell postmaster that the database is consistent now,
2267  * enabling connections.
2268  */
2273  {
2277 
2278  LocalHotStandbyActive = true;
2279 
2281  }
2282 }
#define Assert(condition)
Definition: c.h:858
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:225
bool IsUnderPostmaster
Definition: globals.c:119
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:181
@ PMSIGNAL_BEGIN_HOT_STANDBY
Definition: pmsignal.h:36
void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli)
Definition: xlog.c:6246
#define LSN_FORMAT_ARGS(lsn)
Definition: xlogdefs.h:43
#define XLogRecPtrIsInvalid(r)
Definition: xlogdefs.h:29
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
bool reachedConsistency
Definition: xlogrecovery.c:295
static bool backupEndRequired
Definition: xlogrecovery.c:284
static XLogRecPtr minRecoveryPoint
Definition: xlogrecovery.c:279
static XLogRecPtr backupEndPoint
Definition: xlogrecovery.c:283
bool InArchiveRecovery
Definition: xlogrecovery.c:139
static bool LocalHotStandbyActive
Definition: xlogrecovery.c:177
static void CheckTablespaceDirectory(void)
static XLogRecPtr backupStartPoint
Definition: xlogrecovery.c:282
void XLogCheckInvalidPages(void)
Definition: xlogutils.c:245
@ 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, reachedConsistency, ReachedEndOfBackup(), SendPostmasterSignal(), XLogRecoveryCtlData::SharedHotStandbyActive, SpinLockAcquire, SpinLockRelease, STANDBY_SNAPSHOT_READY, standbyState, XLogCheckInvalidPages(), XLogRecoveryCtl, and XLogRecPtrIsInvalid.

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

◆ CheckTablespaceDirectory()

static void CheckTablespaceDirectory ( void  )
static

Definition at line 2155 of file xlogrecovery.c.

2156 {
2157  DIR *dir;
2158  struct dirent *de;
2159 
2160  dir = AllocateDir(PG_TBLSPC_DIR);
2161  while ((de = ReadDir(dir, PG_TBLSPC_DIR)) != NULL)
2162  {
2163  char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR)];
2164 
2165  /* Skip entries of non-oid names */
2166  if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
2167  continue;
2168 
2169  snprintf(path, sizeof(path), "%s/%s", PG_TBLSPC_DIR, de->d_name);
2170 
2171  if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
2174  errmsg("unexpected directory entry \"%s\" found in %s",
2175  de->d_name, PG_TBLSPC_DIR),
2176  errdetail("All directory entries in %s/ should be symbolic links.",
2177  PG_TBLSPC_DIR),
2178  errhint("Remove those directories, or set \"allow_in_place_tablespaces\" to ON transiently to let recovery complete.")));
2179  }
2180 }
bool allow_in_place_tablespaces
Definition: tablespace.c:85
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:853
#define PANIC
Definition: elog.h:42
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2932
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2866
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:526
@ PGFILETYPE_LNK
Definition: file_utils.h:24
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
#define MAXPGPATH
#define snprintf
Definition: port.h:238
#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 2390 of file xlogrecovery.c.

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

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

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 4042 of file xlogrecovery.c.

4043 {
4044  static XLogRecPtr lastComplaint = 0;
4045 
4046  if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
4047  {
4048  if (RecPtr == lastComplaint)
4049  emode = DEBUG1;
4050  else
4051  lastComplaint = RecPtr;
4052  }
4053  return emode;
4054 }
static XLogSource readSource
Definition: xlogrecovery.c:235

References DEBUG1, LOG, readSource, and XLOG_FROM_PG_WAL.

Referenced by ReadRecord(), and XLogPageRead().

◆ EnableStandbyMode()

static void EnableStandbyMode ( void  )
static

Definition at line 479 of file xlogrecovery.c.

480 {
481  StandbyMode = true;
482 
483  /*
484  * To avoid server log bloat, we don't report recovery progress in a
485  * standby as it will always be in recovery unless promoted. We disable
486  * startup progress timeout in standby mode to avoid calling
487  * startup_progress_timeout_handler() unnecessarily.
488  */
490 }
void disable_startup_progress_timeout(void)
Definition: startup.c:309
bool StandbyMode
Definition: xlogrecovery.c:148

References disable_startup_progress_timeout(), and StandbyMode.

Referenced by InitWalRecovery(), and ReadRecord().

◆ FinishWalRecovery()

EndOfWalRecoveryInfo* FinishWalRecovery ( void  )

Definition at line 1459 of file xlogrecovery.c.

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

Definition at line 4636 of file xlogrecovery.c.

4637 {
4638  TimestampTz xtime;
4639 
4643 
4644  return xtime;
4645 }
TimestampTz currentChunkStartTime
Definition: xlogrecovery.c:357

References XLogRecoveryCtlData::currentChunkStartTime, XLogRecoveryCtlData::info_lck, SpinLockAcquire, SpinLockRelease, and XLogRecoveryCtl.

Referenced by GetReplicationApplyDelay().

◆ GetCurrentReplayRecPtr()

XLogRecPtr GetCurrentReplayRecPtr ( TimeLineID replayEndTLI)

Definition at line 4572 of file xlogrecovery.c.

4573 {
4574  XLogRecPtr recptr;
4575  TimeLineID tli;
4576 
4578  recptr = XLogRecoveryCtl->replayEndRecPtr;
4581 
4582  if (replayEndTLI)
4583  *replayEndTLI = tli;
4584  return recptr;
4585 }

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

Referenced by UpdateMinRecoveryPoint(), and xlog_redo().

◆ GetLatestXTime()

TimestampTz GetLatestXTime ( void  )

◆ getRecordTimestamp()

static bool getRecordTimestamp ( XLogReaderState record,
TimestampTz recordXtime 
)
static

Definition at line 2439 of file xlogrecovery.c.

2440 {
2441  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2442  uint8 xact_info = info & XLOG_XACT_OPMASK;
2443  uint8 rmid = XLogRecGetRmid(record);
2444 
2445  if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2446  {
2447  *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
2448  return true;
2449  }
2450  if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
2451  xact_info == XLOG_XACT_COMMIT_PREPARED))
2452  {
2453  *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
2454  return true;
2455  }
2456  if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
2457  xact_info == XLOG_XACT_ABORT_PREPARED))
2458  {
2459  *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
2460  return true;
2461  }
2462  return false;
2463 }
#define XLOG_RESTORE_POINT
Definition: pg_control.h:75
#define XLOG_XACT_COMMIT_PREPARED
Definition: xact.h:172
#define XLOG_XACT_COMMIT
Definition: xact.h:169
#define XLOG_XACT_OPMASK
Definition: xact.h:179
#define XLOG_XACT_ABORT
Definition: xact.h:171
#define XLOG_XACT_ABORT_PREPARED
Definition: xact.h:173
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetRmid(decoder)
Definition: xlogreader.h:411

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

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

◆ GetRecoveryPauseState()

◆ getRecoveryStopReason()

static char * getRecoveryStopReason ( void  )
static

Definition at line 2899 of file xlogrecovery.c.

2900 {
2901  char reason[200];
2902 
2904  snprintf(reason, sizeof(reason),
2905  "%s transaction %u",
2906  recoveryStopAfter ? "after" : "before",
2907  recoveryStopXid);
2909  snprintf(reason, sizeof(reason),
2910  "%s %s\n",
2911  recoveryStopAfter ? "after" : "before",
2913  else if (recoveryTarget == RECOVERY_TARGET_LSN)
2914  snprintf(reason, sizeof(reason),
2915  "%s LSN %X/%X\n",
2916  recoveryStopAfter ? "after" : "before",
2919  snprintf(reason, sizeof(reason),
2920  "at restore point \"%s\"",
2923  snprintf(reason, sizeof(reason), "reached consistency");
2924  else
2925  snprintf(reason, sizeof(reason), "no recovery target specified");
2926 
2927  return pstrdup(reason);
2928 }
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1843
char * pstrdup(const char *in)
Definition: mcxt.c:1696
static XLogRecPtr recoveryStopLSN
Definition: xlogrecovery.c:382
static TimestampTz recoveryStopTime
Definition: xlogrecovery.c:381
static char recoveryStopName[MAXFNAMELEN]
Definition: xlogrecovery.c:383
static bool recoveryStopAfter
Definition: xlogrecovery.c:384
static TransactionId recoveryStopXid
Definition: xlogrecovery.c:380

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 4652 of file xlogrecovery.c.

4653 {
4654  /*
4655  * This must be executed in the startup process, since we don't export the
4656  * relevant state to shared memory.
4657  */
4658  Assert(InRecovery);
4659 
4660  *rtime = XLogReceiptTime;
4661  *fromStream = (XLogReceiptSource == XLOG_FROM_STREAM);
4662 }
static XLogSource XLogReceiptSource
Definition: xlogrecovery.c:260
static TimestampTz XLogReceiptTime
Definition: xlogrecovery.c:259

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

Referenced by GetStandbyLimitTime().

◆ GetXLogReplayRecPtr()

◆ HotStandbyActive()

bool HotStandbyActive ( void  )

Definition at line 4512 of file xlogrecovery.c.

4513 {
4514  /*
4515  * We check shared state each time only until Hot Standby is active. We
4516  * can't de-activate Hot Standby, so there's no need to keep checking
4517  * after the shared variable has once been seen true.
4518  */
4520  return true;
4521  else
4522  {
4523  /* spinlock is essential on machines with weak memory ordering! */
4527 
4528  return LocalHotStandbyActive;
4529  }
4530 }

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

Referenced by XLogWalRcvSendHSFeedback().

◆ HotStandbyActiveInReplay()

static bool HotStandbyActiveInReplay ( void  )
static

Definition at line 4537 of file xlogrecovery.c.

4538 {
4540  return LocalHotStandbyActive;
4541 }
bool IsPostmasterEnvironment
Definition: globals.c:118
#define AmStartupProcess()
Definition: miscadmin.h:379

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 513 of file xlogrecovery.c.

515 {
516  XLogPageReadPrivate *private;
517  struct stat st;
518  bool wasShutdown;
519  XLogRecord *record;
520  DBState dbstate_at_startup;
521  bool haveTblspcMap = false;
522  bool haveBackupLabel = false;
523  CheckPoint checkPoint;
524  bool backupFromStandby = false;
525 
526  dbstate_at_startup = ControlFile->state;
527 
528  /*
529  * Initialize on the assumption we want to recover to the latest timeline
530  * that's active according to pg_control.
531  */
535  else
537 
538  /*
539  * Check for signal files, and if so set up state for offline recovery
540  */
543 
544  /*
545  * Take ownership of the wakeup latch if we're going to sleep during
546  * recovery, if required.
547  */
550 
551  /*
552  * Set the WAL reading processor now, as it will be needed when reading
553  * the checkpoint record required (backup_label or not).
554  */
555  private = palloc0(sizeof(XLogPageReadPrivate));
556  xlogreader =
558  XL_ROUTINE(.page_read = &XLogPageRead,
559  .segment_open = NULL,
560  .segment_close = wal_segment_close),
561  private);
562  if (!xlogreader)
563  ereport(ERROR,
564  (errcode(ERRCODE_OUT_OF_MEMORY),
565  errmsg("out of memory"),
566  errdetail("Failed while allocating a WAL reading processor.")));
568 
569  /*
570  * Set the WAL decode buffer size. This limits how far ahead we can read
571  * in the WAL.
572  */
574 
575  /* Create a WAL prefetcher. */
577 
578  /*
579  * Allocate two page buffers dedicated to WAL consistency checks. We do
580  * it this way, rather than just making static arrays, for two reasons:
581  * (1) no need to waste the storage in most instantiations of the backend;
582  * (2) a static char array isn't guaranteed to have any particular
583  * alignment, whereas palloc() will provide MAXALIGN'd storage.
584  */
585  replay_image_masked = (char *) palloc(BLCKSZ);
586  primary_image_masked = (char *) palloc(BLCKSZ);
587 
588  /*
589  * Read the backup_label file. We want to run this part of the recovery
590  * process after checking for signal files and after performing validation
591  * of the recovery parameters.
592  */
594  &backupFromStandby))
595  {
596  List *tablespaces = NIL;
597 
598  /*
599  * Archive recovery was requested, and thanks to the backup label
600  * file, we know how far we need to replay to reach consistency. Enter
601  * archive recovery directly.
602  */
603  InArchiveRecovery = true;
606 
607  /*
608  * Omitting backup_label when creating a new replica, PITR node etc.
609  * unfortunately is a common cause of corruption. Logging that
610  * backup_label was used makes it a bit easier to exclude that as the
611  * cause of observed corruption.
612  *
613  * Do so before we try to read the checkpoint record (which can fail),
614  * as otherwise it can be hard to understand why a checkpoint other
615  * than ControlFile->checkPoint is used.
616  */
617  ereport(LOG,
618  (errmsg("starting backup recovery with redo LSN %X/%X, checkpoint LSN %X/%X, on timeline ID %u",
621  CheckPointTLI)));
622 
623  /*
624  * When a backup_label file is present, we want to roll forward from
625  * the checkpoint it identifies, rather than using pg_control.
626  */
628  CheckPointTLI);
629  if (record != NULL)
630  {
631  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
632  wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
633  ereport(DEBUG1,
634  (errmsg_internal("checkpoint record is at %X/%X",
636  InRecovery = true; /* force recovery even if SHUTDOWNED */
637 
638  /*
639  * Make sure that REDO location exists. This may not be the case
640  * if there was a crash during an online backup, which left a
641  * backup_label around that references a WAL segment that's
642  * already been archived.
643  */
644  if (checkPoint.redo < CheckPointLoc)
645  {
647  if (!ReadRecord(xlogprefetcher, LOG, false,
648  checkPoint.ThisTimeLineID))
649  ereport(FATAL,
650  (errmsg("could not find redo location %X/%X referenced by checkpoint record at %X/%X",
652  errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
653  "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
654  "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
656  }
657  }
658  else
659  {
660  ereport(FATAL,
661  (errmsg("could not locate required checkpoint record at %X/%X",
663  errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
664  "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
665  "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
667  wasShutdown = false; /* keep compiler quiet */
668  }
669 
670  /* Read the tablespace_map file if present and create symlinks. */
671  if (read_tablespace_map(&tablespaces))
672  {
673  ListCell *lc;
674 
675  foreach(lc, tablespaces)
676  {
677  tablespaceinfo *ti = lfirst(lc);
678  char *linkloc;
679 
680  linkloc = psprintf("%s/%u", PG_TBLSPC_DIR, ti->oid);
681 
682  /*
683  * Remove the existing symlink if any and Create the symlink
684  * under PGDATA.
685  */
686  remove_tablespace_symlink(linkloc);
687 
688  if (symlink(ti->path, linkloc) < 0)
689  ereport(ERROR,
691  errmsg("could not create symbolic link \"%s\": %m",
692  linkloc)));
693 
694  pfree(ti->path);
695  pfree(ti);
696  }
697 
698  /* tell the caller to delete it later */
699  haveTblspcMap = true;
700  }
701 
702  /* tell the caller to delete it later */
703  haveBackupLabel = true;
704  }
705  else
706  {
707  /* No backup_label file has been found if we are here. */
708 
709  /*
710  * If tablespace_map file is present without backup_label file, there
711  * is no use of such file. There is no harm in retaining it, but it
712  * is better to get rid of the map file so that we don't have any
713  * redundant file in data directory and it will avoid any sort of
714  * confusion. It seems prudent though to just rename the file out of
715  * the way rather than delete it completely, also we ignore any error
716  * that occurs in rename operation as even if map file is present
717  * without backup_label file, it is harmless.
718  */
719  if (stat(TABLESPACE_MAP, &st) == 0)
720  {
721  unlink(TABLESPACE_MAP_OLD);
723  ereport(LOG,
724  (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
726  errdetail("File \"%s\" was renamed to \"%s\".",
728  else
729  ereport(LOG,
730  (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
732  errdetail("Could not rename file \"%s\" to \"%s\": %m.",
734  }
735 
736  /*
737  * It's possible that archive recovery was requested, but we don't
738  * know how far we need to replay the WAL before we reach consistency.
739  * This can happen for example if a base backup is taken from a
740  * running server using an atomic filesystem snapshot, without calling
741  * pg_backup_start/stop. Or if you just kill a running primary server
742  * and put it into archive recovery by creating a recovery signal
743  * file.
744  *
745  * Our strategy in that case is to perform crash recovery first,
746  * replaying all the WAL present in pg_wal, and only enter archive
747  * recovery after that.
748  *
749  * But usually we already know how far we need to replay the WAL (up
750  * to minRecoveryPoint, up to backupEndPoint, or until we see an
751  * end-of-backup record), and we can enter archive recovery directly.
752  */
758  {
759  InArchiveRecovery = true;
762  }
763 
764  /*
765  * For the same reason as when starting up with backup_label present,
766  * emit a log message when we continue initializing from a base
767  * backup.
768  */
770  ereport(LOG,
771  (errmsg("restarting backup recovery with redo LSN %X/%X",
773 
774  /* Get the last valid checkpoint record. */
780  CheckPointTLI);
781  if (record != NULL)
782  {
783  ereport(DEBUG1,
784  (errmsg_internal("checkpoint record is at %X/%X",
786  }
787  else
788  {
789  /*
790  * We used to attempt to go back to a secondary checkpoint record
791  * here, but only when not in standby mode. We now just fail if we
792  * can't read the last checkpoint because this allows us to
793  * simplify processing around checkpoints.
794  */
795  ereport(PANIC,
796  (errmsg("could not locate a valid checkpoint record at %X/%X",
798  }
799  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
800  wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
801  }
802 
804  {
806  ereport(LOG,
807  (errmsg("entering standby mode")));
809  ereport(LOG,
810  (errmsg("starting point-in-time recovery to XID %u",
813  ereport(LOG,
814  (errmsg("starting point-in-time recovery to %s",
817  ereport(LOG,
818  (errmsg("starting point-in-time recovery to \"%s\"",
821  ereport(LOG,
822  (errmsg("starting point-in-time recovery to WAL location (LSN) \"%X/%X\"",
825  ereport(LOG,
826  (errmsg("starting point-in-time recovery to earliest consistent point")));
827  else
828  ereport(LOG,
829  (errmsg("starting archive recovery")));
830  }
831 
832  /*
833  * If the location of the checkpoint record is not on the expected
834  * timeline in the history of the requested timeline, we cannot proceed:
835  * the backup is not part of the history of the requested timeline.
836  */
837  Assert(expectedTLEs); /* was initialized by reading checkpoint
838  * record */
841  {
842  XLogRecPtr switchpoint;
843 
844  /*
845  * tliSwitchPoint will throw an error if the checkpoint's timeline is
846  * not in expectedTLEs at all.
847  */
849  ereport(FATAL,
850  (errmsg("requested timeline %u is not a child of this server's history",
852  errdetail("Latest checkpoint is at %X/%X on timeline %u, but in the history of the requested timeline, the server forked off from that timeline at %X/%X.",
855  LSN_FORMAT_ARGS(switchpoint))));
856  }
857 
858  /*
859  * The min recovery point should be part of the requested timeline's
860  * history, too.
861  */
865  ereport(FATAL,
866  (errmsg("requested timeline %u does not contain minimum recovery point %X/%X on timeline %u",
870 
871  ereport(DEBUG1,
872  (errmsg_internal("redo record is at %X/%X; shutdown %s",
873  LSN_FORMAT_ARGS(checkPoint.redo),
874  wasShutdown ? "true" : "false")));
875  ereport(DEBUG1,
876  (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: %u",
877  U64FromFullTransactionId(checkPoint.nextXid),
878  checkPoint.nextOid)));
879  ereport(DEBUG1,
880  (errmsg_internal("next MultiXactId: %u; next MultiXactOffset: %u",
881  checkPoint.nextMulti, checkPoint.nextMultiOffset)));
882  ereport(DEBUG1,
883  (errmsg_internal("oldest unfrozen transaction ID: %u, in database %u",
884  checkPoint.oldestXid, checkPoint.oldestXidDB)));
885  ereport(DEBUG1,
886  (errmsg_internal("oldest MultiXactId: %u, in database %u",
887  checkPoint.oldestMulti, checkPoint.oldestMultiDB)));
888  ereport(DEBUG1,
889  (errmsg_internal("commit timestamp Xid oldest/newest: %u/%u",
890  checkPoint.oldestCommitTsXid,
891  checkPoint.newestCommitTsXid)));
893  ereport(PANIC,
894  (errmsg("invalid next transaction ID")));
895 
896  /* sanity check */
897  if (checkPoint.redo > CheckPointLoc)
898  ereport(PANIC,
899  (errmsg("invalid redo in checkpoint record")));
900 
901  /*
902  * Check whether we need to force recovery from WAL. If it appears to
903  * have been a clean shutdown and we did not have a recovery signal file,
904  * then assume no recovery needed.
905  */
906  if (checkPoint.redo < CheckPointLoc)
907  {
908  if (wasShutdown)
909  ereport(PANIC,
910  (errmsg("invalid redo record in shutdown checkpoint")));
911  InRecovery = true;
912  }
913  else if (ControlFile->state != DB_SHUTDOWNED)
914  InRecovery = true;
915  else if (ArchiveRecoveryRequested)
916  {
917  /* force recovery due to presence of recovery signal file */
918  InRecovery = true;
919  }
920 
921  /*
922  * If recovery is needed, update our in-memory copy of pg_control to show
923  * that we are recovering and to show the selected checkpoint as the place
924  * we are starting from. We also mark pg_control with any minimum recovery
925  * stop point obtained from a backup history file.
926  *
927  * We don't write the changes to disk yet, though. Only do that after
928  * initializing various subsystems.
929  */
930  if (InRecovery)
931  {
932  if (InArchiveRecovery)
933  {
935  }
936  else
937  {
938  ereport(LOG,
939  (errmsg("database system was not properly shut down; "
940  "automatic recovery in progress")));
942  ereport(LOG,
943  (errmsg("crash recovery starts in timeline %u "
944  "and has target timeline %u",
948  }
950  ControlFile->checkPointCopy = checkPoint;
951  if (InArchiveRecovery)
952  {
953  /* initialize minRecoveryPoint if not set yet */
954  if (ControlFile->minRecoveryPoint < checkPoint.redo)
955  {
956  ControlFile->minRecoveryPoint = checkPoint.redo;
958  }
959  }
960 
961  /*
962  * Set backupStartPoint if we're starting recovery from a base backup.
963  *
964  * Also set backupEndPoint and use minRecoveryPoint as the backup end
965  * location if we're starting recovery from a base backup which was
966  * taken from a standby. In this case, the database system status in
967  * pg_control must indicate that the database was already in recovery.
968  * Usually that will be DB_IN_ARCHIVE_RECOVERY but also can be
969  * DB_SHUTDOWNED_IN_RECOVERY if recovery previously was interrupted
970  * before reaching this point; e.g. because restore_command or
971  * primary_conninfo were faulty.
972  *
973  * Any other state indicates that the backup somehow became corrupted
974  * and we can't sensibly continue with recovery.
975  */
976  if (haveBackupLabel)
977  {
978  ControlFile->backupStartPoint = checkPoint.redo;
980 
981  if (backupFromStandby)
982  {
983  if (dbstate_at_startup != DB_IN_ARCHIVE_RECOVERY &&
984  dbstate_at_startup != DB_SHUTDOWNED_IN_RECOVERY)
985  ereport(FATAL,
986  (errmsg("backup_label contains data inconsistent with control file"),
987  errhint("This means that the backup is corrupted and you will "
988  "have to use another backup for recovery.")));
990  }
991  }
992  }
993 
994  /* remember these, so that we know when we have reached consistency */
998  if (InArchiveRecovery)
999  {
1002  }
1003  else
1004  {
1006  minRecoveryPointTLI = 0;
1007  }
1008 
1009  /*
1010  * Start recovery assuming that the final record isn't lost.
1011  */
1014 
1015  *wasShutdown_ptr = wasShutdown;
1016  *haveBackupLabel_ptr = haveBackupLabel;
1017  *haveTblspcMap_ptr = haveTblspcMap;
1018 }
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:549
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1157
int errcode_for_file_access(void)
Definition: elog.c:876
#define FATAL
Definition: elog.h:41
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:782
char * DataDir
Definition: globals.c:70
void OwnLatch(Latch *latch)
Definition: latch.c:463
void pfree(void *pointer)
Definition: mcxt.c:1521
void * palloc0(Size size)
Definition: mcxt.c:1347
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:46
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:191
#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:235
int wal_decode_buffer_size
Definition: xlog.c:135
static ControlFileData * ControlFile
Definition: xlog.c:573
#define TABLESPACE_MAP_OLD
Definition: xlog.h:305
#define TABLESPACE_MAP
Definition: xlog.h:304
#define BACKUP_LABEL_FILE
Definition: xlog.h:301
XLogPrefetcher * XLogPrefetcherAllocate(XLogReaderState *reader)
void XLogReaderSetDecodeBuffer(XLogReaderState *state, void *buffer, size_t size)
Definition: xlogreader.c:90
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:106
#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:171
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:299
static char * replay_image_masked
Definition: xlogrecovery.c:298
TimeLineID recoveryTargetTLI
Definition: xlogrecovery.c:123
static XLogRecPtr RedoStartLSN
Definition: xlogrecovery.c:170
static void EnableStandbyMode(void)
Definition: xlogrecovery.c:479
TimestampTz recoveryTargetTime
Definition: xlogrecovery.c:91
static bool StandbyModeRequested
Definition: xlogrecovery.c:147
void wal_segment_close(XLogReaderState *state)
Definition: xlogutils.c:842

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, XLogRecPtrIsInvalid, and XLR_INFO_MASK.

Referenced by StartupXLOG().

◆ PerformWalRecovery()

void PerformWalRecovery ( void  )

Definition at line 1653 of file xlogrecovery.c.

1654 {
1655  XLogRecord *record;
1656  bool reachedRecoveryTarget = false;
1657  TimeLineID replayTLI;
1658 
1659  /*
1660  * Initialize shared variables for tracking progress of WAL replay, as if
1661  * we had just replayed the record before the REDO location (or the
1662  * checkpoint record itself, if it's a shutdown checkpoint).
1663  */
1666  {
1670  }
1671  else
1672  {
1676  }
1683 
1684  /* Also ensure XLogReceiptTime has a sane value */
1686 
1687  /*
1688  * Let postmaster know we've started redo now, so that it can launch the
1689  * archiver if necessary.
1690  */
1691  if (IsUnderPostmaster)
1693 
1694  /*
1695  * Allow read-only connections immediately if we're consistent already.
1696  */
1698 
1699  /*
1700  * Find the first record that logically follows the checkpoint --- it
1701  * might physically precede it, though.
1702  */
1704  {
1705  /* back up to find the record */
1706  replayTLI = RedoStartTLI;
1708  record = ReadRecord(xlogprefetcher, PANIC, false, replayTLI);
1709 
1710  /*
1711  * If a checkpoint record's redo pointer points back to an earlier
1712  * LSN, the record at that LSN should be an XLOG_CHECKPOINT_REDO
1713  * record.
1714  */
1715  if (record->xl_rmid != RM_XLOG_ID ||
1716  (record->xl_info & ~XLR_INFO_MASK) != XLOG_CHECKPOINT_REDO)
1717  ereport(FATAL,
1718  (errmsg("unexpected record type found at redo point %X/%X",
1720  }
1721  else
1722  {
1723  /* just have to read next record after CheckPoint */
1725  replayTLI = CheckPointTLI;
1726  record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1727  }
1728 
1729  if (record != NULL)
1730  {
1731  TimestampTz xtime;
1732  PGRUsage ru0;
1733 
1734  pg_rusage_init(&ru0);
1735 
1736  InRedo = true;
1737 
1738  RmgrStartup();
1739 
1740  ereport(LOG,
1741  (errmsg("redo starts at %X/%X",
1743 
1744  /* Prepare to report progress of the redo phase. */
1745  if (!StandbyMode)
1747 
1748  /*
1749  * main redo apply loop
1750  */
1751  do
1752  {
1753  if (!StandbyMode)
1754  ereport_startup_progress("redo in progress, elapsed time: %ld.%02d s, current LSN: %X/%X",
1756 
1757 #ifdef WAL_DEBUG
1758  if (XLOG_DEBUG)
1759  {
1761 
1762  initStringInfo(&buf);
1763  appendStringInfo(&buf, "REDO @ %X/%X; LSN %X/%X: ",
1766  xlog_outrec(&buf, xlogreader);
1767  appendStringInfoString(&buf, " - ");
1769  elog(LOG, "%s", buf.data);
1770  pfree(buf.data);
1771  }
1772 #endif
1773 
1774  /* Handle interrupt signals of startup process */
1776 
1777  /*
1778  * Pause WAL replay, if requested by a hot-standby session via
1779  * SetRecoveryPause().
1780  *
1781  * Note that we intentionally don't take the info_lck spinlock
1782  * here. We might therefore read a slightly stale value of the
1783  * recoveryPause flag, but it can't be very stale (no worse than
1784  * the last spinlock we did acquire). Since a pause request is a
1785  * pretty asynchronous thing anyway, possibly responding to it one
1786  * WAL record later than we otherwise would is a minor issue, so
1787  * it doesn't seem worth adding another spinlock cycle to prevent
1788  * that.
1789  */
1790  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1792  recoveryPausesHere(false);
1793 
1794  /*
1795  * Have we reached our recovery target?
1796  */
1798  {
1799  reachedRecoveryTarget = true;
1800  break;
1801  }
1802 
1803  /*
1804  * If we've been asked to lag the primary, wait on latch until
1805  * enough time has passed.
1806  */
1808  {
1809  /*
1810  * We test for paused recovery again here. If user sets
1811  * delayed apply, it may be because they expect to pause
1812  * recovery in case of problems, so we must test again here
1813  * otherwise pausing during the delay-wait wouldn't work.
1814  */
1815  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1817  recoveryPausesHere(false);
1818  }
1819 
1820  /*
1821  * Apply the record
1822  */
1823  ApplyWalRecord(xlogreader, record, &replayTLI);
1824 
1825  /* Exit loop if we reached inclusive recovery target */
1827  {
1828  reachedRecoveryTarget = true;
1829  break;
1830  }
1831 
1832  /*
1833  * If we replayed an LSN that someone was waiting for then walk
1834  * over the shared memory array and set latches to notify the
1835  * waiters.
1836  */
1837  if (waitLSNState &&
1841 
1842  /* Else, try to fetch the next WAL record */
1843  record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1844  } while (record != NULL);
1845 
1846  /*
1847  * end of main redo apply loop
1848  */
1849 
1850  if (reachedRecoveryTarget)
1851  {
1852  if (!reachedConsistency)
1853  ereport(FATAL,
1854  (errmsg("requested recovery stop point is before consistent recovery point")));
1855 
1856  /*
1857  * This is the last point where we can restart recovery with a new
1858  * recovery target, if we shutdown and begin again. After this,
1859  * Resource Managers may choose to do permanent corrective actions
1860  * at end of recovery.
1861  */
1862  switch (recoveryTargetAction)
1863  {
1865 
1866  /*
1867  * exit with special return code to request shutdown of
1868  * postmaster. Log messages issued from postmaster.
1869  */
1870  proc_exit(3);
1871 
1873  SetRecoveryPause(true);
1874  recoveryPausesHere(true);
1875 
1876  /* drop into promote */
1877 
1879  break;
1880  }
1881  }
1882 
1883  RmgrCleanup();
1884 
1885  ereport(LOG,
1886  (errmsg("redo done at %X/%X system usage: %s",
1888  pg_rusage_show(&ru0))));
1889  xtime = GetLatestXTime();
1890  if (xtime)
1891  ereport(LOG,
1892  (errmsg("last completed transaction was at log time %s",
1893  timestamptz_to_str(xtime))));
1894 
1895  InRedo = false;
1896  }
1897  else
1898  {
1899  /* there are no WAL records following the checkpoint */
1900  ereport(LOG,
1901  (errmsg("redo is not required")));
1902  }
1903 
1904  /*
1905  * This check is intentionally after the above log messages that indicate
1906  * how far recovery went.
1907  */
1910  !reachedRecoveryTarget)
1911  ereport(FATAL,
1912  (errcode(ERRCODE_CONFIG_FILE_ERROR),
1913  errmsg("recovery ended before configured recovery target was reached")));
1914 }
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition: atomics.h:467
void HandleStartupProcInterrupts(void)
Definition: startup.c:154
void begin_startup_progress_phase(void)
Definition: startup.c:343
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1644
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:73
@ 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:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
pg_atomic_uint64 minWaitedLSN
Definition: waitlsn.h:58
struct WaitLSNState * waitLSNState
Definition: waitlsn.c:37
void WaitLSNSetLatches(XLogRecPtr currentLSN)
Definition: waitlsn.c:155
@ RECOVERY_TARGET_ACTION_PAUSE
@ RECOVERY_TARGET_ACTION_PROMOTE
@ RECOVERY_TARGET_ACTION_SHUTDOWN
static bool recoveryStopsBefore(XLogReaderState *record)
int recoveryTargetAction
Definition: xlogrecovery.c:88
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:204
static void ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *replayTLI)
static void recoveryPausesHere(bool endOfRecovery)
TimestampTz GetLatestXTime(void)
@ RECOVERY_NOT_PAUSED
Definition: xlogrecovery.h:46

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(), HandleStartupProcInterrupts(), 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(), 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(), WaitLSNSetLatches(), waitLSNState, XLogRecord::xl_info, XLogRecord::xl_rmid, XLOG_CHECKPOINT_REDO, xlog_outdesc(), xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, XLogReceiptTime, XLogRecoveryCtl, and XLR_INFO_MASK.

Referenced by StartupXLOG().

◆ pg_attribute_noreturn()

static void pg_attribute_noreturn ( )
static

Definition at line 4778 of file xlogrecovery.c.

4780 {
4781  ereport(ERROR,
4782  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4783  errmsg("multiple recovery targets specified"),
4784  errdetail("At most one of \"recovery_target\", \"recovery_target_lsn\", \"recovery_target_name\", \"recovery_target_time\", \"recovery_target_xid\" may be set.")));
4785 }

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

◆ PromoteIsTriggered()

bool PromoteIsTriggered ( void  )

Definition at line 4404 of file xlogrecovery.c.

4405 {
4406  /*
4407  * We check shared state each time only until a standby promotion is
4408  * triggered. We can't trigger a promotion again, so there's no need to
4409  * keep checking after the shared variable has once been seen true.
4410  */
4412  return true;
4413 
4417 
4418  return LocalPromoteIsTriggered;
4419 }

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

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

◆ read_backup_label()

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

Definition at line 1209 of file xlogrecovery.c.

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

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 1355 of file xlogrecovery.c.

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

4063 {
4064  XLogRecord *record;
4065  uint8 info;
4066 
4067  Assert(xlogreader != NULL);
4068 
4069  if (!XRecOffIsValid(RecPtr))
4070  {
4071  ereport(LOG,
4072  (errmsg("invalid checkpoint location")));
4073  return NULL;
4074  }
4075 
4077  record = ReadRecord(xlogprefetcher, LOG, true, replayTLI);
4078 
4079  if (record == NULL)
4080  {
4081  ereport(LOG,
4082  (errmsg("invalid checkpoint record")));
4083  return NULL;
4084  }
4085  if (record->xl_rmid != RM_XLOG_ID)
4086  {
4087  ereport(LOG,
4088  (errmsg("invalid resource manager ID in checkpoint record")));
4089  return NULL;
4090  }
4091  info = record->xl_info & ~XLR_INFO_MASK;
4092  if (info != XLOG_CHECKPOINT_SHUTDOWN &&
4093  info != XLOG_CHECKPOINT_ONLINE)
4094  {
4095  ereport(LOG,
4096  (errmsg("invalid xl_info in checkpoint record")));
4097  return NULL;
4098  }
4100  {
4101  ereport(LOG,
4102  (errmsg("invalid length of checkpoint record")));
4103  return NULL;
4104  }
4105  return record;
4106 }
#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, XLR_INFO_MASK, and XRecOffIsValid.

Referenced by InitWalRecovery().

◆ ReadRecord()

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

Definition at line 3144 of file xlogrecovery.c.

3146 {
3147  XLogRecord *record;
3150 
3151  /* Pass through parameters to XLogPageRead */
3152  private->fetching_ckpt = fetching_ckpt;
3153  private->emode = emode;
3154  private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
3155  private->replayTLI = replayTLI;
3156 
3157  /* This is the first attempt to read this page. */
3158  lastSourceFailed = false;
3159 
3160  for (;;)
3161  {
3162  char *errormsg;
3163 
3164  record = XLogPrefetcherReadRecord(xlogprefetcher, &errormsg);
3165  if (record == NULL)
3166  {
3167  /*
3168  * When we find that WAL ends in an incomplete record, keep track
3169  * of that record. After recovery is done, we'll write a record
3170  * to indicate to downstream WAL readers that that portion is to
3171  * be ignored.
3172  *
3173  * However, when ArchiveRecoveryRequested = true, we're going to
3174  * switch to a new timeline at the end of recovery. We will only
3175  * copy WAL over to the new timeline up to the end of the last
3176  * complete record, so if we did this, we would later create an
3177  * overwrite contrecord in the wrong place, breaking everything.
3178  */
3179  if (!ArchiveRecoveryRequested &&
3181  {
3184  }
3185 
3186  if (readFile >= 0)
3187  {
3188  close(readFile);
3189  readFile = -1;
3190  }
3191 
3192  /*
3193  * We only end up here without a message when XLogPageRead()
3194  * failed - in that case we already logged something. In
3195  * StandbyMode that only happens if we have been triggered, so we
3196  * shouldn't loop anymore in that case.
3197  */
3198  if (errormsg)
3200  (errmsg_internal("%s", errormsg) /* already translated */ ));
3201  }
3202 
3203  /*
3204  * Check page TLI is one of the expected values.
3205  */
3207  {
3208  char fname[MAXFNAMELEN];
3209  XLogSegNo segno;
3210  int32 offset;
3211 
3215  XLogFileName(fname, xlogreader->seg.ws_tli, segno,
3218  (errmsg("unexpected timeline ID %u in WAL segment %s, LSN %X/%X, offset %u",
3220  fname,
3222  offset)));
3223  record = NULL;
3224  }
3225 
3226  if (record)
3227  {
3228  /* Great, got a record */
3229  return record;
3230  }
3231  else
3232  {
3233  /* No valid record available from this source */
3234  lastSourceFailed = true;
3235 
3236  /*
3237  * If archive recovery was requested, but we were still doing
3238  * crash recovery, switch to archive recovery and retry using the
3239  * offline archive. We have now replayed all the valid WAL in
3240  * pg_wal, so we are presumably now consistent.
3241  *
3242  * We require that there's at least some valid WAL present in
3243  * pg_wal, however (!fetching_ckpt). We could recover using the
3244  * WAL from the archive, even if pg_wal is completely empty, but
3245  * we'd have no idea how far we'd have to replay to reach
3246  * consistency. So err on the safe side and give up.
3247  */
3249  !fetching_ckpt)
3250  {
3251  ereport(DEBUG1,
3252  (errmsg_internal("reached end of WAL in pg_wal, entering archive recovery")));
3253  InArchiveRecovery = true;
3256 
3259  minRecoveryPointTLI = replayTLI;
3260 
3262 
3263  /*
3264  * Before we retry, reset lastSourceFailed and currentSource
3265  * so that we will check the archive next.
3266  */
3267  lastSourceFailed = false;
3269 
3270  continue;
3271  }
3272 
3273  /* In standby mode, loop back to retry. Otherwise, give up. */
3275  continue;
3276  else
3277  return NULL;
3278  }
3279  }
3280 }
signed int int32
Definition: c.h:494
XLogRecPtr missingContrecPtr
Definition: xlogreader.h:215
XLogRecPtr abortedRecPtr
Definition: xlogreader.h:214
TimeLineID latestPageTLI
Definition: xlogreader.h:280
XLogRecPtr latestPagePtr
Definition: xlogreader.h:279
void * private_data
Definition: xlogreader.h:196
void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI)
Definition: xlog.c:6208
#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:48
XLogRecord * XLogPrefetcherReadRecord(XLogPrefetcher *prefetcher, char **errmsg)
XLogReaderState * XLogPrefetcherGetReader(XLogPrefetcher *prefetcher)
static bool CheckForStandbyTrigger(void)
static bool lastSourceFailed
Definition: xlogrecovery.c:248
static XLogSource currentSource
Definition: xlogrecovery.c:247
static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)

References abortedRecPtr, XLogReaderState::abortedRecPtr, ArchiveRecoveryRequested, CheckForStandbyTrigger(), CheckRecoveryConsistency(), close, currentSource, DEBUG1, emode_for_corrupt_record(), EnableStandbyMode(), XLogReaderState::EndRecPtr, ereport, errmsg(), errmsg_internal(), expectedTLEs, InArchiveRecovery, InvalidXLogRecPtr, 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, XLogRecPtrIsInvalid, and XLogSegmentOffset.

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

◆ readRecoverySignalFile()

static void readRecoverySignalFile ( void  )
static

Definition at line 1028 of file xlogrecovery.c.

1029 {
1030  struct stat stat_buf;
1031 
1033  return;
1034 
1035  /*
1036  * Check for old recovery API file: recovery.conf
1037  */
1038  if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
1039  ereport(FATAL,
1041  errmsg("using recovery command file \"%s\" is not supported",
1043 
1044  /*
1045  * Remove unused .done file, if present. Ignore if absent.
1046  */
1047  unlink(RECOVERY_COMMAND_DONE);
1048 
1049  /*
1050  * Check for recovery signal files and if found, fsync them since they
1051  * represent server state information. We don't sweat too much about the
1052  * possibility of fsync failure, however.
1053  *
1054  * If present, standby signal file takes precedence. If neither is present
1055  * then we won't enter archive recovery.
1056  */
1057  if (stat(STANDBY_SIGNAL_FILE, &stat_buf) == 0)
1058  {
1059  int fd;
1060 
1062  S_IRUSR | S_IWUSR);
1063  if (fd >= 0)
1064  {
1065  (void) pg_fsync(fd);
1066  close(fd);
1067  }
1069  }
1070  else if (stat(RECOVERY_SIGNAL_FILE, &stat_buf) == 0)
1071  {
1072  int fd;
1073 
1075  S_IRUSR | S_IWUSR);
1076  if (fd >= 0)
1077  {
1078  (void) pg_fsync(fd);
1079  close(fd);
1080  }
1082  }
1083 
1084  StandbyModeRequested = false;
1085  ArchiveRecoveryRequested = false;
1087  {
1088  StandbyModeRequested = true;
1089  ArchiveRecoveryRequested = true;
1090  }
1091  else if (recovery_signal_file_found)
1092  {
1093  StandbyModeRequested = false;
1094  ArchiveRecoveryRequested = true;
1095  }
1096  else
1097  return;
1098 
1099  /*
1100  * We don't support standby mode in standalone backends; that requires
1101  * other processes such as the WAL receiver to be alive.
1102  */
1104  ereport(FATAL,
1105  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1106  errmsg("standby mode is not supported by single-user servers")));
1107 }
#define PG_BINARY
Definition: c.h:1273
int BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition: fd.c:1109
int pg_fsync(int fd)
Definition: fd.c:386
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:451
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define S_IRUSR
Definition: win32_port.h:289
#define S_IWUSR
Definition: win32_port.h:292
#define STANDBY_SIGNAL_FILE
Definition: xlog.h:300
#define RECOVERY_SIGNAL_FILE
Definition: xlog.h:299
#define RECOVERY_COMMAND_FILE
Definition: xlogrecovery.c:69
#define RECOVERY_COMMAND_DONE
Definition: xlogrecovery.c:70

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 2995 of file xlogrecovery.c.

2996 {
2997  uint8 xact_info;
2998  TimestampTz xtime;
2999  TimestampTz delayUntil;
3000  long msecs;
3001 
3002  /* nothing to do if no delay configured */
3003  if (recovery_min_apply_delay <= 0)
3004  return false;
3005 
3006  /* no delay is applied on a database not yet consistent */
3007  if (!reachedConsistency)
3008  return false;
3009 
3010  /* nothing to do if crash recovery is requested */
3012  return false;
3013 
3014  /*
3015  * Is it a COMMIT record?
3016  *
3017  * We deliberately choose not to delay aborts since they have no effect on
3018  * MVCC. We already allow replay of records that don't have a timestamp,
3019  * so there is already opportunity for issues caused by early conflicts on
3020  * standbys.
3021  */
3022  if (XLogRecGetRmid(record) != RM_XACT_ID)
3023  return false;
3024 
3025  xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
3026 
3027  if (xact_info != XLOG_XACT_COMMIT &&
3028  xact_info != XLOG_XACT_COMMIT_PREPARED)
3029  return false;
3030 
3031  if (!getRecordTimestamp(record, &xtime))
3032  return false;
3033 
3035 
3036  /*
3037  * Exit without arming the latch if it's already past time to apply this
3038  * record
3039  */
3041  if (msecs <= 0)
3042  return false;
3043 
3044  while (true)
3045  {
3047 
3048  /* This might change recovery_min_apply_delay. */
3050 
3051  if (CheckForStandbyTrigger())
3052  break;
3053 
3054  /*
3055  * Recalculate delayUntil as recovery_min_apply_delay could have
3056  * changed while waiting in this loop.
3057  */
3059 
3060  /*
3061  * Wait for difference between GetCurrentTimestamp() and delayUntil.
3062  */
3064  delayUntil);
3065 
3066  if (msecs <= 0)
3067  break;
3068 
3069  elog(DEBUG2, "recovery apply delay %ld milliseconds", msecs);
3070 
3073  msecs,
3074  WAIT_EVENT_RECOVERY_APPLY_DELAY);
3075  }
3076  return true;
3077 }
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1756
#define DEBUG2
Definition: elog.h:29
void ResetLatch(Latch *latch)
Definition: latch.c:724
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:517
#define WL_TIMEOUT
Definition: latch.h:130
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:132
#define WL_LATCH_SET
Definition: latch.h:127
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:85
static bool getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
int recovery_min_apply_delay
Definition: xlogrecovery.c:94

References ArchiveRecoveryRequested, CheckForStandbyTrigger(), DEBUG2, elog, GetCurrentTimestamp(), getRecordTimestamp(), HandleStartupProcInterrupts(), 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 2938 of file xlogrecovery.c.

2939 {
2940  /* Don't pause unless users can connect! */
2941  if (!LocalHotStandbyActive)
2942  return;
2943 
2944  /* Don't pause after standby promotion has been triggered */
2946  return;
2947 
2948  if (endOfRecovery)
2949  ereport(LOG,
2950  (errmsg("pausing at the end of recovery"),
2951  errhint("Execute pg_wal_replay_resume() to promote.")));
2952  else
2953  ereport(LOG,
2954  (errmsg("recovery has paused"),
2955  errhint("Execute pg_wal_replay_resume() to continue.")));
2956 
2957  /* loop until recoveryPauseState is set to RECOVERY_NOT_PAUSED */
2959  {
2961  if (CheckForStandbyTrigger())
2962  return;
2963 
2964  /*
2965  * If recovery pause is requested then set it paused. While we are in
2966  * the loop, user might resume and pause again so set this every time.
2967  */
2969 
2970  /*
2971  * We wait on a condition variable that will wake us as soon as the
2972  * pause ends, but we use a timeout so we can check the above exit
2973  * condition periodically too.
2974  */
2976  WAIT_EVENT_RECOVERY_PAUSE);
2977  }
2979 }
bool ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
ConditionVariable recoveryNotPausedCV
Definition: xlogrecovery.c:360
static void ConfirmRecoveryPaused(void)
RecoveryPauseState GetRecoveryPauseState(void)

References CheckForStandbyTrigger(), ConditionVariableCancelSleep(), ConditionVariableTimedSleep(), ConfirmRecoveryPaused(), ereport, errhint(), errmsg(), GetRecoveryPauseState(), HandleStartupProcInterrupts(), LocalHotStandbyActive, LocalPromoteIsTriggered, LOG, 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 4669 of file xlogrecovery.c.

4670 {
4671  if (currValue < minValue)
4672  {
4674  {
4675  bool warned_for_promote = false;
4676 
4677  ereport(WARNING,
4678  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4679  errmsg("hot standby is not possible because of insufficient parameter settings"),
4680  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4681  param_name,
4682  currValue,
4683  minValue)));
4684 
4685  SetRecoveryPause(true);
4686 
4687  ereport(LOG,
4688  (errmsg("recovery has paused"),
4689  errdetail("If recovery is unpaused, the server will shut down."),
4690  errhint("You can then restart the server after making the necessary configuration changes.")));
4691 
4693  {
4695 
4696  if (CheckForStandbyTrigger())
4697  {
4698  if (!warned_for_promote)
4699  ereport(WARNING,
4700  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4701  errmsg("promotion is not possible because of insufficient parameter settings"),
4702 
4703  /*
4704  * Repeat the detail from above so it's easy to find
4705  * in the log.
4706  */
4707  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4708  param_name,
4709  currValue,
4710  minValue),
4711  errhint("Restart the server after making the necessary configuration changes.")));
4712  warned_for_promote = true;
4713  }
4714 
4715  /*
4716  * If recovery pause is requested then set it paused. While
4717  * we are in the loop, user might resume and pause again so
4718  * set this every time.
4719  */
4721 
4722  /*
4723  * We wait on a condition variable that will wake us as soon
4724  * as the pause ends, but we use a timeout so we can check the
4725  * above conditions periodically too.
4726  */
4728  WAIT_EVENT_RECOVERY_PAUSE);
4729  }
4731  }
4732 
4733  ereport(FATAL,
4734  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4735  errmsg("recovery aborted because of insufficient parameter settings"),
4736  /* Repeat the detail from above so it's easy to find in the log. */
4737  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4738  param_name,
4739  currValue,
4740  minValue),
4741  errhint("You can restart the server after making the necessary configuration changes.")));
4742  }
4743 }
static bool HotStandbyActiveInReplay(void)

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

Referenced by CheckRequiredParameterValues().

◆ recoveryStopsAfter()

static bool recoveryStopsAfter ( XLogReaderState record)
static

Definition at line 2739 of file xlogrecovery.c.

2740 {
2741  uint8 info;
2742  uint8 xact_info;
2743  uint8 rmid;
2744  TimestampTz recordXtime = 0;
2745 
2746  /*
2747  * Ignore recovery target settings when not in archive recovery (meaning
2748  * we are in crash recovery).
2749  */
2751  return false;
2752 
2753  info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2754  rmid = XLogRecGetRmid(record);
2755 
2756  /*
2757  * There can be many restore points that share the same name; we stop at
2758  * the first one.
2759  */
2761  rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2762  {
2763  xl_restore_point *recordRestorePointData;
2764 
2765  recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
2766 
2767  if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
2768  {
2769  recoveryStopAfter = true;
2772  (void) getRecordTimestamp(record, &recoveryStopTime);
2773  strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN);
2774 
2775  ereport(LOG,
2776  (errmsg("recovery stopping at restore point \"%s\", time %s",
2779  return true;
2780  }
2781  }
2782 
2783  /* Check if the target LSN has been reached */
2786  record->ReadRecPtr >= recoveryTargetLSN)
2787  {
2788  recoveryStopAfter = true;
2790  recoveryStopLSN = record->ReadRecPtr;
2791  recoveryStopTime = 0;
2792  recoveryStopName[0] = '\0';
2793  ereport(LOG,
2794  (errmsg("recovery stopping after WAL location (LSN) \"%X/%X\"",
2796  return true;
2797  }
2798 
2799  if (rmid != RM_XACT_ID)
2800  return false;
2801 
2802  xact_info = info & XLOG_XACT_OPMASK;
2803 
2804  if (xact_info == XLOG_XACT_COMMIT ||
2805  xact_info == XLOG_XACT_COMMIT_PREPARED ||
2806  xact_info == XLOG_XACT_ABORT ||
2807  xact_info == XLOG_XACT_ABORT_PREPARED)
2808  {
2809  TransactionId recordXid;
2810 
2811  /* Update the last applied transaction timestamp */
2812  if (getRecordTimestamp(record, &recordXtime))
2813  SetLatestXTime(recordXtime);
2814 
2815  /* Extract the XID of the committed/aborted transaction */
2816  if (xact_info == XLOG_XACT_COMMIT_PREPARED)
2817  {
2818  xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
2819  xl_xact_parsed_commit parsed;
2820 
2822  xlrec,
2823  &parsed);
2824  recordXid = parsed.twophase_xid;
2825  }
2826  else if (xact_info == XLOG_XACT_ABORT_PREPARED)
2827  {
2828  xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
2829  xl_xact_parsed_abort parsed;
2830 
2832  xlrec,
2833  &parsed);
2834  recordXid = parsed.twophase_xid;
2835  }
2836  else
2837  recordXid = XLogRecGetXid(record);
2838 
2839  /*
2840  * There can be only one transaction end record with this exact
2841  * transactionid
2842  *
2843  * when testing for an xid, we MUST test for equality only, since
2844  * transactions are numbered in the order they start, not the order
2845  * they complete. A higher numbered xid will complete before you about
2846  * 50% of the time...
2847  */
2849  recordXid == recoveryTargetXid)
2850  {
2851  recoveryStopAfter = true;
2852  recoveryStopXid = recordXid;
2853  recoveryStopTime = recordXtime;
2855  recoveryStopName[0] = '\0';
2856 
2857  if (xact_info == XLOG_XACT_COMMIT ||
2858  xact_info == XLOG_XACT_COMMIT_PREPARED)
2859  {
2860  ereport(LOG,
2861  (errmsg("recovery stopping after commit of transaction %u, time %s",
2864  }
2865  else if (xact_info == XLOG_XACT_ABORT ||
2866  xact_info == XLOG_XACT_ABORT_PREPARED)
2867  {
2868  ereport(LOG,
2869  (errmsg("recovery stopping after abort of transaction %u, time %s",
2872  }
2873  return true;
2874  }
2875  }
2876 
2877  /* Check if we should stop as soon as reaching consistency */
2879  {
2880  ereport(LOG,
2881  (errmsg("recovery stopping after reaching consistency")));
2882 
2883  recoveryStopAfter = true;
2885  recoveryStopTime = 0;
2887  recoveryStopName[0] = '\0';
2888  return true;
2889  }
2890 
2891  return false;
2892 }
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:421
TransactionId twophase_xid
Definition: xact.h:391
#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:412
bool recoveryTargetInclusive
Definition: xlogrecovery.c:87
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, XLogRecGetXid, and XLR_INFO_MASK.

Referenced by PerformWalRecovery().

◆ recoveryStopsBefore()

static bool recoveryStopsBefore ( XLogReaderState record)
static

Definition at line 2586 of file xlogrecovery.c.

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

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 4464 of file xlogrecovery.c.

4465 {
4466  unlink(PROMOTE_SIGNAL_FILE);
4467 }

References PROMOTE_SIGNAL_FILE.

Referenced by CheckForStandbyTrigger(), and PostmasterMain().

◆ rescanLatestTimeLine()

static bool rescanLatestTimeLine ( TimeLineID  replayTLI,
XLogRecPtr  replayLSN 
)
static

Definition at line 4116 of file xlogrecovery.c.

4117 {
4118  List *newExpectedTLEs;
4119  bool found;
4120  ListCell *cell;
4121  TimeLineID newtarget;
4122  TimeLineID oldtarget = recoveryTargetTLI;
4123  TimeLineHistoryEntry *currentTle = NULL;
4124 
4126  if (newtarget == recoveryTargetTLI)
4127  {
4128  /* No new timelines found */
4129  return false;
4130  }
4131 
4132  /*
4133  * Determine the list of expected TLIs for the new TLI
4134  */
4135 
4136  newExpectedTLEs = readTimeLineHistory(newtarget);
4137 
4138  /*
4139  * If the current timeline is not part of the history of the new timeline,
4140  * we cannot proceed to it.
4141  */
4142  found = false;
4143  foreach(cell, newExpectedTLEs)
4144  {
4145  currentTle = (TimeLineHistoryEntry *) lfirst(cell);
4146 
4147  if (currentTle->tli == recoveryTargetTLI)
4148  {
4149  found = true;
4150  break;
4151  }
4152  }
4153  if (!found)
4154  {
4155  ereport(LOG,
4156  (errmsg("new timeline %u is not a child of database system timeline %u",
4157  newtarget,
4158  replayTLI)));
4159  return false;
4160  }
4161 
4162  /*
4163  * The current timeline was found in the history file, but check that the
4164  * next timeline was forked off from it *after* the current recovery
4165  * location.
4166  */
4167  if (currentTle->end < replayLSN)
4168  {
4169  ereport(LOG,
4170  (errmsg("new timeline %u forked off current database system timeline %u before current recovery point %X/%X",
4171  newtarget,
4172  replayTLI,
4173  LSN_FORMAT_ARGS(replayLSN))));
4174  return false;
4175  }
4176 
4177  /* The new timeline history seems valid. Switch target */
4178  recoveryTargetTLI = newtarget;
4180  expectedTLEs = newExpectedTLEs;
4181 
4182  /*
4183  * As in StartupXLOG(), try to ensure we have all the history files
4184  * between the old target and new target in pg_wal.
4185  */
4186  restoreTimeLineHistoryFiles(oldtarget + 1, newtarget);
4187 
4188  ereport(LOG,
4189  (errmsg("new target timeline is %u",
4190  recoveryTargetTLI)));
4191 
4192  return true;
4193 }
TimeLineID findNewestTimeLine(TimeLineID startTLI)
Definition: timeline.c:264
void restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
Definition: timeline.c:50
List * readTimeLineHistory(TimeLineID targetTLI)
Definition: timeline.c:76
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 2288 of file xlogrecovery.c.

2289 {
2290  XLogReaderState *record = (XLogReaderState *) arg;
2292 
2293  initStringInfo(&buf);
2294  xlog_outdesc(&buf, record);
2295  xlog_block_info(&buf, record);
2296 
2297  /* translator: %s is a WAL record description */
2298  errcontext("WAL redo at %X/%X for %s",
2299  LSN_FORMAT_ARGS(record->ReadRecPtr),
2300  buf.data);
2301 
2302  pfree(buf.data);
2303 }
#define errcontext
Definition: elog.h:196
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()

static void SetCurrentChunkStartTime ( TimestampTz  xtime)
static

◆ SetLatestXTime()

static void SetLatestXTime ( TimestampTz  xtime)
static

◆ SetPromoteIsTriggered()

static void SetPromoteIsTriggered ( void  )
static

Definition at line 4422 of file xlogrecovery.c.

4423 {
4427 
4428  /*
4429  * Mark the recovery pause state as 'not paused' because the paused state
4430  * ends and promotion continues if a promotion is triggered while recovery
4431  * is paused. Otherwise pg_get_wal_replay_pause_state() can mistakenly
4432  * return 'paused' while a promotion is ongoing.
4433  */
4434  SetRecoveryPause(false);
4435 
4436  LocalPromoteIsTriggered = true;
4437 }

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

Referenced by CheckForStandbyTrigger().

◆ SetRecoveryPause()

◆ ShutdownWalRecovery()

void ShutdownWalRecovery ( void  )

Definition at line 1609 of file xlogrecovery.c.

1610 {
1611  char recoveryPath[MAXPGPATH];
1612 
1613  /* Final update of pg_stat_recovery_prefetch. */
1615 
1616  /* Shut down xlogreader */
1617  if (readFile >= 0)
1618  {
1619  close(readFile);
1620  readFile = -1;
1621  }
1624 
1626  {
1627  /*
1628  * Since there might be a partial WAL segment named RECOVERYXLOG, get
1629  * rid of it.
1630  */
1631  snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYXLOG");
1632  unlink(recoveryPath); /* ignore any error */
1633 
1634  /* Get rid of any remaining recovered timeline-history file, too */
1635  snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYHISTORY");
1636  unlink(recoveryPath); /* ignore any error */
1637  }
1638 
1639  /*
1640  * We don't need the latch anymore. It's not strictly necessary to disown
1641  * it, but let's do it for the sake of tidiness.
1642  */
1645 }
void DisownLatch(Latch *latch)
Definition: latch.c:489
#define XLOGDIR
void XLogPrefetcherComputeStats(XLogPrefetcher *prefetcher)
void XLogPrefetcherFree(XLogPrefetcher *prefetcher)
void XLogReaderFree(XLogReaderState *state)
Definition: xlogreader.c:161

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

Referenced by StartupXLOG().

◆ StartupRequestWalReceiverRestart()

void StartupRequestWalReceiverRestart ( void  )

Definition at line 4385 of file xlogrecovery.c.

4386 {
4388  {
4389  ereport(LOG,
4390  (errmsg("WAL receiver process shutdown requested")));
4391 
4392  pendingWalRcvRestart = true;
4393  }
4394 }
bool WalRcvRunning(void)
static bool pendingWalRcvRestart
Definition: xlogrecovery.c:249

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

Referenced by StartupRereadConfig().

◆ validateRecoveryParameters()

static void validateRecoveryParameters ( void  )
static

Definition at line 1110 of file xlogrecovery.c.

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

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 2474 of file xlogrecovery.c.

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

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 3554 of file xlogrecovery.c.

3558 {
3559  static TimestampTz last_fail_time = 0;
3560  TimestampTz now;
3561  bool streaming_reply_sent = false;
3562 
3563  /*-------
3564  * Standby mode is implemented by a state machine:
3565  *
3566  * 1. Read from either archive or pg_wal (XLOG_FROM_ARCHIVE), or just
3567  * pg_wal (XLOG_FROM_PG_WAL)
3568  * 2. Check for promotion trigger request
3569  * 3. Read from primary server via walreceiver (XLOG_FROM_STREAM)
3570  * 4. Rescan timelines
3571  * 5. Sleep wal_retrieve_retry_interval milliseconds, and loop back to 1.
3572  *
3573  * Failure to read from the current source advances the state machine to
3574  * the next state.
3575  *
3576  * 'currentSource' indicates the current state. There are no currentSource
3577  * values for "check trigger", "rescan timelines", and "sleep" states,
3578  * those actions are taken when reading from the previous source fails, as
3579  * part of advancing to the next state.
3580  *
3581  * If standby mode is turned off while reading WAL from stream, we move
3582  * to XLOG_FROM_ARCHIVE and reset lastSourceFailed, to force fetching
3583  * the files (which would be required at end of recovery, e.g., timeline
3584  * history file) from archive or pg_wal. We don't need to kill WAL receiver
3585  * here because it's already stopped when standby mode is turned off at
3586  * the end of recovery.
3587  *-------
3588  */
3589  if (!InArchiveRecovery)
3591  else if (currentSource == XLOG_FROM_ANY ||
3593  {
3594  lastSourceFailed = false;
3596  }
3597 
3598  for (;;)
3599  {
3600  XLogSource oldSource = currentSource;
3601  bool startWalReceiver = false;
3602 
3603  /*
3604  * First check if we failed to read from the current source, and
3605  * advance the state machine if so. The failure to read might've
3606  * happened outside this function, e.g when a CRC check fails on a
3607  * record, or within this loop.
3608  */
3609  if (lastSourceFailed)
3610  {
3611  /*
3612  * Don't allow any retry loops to occur during nonblocking
3613  * readahead. Let the caller process everything that has been
3614  * decoded already first.
3615  */
3616  if (nonblocking)
3617  return XLREAD_WOULDBLOCK;
3618 
3619  switch (currentSource)
3620  {
3621  case XLOG_FROM_ARCHIVE:
3622  case XLOG_FROM_PG_WAL:
3623 
3624  /*
3625  * Check to see if promotion is requested. Note that we do
3626  * this only after failure, so when you promote, we still
3627  * finish replaying as much as we can from archive and
3628  * pg_wal before failover.
3629  */
3631  {
3633  return XLREAD_FAIL;
3634  }
3635 
3636  /*
3637  * Not in standby mode, and we've now tried the archive
3638  * and pg_wal.
3639  */
3640  if (!StandbyMode)
3641  return XLREAD_FAIL;
3642 
3643  /*
3644  * Move to XLOG_FROM_STREAM state, and set to start a
3645  * walreceiver if necessary.
3646  */
3648  startWalReceiver = true;
3649  break;
3650 
3651  case XLOG_FROM_STREAM:
3652 
3653  /*
3654  * Failure while streaming. Most likely, we got here
3655  * because streaming replication was terminated, or
3656  * promotion was triggered. But we also get here if we
3657  * find an invalid record in the WAL streamed from the
3658  * primary, in which case something is seriously wrong.
3659  * There's little chance that the problem will just go
3660  * away, but PANIC is not good for availability either,
3661  * especially in hot standby mode. So, we treat that the
3662  * same as disconnection, and retry from archive/pg_wal
3663  * again. The WAL in the archive should be identical to
3664  * what was streamed, so it's unlikely that it helps, but
3665  * one can hope...
3666  */
3667 
3668  /*
3669  * We should be able to move to XLOG_FROM_STREAM only in
3670  * standby mode.
3671  */
3673 
3674  /*
3675  * Before we leave XLOG_FROM_STREAM state, make sure that
3676  * walreceiver is not active, so that it won't overwrite
3677  * WAL that we restore from archive.
3678  */
3680 
3681  /*
3682  * Before we sleep, re-scan for possible new timelines if
3683  * we were requested to recover to the latest timeline.
3684  */
3686  {
3687  if (rescanLatestTimeLine(replayTLI, replayLSN))
3688  {
3690  break;
3691  }
3692  }
3693 
3694  /*
3695  * XLOG_FROM_STREAM is the last state in our state
3696  * machine, so we've exhausted all the options for
3697  * obtaining the requested WAL. We're going to loop back
3698  * and retry from the archive, but if it hasn't been long
3699  * since last attempt, sleep wal_retrieve_retry_interval
3700  * milliseconds to avoid busy-waiting.
3701  */
3703  if (!TimestampDifferenceExceeds(last_fail_time, now,
3705  {
3706  long wait_time;
3707 
3708  wait_time = wal_retrieve_retry_interval -
3709  TimestampDifferenceMilliseconds(last_fail_time, now);
3710 
3711  elog(LOG, "waiting for WAL to become available at %X/%X",
3712  LSN_FORMAT_ARGS(RecPtr));
3713 
3714  /* Do background tasks that might benefit us later. */
3716 
3720  wait_time,
3721  WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL);
3724 
3725  /* Handle interrupt signals of startup process */
3727  }
3728  last_fail_time = now;
3730  break;
3731 
3732  default:
3733  elog(ERROR, "unexpected WAL source %d", currentSource);
3734  }
3735  }
3736  else if (currentSource == XLOG_FROM_PG_WAL)
3737  {
3738  /*
3739  * We just successfully read a file in pg_wal. We prefer files in
3740  * the archive over ones in pg_wal, so try the next file again
3741  * from the archive first.
3742  */
3743  if (InArchiveRecovery)
3745  }
3746 
3747  if (currentSource != oldSource)
3748  elog(DEBUG2, "switched WAL source from %s to %s after %s",
3750  lastSourceFailed ? "failure" : "success");
3751 
3752  /*
3753  * We've now handled possible failure. Try to read from the chosen
3754  * source.
3755  */
3756  lastSourceFailed = false;
3757 
3758  switch (currentSource)
3759  {
3760  case XLOG_FROM_ARCHIVE:
3761  case XLOG_FROM_PG_WAL:
3762 
3763  /*
3764  * WAL receiver must not be running when reading WAL from
3765  * archive or pg_wal.
3766  */
3767  Assert(!WalRcvStreaming());
3768 
3769  /* Close any old file we might have open. */
3770  if (readFile >= 0)
3771  {
3772  close(readFile);
3773  readFile = -1;
3774  }
3775  /* Reset curFileTLI if random fetch. */
3776  if (randAccess)
3777  curFileTLI = 0;
3778 
3779  /*
3780  * Try to restore the file from archive, or read an existing
3781  * file from pg_wal.
3782  */
3785  currentSource);
3786  if (readFile >= 0)
3787  return XLREAD_SUCCESS; /* success! */
3788 
3789  /*
3790  * Nope, not found in archive or pg_wal.
3791  */
3792  lastSourceFailed = true;
3793  break;
3794 
3795  case XLOG_FROM_STREAM:
3796  {
3797  bool havedata;
3798 
3799  /*
3800  * We should be able to move to XLOG_FROM_STREAM only in
3801  * standby mode.
3802  */
3804 
3805  /*
3806  * First, shutdown walreceiver if its restart has been
3807  * requested -- but no point if we're already slated for
3808  * starting it.
3809  */
3810  if (pendingWalRcvRestart && !startWalReceiver)
3811  {
3813 
3814  /*
3815  * Re-scan for possible new timelines if we were
3816  * requested to recover to the latest timeline.
3817  */
3820  rescanLatestTimeLine(replayTLI, replayLSN);
3821 
3822  startWalReceiver = true;
3823  }
3824  pendingWalRcvRestart = false;
3825 
3826  /*
3827  * Launch walreceiver if needed.
3828  *
3829  * If fetching_ckpt is true, RecPtr points to the initial
3830  * checkpoint location. In that case, we use RedoStartLSN
3831  * as the streaming start position instead of RecPtr, so
3832  * that when we later jump backwards to start redo at
3833  * RedoStartLSN, we will have the logs streamed already.
3834  */
3835  if (startWalReceiver &&
3836  PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0)
3837  {
3838  XLogRecPtr ptr;
3839  TimeLineID tli;
3840 
3841  if (fetching_ckpt)
3842  {
3843  ptr = RedoStartLSN;
3844  tli = RedoStartTLI;
3845  }
3846  else
3847  {
3848  ptr = RecPtr;
3849 
3850  /*
3851  * Use the record begin position to determine the
3852  * TLI, rather than the position we're reading.
3853  */
3854  tli = tliOfPointInHistory(tliRecPtr, expectedTLEs);
3855 
3856  if (curFileTLI > 0 && tli < curFileTLI)
3857  elog(ERROR, "according to history file, WAL location %X/%X belongs to timeline %u, but previous recovered WAL file came from timeline %u",
3858  LSN_FORMAT_ARGS(tliRecPtr),
3859  tli, curFileTLI);
3860  }
3861  curFileTLI = tli;
3866  flushedUpto = 0;
3867  }
3868 
3869  /*
3870  * Check if WAL receiver is active or wait to start up.
3871  */
3872  if (!WalRcvStreaming())
3873  {
3874  lastSourceFailed = true;
3875  break;
3876  }
3877 
3878  /*
3879  * Walreceiver is active, so see if new data has arrived.
3880  *
3881  * We only advance XLogReceiptTime when we obtain fresh
3882  * WAL from walreceiver and observe that we had already
3883  * processed everything before the most recent "chunk"
3884  * that it flushed to disk. In steady state where we are
3885  * keeping up with the incoming data, XLogReceiptTime will
3886  * be updated on each cycle. When we are behind,
3887  * XLogReceiptTime will not advance, so the grace time
3888  * allotted to conflicting queries will decrease.
3889  */
3890  if (RecPtr < flushedUpto)
3891  havedata = true;
3892  else
3893  {
3894  XLogRecPtr latestChunkStart;
3895 
3896  flushedUpto = GetWalRcvFlushRecPtr(&latestChunkStart, &receiveTLI);
3897  if (RecPtr < flushedUpto && receiveTLI == curFileTLI)
3898  {
3899  havedata = true;
3900  if (latestChunkStart <= RecPtr)
3901  {
3904  }
3905  }
3906  else
3907  havedata = false;
3908  }
3909  if (havedata)
3910  {
3911  /*
3912  * Great, streamed far enough. Open the file if it's
3913  * not open already. Also read the timeline history
3914  * file if we haven't initialized timeline history
3915  * yet; it should be streamed over and present in
3916  * pg_wal by now. Use XLOG_FROM_STREAM so that source
3917  * info is set correctly and XLogReceiptTime isn't
3918  * changed.
3919  *
3920  * NB: We must set readTimeLineHistory based on
3921  * recoveryTargetTLI, not receiveTLI. Normally they'll