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/procarray.h"
#include "storage/spin.h"
#include "utils/datetime.h"
#include "utils/fmgrprotos.h"
#include "utils/guc_hooks.h"
#include "utils/pg_lsn.h"
#include "utils/ps_status.h"
#include "utils/pg_rusage.h"
Include dependency graph for xlogrecovery.c:

Go to the source code of this file.

Data Structures

struct  XLogPageReadPrivate
 
struct  XLogRecoveryCtlData
 

Macros

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

Typedefs

typedef struct XLogPageReadPrivate XLogPageReadPrivate
 
typedef struct XLogRecoveryCtlData XLogRecoveryCtlData
 

Enumerations

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

Functions

static void ApplyWalRecord (XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *replayTLI)
 
static void EnableStandbyMode (void)
 
static void readRecoverySignalFile (void)
 
static void validateRecoveryParameters (void)
 
static bool read_backup_label (XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, bool *backupEndRequired, bool *backupFromStandby)
 
static bool read_tablespace_map (List **tablespaces)
 
static void xlogrecovery_redo (XLogReaderState *record, TimeLineID replayTLI)
 
static void CheckRecoveryConsistency (void)
 
static void rm_redo_error_callback (void *arg)
 
static void xlog_block_info (StringInfo buf, XLogReaderState *record)
 
static void checkTimeLineSwitch (XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI, TimeLineID replayTLI)
 
static bool getRecordTimestamp (XLogReaderState *record, TimestampTz *recordXtime)
 
static void verifyBackupPageConsistency (XLogReaderState *record)
 
static bool recoveryStopsBefore (XLogReaderState *record)
 
static bool recoveryStopsAfter (XLogReaderState *record)
 
static char * getRecoveryStopReason (void)
 
static void recoveryPausesHere (bool endOfRecovery)
 
static bool recoveryApplyDelay (XLogReaderState *record)
 
static void ConfirmRecoveryPaused (void)
 
static XLogRecordReadRecord (XLogPrefetcher *xlogprefetcher, int emode, bool fetching_ckpt, TimeLineID replayTLI)
 
static int XLogPageRead (XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf)
 
static XLogPageReadResult WaitForWALToBecomeAvailable (XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr, TimeLineID replayTLI, XLogRecPtr replayLSN, bool nonblocking)
 
static int emode_for_corrupt_record (int emode, XLogRecPtr RecPtr)
 
static XLogRecordReadCheckpointRecord (XLogPrefetcher *xlogprefetcher, XLogRecPtr RecPtr, TimeLineID replayTLI)
 
static bool rescanLatestTimeLine (TimeLineID replayTLI, XLogRecPtr replayLSN)
 
static int XLogFileRead (XLogSegNo segno, 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 69 of file xlogrecovery.c.

◆ RECOVERY_COMMAND_FILE

#define RECOVERY_COMMAND_FILE   "recovery.conf"

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

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

Function Documentation

◆ ApplyWalRecord()

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

Definition at line 1908 of file xlogrecovery.c.

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

4796 {
4799  error_multiple_recovery_targets();
4800 
4801  if (newval && strcmp(newval, "") != 0)
4803  else
4805 }
#define newval
RecoveryTargetType recoveryTarget
Definition: xlogrecovery.c:85
@ 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 4834 of file xlogrecovery.c.

4835 {
4838  error_multiple_recovery_targets();
4839 
4840  if (newval && strcmp(newval, "") != 0)
4841  {
4843  recoveryTargetLSN = *((XLogRecPtr *) extra);
4844  }
4845  else
4847 }
uint64 XLogRecPtr
Definition: xlogdefs.h:21
XLogRecPtr recoveryTargetLSN
Definition: xlogrecovery.c:92
@ 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 4869 of file xlogrecovery.c.

4870 {
4873  error_multiple_recovery_targets();
4874 
4875  if (newval && strcmp(newval, "") != 0)
4876  {
4879  }
4880  else
4882 }
const char * recoveryTargetName
Definition: xlogrecovery.c:91
@ 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 4949 of file xlogrecovery.c.

4950 {
4953  error_multiple_recovery_targets();
4954 
4955  if (newval && strcmp(newval, "") != 0)
4957  else
4959 }
@ 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 4998 of file xlogrecovery.c.

4999 {
5002  recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
5003  else
5005 }
RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal
Definition: xlogrecovery.c:120
TimeLineID recoveryTargetTLIRequested
Definition: xlogrecovery.c:121
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 5034 of file xlogrecovery.c.

5035 {
5038  error_multiple_recovery_targets();
5039 
5040  if (newval && strcmp(newval, "") != 0)
5041  {
5043  recoveryTargetXid = *((TransactionId *) extra);
5044  }
5045  else
5047 }
uint32 TransactionId
Definition: c.h:652
TransactionId recoveryTargetXid
Definition: xlogrecovery.c:88
@ 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 4740 of file xlogrecovery.c.

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

References newval, ReplicationSlotValidateName(), and WARNING.

◆ check_recovery_target()

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

Definition at line 4781 of file xlogrecovery.c.

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

References GUC_check_errdetail, and newval.

◆ check_recovery_target_lsn()

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

Definition at line 4811 of file xlogrecovery.c.

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

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

◆ check_recovery_target_name()

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

Definition at line 4853 of file xlogrecovery.c.

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

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

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

◆ check_recovery_target_timeline()

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

Definition at line 4965 of file xlogrecovery.c.

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

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

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

◆ CheckForStandbyTrigger()

static bool CheckForStandbyTrigger ( void  )
static

Definition at line 4433 of file xlogrecovery.c.

4434 {
4436  return true;
4437 
4439  {
4440  ereport(LOG, (errmsg("received promote request")));
4444  return true;
4445  }
4446 
4447  return false;
4448 }
bool IsPromoteSignaled(void)
Definition: startup.c:288
void ResetPromoteSignaled(void)
Definition: startup.c:294
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define LOG
Definition: elog.h:31
#define ereport(elevel,...)
Definition: elog.h:149
bool CheckPromoteSignal(void)
static bool LocalPromoteIsTriggered
Definition: xlogrecovery.c:182
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 4463 of file xlogrecovery.c.

4464 {
4465  struct stat stat_buf;
4466 
4467  if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
4468  return true;
4469 
4470  return false;
4471 }
#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 2175 of file xlogrecovery.c.

2176 {
2177  XLogRecPtr lastReplayedEndRecPtr;
2178  TimeLineID lastReplayedTLI;
2179 
2180  /*
2181  * During crash recovery, we don't reach a consistent state until we've
2182  * replayed all the WAL.
2183  */
2185  return;
2186 
2188 
2189  /*
2190  * assume that we are called in the startup process, and hence don't need
2191  * a lock to read lastReplayedEndRecPtr
2192  */
2193  lastReplayedEndRecPtr = XLogRecoveryCtl->lastReplayedEndRecPtr;
2194  lastReplayedTLI = XLogRecoveryCtl->lastReplayedTLI;
2195 
2196  /*
2197  * Have we reached the point where our base backup was completed?
2198  */
2200  backupEndPoint <= lastReplayedEndRecPtr)
2201  {
2202  XLogRecPtr saveBackupStartPoint = backupStartPoint;
2203  XLogRecPtr saveBackupEndPoint = backupEndPoint;
2204 
2205  elog(DEBUG1, "end of backup reached");
2206 
2207  /*
2208  * We have reached the end of base backup, as indicated by pg_control.
2209  * Update the control file accordingly.
2210  */
2211  ReachedEndOfBackup(lastReplayedEndRecPtr, lastReplayedTLI);
2214  backupEndRequired = false;
2215 
2216  ereport(LOG,
2217  (errmsg("completed backup recovery with redo LSN %X/%X and end LSN %X/%X",
2218  LSN_FORMAT_ARGS(saveBackupStartPoint),
2219  LSN_FORMAT_ARGS(saveBackupEndPoint))));
2220  }
2221 
2222  /*
2223  * Have we passed our safe starting point? Note that minRecoveryPoint is
2224  * known to be incorrectly set if recovering from a backup, until the
2225  * XLOG_BACKUP_END arrives to advise us of the correct minRecoveryPoint.
2226  * All we know prior to that is that we're not consistent yet.
2227  */
2229  minRecoveryPoint <= lastReplayedEndRecPtr)
2230  {
2231  /*
2232  * Check to see if the XLOG sequence contained any unresolved
2233  * references to uninitialized pages.
2234  */
2236 
2237  /*
2238  * Check that pg_tblspc doesn't contain any real directories. Replay
2239  * of Database/CREATE_* records may have created fictitious tablespace
2240  * directories that should have been removed by the time consistency
2241  * was reached.
2242  */
2244 
2245  reachedConsistency = true;
2246  ereport(LOG,
2247  (errmsg("consistent recovery state reached at %X/%X",
2248  LSN_FORMAT_ARGS(lastReplayedEndRecPtr))));
2249  }
2250 
2251  /*
2252  * Have we got a valid starting snapshot that will allow queries to be
2253  * run? If so, we can tell postmaster that the database is consistent now,
2254  * enabling connections.
2255  */
2260  {
2264 
2265  LocalHotStandbyActive = true;
2266 
2268  }
2269 }
#define Assert(condition)
Definition: c.h:858
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:224
bool IsUnderPostmaster
Definition: globals.c:117
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:6203
#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:294
static bool backupEndRequired
Definition: xlogrecovery.c:283
static XLogRecPtr minRecoveryPoint
Definition: xlogrecovery.c:278
static XLogRecPtr backupEndPoint
Definition: xlogrecovery.c:282
bool InArchiveRecovery
Definition: xlogrecovery.c:138
static bool LocalHotStandbyActive
Definition: xlogrecovery.c:176
static void CheckTablespaceDirectory(void)
static XLogRecPtr backupStartPoint
Definition: xlogrecovery.c:281
void XLogCheckInvalidPages(void)
Definition: xlogutils.c:245
@ 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 2143 of file xlogrecovery.c.

2144 {
2145  DIR *dir;
2146  struct dirent *de;
2147 
2148  dir = AllocateDir("pg_tblspc");
2149  while ((de = ReadDir(dir, "pg_tblspc")) != NULL)
2150  {
2151  char path[MAXPGPATH + 10];
2152 
2153  /* Skip entries of non-oid names */
2154  if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
2155  continue;
2156 
2157  snprintf(path, sizeof(path), "pg_tblspc/%s", de->d_name);
2158 
2159  if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
2162  errmsg("unexpected directory entry \"%s\" found in %s",
2163  de->d_name, "pg_tblspc/"),
2164  errdetail("All directory entries in pg_tblspc/ should be symbolic links."),
2165  errhint("Remove those directories, or set \"allow_in_place_tablespaces\" to ON transiently to let recovery complete.")));
2166  }
2167 }
bool allow_in_place_tablespaces
Definition: tablespace.c:85
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errhint(const char *fmt,...)
Definition: elog.c:1317
int errcode(int sqlerrcode)
Definition: elog.c:857
#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 2377 of file xlogrecovery.c.

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

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

4031 {
4032  static XLogRecPtr lastComplaint = 0;
4033 
4034  if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
4035  {
4036  if (RecPtr == lastComplaint)
4037  emode = DEBUG1;
4038  else
4039  lastComplaint = RecPtr;
4040  }
4041  return emode;
4042 }
static XLogSource readSource
Definition: xlogrecovery.c:234

References DEBUG1, LOG, readSource, and XLOG_FROM_PG_WAL.

Referenced by ReadRecord(), and XLogPageRead().

◆ EnableStandbyMode()

static void EnableStandbyMode ( void  )
static

Definition at line 478 of file xlogrecovery.c.

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

References disable_startup_progress_timeout(), and StandbyMode.

Referenced by InitWalRecovery(), and ReadRecord().

◆ FinishWalRecovery()

EndOfWalRecoveryInfo* FinishWalRecovery ( void  )

Definition at line 1458 of file xlogrecovery.c.

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

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

Referenced by StartupXLOG().

◆ GetCurrentChunkReplayStartTime()

TimestampTz GetCurrentChunkReplayStartTime ( void  )

Definition at line 4626 of file xlogrecovery.c.

4627 {
4628  TimestampTz xtime;
4629 
4633 
4634  return xtime;
4635 }
TimestampTz currentChunkStartTime
Definition: xlogrecovery.c:356

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

Referenced by GetReplicationApplyDelay().

◆ GetCurrentReplayRecPtr()

XLogRecPtr GetCurrentReplayRecPtr ( TimeLineID replayEndTLI)

Definition at line 4562 of file xlogrecovery.c.

4563 {
4564  XLogRecPtr recptr;
4565  TimeLineID tli;
4566 
4568  recptr = XLogRecoveryCtl->replayEndRecPtr;
4571 
4572  if (replayEndTLI)
4573  *replayEndTLI = tli;
4574  return recptr;
4575 }

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

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

2887 {
2888  char reason[200];
2889 
2891  snprintf(reason, sizeof(reason),
2892  "%s transaction %u",
2893  recoveryStopAfter ? "after" : "before",
2894  recoveryStopXid);
2896  snprintf(reason, sizeof(reason),
2897  "%s %s\n",
2898  recoveryStopAfter ? "after" : "before",
2900  else if (recoveryTarget == RECOVERY_TARGET_LSN)
2901  snprintf(reason, sizeof(reason),
2902  "%s LSN %X/%X\n",
2903  recoveryStopAfter ? "after" : "before",
2906  snprintf(reason, sizeof(reason),
2907  "at restore point \"%s\"",
2910  snprintf(reason, sizeof(reason), "reached consistency");
2911  else
2912  snprintf(reason, sizeof(reason), "no recovery target specified");
2913 
2914  return pstrdup(reason);
2915 }
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1853
char * pstrdup(const char *in)
Definition: mcxt.c:1695
static XLogRecPtr recoveryStopLSN
Definition: xlogrecovery.c:381
static TimestampTz recoveryStopTime
Definition: xlogrecovery.c:380
static char recoveryStopName[MAXFNAMELEN]
Definition: xlogrecovery.c:382
static bool recoveryStopAfter
Definition: xlogrecovery.c:383
static TransactionId recoveryStopXid
Definition: xlogrecovery.c:379

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

4643 {
4644  /*
4645  * This must be executed in the startup process, since we don't export the
4646  * relevant state to shared memory.
4647  */
4648  Assert(InRecovery);
4649 
4650  *rtime = XLogReceiptTime;
4651  *fromStream = (XLogReceiptSource == XLOG_FROM_STREAM);
4652 }
static XLogSource XLogReceiptSource
Definition: xlogrecovery.c:259
static TimestampTz XLogReceiptTime
Definition: xlogrecovery.c:258

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

Referenced by GetStandbyLimitTime().

◆ GetXLogReplayRecPtr()

◆ HotStandbyActive()

bool HotStandbyActive ( void  )

Definition at line 4502 of file xlogrecovery.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ HotStandbyActiveInReplay()

static bool HotStandbyActiveInReplay ( void  )
static

Definition at line 4527 of file xlogrecovery.c.

4528 {
4530  return LocalHotStandbyActive;
4531 }
bool IsPostmasterEnvironment
Definition: globals.c:116
#define AmStartupProcess()
Definition: miscadmin.h:382

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

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

References abortedRecPtr, ArchiveRecoveryRequested, Assert, BACKUP_LABEL_FILE, backupEndPoint, ControlFileData::backupEndPoint, backupEndRequired, ControlFileData::backupEndRequired, backupStartPoint, ControlFileData::backupStartPoint, ControlFileData::checkPoint, ControlFileData::checkPointCopy, CheckPointLoc, CheckPointTLI, ControlFile, DataDir, DB_IN_ARCHIVE_RECOVERY, DB_IN_CRASH_RECOVERY, DB_SHUTDOWNED, DB_SHUTDOWNED_IN_RECOVERY, DEBUG1, durable_rename(), EnableStandbyMode(), ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), errmsg_internal(), ERROR, expectedTLEs, FATAL, InArchiveRecovery, InRecovery, InvalidXLogRecPtr, lfirst, LOG, LSN_FORMAT_ARGS, minRecoveryPoint, ControlFileData::minRecoveryPoint, minRecoveryPointTLI, ControlFileData::minRecoveryPointTLI, missingContrecPtr, CheckPoint::newestCommitTsXid, CheckPoint::nextMulti, CheckPoint::nextMultiOffset, CheckPoint::nextOid, CheckPoint::nextXid, NIL, tablespaceinfo::oid, CheckPoint::oldestCommitTsXid, CheckPoint::oldestMulti, CheckPoint::oldestMultiDB, CheckPoint::oldestXid, CheckPoint::oldestXidDB, OwnLatch(), palloc(), palloc0(), PANIC, tablespaceinfo::path, pfree(), 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 1652 of file xlogrecovery.c.

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

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

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

◆ PromoteIsTriggered()

bool PromoteIsTriggered ( void  )

Definition at line 4394 of file xlogrecovery.c.

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

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

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

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

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

Referenced by InitWalRecovery().

◆ ReadCheckpointRecord()

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

Definition at line 4049 of file xlogrecovery.c.

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

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

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

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

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

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

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

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

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

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

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

4455 {
4456  unlink(PROMOTE_SIGNAL_FILE);
4457 }

References PROMOTE_SIGNAL_FILE.

Referenced by CheckForStandbyTrigger(), and PostmasterMain().

◆ rescanLatestTimeLine()

static bool rescanLatestTimeLine ( TimeLineID  replayTLI,
XLogRecPtr  replayLSN 
)
static

Definition at line 4104 of file xlogrecovery.c.

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

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

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

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

Referenced by CheckForStandbyTrigger().

◆ SetRecoveryPause()

◆ ShutdownWalRecovery()

void ShutdownWalRecovery ( void  )

Definition at line 1608 of file xlogrecovery.c.

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

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

Referenced by StartupXLOG().

◆ StartupRequestWalReceiverRestart()

void StartupRequestWalReceiverRestart ( void  )

Definition at line 4375 of file xlogrecovery.c.

4376 {
4378  {
4379  ereport(LOG,
4380  (errmsg("WAL receiver process shutdown requested")));
4381 
4382  pendingWalRcvRestart = true;
4383  }
4384 }
bool WalRcvRunning(void)
static bool pendingWalRcvRestart
Definition: xlogrecovery.c:248

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

Referenced by StartupRereadConfig().

◆ validateRecoveryParameters()

static void validateRecoveryParameters ( void  )
static

Definition at line 1109 of file xlogrecovery.c.

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

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

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

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

Referenced by ApplyWalRecord().

◆ WaitForWALToBecomeAvailable()

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

Definition at line 3541 of file xlogrecovery.c.

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