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 "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/proc.h"
#include "storage/procarray.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/datetime.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, int emode, TimeLineID tli, XLogSource source, bool notfoundOk)
 
static int XLogFileReadAnyTLI (XLogSegNo segno, int emode, 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 1905 of file xlogrecovery.c.

1906 {
1907  ErrorContextCallback errcallback;
1908  bool switchedTLI = false;
1909 
1910  /* Setup error traceback support for ereport() */
1911  errcallback.callback = rm_redo_error_callback;
1912  errcallback.arg = (void *) xlogreader;
1913  errcallback.previous = error_context_stack;
1914  error_context_stack = &errcallback;
1915 
1916  /*
1917  * TransamVariables->nextXid must be beyond record's xid.
1918  */
1920 
1921  /*
1922  * Before replaying this record, check if this record causes the current
1923  * timeline to change. The record is already considered to be part of the
1924  * new timeline, so we update replayTLI before replaying it. That's
1925  * important so that replayEndTLI, which is recorded as the minimum
1926  * recovery point's TLI if recovery stops after this record, is set
1927  * correctly.
1928  */
1929  if (record->xl_rmid == RM_XLOG_ID)
1930  {
1931  TimeLineID newReplayTLI = *replayTLI;
1932  TimeLineID prevReplayTLI = *replayTLI;
1933  uint8 info = record->xl_info & ~XLR_INFO_MASK;
1934 
1935  if (info == XLOG_CHECKPOINT_SHUTDOWN)
1936  {
1937  CheckPoint checkPoint;
1938 
1939  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
1940  newReplayTLI = checkPoint.ThisTimeLineID;
1941  prevReplayTLI = checkPoint.PrevTimeLineID;
1942  }
1943  else if (info == XLOG_END_OF_RECOVERY)
1944  {
1945  xl_end_of_recovery xlrec;
1946 
1947  memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
1948  newReplayTLI = xlrec.ThisTimeLineID;
1949  prevReplayTLI = xlrec.PrevTimeLineID;
1950  }
1951 
1952  if (newReplayTLI != *replayTLI)
1953  {
1954  /* Check that it's OK to switch to this TLI */
1956  newReplayTLI, prevReplayTLI, *replayTLI);
1957 
1958  /* Following WAL records should be run with new TLI */
1959  *replayTLI = newReplayTLI;
1960  switchedTLI = true;
1961  }
1962  }
1963 
1964  /*
1965  * Update shared replayEndRecPtr before replaying this record, so that
1966  * XLogFlush will update minRecoveryPoint correctly.
1967  */
1970  XLogRecoveryCtl->replayEndTLI = *replayTLI;
1972 
1973  /*
1974  * If we are attempting to enter Hot Standby mode, process XIDs we see
1975  */
1977  TransactionIdIsValid(record->xl_xid))
1979 
1980  /*
1981  * Some XLOG record types that are related to recovery are processed
1982  * directly here, rather than in xlog_redo()
1983  */
1984  if (record->xl_rmid == RM_XLOG_ID)
1985  xlogrecovery_redo(xlogreader, *replayTLI);
1986 
1987  /* Now apply the WAL record itself */
1988  GetRmgr(record->xl_rmid).rm_redo(xlogreader);
1989 
1990  /*
1991  * After redo, check whether the backup pages associated with the WAL
1992  * record are consistent with the existing pages. This check is done only
1993  * if consistency check is enabled for this record.
1994  */
1995  if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
1997 
1998  /* Pop the error context stack */
1999  error_context_stack = errcallback.previous;
2000 
2001  /*
2002  * Update lastReplayedEndRecPtr after this record has been successfully
2003  * replayed.
2004  */
2008  XLogRecoveryCtl->lastReplayedTLI = *replayTLI;
2010 
2011  /* ------
2012  * Wakeup walsenders:
2013  *
2014  * On the standby, the WAL is flushed first (which will only wake up
2015  * physical walsenders) and then applied, which will only wake up logical
2016  * walsenders.
2017  *
2018  * Indeed, logical walsenders on standby can't decode and send data until
2019  * it's been applied.
2020  *
2021  * Physical walsenders don't need to be woken up during replay unless
2022  * cascading replication is allowed and time line change occurred (so that
2023  * they can notice that they are on a new time line).
2024  *
2025  * That's why the wake up conditions are for:
2026  *
2027  * - physical walsenders in case of new time line and cascade
2028  * replication is allowed
2029  * - logical walsenders in case cascade replication is allowed (could not
2030  * be created otherwise)
2031  * ------
2032  */
2034  WalSndWakeup(switchedTLI, true);
2035 
2036  /*
2037  * If rm_redo called XLogRequestWalReceiverReply, then we wake up the
2038  * receiver so that it notices the updated lastReplayedEndRecPtr and sends
2039  * a reply to the primary.
2040  */
2042  {
2043  doRequestWalReceiverReply = false;
2044  WalRcvForceReply();
2045  }
2046 
2047  /* Allow read-only connections if we're consistent now */
2049 
2050  /* Is this a timeline switch? */
2051  if (switchedTLI)
2052  {
2053  /*
2054  * Before we continue on the new timeline, clean up any (possibly
2055  * bogus) future WAL segments on the old timeline.
2056  */
2058 
2059  /* Reset the prefetcher. */
2061  }
2062 }
unsigned char uint8
Definition: c.h:493
ErrorContextCallback * error_context_stack
Definition: elog.c:95
#define XLOG_CHECKPOINT_SHUTDOWN
Definition: pg_control.h:67
#define XLOG_END_OF_RECOVERY
Definition: pg_control.h:76
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4344
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
TimeLineID PrevTimeLineID
Definition: pg_control.h:40
TimeLineID ThisTimeLineID
Definition: pg_control.h:39
struct ErrorContextCallback * previous
Definition: elog.h:295
void(* callback)(void *arg)
Definition: elog.h:296
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:1356
#define AllowCascadeReplication()
Definition: walreceiver.h:41
void WalSndWakeup(bool physical, bool logical)
Definition: walsender.c:3560
void RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
Definition: xlog.c:3875
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:56
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

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

4793 {
4796  error_multiple_recovery_targets();
4797 
4798  if (newval && strcmp(newval, "") != 0)
4800  else
4802 }
#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 4831 of file xlogrecovery.c.

4832 {
4835  error_multiple_recovery_targets();
4836 
4837  if (newval && strcmp(newval, "") != 0)
4838  {
4840  recoveryTargetLSN = *((XLogRecPtr *) extra);
4841  }
4842  else
4844 }
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 4866 of file xlogrecovery.c.

4867 {
4870  error_multiple_recovery_targets();
4871 
4872  if (newval && strcmp(newval, "") != 0)
4873  {
4876  }
4877  else
4879 }
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 4946 of file xlogrecovery.c.

4947 {
4950  error_multiple_recovery_targets();
4951 
4952  if (newval && strcmp(newval, "") != 0)
4954  else
4956 }
@ 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 4995 of file xlogrecovery.c.

4996 {
4999  recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
5000  else
5002 }
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 5031 of file xlogrecovery.c.

5032 {
5035  error_multiple_recovery_targets();
5036 
5037  if (newval && strcmp(newval, "") != 0)
5038  {
5040  recoveryTargetXid = *((TransactionId *) extra);
5041  }
5042  else
5044 }
uint32 TransactionId
Definition: c.h:641
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 4737 of file xlogrecovery.c.

4738 {
4739  if (*newval && strcmp(*newval, "") != 0 &&
4741  return false;
4742 
4743  return true;
4744 }
#define WARNING
Definition: elog.h:36
bool ReplicationSlotValidateName(const char *name, int elevel)
Definition: slot.c:215

References newval, ReplicationSlotValidateName(), and WARNING.

◆ check_recovery_target()

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

Definition at line 4778 of file xlogrecovery.c.

4779 {
4780  if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
4781  {
4782  GUC_check_errdetail("The only allowed value is \"immediate\".");
4783  return false;
4784  }
4785  return true;
4786 }
#define GUC_check_errdetail
Definition: guc.h:446

References GUC_check_errdetail, and newval.

◆ check_recovery_target_lsn()

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

Definition at line 4808 of file xlogrecovery.c.

4809 {
4810  if (strcmp(*newval, "") != 0)
4811  {
4812  XLogRecPtr lsn;
4813  XLogRecPtr *myextra;
4814  bool have_error = false;
4815 
4816  lsn = pg_lsn_in_internal(*newval, &have_error);
4817  if (have_error)
4818  return false;
4819 
4820  myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
4821  *myextra = lsn;
4822  *extra = (void *) myextra;
4823  }
4824  return true;
4825 }
#define ERROR
Definition: elog.h:39
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:633
XLogRecPtr pg_lsn_in_internal(const char *str, bool *have_error)
Definition: pg_lsn.c:30

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

4851 {
4852  /* Use the value of newval directly */
4853  if (strlen(*newval) >= MAXFNAMELEN)
4854  {
4855  GUC_check_errdetail("%s is too long (maximum %d characters).",
4856  "recovery_target_name", MAXFNAMELEN - 1);
4857  return false;
4858  }
4859  return true;
4860 }
#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 4891 of file xlogrecovery.c.

4892 {
4893  if (strcmp(*newval, "") != 0)
4894  {
4895  /* reject some special values */
4896  if (strcmp(*newval, "now") == 0 ||
4897  strcmp(*newval, "today") == 0 ||
4898  strcmp(*newval, "tomorrow") == 0 ||
4899  strcmp(*newval, "yesterday") == 0)
4900  {
4901  return false;
4902  }
4903 
4904  /*
4905  * parse timestamp value (see also timestamptz_in())
4906  */
4907  {
4908  char *str = *newval;
4909  fsec_t fsec;
4910  struct pg_tm tt,
4911  *tm = &tt;
4912  int tz;
4913  int dtype;
4914  int nf;
4915  int dterr;
4916  char *field[MAXDATEFIELDS];
4917  int ftype[MAXDATEFIELDS];
4918  char workbuf[MAXDATELEN + MAXDATEFIELDS];
4919  DateTimeErrorExtra dtextra;
4921 
4922  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
4923  field, ftype, MAXDATEFIELDS, &nf);
4924  if (dterr == 0)
4925  dterr = DecodeDateTime(field, ftype, nf,
4926  &dtype, tm, &fsec, &tz, &dtextra);
4927  if (dterr != 0)
4928  return false;
4929  if (dtype != DTK_DATE)
4930  return false;
4931 
4932  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
4933  {
4934  GUC_check_errdetail("timestamp out of range: \"%s\"", str);
4935  return false;
4936  }
4937  }
4938  }
4939  return true;
4940 }
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:756
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, DateTimeErrorExtra *extra)
Definition: datetime.c:980
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:1998
int64 TimestampTz
Definition: timestamp.h:39
int32 fsec_t
Definition: timestamp.h:41
#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(), generate_unaccent_rules::str, tm, and tm2timestamp().

◆ check_recovery_target_timeline()

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

Definition at line 4962 of file xlogrecovery.c.

4963 {
4965  RecoveryTargetTimeLineGoal *myextra;
4966 
4967  if (strcmp(*newval, "current") == 0)
4969  else if (strcmp(*newval, "latest") == 0)
4971  else
4972  {
4974 
4975  errno = 0;
4976  strtoul(*newval, NULL, 0);
4977  if (errno == EINVAL || errno == ERANGE)
4978  {
4979  GUC_check_errdetail("recovery_target_timeline is not a valid number.");
4980  return false;
4981  }
4982  }
4983 
4985  *myextra = rttg;
4986  *extra = (void *) myextra;
4987 
4988  return true;
4989 }
@ 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 5008 of file xlogrecovery.c.

5009 {
5010  if (strcmp(*newval, "") != 0)
5011  {
5012  TransactionId xid;
5013  TransactionId *myextra;
5014 
5015  errno = 0;
5016  xid = (TransactionId) strtou64(*newval, NULL, 0);
5017  if (errno == EINVAL || errno == ERANGE)
5018  return false;
5019 
5020  myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
5021  *myextra = xid;
5022  *extra = (void *) myextra;
5023  }
5024  return true;
5025 }
#define strtou64(str, endptr, base)
Definition: c.h:1287

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

◆ CheckForStandbyTrigger()

static bool CheckForStandbyTrigger ( void  )
static

Definition at line 4430 of file xlogrecovery.c.

4431 {
4433  return true;
4434 
4436  {
4437  ereport(LOG, (errmsg("received promote request")));
4441  return true;
4442  }
4443 
4444  return false;
4445 }
bool IsPromoteSignaled(void)
Definition: startup.c:284
void ResetPromoteSignaled(void)
Definition: startup.c:290
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#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 4460 of file xlogrecovery.c.

4461 {
4462  struct stat stat_buf;
4463 
4464  if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
4465  return true;
4466 
4467  return false;
4468 }
#define stat
Definition: win32_port.h:284
#define PROMOTE_SIGNAL_FILE
Definition: xlog.h:305

References PROMOTE_SIGNAL_FILE, and stat.

Referenced by CheckForStandbyTrigger(), and process_pm_pmsignal().

◆ CheckRecoveryConsistency()

static void CheckRecoveryConsistency ( void  )
static

Definition at line 2172 of file xlogrecovery.c.

2173 {
2174  XLogRecPtr lastReplayedEndRecPtr;
2175  TimeLineID lastReplayedTLI;
2176 
2177  /*
2178  * During crash recovery, we don't reach a consistent state until we've
2179  * replayed all the WAL.
2180  */
2182  return;
2183 
2185 
2186  /*
2187  * assume that we are called in the startup process, and hence don't need
2188  * a lock to read lastReplayedEndRecPtr
2189  */
2190  lastReplayedEndRecPtr = XLogRecoveryCtl->lastReplayedEndRecPtr;
2191  lastReplayedTLI = XLogRecoveryCtl->lastReplayedTLI;
2192 
2193  /*
2194  * Have we reached the point where our base backup was completed?
2195  */
2197  backupEndPoint <= lastReplayedEndRecPtr)
2198  {
2199  XLogRecPtr saveBackupStartPoint = backupStartPoint;
2200  XLogRecPtr saveBackupEndPoint = backupEndPoint;
2201 
2202  elog(DEBUG1, "end of backup reached");
2203 
2204  /*
2205  * We have reached the end of base backup, as indicated by pg_control.
2206  * Update the control file accordingly.
2207  */
2208  ReachedEndOfBackup(lastReplayedEndRecPtr, lastReplayedTLI);
2211  backupEndRequired = false;
2212 
2213  ereport(LOG,
2214  (errmsg("completed backup recovery with redo LSN %X/%X and end LSN %X/%X",
2215  LSN_FORMAT_ARGS(saveBackupStartPoint),
2216  LSN_FORMAT_ARGS(saveBackupEndPoint))));
2217  }
2218 
2219  /*
2220  * Have we passed our safe starting point? Note that minRecoveryPoint is
2221  * known to be incorrectly set if recovering from a backup, until the
2222  * XLOG_BACKUP_END arrives to advise us of the correct minRecoveryPoint.
2223  * All we know prior to that is that we're not consistent yet.
2224  */
2226  minRecoveryPoint <= lastReplayedEndRecPtr)
2227  {
2228  /*
2229  * Check to see if the XLOG sequence contained any unresolved
2230  * references to uninitialized pages.
2231  */
2233 
2234  /*
2235  * Check that pg_tblspc doesn't contain any real directories. Replay
2236  * of Database/CREATE_* records may have created fictitious tablespace
2237  * directories that should have been removed by the time consistency
2238  * was reached.
2239  */
2241 
2242  reachedConsistency = true;
2243  ereport(LOG,
2244  (errmsg("consistent recovery state reached at %X/%X",
2245  LSN_FORMAT_ARGS(lastReplayedEndRecPtr))));
2246  }
2247 
2248  /*
2249  * Have we got a valid starting snapshot that will allow queries to be
2250  * run? If so, we can tell postmaster that the database is consistent now,
2251  * enabling connections.
2252  */
2257  {
2261 
2262  LocalHotStandbyActive = true;
2263 
2265  }
2266 }
#define DEBUG1
Definition: elog.h:30
bool IsUnderPostmaster
Definition: globals.c:116
Assert(fmt[strlen(fmt) - 1] !='\n')
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:6124
#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:248
@ STANDBY_SNAPSHOT_READY
Definition: xlogutils.h:52

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

2141 {
2142  DIR *dir;
2143  struct dirent *de;
2144 
2145  dir = AllocateDir("pg_tblspc");
2146  while ((de = ReadDir(dir, "pg_tblspc")) != NULL)
2147  {
2148  char path[MAXPGPATH + 10];
2149 
2150  /* Skip entries of non-oid names */
2151  if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
2152  continue;
2153 
2154  snprintf(path, sizeof(path), "pg_tblspc/%s", de->d_name);
2155 
2156  if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
2159  errmsg("unexpected directory entry \"%s\" found in %s",
2160  de->d_name, "pg_tblspc/"),
2161  errdetail("All directory entries in pg_tblspc/ should be symbolic links."),
2162  errhint("Remove those directories, or set allow_in_place_tablespaces to ON transiently to let recovery complete.")));
2163  }
2164 }
bool allow_in_place_tablespaces
Definition: tablespace.c:91
int errdetail(const char *fmt,...)
Definition: elog.c:1208
int errhint(const char *fmt,...)
Definition: elog.c:1322
int errcode(int sqlerrcode)
Definition: elog.c:860
#define PANIC
Definition: elog.h:42
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2909
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2843
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition: file_utils.c:525
@ PGFILETYPE_LNK
Definition: file_utils.h:24
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:41
#define MAXPGPATH
#define snprintf
Definition: port.h:238
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, 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 2374 of file xlogrecovery.c.

2376 {
2377  /* Check that the record agrees on what the current (old) timeline is */
2378  if (prevTLI != replayTLI)
2379  ereport(PANIC,
2380  (errmsg("unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record",
2381  prevTLI, replayTLI)));
2382 
2383  /*
2384  * The new timeline better be in the list of timelines we expect to see,
2385  * according to the timeline history. It should also not decrease.
2386  */
2387  if (newTLI < replayTLI || !tliInHistory(newTLI, expectedTLEs))
2388  ereport(PANIC,
2389  (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
2390  newTLI, replayTLI)));
2391 
2392  /*
2393  * If we have not yet reached min recovery point, and we're about to
2394  * switch to a timeline greater than the timeline of the min recovery
2395  * point: trouble. After switching to the new timeline, we could not
2396  * possibly visit the min recovery point on the correct timeline anymore.
2397  * This can happen if there is a newer timeline in the archive that
2398  * branched before the timeline the min recovery point is on, and you
2399  * attempt to do PITR to the new timeline.
2400  */
2402  lsn < minRecoveryPoint &&
2403  newTLI > minRecoveryPointTLI)
2404  ereport(PANIC,
2405  (errmsg("unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%X on timeline %u",
2406  newTLI,
2409 
2410  /* Looks good */
2411 }
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 4027 of file xlogrecovery.c.

4028 {
4029  static XLogRecPtr lastComplaint = 0;
4030 
4031  if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
4032  {
4033  if (RecPtr == lastComplaint)
4034  emode = DEBUG1;
4035  else
4036  lastComplaint = RecPtr;
4037  }
4038  return emode;
4039 }
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:305
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 1456 of file xlogrecovery.c.

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

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

4624 {
4625  TimestampTz xtime;
4626 
4630 
4631  return xtime;
4632 }
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 4559 of file xlogrecovery.c.

4560 {
4561  XLogRecPtr recptr;
4562  TimeLineID tli;
4563 
4565  recptr = XLogRecoveryCtl->replayEndRecPtr;
4568 
4569  if (replayEndTLI)
4570  *replayEndTLI = tli;
4571  return recptr;
4572 }

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

2424 {
2425  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2426  uint8 xact_info = info & XLOG_XACT_OPMASK;
2427  uint8 rmid = XLogRecGetRmid(record);
2428 
2429  if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2430  {
2431  *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
2432  return true;
2433  }
2434  if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
2435  xact_info == XLOG_XACT_COMMIT_PREPARED))
2436  {
2437  *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
2438  return true;
2439  }
2440  if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
2441  xact_info == XLOG_XACT_ABORT_PREPARED))
2442  {
2443  *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
2444  return true;
2445  }
2446  return false;
2447 }
#define XLOG_RESTORE_POINT
Definition: pg_control.h:74
#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 2883 of file xlogrecovery.c.

2884 {
2885  char reason[200];
2886 
2888  snprintf(reason, sizeof(reason),
2889  "%s transaction %u",
2890  recoveryStopAfter ? "after" : "before",
2891  recoveryStopXid);
2893  snprintf(reason, sizeof(reason),
2894  "%s %s\n",
2895  recoveryStopAfter ? "after" : "before",
2897  else if (recoveryTarget == RECOVERY_TARGET_LSN)
2898  snprintf(reason, sizeof(reason),
2899  "%s LSN %X/%X\n",
2900  recoveryStopAfter ? "after" : "before",
2903  snprintf(reason, sizeof(reason),
2904  "at restore point \"%s\"",
2907  snprintf(reason, sizeof(reason), "reached consistency");
2908  else
2909  snprintf(reason, sizeof(reason), "no recovery target specified");
2910 
2911  return pstrdup(reason);
2912 }
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1854
char * pstrdup(const char *in)
Definition: mcxt.c:1619
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 4639 of file xlogrecovery.c.

4640 {
4641  /*
4642  * This must be executed in the startup process, since we don't export the
4643  * relevant state to shared memory.
4644  */
4645  Assert(InRecovery);
4646 
4647  *rtime = XLogReceiptTime;
4648  *fromStream = (XLogReceiptSource == XLOG_FROM_STREAM);
4649 }
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 4499 of file xlogrecovery.c.

4500 {
4501  /*
4502  * We check shared state each time only until Hot Standby is active. We
4503  * can't de-activate Hot Standby, so there's no need to keep checking
4504  * after the shared variable has once been seen true.
4505  */
4507  return true;
4508  else
4509  {
4510  /* spinlock is essential on machines with weak memory ordering! */
4514 
4515  return LocalHotStandbyActive;
4516  }
4517 }

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

Referenced by XLogWalRcvSendHSFeedback().

◆ HotStandbyActiveInReplay()

static bool HotStandbyActiveInReplay ( void  )
static

Definition at line 4524 of file xlogrecovery.c.

4525 {
4527  return LocalHotStandbyActive;
4528 }
bool IsPostmasterEnvironment
Definition: globals.c:115
#define AmStartupProcess()
Definition: miscadmin.h:455

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 referenced by checkpoint record"),
651  errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
652  "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
653  "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
655  }
656  }
657  else
658  {
659  ereport(FATAL,
660  (errmsg("could not locate required checkpoint record"),
661  errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
662  "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
663  "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
665  wasShutdown = false; /* keep compiler quiet */
666  }
667 
668  /* Read the tablespace_map file if present and create symlinks. */
669  if (read_tablespace_map(&tablespaces))
670  {
671  ListCell *lc;
672 
673  foreach(lc, tablespaces)
674  {
675  tablespaceinfo *ti = lfirst(lc);
676  char *linkloc;
677 
678  linkloc = psprintf("pg_tblspc/%u", ti->oid);
679 
680  /*
681  * Remove the existing symlink if any and Create the symlink
682  * under PGDATA.
683  */
684  remove_tablespace_symlink(linkloc);
685 
686  if (symlink(ti->path, linkloc) < 0)
687  ereport(ERROR,
689  errmsg("could not create symbolic link \"%s\": %m",
690  linkloc)));
691 
692  pfree(ti->path);
693  pfree(ti);
694  }
695 
696  /* tell the caller to delete it later */
697  haveTblspcMap = true;
698  }
699 
700  /* tell the caller to delete it later */
701  haveBackupLabel = true;
702  }
703  else
704  {
705  /* No backup_label file has been found if we are here. */
706 
707  /*
708  * If tablespace_map file is present without backup_label file, there
709  * is no use of such file. There is no harm in retaining it, but it
710  * is better to get rid of the map file so that we don't have any
711  * redundant file in data directory and it will avoid any sort of
712  * confusion. It seems prudent though to just rename the file out of
713  * the way rather than delete it completely, also we ignore any error
714  * that occurs in rename operation as even if map file is present
715  * without backup_label file, it is harmless.
716  */
717  if (stat(TABLESPACE_MAP, &st) == 0)
718  {
719  unlink(TABLESPACE_MAP_OLD);
721  ereport(LOG,
722  (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
724  errdetail("File \"%s\" was renamed to \"%s\".",
726  else
727  ereport(LOG,
728  (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
730  errdetail("Could not rename file \"%s\" to \"%s\": %m.",
732  }
733 
734  /*
735  * It's possible that archive recovery was requested, but we don't
736  * know how far we need to replay the WAL before we reach consistency.
737  * This can happen for example if a base backup is taken from a
738  * running server using an atomic filesystem snapshot, without calling
739  * pg_backup_start/stop. Or if you just kill a running primary server
740  * and put it into archive recovery by creating a recovery signal
741  * file.
742  *
743  * Our strategy in that case is to perform crash recovery first,
744  * replaying all the WAL present in pg_wal, and only enter archive
745  * recovery after that.
746  *
747  * But usually we already know how far we need to replay the WAL (up
748  * to minRecoveryPoint, up to backupEndPoint, or until we see an
749  * end-of-backup record), and we can enter archive recovery directly.
750  */
756  {
757  InArchiveRecovery = true;
760  }
761 
762  /*
763  * For the same reason as when starting up with backup_label present,
764  * emit a log message when we continue initializing from a base
765  * backup.
766  */
768  ereport(LOG,
769  (errmsg("restarting backup recovery with redo LSN %X/%X",
771 
772  /* Get the last valid checkpoint record. */
778  CheckPointTLI);
779  if (record != NULL)
780  {
781  ereport(DEBUG1,
782  (errmsg_internal("checkpoint record is at %X/%X",
784  }
785  else
786  {
787  /*
788  * We used to attempt to go back to a secondary checkpoint record
789  * here, but only when not in standby mode. We now just fail if we
790  * can't read the last checkpoint because this allows us to
791  * simplify processing around checkpoints.
792  */
793  ereport(PANIC,
794  (errmsg("could not locate a valid checkpoint record")));
795  }
796  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
797  wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
798  }
799 
801  {
803  ereport(LOG,
804  (errmsg("entering standby mode")));
806  ereport(LOG,
807  (errmsg("starting point-in-time recovery to XID %u",
810  ereport(LOG,
811  (errmsg("starting point-in-time recovery to %s",
814  ereport(LOG,
815  (errmsg("starting point-in-time recovery to \"%s\"",
818  ereport(LOG,
819  (errmsg("starting point-in-time recovery to WAL location (LSN) \"%X/%X\"",
822  ereport(LOG,
823  (errmsg("starting point-in-time recovery to earliest consistent point")));
824  else
825  ereport(LOG,
826  (errmsg("starting archive recovery")));
827  }
828 
829  /*
830  * If the location of the checkpoint record is not on the expected
831  * timeline in the history of the requested timeline, we cannot proceed:
832  * the backup is not part of the history of the requested timeline.
833  */
834  Assert(expectedTLEs); /* was initialized by reading checkpoint
835  * record */
838  {
839  XLogRecPtr switchpoint;
840 
841  /*
842  * tliSwitchPoint will throw an error if the checkpoint's timeline is
843  * not in expectedTLEs at all.
844  */
846  ereport(FATAL,
847  (errmsg("requested timeline %u is not a child of this server's history",
849  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.",
852  LSN_FORMAT_ARGS(switchpoint))));
853  }
854 
855  /*
856  * The min recovery point should be part of the requested timeline's
857  * history, too.
858  */
862  ereport(FATAL,
863  (errmsg("requested timeline %u does not contain minimum recovery point %X/%X on timeline %u",
867 
868  ereport(DEBUG1,
869  (errmsg_internal("redo record is at %X/%X; shutdown %s",
870  LSN_FORMAT_ARGS(checkPoint.redo),
871  wasShutdown ? "true" : "false")));
872  ereport(DEBUG1,
873  (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: %u",
874  U64FromFullTransactionId(checkPoint.nextXid),
875  checkPoint.nextOid)));
876  ereport(DEBUG1,
877  (errmsg_internal("next MultiXactId: %u; next MultiXactOffset: %u",
878  checkPoint.nextMulti, checkPoint.nextMultiOffset)));
879  ereport(DEBUG1,
880  (errmsg_internal("oldest unfrozen transaction ID: %u, in database %u",
881  checkPoint.oldestXid, checkPoint.oldestXidDB)));
882  ereport(DEBUG1,
883  (errmsg_internal("oldest MultiXactId: %u, in database %u",
884  checkPoint.oldestMulti, checkPoint.oldestMultiDB)));
885  ereport(DEBUG1,
886  (errmsg_internal("commit timestamp Xid oldest/newest: %u/%u",
887  checkPoint.oldestCommitTsXid,
888  checkPoint.newestCommitTsXid)));
890  ereport(PANIC,
891  (errmsg("invalid next transaction ID")));
892 
893  /* sanity check */
894  if (checkPoint.redo > CheckPointLoc)
895  ereport(PANIC,
896  (errmsg("invalid redo in checkpoint record")));
897 
898  /*
899  * Check whether we need to force recovery from WAL. If it appears to
900  * have been a clean shutdown and we did not have a recovery signal file,
901  * then assume no recovery needed.
902  */
903  if (checkPoint.redo < CheckPointLoc)
904  {
905  if (wasShutdown)
906  ereport(PANIC,
907  (errmsg("invalid redo record in shutdown checkpoint")));
908  InRecovery = true;
909  }
910  else if (ControlFile->state != DB_SHUTDOWNED)
911  InRecovery = true;
912  else if (ArchiveRecoveryRequested)
913  {
914  /* force recovery due to presence of recovery signal file */
915  InRecovery = true;
916  }
917 
918  /*
919  * If recovery is needed, update our in-memory copy of pg_control to show
920  * that we are recovering and to show the selected checkpoint as the place
921  * we are starting from. We also mark pg_control with any minimum recovery
922  * stop point obtained from a backup history file.
923  *
924  * We don't write the changes to disk yet, though. Only do that after
925  * initializing various subsystems.
926  */
927  if (InRecovery)
928  {
929  if (InArchiveRecovery)
930  {
932  }
933  else
934  {
935  ereport(LOG,
936  (errmsg("database system was not properly shut down; "
937  "automatic recovery in progress")));
939  ereport(LOG,
940  (errmsg("crash recovery starts in timeline %u "
941  "and has target timeline %u",
945  }
947  ControlFile->checkPointCopy = checkPoint;
948  if (InArchiveRecovery)
949  {
950  /* initialize minRecoveryPoint if not set yet */
951  if (ControlFile->minRecoveryPoint < checkPoint.redo)
952  {
953  ControlFile->minRecoveryPoint = checkPoint.redo;
955  }
956  }
957 
958  /*
959  * Set backupStartPoint if we're starting recovery from a base backup.
960  *
961  * Also set backupEndPoint and use minRecoveryPoint as the backup end
962  * location if we're starting recovery from a base backup which was
963  * taken from a standby. In this case, the database system status in
964  * pg_control must indicate that the database was already in recovery.
965  * Usually that will be DB_IN_ARCHIVE_RECOVERY but also can be
966  * DB_SHUTDOWNED_IN_RECOVERY if recovery previously was interrupted
967  * before reaching this point; e.g. because restore_command or
968  * primary_conninfo were faulty.
969  *
970  * Any other state indicates that the backup somehow became corrupted
971  * and we can't sensibly continue with recovery.
972  */
973  if (haveBackupLabel)
974  {
975  ControlFile->backupStartPoint = checkPoint.redo;
977 
978  if (backupFromStandby)
979  {
980  if (dbstate_at_startup != DB_IN_ARCHIVE_RECOVERY &&
981  dbstate_at_startup != DB_SHUTDOWNED_IN_RECOVERY)
982  ereport(FATAL,
983  (errmsg("backup_label contains data inconsistent with control file"),
984  errhint("This means that the backup is corrupted and you will "
985  "have to use another backup for recovery.")));
987  }
988  }
989  }
990 
991  /* remember these, so that we know when we have reached consistency */
995  if (InArchiveRecovery)
996  {
999  }
1000  else
1001  {
1003  minRecoveryPointTLI = 0;
1004  }
1005 
1006  /*
1007  * Start recovery assuming that the final record isn't lost.
1008  */
1011 
1012  *wasShutdown_ptr = wasShutdown;
1013  *haveBackupLabel_ptr = haveBackupLabel;
1014  *haveTblspcMap_ptr = haveTblspcMap;
1015 }
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:889
#define UINT64_FORMAT
Definition: c.h:538
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1162
int errcode_for_file_access(void)
Definition: elog.c:883
#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:67
void OwnLatch(Latch *latch)
Definition: latch.c:464
void pfree(void *pointer)
Definition: mcxt.c:1431
void * palloc0(Size size)
Definition: mcxt.c:1232
DBState
Definition: pg_control.h:89
@ DB_IN_ARCHIVE_RECOVERY
Definition: pg_control.h:95
@ DB_SHUTDOWNED_IN_RECOVERY
Definition: pg_control.h:92
@ DB_SHUTDOWNED
Definition: pg_control.h:91
@ DB_IN_CRASH_RECOVERY
Definition: pg_control.h:94
#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:50
MultiXactId oldestMulti
Definition: pg_control.h:49
MultiXactOffset nextMultiOffset
Definition: pg_control.h:46
TransactionId newestCommitTsXid
Definition: pg_control.h:54
TransactionId oldestXid
Definition: pg_control.h:47
Oid nextOid
Definition: pg_control.h:44
MultiXactId nextMulti
Definition: pg_control.h:45
FullTransactionId nextXid
Definition: pg_control.h:43
TransactionId oldestCommitTsXid
Definition: pg_control.h:52
XLogRecPtr redo
Definition: pg_control.h:37
Oid oldestXidDB
Definition: pg_control.h:48
XLogRecPtr backupStartPoint
Definition: pg_control.h:169
bool backupEndRequired
Definition: pg_control.h:171
CheckPoint checkPointCopy
Definition: pg_control.h:134
XLogRecPtr backupEndPoint
Definition: pg_control.h:170
XLogRecPtr minRecoveryPoint
Definition: pg_control.h:167
XLogRecPtr checkPoint
Definition: pg_control.h:132
uint64 system_identifier
Definition: pg_control.h:109
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:168
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:140
static ControlFileData * ControlFile
Definition: xlog.c:581
#define TABLESPACE_MAP_OLD
Definition: xlog.h:302
#define TABLESPACE_MAP
Definition: xlog.h:301
#define BACKUP_LABEL_FILE
Definition: xlog.h:298
XLogPrefetcher * XLogPrefetcherAllocate(XLogReaderState *reader)
void XLogReaderSetDecodeBuffer(XLogReaderState *state, void *buffer, size_t size)
Definition: xlogreader.c:92
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:108
#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:845

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(), 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 1649 of file xlogrecovery.c.

1650 {
1651  XLogRecord *record;
1652  bool reachedRecoveryTarget = false;
1653  TimeLineID replayTLI;
1654 
1655  /*
1656  * Initialize shared variables for tracking progress of WAL replay, as if
1657  * we had just replayed the record before the REDO location (or the
1658  * checkpoint record itself, if it's a shutdown checkpoint).
1659  */
1662  {
1666  }
1667  else
1668  {
1672  }
1679 
1680  /* Also ensure XLogReceiptTime has a sane value */
1682 
1683  /*
1684  * Let postmaster know we've started redo now, so that it can launch the
1685  * archiver if necessary.
1686  */
1687  if (IsUnderPostmaster)
1689 
1690  /*
1691  * Allow read-only connections immediately if we're consistent already.
1692  */
1694 
1695  /*
1696  * Find the first record that logically follows the checkpoint --- it
1697  * might physically precede it, though.
1698  */
1700  {
1701  /* back up to find the record */
1702  replayTLI = RedoStartTLI;
1704  record = ReadRecord(xlogprefetcher, PANIC, false, replayTLI);
1705 
1706  /*
1707  * If a checkpoint record's redo pointer points back to an earlier
1708  * LSN, the record at that LSN should be an XLOG_CHECKPOINT_REDO
1709  * record.
1710  */
1711  if (record->xl_rmid != RM_XLOG_ID ||
1712  (record->xl_info & ~XLR_INFO_MASK) != XLOG_CHECKPOINT_REDO)
1713  ereport(FATAL,
1714  (errmsg("unexpected record type found at redo point %X/%X",
1716  }
1717  else
1718  {
1719  /* just have to read next record after CheckPoint */
1721  replayTLI = CheckPointTLI;
1722  record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1723  }
1724 
1725  if (record != NULL)
1726  {
1727  TimestampTz xtime;
1728  PGRUsage ru0;
1729 
1730  pg_rusage_init(&ru0);
1731 
1732  InRedo = true;
1733 
1734  RmgrStartup();
1735 
1736  ereport(LOG,
1737  (errmsg("redo starts at %X/%X",
1739 
1740  /* Prepare to report progress of the redo phase. */
1741  if (!StandbyMode)
1743 
1744  /*
1745  * main redo apply loop
1746  */
1747  do
1748  {
1749  if (!StandbyMode)
1750  ereport_startup_progress("redo in progress, elapsed time: %ld.%02d s, current LSN: %X/%X",
1752 
1753 #ifdef WAL_DEBUG
1754  if (XLOG_DEBUG)
1755  {
1757 
1758  initStringInfo(&buf);
1759  appendStringInfo(&buf, "REDO @ %X/%X; LSN %X/%X: ",
1762  xlog_outrec(&buf, xlogreader);
1763  appendStringInfoString(&buf, " - ");
1765  elog(LOG, "%s", buf.data);
1766  pfree(buf.data);
1767  }
1768 #endif
1769 
1770  /* Handle interrupt signals of startup process */
1772 
1773  /*
1774  * Pause WAL replay, if requested by a hot-standby session via
1775  * SetRecoveryPause().
1776  *
1777  * Note that we intentionally don't take the info_lck spinlock
1778  * here. We might therefore read a slightly stale value of the
1779  * recoveryPause flag, but it can't be very stale (no worse than
1780  * the last spinlock we did acquire). Since a pause request is a
1781  * pretty asynchronous thing anyway, possibly responding to it one
1782  * WAL record later than we otherwise would is a minor issue, so
1783  * it doesn't seem worth adding another spinlock cycle to prevent
1784  * that.
1785  */
1786  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1788  recoveryPausesHere(false);
1789 
1790  /*
1791  * Have we reached our recovery target?
1792  */
1794  {
1795  reachedRecoveryTarget = true;
1796  break;
1797  }
1798 
1799  /*
1800  * If we've been asked to lag the primary, wait on latch until
1801  * enough time has passed.
1802  */
1804  {
1805  /*
1806  * We test for paused recovery again here. If user sets
1807  * delayed apply, it may be because they expect to pause
1808  * recovery in case of problems, so we must test again here
1809  * otherwise pausing during the delay-wait wouldn't work.
1810  */
1811  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1813  recoveryPausesHere(false);
1814  }
1815 
1816  /*
1817  * Apply the record
1818  */
1819  ApplyWalRecord(xlogreader, record, &replayTLI);
1820 
1821  /* Exit loop if we reached inclusive recovery target */
1823  {
1824  reachedRecoveryTarget = true;
1825  break;
1826  }
1827 
1828  /* Else, try to fetch the next WAL record */
1829  record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1830  } while (record != NULL);
1831 
1832  /*
1833  * end of main redo apply loop
1834  */
1835 
1836  if (reachedRecoveryTarget)
1837  {
1838  if (!reachedConsistency)
1839  ereport(FATAL,
1840  (errmsg("requested recovery stop point is before consistent recovery point")));
1841 
1842  /*
1843  * This is the last point where we can restart recovery with a new
1844  * recovery target, if we shutdown and begin again. After this,
1845  * Resource Managers may choose to do permanent corrective actions
1846  * at end of recovery.
1847  */
1848  switch (recoveryTargetAction)
1849  {
1851 
1852  /*
1853  * exit with special return code to request shutdown of
1854  * postmaster. Log messages issued from postmaster.
1855  */
1856  proc_exit(3);
1857 
1859  SetRecoveryPause(true);
1860  recoveryPausesHere(true);
1861 
1862  /* drop into promote */
1863 
1865  break;
1866  }
1867  }
1868 
1869  RmgrCleanup();
1870 
1871  ereport(LOG,
1872  (errmsg("redo done at %X/%X system usage: %s",
1874  pg_rusage_show(&ru0))));
1875  xtime = GetLatestXTime();
1876  if (xtime)
1877  ereport(LOG,
1878  (errmsg("last completed transaction was at log time %s",
1879  timestamptz_to_str(xtime))));
1880 
1881  InRedo = false;
1882  }
1883  else
1884  {
1885  /* there are no WAL records following the checkpoint */
1886  ereport(LOG,
1887  (errmsg("redo is not required")));
1888  }
1889 
1890  /*
1891  * This check is intentionally after the above log messages that indicate
1892  * how far recovery went.
1893  */
1896  !reachedRecoveryTarget)
1897  ereport(FATAL,
1898  (errmsg("recovery ended before configured recovery target was reached")));
1899 }
void HandleStartupProcInterrupts(void)
Definition: startup.c:155
void begin_startup_progress_phase(void)
Definition: startup.c:339
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1655
void proc_exit(int code)
Definition: ipc.c:104
#define XLOG_CHECKPOINT_REDO
Definition: pg_control.h:81
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:49
void RmgrCleanup(void)
Definition: rmgr.c:65
#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
@ 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, errmsg(), FATAL, GetCurrentTimestamp(), GetLatestXTime(), HandleStartupProcInterrupts(), XLogRecoveryCtlData::info_lck, initStringInfo(), InRedo, InvalidXLogRecPtr, IsUnderPostmaster, XLogRecoveryCtlData::lastReplayedEndRecPtr, XLogRecoveryCtlData::lastReplayedReadRecPtr, XLogRecoveryCtlData::lastReplayedTLI, LOG, LSN_FORMAT_ARGS, PANIC, pfree(), 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(), 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 4765 of file xlogrecovery.c.

4767 {
4768  ereport(ERROR,
4769  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4770  errmsg("multiple recovery targets specified"),
4771  errdetail("At most one of recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time, recovery_target_xid may be set.")));
4772 }

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

◆ PromoteIsTriggered()

bool PromoteIsTriggered ( void  )

Definition at line 4391 of file xlogrecovery.c.

4392 {
4393  /*
4394  * We check shared state each time only until a standby promotion is
4395  * triggered. We can't trigger a promotion again, so there's no need to
4396  * keep checking after the shared variable has once been seen true.
4397  */
4399  return true;
4400 
4404 
4405  return LocalPromoteIsTriggered;
4406 }

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

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

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

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

Referenced by InitWalRecovery().

◆ ReadCheckpointRecord()

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

Definition at line 4046 of file xlogrecovery.c.

4048 {
4049  XLogRecord *record;
4050  uint8 info;
4051 
4052  Assert(xlogreader != NULL);
4053 
4054  if (!XRecOffIsValid(RecPtr))
4055  {
4056  ereport(LOG,
4057  (errmsg("invalid checkpoint location")));
4058  return NULL;
4059  }
4060 
4062  record = ReadRecord(xlogprefetcher, LOG, true, replayTLI);
4063 
4064  if (record == NULL)
4065  {
4066  ereport(LOG,
4067  (errmsg("invalid checkpoint record")));
4068  return NULL;
4069  }
4070  if (record->xl_rmid != RM_XLOG_ID)
4071  {
4072  ereport(LOG,
4073  (errmsg("invalid resource manager ID in checkpoint record")));
4074  return NULL;
4075  }
4076  info = record->xl_info & ~XLR_INFO_MASK;
4077  if (info != XLOG_CHECKPOINT_SHUTDOWN &&
4078  info != XLOG_CHECKPOINT_ONLINE)
4079  {
4080  ereport(LOG,
4081  (errmsg("invalid xl_info in checkpoint record")));
4082  return NULL;
4083  }
4085  {
4086  ereport(LOG,
4087  (errmsg("invalid length of checkpoint record")));
4088  return NULL;
4089  }
4090  return record;
4091 }
#define XLOG_CHECKPOINT_ONLINE
Definition: pg_control.h:68
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 3128 of file xlogrecovery.c.

3130 {
3131  XLogRecord *record;
3134 
3135  /* Pass through parameters to XLogPageRead */
3136  private->fetching_ckpt = fetching_ckpt;
3137  private->emode = emode;
3138  private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
3139  private->replayTLI = replayTLI;
3140 
3141  /* This is the first attempt to read this page. */
3142  lastSourceFailed = false;
3143 
3144  for (;;)
3145  {
3146  char *errormsg;
3147 
3148  record = XLogPrefetcherReadRecord(xlogprefetcher, &errormsg);
3149  if (record == NULL)
3150  {
3151  /*
3152  * When we find that WAL ends in an incomplete record, keep track
3153  * of that record. After recovery is done, we'll write a record
3154  * to indicate to downstream WAL readers that that portion is to
3155  * be ignored.
3156  *
3157  * However, when ArchiveRecoveryRequested = true, we're going to
3158  * switch to a new timeline at the end of recovery. We will only
3159  * copy WAL over to the new timeline up to the end of the last
3160  * complete record, so if we did this, we would later create an
3161  * overwrite contrecord in the wrong place, breaking everything.
3162  */
3163  if (!ArchiveRecoveryRequested &&
3165  {
3168  }
3169 
3170  if (readFile >= 0)
3171  {
3172  close(readFile);
3173  readFile = -1;
3174  }
3175 
3176  /*
3177  * We only end up here without a message when XLogPageRead()
3178  * failed - in that case we already logged something. In
3179  * StandbyMode that only happens if we have been triggered, so we
3180  * shouldn't loop anymore in that case.
3181  */
3182  if (errormsg)
3184  (errmsg_internal("%s", errormsg) /* already translated */ ));
3185  }
3186 
3187  /*
3188  * Check page TLI is one of the expected values.
3189  */
3191  {
3192  char fname[MAXFNAMELEN];
3193  XLogSegNo segno;
3194  int32 offset;
3195 
3199  XLogFileName(fname, xlogreader->seg.ws_tli, segno,
3202  (errmsg("unexpected timeline ID %u in WAL segment %s, LSN %X/%X, offset %u",
3204  fname,
3206  offset)));
3207  record = NULL;
3208  }
3209 
3210  if (record)
3211  {
3212  /* Great, got a record */
3213  return record;
3214  }
3215  else
3216  {
3217  /* No valid record available from this source */
3218  lastSourceFailed = true;
3219 
3220  /*
3221  * If archive recovery was requested, but we were still doing
3222  * crash recovery, switch to archive recovery and retry using the
3223  * offline archive. We have now replayed all the valid WAL in
3224  * pg_wal, so we are presumably now consistent.
3225  *
3226  * We require that there's at least some valid WAL present in
3227  * pg_wal, however (!fetching_ckpt). We could recover using the
3228  * WAL from the archive, even if pg_wal is completely empty, but
3229  * we'd have no idea how far we'd have to replay to reach
3230  * consistency. So err on the safe side and give up.
3231  */
3233  !fetching_ckpt)
3234  {
3235  ereport(DEBUG1,
3236  (errmsg_internal("reached end of WAL in pg_wal, entering archive recovery")));
3237  InArchiveRecovery = true;
3240 
3243  minRecoveryPointTLI = replayTLI;
3244 
3246 
3247  /*
3248  * Before we retry, reset lastSourceFailed and currentSource
3249  * so that we will check the archive next.
3250  */
3251  lastSourceFailed = false;
3253 
3254  continue;
3255  }
3256 
3257  /* In standby mode, loop back to retry. Otherwise, give up. */
3259  continue;
3260  else
3261  return NULL;
3262  }
3263  }
3264 }
signed int int32
Definition: c.h:483
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:6086
#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 1025 of file xlogrecovery.c.

1026 {
1027  struct stat stat_buf;
1028 
1030  return;
1031 
1032  /*
1033  * Check for old recovery API file: recovery.conf
1034  */
1035  if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
1036  ereport(FATAL,
1038  errmsg("using recovery command file \"%s\" is not supported",
1040 
1041  /*
1042  * Remove unused .done file, if present. Ignore if absent.
1043  */
1044  unlink(RECOVERY_COMMAND_DONE);
1045 
1046  /*
1047  * Check for recovery signal files and if found, fsync them since they
1048  * represent server state information. We don't sweat too much about the
1049  * possibility of fsync failure, however.
1050  *
1051  * If present, standby signal file takes precedence. If neither is present
1052  * then we won't enter archive recovery.
1053  */
1054  if (stat(STANDBY_SIGNAL_FILE, &stat_buf) == 0)
1055  {
1056  int fd;
1057 
1059  S_IRUSR | S_IWUSR);
1060  if (fd >= 0)
1061  {
1062  (void) pg_fsync(fd);
1063  close(fd);
1064  }
1066  }
1067  else if (stat(RECOVERY_SIGNAL_FILE, &stat_buf) == 0)
1068  {
1069  int fd;
1070 
1072  S_IRUSR | S_IWUSR);
1073  if (fd >= 0)
1074  {
1075  (void) pg_fsync(fd);
1076  close(fd);
1077  }
1079  }
1080 
1081  StandbyModeRequested = false;
1082  ArchiveRecoveryRequested = false;
1084  {
1085  StandbyModeRequested = true;
1086  ArchiveRecoveryRequested = true;
1087  }
1088  else if (recovery_signal_file_found)
1089  {
1090  StandbyModeRequested = false;
1091  ArchiveRecoveryRequested = true;
1092  }
1093  else
1094  return;
1095 
1096  /*
1097  * We don't support standby mode in standalone backends; that requires
1098  * other processes such as the WAL receiver to be alive.
1099  */
1101  ereport(FATAL,
1102  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1103  errmsg("standby mode is not supported by single-user servers")));
1104 }
#define PG_BINARY
Definition: c.h:1262
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:416
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:297
#define RECOVERY_SIGNAL_FILE
Definition: xlog.h:296
#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 2979 of file xlogrecovery.c.

2980 {
2981  uint8 xact_info;
2982  TimestampTz xtime;
2983  TimestampTz delayUntil;
2984  long msecs;
2985 
2986  /* nothing to do if no delay configured */
2987  if (recovery_min_apply_delay <= 0)
2988  return false;
2989 
2990  /* no delay is applied on a database not yet consistent */
2991  if (!reachedConsistency)
2992  return false;
2993 
2994  /* nothing to do if crash recovery is requested */
2996  return false;
2997 
2998  /*
2999  * Is it a COMMIT record?
3000  *
3001  * We deliberately choose not to delay aborts since they have no effect on
3002  * MVCC. We already allow replay of records that don't have a timestamp,
3003  * so there is already opportunity for issues caused by early conflicts on
3004  * standbys.
3005  */
3006  if (XLogRecGetRmid(record) != RM_XACT_ID)
3007  return false;
3008 
3009  xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
3010 
3011  if (xact_info != XLOG_XACT_COMMIT &&
3012  xact_info != XLOG_XACT_COMMIT_PREPARED)
3013  return false;
3014 
3015  if (!getRecordTimestamp(record, &xtime))
3016  return false;
3017 
3019 
3020  /*
3021  * Exit without arming the latch if it's already past time to apply this
3022  * record
3023  */
3025  if (msecs <= 0)
3026  return false;
3027 
3028  while (true)
3029  {
3031 
3032  /* This might change recovery_min_apply_delay. */
3034 
3035  if (CheckForStandbyTrigger())
3036  break;
3037 
3038  /*
3039  * Recalculate delayUntil as recovery_min_apply_delay could have
3040  * changed while waiting in this loop.
3041  */
3043 
3044  /*
3045  * Wait for difference between GetCurrentTimestamp() and delayUntil.
3046  */
3048  delayUntil);
3049 
3050  if (msecs <= 0)
3051  break;
3052 
3053  elog(DEBUG2, "recovery apply delay %ld milliseconds", msecs);
3054 
3057  msecs,
3058  WAIT_EVENT_RECOVERY_APPLY_DELAY);
3059  }
3060  return true;
3061 }
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1767
#define DEBUG2
Definition: elog.h:29
void ResetLatch(Latch *latch)
Definition: latch.c:725
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:518
#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 2922 of file xlogrecovery.c.

2923 {
2924  /* Don't pause unless users can connect! */
2925  if (!LocalHotStandbyActive)
2926  return;
2927 
2928  /* Don't pause after standby promotion has been triggered */
2930  return;
2931 
2932  if (endOfRecovery)
2933  ereport(LOG,
2934  (errmsg("pausing at the end of recovery"),
2935  errhint("Execute pg_wal_replay_resume() to promote.")));
2936  else
2937  ereport(LOG,
2938  (errmsg("recovery has paused"),
2939  errhint("Execute pg_wal_replay_resume() to continue.")));
2940 
2941  /* loop until recoveryPauseState is set to RECOVERY_NOT_PAUSED */
2943  {
2945  if (CheckForStandbyTrigger())
2946  return;
2947 
2948  /*
2949  * If recovery pause is requested then set it paused. While we are in
2950  * the loop, user might resume and pause again so set this every time.
2951  */
2953 
2954  /*
2955  * We wait on a condition variable that will wake us as soon as the
2956  * pause ends, but we use a timeout so we can check the above exit
2957  * condition periodically too.
2958  */
2960  WAIT_EVENT_RECOVERY_PAUSE);
2961  }
2963 }
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 4656 of file xlogrecovery.c.

4657 {
4658  if (currValue < minValue)
4659  {
4661  {
4662  bool warned_for_promote = false;
4663 
4664  ereport(WARNING,
4665  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4666  errmsg("hot standby is not possible because of insufficient parameter settings"),
4667  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4668  param_name,
4669  currValue,
4670  minValue)));
4671 
4672  SetRecoveryPause(true);
4673 
4674  ereport(LOG,
4675  (errmsg("recovery has paused"),
4676  errdetail("If recovery is unpaused, the server will shut down."),
4677  errhint("You can then restart the server after making the necessary configuration changes.")));
4678 
4680  {
4682 
4683  if (CheckForStandbyTrigger())
4684  {
4685  if (!warned_for_promote)
4686  ereport(WARNING,
4687  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4688  errmsg("promotion is not possible because of insufficient parameter settings"),
4689 
4690  /*
4691  * Repeat the detail from above so it's easy to find
4692  * in the log.
4693  */
4694  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4695  param_name,
4696  currValue,
4697  minValue),
4698  errhint("Restart the server after making the necessary configuration changes.")));
4699  warned_for_promote = true;
4700  }
4701 
4702  /*
4703  * If recovery pause is requested then set it paused. While
4704  * we are in the loop, user might resume and pause again so
4705  * set this every time.
4706  */
4708 
4709  /*
4710  * We wait on a condition variable that will wake us as soon
4711  * as the pause ends, but we use a timeout so we can check the
4712  * above conditions periodically too.
4713  */
4715  WAIT_EVENT_RECOVERY_PAUSE);
4716  }
4718  }
4719 
4720  ereport(FATAL,
4721  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4722  errmsg("recovery aborted because of insufficient parameter settings"),
4723  /* Repeat the detail from above so it's easy to find in the log. */
4724  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4725  param_name,
4726  currValue,
4727  minValue),
4728  errhint("You can restart the server after making the necessary configuration changes.")));
4729  }
4730 }
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 2723 of file xlogrecovery.c.

2724 {
2725  uint8 info;
2726  uint8 xact_info;
2727  uint8 rmid;
2728  TimestampTz recordXtime = 0;
2729 
2730  /*
2731  * Ignore recovery target settings when not in archive recovery (meaning
2732  * we are in crash recovery).
2733  */
2735  return false;
2736 
2737  info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2738  rmid = XLogRecGetRmid(record);
2739 
2740  /*
2741  * There can be many restore points that share the same name; we stop at
2742  * the first one.
2743  */
2745  rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2746  {
2747  xl_restore_point *recordRestorePointData;
2748 
2749  recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
2750 
2751  if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
2752  {
2753  recoveryStopAfter = true;
2756  (void) getRecordTimestamp(record, &recoveryStopTime);
2757  strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN);
2758 
2759  ereport(LOG,
2760  (errmsg("recovery stopping at restore point \"%s\", time %s",
2763  return true;
2764  }
2765  }
2766 
2767  /* Check if the target LSN has been reached */
2770  record->ReadRecPtr >= recoveryTargetLSN)
2771  {
2772  recoveryStopAfter = true;
2774  recoveryStopLSN = record->ReadRecPtr;
2775  recoveryStopTime = 0;
2776  recoveryStopName[0] = '\0';
2777  ereport(LOG,
2778  (errmsg("recovery stopping after WAL location (LSN) \"%X/%X\"",
2780  return true;
2781  }
2782 
2783  if (rmid != RM_XACT_ID)
2784  return false;
2785 
2786  xact_info = info & XLOG_XACT_OPMASK;
2787 
2788  if (xact_info == XLOG_XACT_COMMIT ||
2789  xact_info == XLOG_XACT_COMMIT_PREPARED ||
2790  xact_info == XLOG_XACT_ABORT ||
2791  xact_info == XLOG_XACT_ABORT_PREPARED)
2792  {
2793  TransactionId recordXid;
2794 
2795  /* Update the last applied transaction timestamp */
2796  if (getRecordTimestamp(record, &recordXtime))
2797  SetLatestXTime(recordXtime);
2798 
2799  /* Extract the XID of the committed/aborted transaction */
2800  if (xact_info == XLOG_XACT_COMMIT_PREPARED)
2801  {
2802  xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
2803  xl_xact_parsed_commit parsed;
2804 
2806  xlrec,
2807  &parsed);
2808  recordXid = parsed.twophase_xid;
2809  }
2810  else if (xact_info == XLOG_XACT_ABORT_PREPARED)
2811  {
2812  xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
2813  xl_xact_parsed_abort parsed;
2814 
2816  xlrec,
2817  &parsed);
2818  recordXid = parsed.twophase_xid;
2819  }
2820  else
2821  recordXid = XLogRecGetXid(record);
2822 
2823  /*
2824  * There can be only one transaction end record with this exact
2825  * transactionid
2826  *
2827  * when testing for an xid, we MUST test for equality only, since
2828  * transactions are numbered in the order they start, not the order
2829  * they complete. A higher numbered xid will complete before you about
2830  * 50% of the time...
2831  */
2833  recordXid == recoveryTargetXid)
2834  {
2835  recoveryStopAfter = true;
2836  recoveryStopXid = recordXid;
2837  recoveryStopTime = recordXtime;
2839  recoveryStopName[0] = '\0';
2840 
2841  if (xact_info == XLOG_XACT_COMMIT ||
2842  xact_info == XLOG_XACT_COMMIT_PREPARED)
2843  {
2844  ereport(LOG,
2845  (errmsg("recovery stopping after commit of transaction %u, time %s",
2848  }
2849  else if (xact_info == XLOG_XACT_ABORT ||
2850  xact_info == XLOG_XACT_ABORT_PREPARED)
2851  {
2852  ereport(LOG,
2853  (errmsg("recovery stopping after abort of transaction %u, time %s",
2856  }
2857  return true;
2858  }
2859  }
2860 
2861  /* Check if we should stop as soon as reaching consistency */
2863  {
2864  ereport(LOG,
2865  (errmsg("recovery stopping after reaching consistency")));
2866 
2867  recoveryStopAfter = true;
2869  recoveryStopTime = 0;
2871  recoveryStopName[0] = '\0';
2872  return true;
2873  }
2874 
2875  return false;
2876 }
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 2570 of file xlogrecovery.c.

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

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

4452 {
4453  unlink(PROMOTE_SIGNAL_FILE);
4454 }

References PROMOTE_SIGNAL_FILE.

Referenced by CheckForStandbyTrigger(), and PostmasterMain().

◆ rescanLatestTimeLine()

static bool rescanLatestTimeLine ( TimeLineID  replayTLI,
XLogRecPtr  replayLSN 
)
static

Definition at line 4101 of file xlogrecovery.c.

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

2273 {
2274  XLogReaderState *record = (XLogReaderState *) arg;
2276 
2277  initStringInfo(&buf);
2278  xlog_outdesc(&buf, record);
2279  xlog_block_info(&buf, record);
2280 
2281  /* translator: %s is a WAL record description */
2282  errcontext("WAL redo at %X/%X for %s",
2283  LSN_FORMAT_ARGS(record->ReadRecPtr),
2284  buf.data);
2285 
2286  pfree(buf.data);
2287 }
#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 4409 of file xlogrecovery.c.

4410 {
4414 
4415  /*
4416  * Mark the recovery pause state as 'not paused' because the paused state
4417  * ends and promotion continues if a promotion is triggered while recovery
4418  * is paused. Otherwise pg_get_wal_replay_pause_state() can mistakenly
4419  * return 'paused' while a promotion is ongoing.
4420  */
4421  SetRecoveryPause(false);
4422 
4423  LocalPromoteIsTriggered = true;
4424 }

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

Referenced by CheckForStandbyTrigger().

◆ SetRecoveryPause()

◆ ShutdownWalRecovery()

void ShutdownWalRecovery ( void  )

Definition at line 1605 of file xlogrecovery.c.

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

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

4373 {
4375  {
4376  ereport(LOG,
4377  (errmsg("WAL receiver process shutdown requested")));
4378 
4379  pendingWalRcvRestart = true;
4380  }
4381 }
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 1107 of file xlogrecovery.c.

1108 {
1110  return;
1111 
1112  /*
1113  * Check for compulsory parameters
1114  */
1116  {
1117  if ((PrimaryConnInfo == NULL || strcmp(PrimaryConnInfo, "") == 0) &&
1118  (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0))
1119  ereport(WARNING,
1120  (errmsg("specified neither primary_conninfo nor restore_command"),
1121  errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
1122  }
1123  else
1124  {
1125  if (recoveryRestoreCommand == NULL ||
1126  strcmp(recoveryRestoreCommand, "") == 0)
1127  ereport(FATAL,
1128  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1129  errmsg("must specify restore_command when standby mode is not enabled")));
1130  }
1131 
1132  /*
1133  * Override any inconsistent requests. Note that this is a change of
1134  * behaviour in 9.5; prior to this we simply ignored a request to pause if
1135  * hot_standby = off, which was surprising behaviour.
1136  */
1140 
1141  /*
1142  * Final parsing of recovery_target_time string; see also
1143  * check_recovery_target_time().
1144  */
1146  {
1150  Int32GetDatum(-1)));
1151  }
1152 
1153  /*
1154  * If user specified recovery_target_timeline, validate it or compute the
1155  * "latest" value. We can't do this until after we've gotten the restore
1156  * command and set InArchiveRecovery, because we need to fetch timeline
1157  * history files from the archive.
1158  */
1160  {
1162 
1163  /* Timeline 1 does not have a history file, all else should */
1164  if (rtli != 1 && !existsTimeLineHistory(rtli))
1165  ereport(FATAL,
1166  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1167  errmsg("recovery target timeline %u does not exist",
1168  rtli)));
1169  recoveryTargetTLI = rtli;
1170  }
1172  {
1173  /* We start the "latest" search from pg_control's timeline */
1175  }
1176  else
1177  {
1178  /*
1179  * else we just use the recoveryTargetTLI as already read from
1180  * ControlFile
1181  */
1183  }
1184 }
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:646
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:125
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 2458 of file xlogrecovery.c.

2459 {
2460  RmgrData rmgr = GetRmgr(XLogRecGetRmid(record));
2461  RelFileLocator rlocator;
2462  ForkNumber forknum;
2463  BlockNumber blkno;
2464  int block_id;
2465 
2466  /* Records with no backup blocks have no need for consistency checks. */
2467  if (!XLogRecHasAnyBlockRefs(record))
2468  return;
2469 
2470  Assert((XLogRecGetInfo(record) & XLR_CHECK_CONSISTENCY) != 0);
2471 
2472  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
2473  {
2474  Buffer buf;
2475  Page page;
2476 
2477  if (!XLogRecGetBlockTagExtended(record, block_id,
2478  &rlocator, &forknum, &blkno, NULL))
2479  {
2480  /*
2481  * WAL record doesn't contain a block reference with the given id.
2482  * Do nothing.
2483  */
2484  continue;
2485  }
2486 
2487  Assert(XLogRecHasBlockImage(record, block_id));
2488 
2489  if (XLogRecBlockImageApply(record, block_id))
2490  {
2491  /*
2492  * WAL record has already applied the page, so bypass the
2493  * consistency check as that would result in comparing the full
2494  * page stored in the record with itself.
2495  */
2496  continue;
2497  }
2498 
2499  /*
2500  * Read the contents from the current buffer and store it in a
2501  * temporary page.
2502  */
2503  buf = XLogReadBufferExtended(rlocator, forknum, blkno,
2505  InvalidBuffer);
2506  if (!BufferIsValid(buf))
2507  continue;
2508 
2510  page = BufferGetPage(buf);
2511 
2512  /*
2513  * Take a copy of the local page where WAL has been applied to have a
2514  * comparison base before masking it...
2515  */
2516  memcpy(replay_image_masked, page, BLCKSZ);
2517 
2518  /* No need for this page anymore now that a copy is in. */
2520 
2521  /*
2522  * If the block LSN is already ahead of this WAL record, we can't
2523  * expect contents to match. This can happen if recovery is
2524  * restarted.
2525  */
2526  if (PageGetLSN(replay_image_masked) > record->EndRecPtr)
2527  continue;
2528 
2529  /*
2530  * Read the contents from the backup copy, stored in WAL record and
2531  * store it in a temporary page. There is no need to allocate a new
2532  * page here, a local buffer is fine to hold its contents and a mask
2533  * can be directly applied on it.
2534  */
2535  if (!RestoreBlockImage(record, block_id, primary_image_masked))
2536  ereport(ERROR,
2537  (errcode(ERRCODE_INTERNAL_ERROR),
2538  errmsg_internal("%s", record->errormsg_buf)));
2539 
2540  /*
2541  * If masking function is defined, mask both the primary and replay
2542  * images
2543  */
2544  if (rmgr.rm_mask != NULL)
2545  {
2546  rmgr.rm_mask(replay_image_masked, blkno);
2547  rmgr.rm_mask(primary_image_masked, blkno);
2548  }
2549 
2550  /* Time to compare the primary and replay images. */
2551  if (memcmp(replay_image_masked, primary_image_masked, BLCKSZ) != 0)
2552  {
2553  elog(FATAL,
2554  "inconsistent page found, rel %u/%u/%u, forknum %u, blkno %u",
2555  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
2556  forknum, blkno);
2557  }
2558  }
2559 }
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:4578
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4796
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:159
@ RBM_NORMAL_NO_LOG
Definition: bufmgr.h:50
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:301
Pointer Page
Definition: bufpage.h:78
static XLogRecPtr PageGetLSN(Page page)
Definition: bufpage.h:383
ForkNumber
Definition: relpath.h:48
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:1999
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
Definition: xlogreader.c:2058
#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:474

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

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