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/walreceiver.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/latch.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/spin.h"
#include "utils/builtins.h"
#include "utils/datetime.h"
#include "utils/guc_hooks.h"
#include "utils/pg_lsn.h"
#include "utils/ps_status.h"
#include "utils/pg_rusage.h"
Include dependency graph for xlogrecovery.c:

Go to the source code of this file.

Data Structures

struct  XLogPageReadPrivate
 
struct  XLogRecoveryCtlData
 

Macros

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

Typedefs

typedef struct XLogPageReadPrivate XLogPageReadPrivate
 
typedef struct XLogRecoveryCtlData XLogRecoveryCtlData
 

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ RECOVERY_COMMAND_DONE

#define RECOVERY_COMMAND_DONE   "recovery.done"

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

1833 {
1834  ErrorContextCallback errcallback;
1835  bool switchedTLI = false;
1836 
1837  /* Setup error traceback support for ereport() */
1838  errcallback.callback = rm_redo_error_callback;
1839  errcallback.arg = (void *) xlogreader;
1840  errcallback.previous = error_context_stack;
1841  error_context_stack = &errcallback;
1842 
1843  /*
1844  * ShmemVariableCache->nextXid must be beyond record's xid.
1845  */
1847 
1848  /*
1849  * Before replaying this record, check if this record causes the current
1850  * timeline to change. The record is already considered to be part of the
1851  * new timeline, so we update replayTLI before replaying it. That's
1852  * important so that replayEndTLI, which is recorded as the minimum
1853  * recovery point's TLI if recovery stops after this record, is set
1854  * correctly.
1855  */
1856  if (record->xl_rmid == RM_XLOG_ID)
1857  {
1858  TimeLineID newReplayTLI = *replayTLI;
1859  TimeLineID prevReplayTLI = *replayTLI;
1860  uint8 info = record->xl_info & ~XLR_INFO_MASK;
1861 
1862  if (info == XLOG_CHECKPOINT_SHUTDOWN)
1863  {
1864  CheckPoint checkPoint;
1865 
1866  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
1867  newReplayTLI = checkPoint.ThisTimeLineID;
1868  prevReplayTLI = checkPoint.PrevTimeLineID;
1869  }
1870  else if (info == XLOG_END_OF_RECOVERY)
1871  {
1872  xl_end_of_recovery xlrec;
1873 
1874  memcpy(&xlrec, XLogRecGetData(xlogreader), sizeof(xl_end_of_recovery));
1875  newReplayTLI = xlrec.ThisTimeLineID;
1876  prevReplayTLI = xlrec.PrevTimeLineID;
1877  }
1878 
1879  if (newReplayTLI != *replayTLI)
1880  {
1881  /* Check that it's OK to switch to this TLI */
1883  newReplayTLI, prevReplayTLI, *replayTLI);
1884 
1885  /* Following WAL records should be run with new TLI */
1886  *replayTLI = newReplayTLI;
1887  switchedTLI = true;
1888  }
1889  }
1890 
1891  /*
1892  * Update shared replayEndRecPtr before replaying this record, so that
1893  * XLogFlush will update minRecoveryPoint correctly.
1894  */
1897  XLogRecoveryCtl->replayEndTLI = *replayTLI;
1899 
1900  /*
1901  * If we are attempting to enter Hot Standby mode, process XIDs we see
1902  */
1904  TransactionIdIsValid(record->xl_xid))
1906 
1907  /*
1908  * Some XLOG record types that are related to recovery are processed
1909  * directly here, rather than in xlog_redo()
1910  */
1911  if (record->xl_rmid == RM_XLOG_ID)
1912  xlogrecovery_redo(xlogreader, *replayTLI);
1913 
1914  /* Now apply the WAL record itself */
1915  GetRmgr(record->xl_rmid).rm_redo(xlogreader);
1916 
1917  /*
1918  * After redo, check whether the backup pages associated with the WAL
1919  * record are consistent with the existing pages. This check is done only
1920  * if consistency check is enabled for this record.
1921  */
1922  if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
1924 
1925  /* Pop the error context stack */
1926  error_context_stack = errcallback.previous;
1927 
1928  /*
1929  * Update lastReplayedEndRecPtr after this record has been successfully
1930  * replayed.
1931  */
1935  XLogRecoveryCtl->lastReplayedTLI = *replayTLI;
1937 
1938  /* ------
1939  * Wakeup walsenders:
1940  *
1941  * On the standby, the WAL is flushed first (which will only wake up
1942  * physical walsenders) and then applied, which will only wake up logical
1943  * walsenders.
1944  *
1945  * Indeed, logical walsenders on standby can't decode and send data until
1946  * it's been applied.
1947  *
1948  * Physical walsenders don't need to be woken up during replay unless
1949  * cascading replication is allowed and time line change occurred (so that
1950  * they can notice that they are on a new time line).
1951  *
1952  * That's why the wake up conditions are for:
1953  *
1954  * - physical walsenders in case of new time line and cascade
1955  * replication is allowed
1956  * - logical walsenders in case cascade replication is allowed (could not
1957  * be created otherwise)
1958  * ------
1959  */
1961  WalSndWakeup(switchedTLI, true);
1962 
1963  /*
1964  * If rm_redo called XLogRequestWalReceiverReply, then we wake up the
1965  * receiver so that it notices the updated lastReplayedEndRecPtr and sends
1966  * a reply to the primary.
1967  */
1969  {
1970  doRequestWalReceiverReply = false;
1971  WalRcvForceReply();
1972  }
1973 
1974  /* Allow read-only connections if we're consistent now */
1976 
1977  /* Is this a timeline switch? */
1978  if (switchedTLI)
1979  {
1980  /*
1981  * Before we continue on the new timeline, clean up any (possibly
1982  * bogus) future WAL segments on the old timeline.
1983  */
1985 
1986  /* Reset the prefetcher. */
1988  }
1989 }
unsigned char uint8
Definition: c.h:493
ErrorContextCallback * error_context_stack
Definition: elog.c:95
#define XLOG_CHECKPOINT_SHUTDOWN
Definition: pg_control.h:67
#define XLOG_END_OF_RECOVERY
Definition: pg_control.h:76
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4337
#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:277
void WalRcvForceReply(void)
Definition: walreceiver.c:1353
#define AllowCascadeReplication()
Definition: walreceiver.h:42
void WalSndWakeup(bool physical, bool logical)
Definition: walsender.c:3333
void RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
Definition: xlog.c:3635
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:56
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

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

Referenced by PerformWalRecovery().

◆ assign_recovery_target()

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

Definition at line 4711 of file xlogrecovery.c.

4712 {
4715  error_multiple_recovery_targets();
4716 
4717  if (newval && strcmp(newval, "") != 0)
4719  else
4721 }
#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 4750 of file xlogrecovery.c.

4751 {
4754  error_multiple_recovery_targets();
4755 
4756  if (newval && strcmp(newval, "") != 0)
4757  {
4759  recoveryTargetLSN = *((XLogRecPtr *) extra);
4760  }
4761  else
4763 }
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 4785 of file xlogrecovery.c.

4786 {
4789  error_multiple_recovery_targets();
4790 
4791  if (newval && strcmp(newval, "") != 0)
4792  {
4795  }
4796  else
4798 }
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 4865 of file xlogrecovery.c.

4866 {
4869  error_multiple_recovery_targets();
4870 
4871  if (newval && strcmp(newval, "") != 0)
4873  else
4875 }
@ 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 4914 of file xlogrecovery.c.

4915 {
4918  recoveryTargetTLIRequested = (TimeLineID) strtoul(newval, NULL, 0);
4919  else
4921 }
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 4950 of file xlogrecovery.c.

4951 {
4954  error_multiple_recovery_targets();
4955 
4956  if (newval && strcmp(newval, "") != 0)
4957  {
4959  recoveryTargetXid = *((TransactionId *) extra);
4960  }
4961  else
4963 }
uint32 TransactionId
Definition: c.h:641
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 4656 of file xlogrecovery.c.

4657 {
4658  if (*newval && strcmp(*newval, "") != 0 &&
4660  return false;
4661 
4662  return true;
4663 }
#define WARNING
Definition: elog.h:36
bool ReplicationSlotValidateName(const char *name, int elevel)
Definition: slot.c:199

References newval, ReplicationSlotValidateName(), and WARNING.

◆ check_recovery_target()

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

Definition at line 4697 of file xlogrecovery.c.

4698 {
4699  if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
4700  {
4701  GUC_check_errdetail("The only allowed value is \"immediate\".");
4702  return false;
4703  }
4704  return true;
4705 }
#define GUC_check_errdetail
Definition: guc.h:436

References GUC_check_errdetail, and newval.

◆ check_recovery_target_lsn()

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

Definition at line 4727 of file xlogrecovery.c.

4728 {
4729  if (strcmp(*newval, "") != 0)
4730  {
4731  XLogRecPtr lsn;
4732  XLogRecPtr *myextra;
4733  bool have_error = false;
4734 
4735  lsn = pg_lsn_in_internal(*newval, &have_error);
4736  if (have_error)
4737  return false;
4738 
4739  myextra = (XLogRecPtr *) guc_malloc(ERROR, sizeof(XLogRecPtr));
4740  *myextra = lsn;
4741  *extra = (void *) myextra;
4742  }
4743  return true;
4744 }
#define ERROR
Definition: elog.h:39
void * guc_malloc(int elevel, size_t size)
Definition: guc.c:631
XLogRecPtr pg_lsn_in_internal(const char *str, bool *have_error)
Definition: pg_lsn.c:30

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

◆ check_recovery_target_name()

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

Definition at line 4769 of file xlogrecovery.c.

4770 {
4771  /* Use the value of newval directly */
4772  if (strlen(*newval) >= MAXFNAMELEN)
4773  {
4774  GUC_check_errdetail("%s is too long (maximum %d characters).",
4775  "recovery_target_name", MAXFNAMELEN - 1);
4776  return false;
4777  }
4778  return true;
4779 }
#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 4810 of file xlogrecovery.c.

4811 {
4812  if (strcmp(*newval, "") != 0)
4813  {
4814  /* reject some special values */
4815  if (strcmp(*newval, "now") == 0 ||
4816  strcmp(*newval, "today") == 0 ||
4817  strcmp(*newval, "tomorrow") == 0 ||
4818  strcmp(*newval, "yesterday") == 0)
4819  {
4820  return false;
4821  }
4822 
4823  /*
4824  * parse timestamp value (see also timestamptz_in())
4825  */
4826  {
4827  char *str = *newval;
4828  fsec_t fsec;
4829  struct pg_tm tt,
4830  *tm = &tt;
4831  int tz;
4832  int dtype;
4833  int nf;
4834  int dterr;
4835  char *field[MAXDATEFIELDS];
4836  int ftype[MAXDATEFIELDS];
4837  char workbuf[MAXDATELEN + MAXDATEFIELDS];
4838  DateTimeErrorExtra dtextra;
4840 
4841  dterr = ParseDateTime(str, workbuf, sizeof(workbuf),
4842  field, ftype, MAXDATEFIELDS, &nf);
4843  if (dterr == 0)
4844  dterr = DecodeDateTime(field, ftype, nf,
4845  &dtype, tm, &fsec, &tz, &dtextra);
4846  if (dterr != 0)
4847  return false;
4848  if (dtype != DTK_DATE)
4849  return false;
4850 
4851  if (tm2timestamp(tm, fsec, &tz, &timestamp) != 0)
4852  {
4853  GUC_check_errdetail("timestamp out of range: \"%s\"", str);
4854  return false;
4855  }
4856  }
4857  }
4858  return true;
4859 }
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:756
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, DateTimeErrorExtra *extra)
Definition: datetime.c:980
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:1926
int64 TimestampTz
Definition: timestamp.h:39
int32 fsec_t
Definition: timestamp.h:41
#define MAXDATEFIELDS
Definition: datetime.h:202
#define DTK_DATE
Definition: datetime.h:144
#define MAXDATELEN
Definition: datetime.h:200
static struct pg_tm tm
Definition: localtime.c:104
int64 timestamp
Definition: pgtime.h:35

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

◆ check_recovery_target_timeline()

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

Definition at line 4881 of file xlogrecovery.c.

4882 {
4884  RecoveryTargetTimeLineGoal *myextra;
4885 
4886  if (strcmp(*newval, "current") == 0)
4888  else if (strcmp(*newval, "latest") == 0)
4890  else
4891  {
4893 
4894  errno = 0;
4895  strtoul(*newval, NULL, 0);
4896  if (errno == EINVAL || errno == ERANGE)
4897  {
4898  GUC_check_errdetail("recovery_target_timeline is not a valid number.");
4899  return false;
4900  }
4901  }
4902 
4904  *myextra = rttg;
4905  *extra = (void *) myextra;
4906 
4907  return true;
4908 }
@ 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 4927 of file xlogrecovery.c.

4928 {
4929  if (strcmp(*newval, "") != 0)
4930  {
4931  TransactionId xid;
4932  TransactionId *myextra;
4933 
4934  errno = 0;
4935  xid = (TransactionId) strtou64(*newval, NULL, 0);
4936  if (errno == EINVAL || errno == ERANGE)
4937  return false;
4938 
4939  myextra = (TransactionId *) guc_malloc(ERROR, sizeof(TransactionId));
4940  *myextra = xid;
4941  *extra = (void *) myextra;
4942  }
4943  return true;
4944 }
#define strtou64(str, endptr, base)
Definition: c.h:1308

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

◆ CheckForStandbyTrigger()

static bool CheckForStandbyTrigger ( void  )
static

Definition at line 4349 of file xlogrecovery.c.

4350 {
4352  return true;
4353 
4355  {
4356  ereport(LOG, (errmsg("received promote request")));
4360  return true;
4361  }
4362 
4363  return false;
4364 }
bool IsPromoteSignaled(void)
Definition: startup.c:297
void ResetPromoteSignaled(void)
Definition: startup.c:303
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#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 4379 of file xlogrecovery.c.

4380 {
4381  struct stat stat_buf;
4382 
4383  if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
4384  return true;
4385 
4386  return false;
4387 }
#define stat
Definition: win32_port.h:284
#define PROMOTE_SIGNAL_FILE
Definition: xlog.h:298

References PROMOTE_SIGNAL_FILE, and stat.

Referenced by CheckForStandbyTrigger(), and process_pm_pmsignal().

◆ CheckRecoveryConsistency()

static void CheckRecoveryConsistency ( void  )
static

Definition at line 2099 of file xlogrecovery.c.

2100 {
2101  XLogRecPtr lastReplayedEndRecPtr;
2102  TimeLineID lastReplayedTLI;
2103 
2104  /*
2105  * During crash recovery, we don't reach a consistent state until we've
2106  * replayed all the WAL.
2107  */
2109  return;
2110 
2112 
2113  /*
2114  * assume that we are called in the startup process, and hence don't need
2115  * a lock to read lastReplayedEndRecPtr
2116  */
2117  lastReplayedEndRecPtr = XLogRecoveryCtl->lastReplayedEndRecPtr;
2118  lastReplayedTLI = XLogRecoveryCtl->lastReplayedTLI;
2119 
2120  /*
2121  * Have we reached the point where our base backup was completed?
2122  */
2124  backupEndPoint <= lastReplayedEndRecPtr)
2125  {
2126  elog(DEBUG1, "end of backup reached");
2127 
2128  /*
2129  * We have reached the end of base backup, as indicated by pg_control.
2130  * Update the control file accordingly.
2131  */
2132  ReachedEndOfBackup(lastReplayedEndRecPtr, lastReplayedTLI);
2135  backupEndRequired = false;
2136  }
2137 
2138  /*
2139  * Have we passed our safe starting point? Note that minRecoveryPoint is
2140  * known to be incorrectly set if recovering from a backup, until the
2141  * XLOG_BACKUP_END arrives to advise us of the correct minRecoveryPoint.
2142  * All we know prior to that is that we're not consistent yet.
2143  */
2145  minRecoveryPoint <= lastReplayedEndRecPtr)
2146  {
2147  /*
2148  * Check to see if the XLOG sequence contained any unresolved
2149  * references to uninitialized pages.
2150  */
2152 
2153  /*
2154  * Check that pg_tblspc doesn't contain any real directories. Replay
2155  * of Database/CREATE_* records may have created fictitious tablespace
2156  * directories that should have been removed by the time consistency
2157  * was reached.
2158  */
2160 
2161  reachedConsistency = true;
2162  ereport(LOG,
2163  (errmsg("consistent recovery state reached at %X/%X",
2164  LSN_FORMAT_ARGS(lastReplayedEndRecPtr))));
2165  }
2166 
2167  /*
2168  * Have we got a valid starting snapshot that will allow queries to be
2169  * run? If so, we can tell postmaster that the database is consistent now,
2170  * enabling connections.
2171  */
2176  {
2180 
2181  LocalHotStandbyActive = true;
2182 
2184  }
2185 }
#define DEBUG1
Definition: elog.h:30
bool IsUnderPostmaster
Definition: globals.c:113
Assert(fmt[strlen(fmt) - 1] !='\n')
void SendPostmasterSignal(PMSignalReason reason)
Definition: pmsignal.c:181
@ PMSIGNAL_BEGIN_HOT_STANDBY
Definition: pmsignal.h:36
void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli)
Definition: xlog.c:5861
#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:248
@ STANDBY_SNAPSHOT_READY
Definition: xlogutils.h:52

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

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

◆ CheckTablespaceDirectory()

static void CheckTablespaceDirectory ( void  )
static

Definition at line 2067 of file xlogrecovery.c.

2068 {
2069  DIR *dir;
2070  struct dirent *de;
2071 
2072  dir = AllocateDir("pg_tblspc");
2073  while ((de = ReadDir(dir, "pg_tblspc")) != NULL)
2074  {
2075  char path[MAXPGPATH + 10];
2076 
2077  /* Skip entries of non-oid names */
2078  if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
2079  continue;
2080 
2081  snprintf(path, sizeof(path), "pg_tblspc/%s", de->d_name);
2082 
2083  if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
2086  errmsg("unexpected directory entry \"%s\" found in %s",
2087  de->d_name, "pg_tblspc/"),
2088  errdetail("All directory entries in pg_tblspc/ should be symbolic links."),
2089  errhint("Remove those directories, or set allow_in_place_tablespaces to ON transiently to let recovery complete.")));
2090  }
2091 }
bool allow_in_place_tablespaces
Definition: tablespace.c:91
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errhint(const char *fmt,...)
Definition: elog.c:1316
int errcode(int sqlerrcode)
Definition: elog.c:858
#define PANIC
Definition: elog.h:42
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2854
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2788
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 2293 of file xlogrecovery.c.

2295 {
2296  /* Check that the record agrees on what the current (old) timeline is */
2297  if (prevTLI != replayTLI)
2298  ereport(PANIC,
2299  (errmsg("unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record",
2300  prevTLI, replayTLI)));
2301 
2302  /*
2303  * The new timeline better be in the list of timelines we expect to see,
2304  * according to the timeline history. It should also not decrease.
2305  */
2306  if (newTLI < replayTLI || !tliInHistory(newTLI, expectedTLEs))
2307  ereport(PANIC,
2308  (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
2309  newTLI, replayTLI)));
2310 
2311  /*
2312  * If we have not yet reached min recovery point, and we're about to
2313  * switch to a timeline greater than the timeline of the min recovery
2314  * point: trouble. After switching to the new timeline, we could not
2315  * possibly visit the min recovery point on the correct timeline anymore.
2316  * This can happen if there is a newer timeline in the archive that
2317  * branched before the timeline the min recovery point is on, and you
2318  * attempt to do PITR to the new timeline.
2319  */
2321  lsn < minRecoveryPoint &&
2322  newTLI > minRecoveryPointTLI)
2323  ereport(PANIC,
2324  (errmsg("unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%X on timeline %u",
2325  newTLI,
2328 
2329  /* Looks good */
2330 }
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 3946 of file xlogrecovery.c.

3947 {
3948  static XLogRecPtr lastComplaint = 0;
3949 
3950  if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
3951  {
3952  if (RecPtr == lastComplaint)
3953  emode = DEBUG1;
3954  else
3955  lastComplaint = RecPtr;
3956  }
3957  return emode;
3958 }
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:318
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 1406 of file xlogrecovery.c.

1407 {
1409  XLogRecPtr lastRec;
1410  TimeLineID lastRecTLI;
1411  XLogRecPtr endOfLog;
1412 
1413  /*
1414  * Kill WAL receiver, if it's still running, before we continue to write
1415  * the startup checkpoint and aborted-contrecord records. It will trump
1416  * over these records and subsequent ones if it's still alive when we
1417  * start writing WAL.
1418  */
1420 
1421  /*
1422  * We are now done reading the xlog from stream. Turn off streaming
1423  * recovery to force fetching the files (which would be required at end of
1424  * recovery, e.g., timeline history file) from archive or pg_wal.
1425  *
1426  * Note that standby mode must be turned off after killing WAL receiver,
1427  * i.e., calling XLogShutdownWalRcv().
1428  */
1429  Assert(!WalRcvStreaming());
1430  StandbyMode = false;
1431 
1432  /*
1433  * Determine where to start writing WAL next.
1434  *
1435  * Re-fetch the last valid or last applied record, so we can identify the
1436  * exact endpoint of what we consider the valid portion of WAL. There may
1437  * be an incomplete continuation record after that, in which case
1438  * 'abortedRecPtr' and 'missingContrecPtr' are set and the caller will
1439  * write a special OVERWRITE_CONTRECORD message to mark that the rest of
1440  * it is intentionally missing. See CreateOverwriteContrecordRecord().
1441  *
1442  * An important side-effect of this is to load the last page into
1443  * xlogreader. The caller uses it to initialize the WAL for writing.
1444  */
1445  if (!InRecovery)
1446  {
1447  lastRec = CheckPointLoc;
1448  lastRecTLI = CheckPointTLI;
1449  }
1450  else
1451  {
1453  lastRecTLI = XLogRecoveryCtl->lastReplayedTLI;
1454  }
1456  (void) ReadRecord(xlogprefetcher, PANIC, false, lastRecTLI);
1457  endOfLog = xlogreader->EndRecPtr;
1458 
1459  /*
1460  * Remember the TLI in the filename of the XLOG segment containing the
1461  * end-of-log. It could be different from the timeline that endOfLog
1462  * nominally belongs to, if there was a timeline switch in that segment,
1463  * and we were reading the old WAL from a segment belonging to a higher
1464  * timeline.
1465  */
1466  result->endOfLogTLI = xlogreader->seg.ws_tli;
1467 
1469  {
1470  /*
1471  * We are no longer in archive recovery state.
1472  *
1473  * We are now done reading the old WAL. Turn off archive fetching if
1474  * it was active.
1475  */
1477  InArchiveRecovery = false;
1478 
1479  /*
1480  * If the ending log segment is still open, close it (to avoid
1481  * problems on Windows with trying to rename or delete an open file).
1482  */
1483  if (readFile >= 0)
1484  {
1485  close(readFile);
1486  readFile = -1;
1487  }
1488  }
1489 
1490  /*
1491  * Copy the last partial block to the caller, for initializing the WAL
1492  * buffer for appending new WAL.
1493  */
1494  if (endOfLog % XLOG_BLCKSZ != 0)
1495  {
1496  char *page;
1497  int len;
1498  XLogRecPtr pageBeginPtr;
1499 
1500  pageBeginPtr = endOfLog - (endOfLog % XLOG_BLCKSZ);
1501  Assert(readOff == XLogSegmentOffset(pageBeginPtr, wal_segment_size));
1502 
1503  /* Copy the valid part of the last block */
1504  len = endOfLog % XLOG_BLCKSZ;
1505  page = palloc(len);
1506  memcpy(page, xlogreader->readBuf, len);
1507 
1508  result->lastPageBeginPtr = pageBeginPtr;
1509  result->lastPage = page;
1510  }
1511  else
1512  {
1513  /* There is no partial block to copy. */
1514  result->lastPageBeginPtr = endOfLog;
1515  result->lastPage = NULL;
1516  }
1517 
1518  /*
1519  * Create a comment for the history file to explain why and where timeline
1520  * changed.
1521  */
1523 
1524  result->lastRec = lastRec;
1525  result->lastRecTLI = lastRecTLI;
1526  result->endOfLog = endOfLog;
1527 
1528  result->abortedRecPtr = abortedRecPtr;
1530 
1533 
1534  return result;
1535 }
#define close(a)
Definition: win32.h:12
void * palloc(Size size)
Definition: mcxt.c:1226
const void size_t len
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:146
void XLogShutdownWalRcv(void)
Definition: xlog.c:8963
#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:53

References abortedRecPtr, EndOfWalRecoveryInfo::abortedRecPtr, ArchiveRecoveryRequested, Assert(), CheckPointLoc, CheckPointTLI, close, EndOfWalRecoveryInfo::endOfLog, EndOfWalRecoveryInfo::endOfLogTLI, XLogReaderState::EndRecPtr, getRecoveryStopReason(), InArchiveRecovery, InRecovery, EndOfWalRecoveryInfo::lastPage, EndOfWalRecoveryInfo::lastPageBeginPtr, EndOfWalRecoveryInfo::lastRec, EndOfWalRecoveryInfo::lastRecTLI, XLogRecoveryCtlData::lastReplayedReadRecPtr, XLogRecoveryCtlData::lastReplayedTLI, len, missingContrecPtr, EndOfWalRecoveryInfo::missingContrecPtr, palloc(), PANIC, XLogReaderState::readBuf, readFile, readOff, ReadRecord(), recovery_signal_file_found, EndOfWalRecoveryInfo::recovery_signal_file_found, EndOfWalRecoveryInfo::recoveryStopReason, XLogReaderState::seg, 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 4542 of file xlogrecovery.c.

4543 {
4544  TimestampTz xtime;
4545 
4549 
4550  return xtime;
4551 }
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 4478 of file xlogrecovery.c.

4479 {
4480  XLogRecPtr recptr;
4481  TimeLineID tli;
4482 
4484  recptr = XLogRecoveryCtl->replayEndRecPtr;
4487 
4488  if (replayEndTLI)
4489  *replayEndTLI = tli;
4490  return recptr;
4491 }

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

2343 {
2344  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2345  uint8 xact_info = info & XLOG_XACT_OPMASK;
2346  uint8 rmid = XLogRecGetRmid(record);
2347 
2348  if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2349  {
2350  *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
2351  return true;
2352  }
2353  if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
2354  xact_info == XLOG_XACT_COMMIT_PREPARED))
2355  {
2356  *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
2357  return true;
2358  }
2359  if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
2360  xact_info == XLOG_XACT_ABORT_PREPARED))
2361  {
2362  *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
2363  return true;
2364  }
2365  return false;
2366 }
#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 2802 of file xlogrecovery.c.

2803 {
2804  char reason[200];
2805 
2807  snprintf(reason, sizeof(reason),
2808  "%s transaction %u",
2809  recoveryStopAfter ? "after" : "before",
2810  recoveryStopXid);
2812  snprintf(reason, sizeof(reason),
2813  "%s %s\n",
2814  recoveryStopAfter ? "after" : "before",
2816  else if (recoveryTarget == RECOVERY_TARGET_LSN)
2817  snprintf(reason, sizeof(reason),
2818  "%s LSN %X/%X\n",
2819  recoveryStopAfter ? "after" : "before",
2822  snprintf(reason, sizeof(reason),
2823  "at restore point \"%s\"",
2826  snprintf(reason, sizeof(reason), "reached consistency");
2827  else
2828  snprintf(reason, sizeof(reason), "no recovery target specified");
2829 
2830  return pstrdup(reason);
2831 }
const char * timestamptz_to_str(TimestampTz t)
Definition: timestamp.c:1782
char * pstrdup(const char *in)
Definition: mcxt.c:1644
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 4558 of file xlogrecovery.c.

4559 {
4560  /*
4561  * This must be executed in the startup process, since we don't export the
4562  * relevant state to shared memory.
4563  */
4564  Assert(InRecovery);
4565 
4566  *rtime = XLogReceiptTime;
4567  *fromStream = (XLogReceiptSource == XLOG_FROM_STREAM);
4568 }
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 4418 of file xlogrecovery.c.

4419 {
4420  /*
4421  * We check shared state each time only until Hot Standby is active. We
4422  * can't de-activate Hot Standby, so there's no need to keep checking
4423  * after the shared variable has once been seen true.
4424  */
4426  return true;
4427  else
4428  {
4429  /* spinlock is essential on machines with weak memory ordering! */
4433 
4434  return LocalHotStandbyActive;
4435  }
4436 }

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

Referenced by XLogWalRcvSendHSFeedback().

◆ HotStandbyActiveInReplay()

static bool HotStandbyActiveInReplay ( void  )
static

Definition at line 4443 of file xlogrecovery.c.

4444 {
4446  return LocalHotStandbyActive;
4447 }
bool IsPostmasterEnvironment
Definition: globals.c:112
#define AmStartupProcess()
Definition: miscadmin.h:452

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 
544  {
546  ereport(LOG,
547  (errmsg("entering standby mode")));
549  ereport(LOG,
550  (errmsg("starting point-in-time recovery to XID %u",
553  ereport(LOG,
554  (errmsg("starting point-in-time recovery to %s",
557  ereport(LOG,
558  (errmsg("starting point-in-time recovery to \"%s\"",
561  ereport(LOG,
562  (errmsg("starting point-in-time recovery to WAL location (LSN) \"%X/%X\"",
565  ereport(LOG,
566  (errmsg("starting point-in-time recovery to earliest consistent point")));
567  else
568  ereport(LOG,
569  (errmsg("starting archive recovery")));
570  }
571 
572  /*
573  * Take ownership of the wakeup latch if we're going to sleep during
574  * recovery.
575  */
578 
579  private = palloc0(sizeof(XLogPageReadPrivate));
580  xlogreader =
582  XL_ROUTINE(.page_read = &XLogPageRead,
583  .segment_open = NULL,
584  .segment_close = wal_segment_close),
585  private);
586  if (!xlogreader)
587  ereport(ERROR,
588  (errcode(ERRCODE_OUT_OF_MEMORY),
589  errmsg("out of memory"),
590  errdetail("Failed while allocating a WAL reading processor.")));
592 
593  /*
594  * Set the WAL decode buffer size. This limits how far ahead we can read
595  * in the WAL.
596  */
598 
599  /* Create a WAL prefetcher. */
601 
602  /*
603  * Allocate two page buffers dedicated to WAL consistency checks. We do
604  * it this way, rather than just making static arrays, for two reasons:
605  * (1) no need to waste the storage in most instantiations of the backend;
606  * (2) a static char array isn't guaranteed to have any particular
607  * alignment, whereas palloc() will provide MAXALIGN'd storage.
608  */
609  replay_image_masked = (char *) palloc(BLCKSZ);
610  primary_image_masked = (char *) palloc(BLCKSZ);
611 
613  &backupFromStandby))
614  {
615  List *tablespaces = NIL;
616 
617  /*
618  * Archive recovery was requested, and thanks to the backup label
619  * file, we know how far we need to replay to reach consistency. Enter
620  * archive recovery directly.
621  */
622  InArchiveRecovery = true;
625 
626  /*
627  * When a backup_label file is present, we want to roll forward from
628  * the checkpoint it identifies, rather than using pg_control.
629  */
631  CheckPointTLI);
632  if (record != NULL)
633  {
634  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
635  wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
636  ereport(DEBUG1,
637  (errmsg_internal("checkpoint record is at %X/%X",
639  InRecovery = true; /* force recovery even if SHUTDOWNED */
640 
641  /*
642  * Make sure that REDO location exists. This may not be the case
643  * if there was a crash during an online backup, which left a
644  * backup_label around that references a WAL segment that's
645  * already been archived.
646  */
647  if (checkPoint.redo < CheckPointLoc)
648  {
650  if (!ReadRecord(xlogprefetcher, LOG, false,
651  checkPoint.ThisTimeLineID))
652  ereport(FATAL,
653  (errmsg("could not find redo location referenced by checkpoint record"),
654  errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" and add required recovery options.\n"
655  "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
656  "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
657  DataDir, DataDir, DataDir)));
658  }
659  }
660  else
661  {
662  ereport(FATAL,
663  (errmsg("could not locate required checkpoint record"),
664  errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" and add required recovery options.\n"
665  "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
666  "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
667  DataDir, DataDir, DataDir)));
668  wasShutdown = false; /* keep compiler quiet */
669  }
670 
671  /* Read the tablespace_map file if present and create symlinks. */
672  if (read_tablespace_map(&tablespaces))
673  {
674  ListCell *lc;
675 
676  foreach(lc, tablespaces)
677  {
678  tablespaceinfo *ti = lfirst(lc);
679  char *linkloc;
680 
681  linkloc = psprintf("pg_tblspc/%s", ti->oid);
682 
683  /*
684  * Remove the existing symlink if any and Create the symlink
685  * under PGDATA.
686  */
687  remove_tablespace_symlink(linkloc);
688 
689  if (symlink(ti->path, linkloc) < 0)
690  ereport(ERROR,
692  errmsg("could not create symbolic link \"%s\": %m",
693  linkloc)));
694 
695  pfree(ti->oid);
696  pfree(ti->path);
697  pfree(ti);
698  }
699 
700  /* tell the caller to delete it later */
701  haveTblspcMap = true;
702  }
703 
704  /* tell the caller to delete it later */
705  haveBackupLabel = true;
706  }
707  else
708  {
709  /*
710  * If tablespace_map file is present without backup_label file, there
711  * is no use of such file. There is no harm in retaining it, but it
712  * is better to get rid of the map file so that we don't have any
713  * redundant file in data directory and it will avoid any sort of
714  * confusion. It seems prudent though to just rename the file out of
715  * the way rather than delete it completely, also we ignore any error
716  * that occurs in rename operation as even if map file is present
717  * without backup_label file, it is harmless.
718  */
719  if (stat(TABLESPACE_MAP, &st) == 0)
720  {
721  unlink(TABLESPACE_MAP_OLD);
723  ereport(LOG,
724  (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
726  errdetail("File \"%s\" was renamed to \"%s\".",
728  else
729  ereport(LOG,
730  (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
732  errdetail("Could not rename file \"%s\" to \"%s\": %m.",
734  }
735 
736  /*
737  * It's possible that archive recovery was requested, but we don't
738  * know how far we need to replay the WAL before we reach consistency.
739  * This can happen for example if a base backup is taken from a
740  * running server using an atomic filesystem snapshot, without calling
741  * pg_backup_start/stop. Or if you just kill a running primary server
742  * and put it into archive recovery by creating a recovery signal
743  * file.
744  *
745  * Our strategy in that case is to perform crash recovery first,
746  * replaying all the WAL present in pg_wal, and only enter archive
747  * recovery after that.
748  *
749  * But usually we already know how far we need to replay the WAL (up
750  * to minRecoveryPoint, up to backupEndPoint, or until we see an
751  * end-of-backup record), and we can enter archive recovery directly.
752  */
758  {
759  InArchiveRecovery = true;
762  }
763 
764  /* Get the last valid checkpoint record. */
770  CheckPointTLI);
771  if (record != NULL)
772  {
773  ereport(DEBUG1,
774  (errmsg_internal("checkpoint record is at %X/%X",
776  }
777  else
778  {
779  /*
780  * We used to attempt to go back to a secondary checkpoint record
781  * here, but only when not in standby mode. We now just fail if we
782  * can't read the last checkpoint because this allows us to
783  * simplify processing around checkpoints.
784  */
785  ereport(PANIC,
786  (errmsg("could not locate a valid checkpoint record")));
787  }
788  memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
789  wasShutdown = ((record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN);
790  }
791 
792  /*
793  * If the location of the checkpoint record is not on the expected
794  * timeline in the history of the requested timeline, we cannot proceed:
795  * the backup is not part of the history of the requested timeline.
796  */
797  Assert(expectedTLEs); /* was initialized by reading checkpoint
798  * record */
801  {
802  XLogRecPtr switchpoint;
803 
804  /*
805  * tliSwitchPoint will throw an error if the checkpoint's timeline is
806  * not in expectedTLEs at all.
807  */
809  ereport(FATAL,
810  (errmsg("requested timeline %u is not a child of this server's history",
812  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.",
815  LSN_FORMAT_ARGS(switchpoint))));
816  }
817 
818  /*
819  * The min recovery point should be part of the requested timeline's
820  * history, too.
821  */
825  ereport(FATAL,
826  (errmsg("requested timeline %u does not contain minimum recovery point %X/%X on timeline %u",
830 
831  ereport(DEBUG1,
832  (errmsg_internal("redo record is at %X/%X; shutdown %s",
833  LSN_FORMAT_ARGS(checkPoint.redo),
834  wasShutdown ? "true" : "false")));
835  ereport(DEBUG1,
836  (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: %u",
837  U64FromFullTransactionId(checkPoint.nextXid),
838  checkPoint.nextOid)));
839  ereport(DEBUG1,
840  (errmsg_internal("next MultiXactId: %u; next MultiXactOffset: %u",
841  checkPoint.nextMulti, checkPoint.nextMultiOffset)));
842  ereport(DEBUG1,
843  (errmsg_internal("oldest unfrozen transaction ID: %u, in database %u",
844  checkPoint.oldestXid, checkPoint.oldestXidDB)));
845  ereport(DEBUG1,
846  (errmsg_internal("oldest MultiXactId: %u, in database %u",
847  checkPoint.oldestMulti, checkPoint.oldestMultiDB)));
848  ereport(DEBUG1,
849  (errmsg_internal("commit timestamp Xid oldest/newest: %u/%u",
850  checkPoint.oldestCommitTsXid,
851  checkPoint.newestCommitTsXid)));
853  ereport(PANIC,
854  (errmsg("invalid next transaction ID")));
855 
856  /* sanity check */
857  if (checkPoint.redo > CheckPointLoc)
858  ereport(PANIC,
859  (errmsg("invalid redo in checkpoint record")));
860 
861  /*
862  * Check whether we need to force recovery from WAL. If it appears to
863  * have been a clean shutdown and we did not have a recovery signal file,
864  * then assume no recovery needed.
865  */
866  if (checkPoint.redo < CheckPointLoc)
867  {
868  if (wasShutdown)
869  ereport(PANIC,
870  (errmsg("invalid redo record in shutdown checkpoint")));
871  InRecovery = true;
872  }
873  else if (ControlFile->state != DB_SHUTDOWNED)
874  InRecovery = true;
875  else if (ArchiveRecoveryRequested)
876  {
877  /* force recovery due to presence of recovery signal file */
878  InRecovery = true;
879  }
880 
881  /*
882  * If recovery is needed, update our in-memory copy of pg_control to show
883  * that we are recovering and to show the selected checkpoint as the place
884  * we are starting from. We also mark pg_control with any minimum recovery
885  * stop point obtained from a backup history file.
886  *
887  * We don't write the changes to disk yet, though. Only do that after
888  * initializing various subsystems.
889  */
890  if (InRecovery)
891  {
892  if (InArchiveRecovery)
893  {
895  }
896  else
897  {
898  ereport(LOG,
899  (errmsg("database system was not properly shut down; "
900  "automatic recovery in progress")));
902  ereport(LOG,
903  (errmsg("crash recovery starts in timeline %u "
904  "and has target timeline %u",
908  }
910  ControlFile->checkPointCopy = checkPoint;
911  if (InArchiveRecovery)
912  {
913  /* initialize minRecoveryPoint if not set yet */
914  if (ControlFile->minRecoveryPoint < checkPoint.redo)
915  {
916  ControlFile->minRecoveryPoint = checkPoint.redo;
918  }
919  }
920 
921  /*
922  * Set backupStartPoint if we're starting recovery from a base backup.
923  *
924  * Also set backupEndPoint and use minRecoveryPoint as the backup end
925  * location if we're starting recovery from a base backup which was
926  * taken from a standby. In this case, the database system status in
927  * pg_control must indicate that the database was already in recovery.
928  * Usually that will be DB_IN_ARCHIVE_RECOVERY but also can be
929  * DB_SHUTDOWNED_IN_RECOVERY if recovery previously was interrupted
930  * before reaching this point; e.g. because restore_command or
931  * primary_conninfo were faulty.
932  *
933  * Any other state indicates that the backup somehow became corrupted
934  * and we can't sensibly continue with recovery.
935  */
936  if (haveBackupLabel)
937  {
938  ControlFile->backupStartPoint = checkPoint.redo;
940 
941  if (backupFromStandby)
942  {
943  if (dbstate_at_startup != DB_IN_ARCHIVE_RECOVERY &&
944  dbstate_at_startup != DB_SHUTDOWNED_IN_RECOVERY)
945  ereport(FATAL,
946  (errmsg("backup_label contains data inconsistent with control file"),
947  errhint("This means that the backup is corrupted and you will "
948  "have to use another backup for recovery.")));
950  }
951  }
952  }
953 
954  /* remember these, so that we know when we have reached consistency */
958  if (InArchiveRecovery)
959  {
962  }
963  else
964  {
967  }
968 
969  /*
970  * Start recovery assuming that the final record isn't lost.
971  */
974 
975  *wasShutdown_ptr = wasShutdown;
976  *haveBackupLabel_ptr = haveBackupLabel;
977  *haveTblspcMap_ptr = haveTblspcMap;
978 }
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition: timeline.c:544
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition: timeline.c:572
void remove_tablespace_symlink(const char *linkloc)
Definition: tablespace.c:889
#define UINT64_FORMAT
Definition: c.h:538
int errmsg_internal(const char *fmt,...)
Definition: elog.c:1156
int errcode_for_file_access(void)
Definition: elog.c:881
#define FATAL
Definition: elog.h:41
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:734
char * DataDir
Definition: globals.c:66
void OwnLatch(Latch *latch)
Definition: latch.c:436
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc0(Size size)
Definition: mcxt.c:1257
DBState
Definition: pg_control.h:88
@ DB_IN_ARCHIVE_RECOVERY
Definition: pg_control.h:94
@ DB_SHUTDOWNED_IN_RECOVERY
Definition: pg_control.h:91
@ DB_SHUTDOWNED
Definition: pg_control.h:90
@ DB_IN_CRASH_RECOVERY
Definition: pg_control.h:93
#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:168
bool backupEndRequired
Definition: pg_control.h:170
CheckPoint checkPointCopy
Definition: pg_control.h:133
XLogRecPtr backupEndPoint
Definition: pg_control.h:169
XLogRecPtr minRecoveryPoint
Definition: pg_control.h:166
XLogRecPtr checkPoint
Definition: pg_control.h:131
uint64 system_identifier
Definition: pg_control.h:108
TimeLineID minRecoveryPointTLI
Definition: pg_control.h:167
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:139
static ControlFileData * ControlFile
Definition: xlog.c:570
#define TABLESPACE_MAP_OLD
Definition: xlog.h:295
#define TABLESPACE_MAP
Definition: xlog.h:294
#define BACKUP_LABEL_FILE
Definition: xlog.h:291
XLogPrefetcher * XLogPrefetcherAllocate(XLogReaderState *reader)
void XLogReaderSetDecodeBuffer(XLogReaderState *state, void *buffer, size_t size)
Definition: xlogreader.c:92
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition: xlogreader.c:108
#define XL_ROUTINE(...)
Definition: xlogreader.h:117
static int XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf)
static void validateRecoveryParameters(void)
static XLogRecord * ReadCheckpointRecord(XLogPrefetcher *xlogprefetcher, XLogRecPtr RecPtr, TimeLineID replayTLI)
static TimeLineID RedoStartTLI
Definition: xlogrecovery.c:170
static void readRecoverySignalFile(void)
Definition: xlogrecovery.c:988
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:844

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

1586 {
1587  XLogRecord *record;
1588  bool reachedRecoveryTarget = false;
1589  TimeLineID replayTLI;
1590 
1591  /*
1592  * Initialize shared variables for tracking progress of WAL replay, as if
1593  * we had just replayed the record before the REDO location (or the
1594  * checkpoint record itself, if it's a shutdown checkpoint).
1595  */
1598  {
1602  }
1603  else
1604  {
1608  }
1615 
1616  /* Also ensure XLogReceiptTime has a sane value */
1618 
1619  /*
1620  * Let postmaster know we've started redo now, so that it can launch the
1621  * archiver if necessary.
1622  */
1623  if (IsUnderPostmaster)
1625 
1626  /*
1627  * Allow read-only connections immediately if we're consistent already.
1628  */
1630 
1631  /*
1632  * Find the first record that logically follows the checkpoint --- it
1633  * might physically precede it, though.
1634  */
1636  {
1637  /* back up to find the record */
1638  replayTLI = RedoStartTLI;
1640  record = ReadRecord(xlogprefetcher, PANIC, false, replayTLI);
1641  }
1642  else
1643  {
1644  /* just have to read next record after CheckPoint */
1646  replayTLI = CheckPointTLI;
1647  record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1648  }
1649 
1650  if (record != NULL)
1651  {
1652  TimestampTz xtime;
1653  PGRUsage ru0;
1654 
1655  pg_rusage_init(&ru0);
1656 
1657  InRedo = true;
1658 
1659  RmgrStartup();
1660 
1661  ereport(LOG,
1662  (errmsg("redo starts at %X/%X",
1664 
1665  /* Prepare to report progress of the redo phase. */
1666  if (!StandbyMode)
1668 
1669  /*
1670  * main redo apply loop
1671  */
1672  do
1673  {
1674  if (!StandbyMode)
1675  ereport_startup_progress("redo in progress, elapsed time: %ld.%02d s, current LSN: %X/%X",
1677 
1678 #ifdef WAL_DEBUG
1679  if (XLOG_DEBUG ||
1680  (record->xl_rmid == RM_XACT_ID && trace_recovery_messages <= DEBUG2) ||
1681  (record->xl_rmid != RM_XACT_ID && trace_recovery_messages <= DEBUG3))
1682  {
1684 
1685  initStringInfo(&buf);
1686  appendStringInfo(&buf, "REDO @ %X/%X; LSN %X/%X: ",
1689  xlog_outrec(&buf, xlogreader);
1690  appendStringInfoString(&buf, " - ");
1692  elog(LOG, "%s", buf.data);
1693  pfree(buf.data);
1694  }
1695 #endif
1696 
1697  /* Handle interrupt signals of startup process */
1699 
1700  /*
1701  * Pause WAL replay, if requested by a hot-standby session via
1702  * SetRecoveryPause().
1703  *
1704  * Note that we intentionally don't take the info_lck spinlock
1705  * here. We might therefore read a slightly stale value of the
1706  * recoveryPause flag, but it can't be very stale (no worse than
1707  * the last spinlock we did acquire). Since a pause request is a
1708  * pretty asynchronous thing anyway, possibly responding to it one
1709  * WAL record later than we otherwise would is a minor issue, so
1710  * it doesn't seem worth adding another spinlock cycle to prevent
1711  * that.
1712  */
1713  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1715  recoveryPausesHere(false);
1716 
1717  /*
1718  * Have we reached our recovery target?
1719  */
1721  {
1722  reachedRecoveryTarget = true;
1723  break;
1724  }
1725 
1726  /*
1727  * If we've been asked to lag the primary, wait on latch until
1728  * enough time has passed.
1729  */
1731  {
1732  /*
1733  * We test for paused recovery again here. If user sets
1734  * delayed apply, it may be because they expect to pause
1735  * recovery in case of problems, so we must test again here
1736  * otherwise pausing during the delay-wait wouldn't work.
1737  */
1738  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1740  recoveryPausesHere(false);
1741  }
1742 
1743  /*
1744  * Apply the record
1745  */
1746  ApplyWalRecord(xlogreader, record, &replayTLI);
1747 
1748  /* Exit loop if we reached inclusive recovery target */
1750  {
1751  reachedRecoveryTarget = true;
1752  break;
1753  }
1754 
1755  /* Else, try to fetch the next WAL record */
1756  record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1757  } while (record != NULL);
1758 
1759  /*
1760  * end of main redo apply loop
1761  */
1762 
1763  if (reachedRecoveryTarget)
1764  {
1765  if (!reachedConsistency)
1766  ereport(FATAL,
1767  (errmsg("requested recovery stop point is before consistent recovery point")));
1768 
1769  /*
1770  * This is the last point where we can restart recovery with a new
1771  * recovery target, if we shutdown and begin again. After this,
1772  * Resource Managers may choose to do permanent corrective actions
1773  * at end of recovery.
1774  */
1775  switch (recoveryTargetAction)
1776  {
1778 
1779  /*
1780  * exit with special return code to request shutdown of
1781  * postmaster. Log messages issued from postmaster.
1782  */
1783  proc_exit(3);
1784 
1786  SetRecoveryPause(true);
1787  recoveryPausesHere(true);
1788 
1789  /* drop into promote */
1790 
1792  break;
1793  }
1794  }
1795 
1796  RmgrCleanup();
1797 
1798  ereport(LOG,
1799  (errmsg("redo done at %X/%X system usage: %s",
1801  pg_rusage_show(&ru0))));
1802  xtime = GetLatestXTime();
1803  if (xtime)
1804  ereport(LOG,
1805  (errmsg("last completed transaction was at log time %s",
1806  timestamptz_to_str(xtime))));
1807 
1808  InRedo = false;
1809  }
1810  else
1811  {
1812  /* there are no WAL records following the checkpoint */
1813  ereport(LOG,
1814  (errmsg("redo is not required")));
1815  }
1816 
1817  /*
1818  * This check is intentionally after the above log messages that indicate
1819  * how far recovery went.
1820  */
1823  !reachedRecoveryTarget)
1824  ereport(FATAL,
1825  (errmsg("recovery ended before configured recovery target was reached")));
1826 }
void HandleStartupProcInterrupts(void)
Definition: startup.c:168
void begin_startup_progress_phase(void)
Definition: startup.c:352
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
#define DEBUG3
Definition: elog.h:28
#define DEBUG2
Definition: elog.h:29
int trace_recovery_messages
Definition: guc_tables.c:528
void proc_exit(int code)
Definition: ipc.c:104
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:67
@ PMSIGNAL_RECOVERY_STARTED
Definition: pmsignal.h:35
void RmgrStartup(void)
Definition: rmgr.c:49
void RmgrCleanup(void)
Definition: rmgr.c:65
#define ereport_startup_progress(msg,...)
Definition: startup.h:18
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
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, DEBUG2, DEBUG3, 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(), trace_recovery_messages, XLogRecord::xl_rmid, xlog_outdesc(), xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, XLogReceiptTime, and XLogRecoveryCtl.

Referenced by StartupXLOG().

◆ pg_attribute_noreturn()

static void pg_attribute_noreturn ( )
static

Definition at line 4684 of file xlogrecovery.c.

4686 {
4687  ereport(ERROR,
4688  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4689  errmsg("multiple recovery targets specified"),
4690  errdetail("At most one of recovery_target, recovery_target_lsn, recovery_target_name, recovery_target_time, recovery_target_xid may be set.")));
4691 }

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

◆ PromoteIsTriggered()

bool PromoteIsTriggered ( void  )

Definition at line 4310 of file xlogrecovery.c.

4311 {
4312  /*
4313  * We check shared state each time only until a standby promotion is
4314  * triggered. We can't trigger a promotion again, so there's no need to
4315  * keep checking after the shared variable has once been seen true.
4316  */
4318  return true;
4319 
4323 
4324  return LocalPromoteIsTriggered;
4325 }

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

1171 {
1172  char startxlogfilename[MAXFNAMELEN];
1173  TimeLineID tli_from_walseg,
1174  tli_from_file;
1175  FILE *lfp;
1176  char ch;
1177  char backuptype[20];
1178  char backupfrom[20];
1179  char backuplabel[MAXPGPATH];
1180  char backuptime[128];
1181  uint32 hi,
1182  lo;
1183 
1184  /* suppress possible uninitialized-variable warnings */
1185  *checkPointLoc = InvalidXLogRecPtr;
1186  *backupLabelTLI = 0;
1187  *backupEndRequired = false;
1188  *backupFromStandby = false;
1189 
1190  /*
1191  * See if label file is present
1192  */
1193  lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
1194  if (!lfp)
1195  {
1196  if (errno != ENOENT)
1197  ereport(FATAL,
1199  errmsg("could not read file \"%s\": %m",
1200  BACKUP_LABEL_FILE)));
1201  return false; /* it's not there, all is fine */
1202  }
1203 
1204  /*
1205  * Read and parse the START WAL LOCATION and CHECKPOINT lines (this code
1206  * is pretty crude, but we are not expecting any variability in the file
1207  * format).
1208  */
1209  if (fscanf(lfp, "START WAL LOCATION: %X/%X (file %08X%16s)%c",
1210  &hi, &lo, &tli_from_walseg, startxlogfilename, &ch) != 5 || ch != '\n')
1211  ereport(FATAL,
1212  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1213  errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
1214  RedoStartLSN = ((uint64) hi) << 32 | lo;
1215  RedoStartTLI = tli_from_walseg;
1216  if (fscanf(lfp, "CHECKPOINT LOCATION: %X/%X%c",
1217  &hi, &lo, &ch) != 3 || ch != '\n')
1218  ereport(FATAL,
1219  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1220  errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
1221  *checkPointLoc = ((uint64) hi) << 32 | lo;
1222  *backupLabelTLI = tli_from_walseg;
1223 
1224  /*
1225  * BACKUP METHOD lets us know if this was a typical backup ("streamed",
1226  * which could mean either pg_basebackup or the pg_backup_start/stop
1227  * method was used) or if this label came from somewhere else (the only
1228  * other option today being from pg_rewind). If this was a streamed
1229  * backup then we know that we need to play through until we get to the
1230  * end of the WAL which was generated during the backup (at which point we
1231  * will have reached consistency and backupEndRequired will be reset to be
1232  * false).
1233  */
1234  if (fscanf(lfp, "BACKUP METHOD: %19s\n", backuptype) == 1)
1235  {
1236  if (strcmp(backuptype, "streamed") == 0)
1237  *backupEndRequired = true;
1238  }
1239 
1240  /*
1241  * BACKUP FROM lets us know if this was from a primary or a standby. If
1242  * it was from a standby, we'll double-check that the control file state
1243  * matches that of a standby.
1244  */
1245  if (fscanf(lfp, "BACKUP FROM: %19s\n", backupfrom) == 1)
1246  {
1247  if (strcmp(backupfrom, "standby") == 0)
1248  *backupFromStandby = true;
1249  }
1250 
1251  /*
1252  * Parse START TIME and LABEL. Those are not mandatory fields for recovery
1253  * but checking for their presence is useful for debugging and the next
1254  * sanity checks. Cope also with the fact that the result buffers have a
1255  * pre-allocated size, hence if the backup_label file has been generated
1256  * with strings longer than the maximum assumed here an incorrect parsing
1257  * happens. That's fine as only minor consistency checks are done
1258  * afterwards.
1259  */
1260  if (fscanf(lfp, "START TIME: %127[^\n]\n", backuptime) == 1)
1261  ereport(DEBUG1,
1262  (errmsg_internal("backup time %s in file \"%s\"",
1263  backuptime, BACKUP_LABEL_FILE)));
1264 
1265  if (fscanf(lfp, "LABEL: %1023[^\n]\n", backuplabel) == 1)
1266  ereport(DEBUG1,
1267  (errmsg_internal("backup label %s in file \"%s\"",
1268  backuplabel, BACKUP_LABEL_FILE)));
1269 
1270  /*
1271  * START TIMELINE is new as of 11. Its parsing is not mandatory, still use
1272  * it as a sanity check if present.
1273  */
1274  if (fscanf(lfp, "START TIMELINE: %u\n", &tli_from_file) == 1)
1275  {
1276  if (tli_from_walseg != tli_from_file)
1277  ereport(FATAL,
1278  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1279  errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE),
1280  errdetail("Timeline ID parsed is %u, but expected %u.",
1281  tli_from_file, tli_from_walseg)));
1282 
1283  ereport(DEBUG1,
1284  (errmsg_internal("backup timeline %u in file \"%s\"",
1285  tli_from_file, BACKUP_LABEL_FILE)));
1286  }
1287 
1288  if (ferror(lfp) || FreeFile(lfp))
1289  ereport(FATAL,
1291  errmsg("could not read file \"%s\": %m",
1292  BACKUP_LABEL_FILE)));
1293 
1294  return true;
1295 }
unsigned int uint32
Definition: c.h:495
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2528
int FreeFile(FILE *file)
Definition: fd.c:2726

References AllocateFile(), BACKUP_LABEL_FILE, backupEndRequired, DEBUG1, ereport, errcode(), errcode_for_file_access(), errdetail(), 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 1309 of file xlogrecovery.c.

1310 {
1311  tablespaceinfo *ti;
1312  FILE *lfp;
1313  char str[MAXPGPATH];
1314  int ch,
1315  i,
1316  n;
1317  bool was_backslash;
1318 
1319  /*
1320  * See if tablespace_map file is present
1321  */
1322  lfp = AllocateFile(TABLESPACE_MAP, "r");
1323  if (!lfp)
1324  {
1325  if (errno != ENOENT)
1326  ereport(FATAL,
1328  errmsg("could not read file \"%s\": %m",
1329  TABLESPACE_MAP)));
1330  return false; /* it's not there, all is fine */
1331  }
1332 
1333  /*
1334  * Read and parse the link name and path lines from tablespace_map file
1335  * (this code is pretty crude, but we are not expecting any variability in
1336  * the file format). De-escape any backslashes that were inserted.
1337  */
1338  i = 0;
1339  was_backslash = false;
1340  while ((ch = fgetc(lfp)) != EOF)
1341  {
1342  if (!was_backslash && (ch == '\n' || ch == '\r'))
1343  {
1344  if (i == 0)
1345  continue; /* \r immediately followed by \n */
1346 
1347  /*
1348  * The de-escaped line should contain an OID followed by exactly
1349  * one space followed by a path. The path might start with
1350  * spaces, so don't be too liberal about parsing.
1351  */
1352  str[i] = '\0';
1353  n = 0;
1354  while (str[n] && str[n] != ' ')
1355  n++;
1356  if (n < 1 || n >= i - 1)
1357  ereport(FATAL,
1358  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1359  errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
1360  str[n++] = '\0';
1361 
1362  ti = palloc0(sizeof(tablespaceinfo));
1363  ti->oid = pstrdup(str);
1364  ti->path = pstrdup(str + n);
1365  *tablespaces = lappend(*tablespaces, ti);
1366 
1367  i = 0;
1368  continue;
1369  }
1370  else if (!was_backslash && ch == '\\')
1371  was_backslash = true;
1372  else
1373  {
1374  if (i < sizeof(str) - 1)
1375  str[i++] = ch;
1376  was_backslash = false;
1377  }
1378  }
1379 
1380  if (i != 0 || was_backslash) /* last line not terminated? */
1381  ereport(FATAL,
1382  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1383  errmsg("invalid data in file \"%s\"", TABLESPACE_MAP)));
1384 
1385  if (ferror(lfp) || FreeFile(lfp))
1386  ereport(FATAL,
1388  errmsg("could not read file \"%s\": %m",
1389  TABLESPACE_MAP)));
1390 
1391  return true;
1392 }
int i
Definition: isn.c:73
List * lappend(List *list, void *datum)
Definition: list.c:338

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

Referenced by InitWalRecovery().

◆ ReadCheckpointRecord()

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

Definition at line 3965 of file xlogrecovery.c.

3967 {
3968  XLogRecord *record;
3969  uint8 info;
3970 
3971  Assert(xlogreader != NULL);
3972 
3973  if (!XRecOffIsValid(RecPtr))
3974  {
3975  ereport(LOG,
3976  (errmsg("invalid checkpoint location")));
3977  return NULL;
3978  }
3979 
3981  record = ReadRecord(xlogprefetcher, LOG, true, replayTLI);
3982 
3983  if (record == NULL)
3984  {
3985  ereport(LOG,
3986  (errmsg("invalid checkpoint record")));
3987  return NULL;
3988  }
3989  if (record->xl_rmid != RM_XLOG_ID)
3990  {
3991  ereport(LOG,
3992  (errmsg("invalid resource manager ID in checkpoint record")));
3993  return NULL;
3994  }
3995  info = record->xl_info & ~XLR_INFO_MASK;
3996  if (info != XLOG_CHECKPOINT_SHUTDOWN &&
3997  info != XLOG_CHECKPOINT_ONLINE)
3998  {
3999  ereport(LOG,
4000  (errmsg("invalid xl_info in checkpoint record")));
4001  return NULL;
4002  }
4004  {
4005  ereport(LOG,
4006  (errmsg("invalid length of checkpoint record")));
4007  return NULL;
4008  }
4009  return record;
4010 }
#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 3047 of file xlogrecovery.c.

3049 {
3050  XLogRecord *record;
3053 
3054  /* Pass through parameters to XLogPageRead */
3055  private->fetching_ckpt = fetching_ckpt;
3056  private->emode = emode;
3057  private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
3058  private->replayTLI = replayTLI;
3059 
3060  /* This is the first attempt to read this page. */
3061  lastSourceFailed = false;
3062 
3063  for (;;)
3064  {
3065  char *errormsg;
3066 
3067  record = XLogPrefetcherReadRecord(xlogprefetcher, &errormsg);
3068  if (record == NULL)
3069  {
3070  /*
3071  * When we find that WAL ends in an incomplete record, keep track
3072  * of that record. After recovery is done, we'll write a record
3073  * to indicate to downstream WAL readers that that portion is to
3074  * be ignored.
3075  *
3076  * However, when ArchiveRecoveryRequested = true, we're going to
3077  * switch to a new timeline at the end of recovery. We will only
3078  * copy WAL over to the new timeline up to the end of the last
3079  * complete record, so if we did this, we would later create an
3080  * overwrite contrecord in the wrong place, breaking everything.
3081  */
3082  if (!ArchiveRecoveryRequested &&
3084  {
3087  }
3088 
3089  if (readFile >= 0)
3090  {
3091  close(readFile);
3092  readFile = -1;
3093  }
3094 
3095  /*
3096  * We only end up here without a message when XLogPageRead()
3097  * failed - in that case we already logged something. In
3098  * StandbyMode that only happens if we have been triggered, so we
3099  * shouldn't loop anymore in that case.
3100  */
3101  if (errormsg)
3103  (errmsg_internal("%s", errormsg) /* already translated */ ));
3104  }
3105 
3106  /*
3107  * Check page TLI is one of the expected values.
3108  */
3110  {
3111  char fname[MAXFNAMELEN];
3112  XLogSegNo segno;
3113  int32 offset;
3114 
3118  XLogFileName(fname, xlogreader->seg.ws_tli, segno,
3121  (errmsg("unexpected timeline ID %u in WAL segment %s, LSN %X/%X, offset %u",
3123  fname,
3125  offset)));
3126  record = NULL;
3127  }
3128 
3129  if (record)
3130  {
3131  /* Great, got a record */
3132  return record;
3133  }
3134  else
3135  {
3136  /* No valid record available from this source */
3137  lastSourceFailed = true;
3138 
3139  /*
3140  * If archive recovery was requested, but we were still doing
3141  * crash recovery, switch to archive recovery and retry using the
3142  * offline archive. We have now replayed all the valid WAL in
3143  * pg_wal, so we are presumably now consistent.
3144  *
3145  * We require that there's at least some valid WAL present in
3146  * pg_wal, however (!fetching_ckpt). We could recover using the
3147  * WAL from the archive, even if pg_wal is completely empty, but
3148  * we'd have no idea how far we'd have to replay to reach
3149  * consistency. So err on the safe side and give up.
3150  */
3152  !fetching_ckpt)
3153  {
3154  ereport(DEBUG1,
3155  (errmsg_internal("reached end of WAL in pg_wal, entering archive recovery")));
3156  InArchiveRecovery = true;
3159 
3162  minRecoveryPointTLI = replayTLI;
3163 
3165 
3166  /*
3167  * Before we retry, reset lastSourceFailed and currentSource
3168  * so that we will check the archive next.
3169  */
3170  lastSourceFailed = false;
3172 
3173  continue;
3174  }
3175 
3176  /* In standby mode, loop back to retry. Otherwise, give up. */
3178  continue;
3179  else
3180  return NULL;
3181  }
3182  }
3183 }
signed int int32
Definition: c.h:483
XLogRecPtr missingContrecPtr
Definition: xlogreader.h:215
XLogRecPtr abortedRecPtr
Definition: xlogreader.h:214
TimeLineID latestPageTLI
Definition: xlogreader.h:280
XLogRecPtr latestPagePtr
Definition: xlogreader.h:279
void * private_data
Definition: xlogreader.h:196
void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI)
Definition: xlog.c:5823
#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 988 of file xlogrecovery.c.

989 {
990  struct stat stat_buf;
991 
993  return;
994 
995  /*
996  * Check for old recovery API file: recovery.conf
997  */
998  if (stat(RECOVERY_COMMAND_FILE, &stat_buf) == 0)
999  ereport(FATAL,
1001  errmsg("using recovery command file \"%s\" is not supported",
1003 
1004  /*
1005  * Remove unused .done file, if present. Ignore if absent.
1006  */
1007  unlink(RECOVERY_COMMAND_DONE);
1008 
1009  /*
1010  * Check for recovery signal files and if found, fsync them since they
1011  * represent server state information. We don't sweat too much about the
1012  * possibility of fsync failure, however.
1013  *
1014  * If present, standby signal file takes precedence. If neither is present
1015  * then we won't enter archive recovery.
1016  */
1017  if (stat(STANDBY_SIGNAL_FILE, &stat_buf) == 0)
1018  {
1019  int fd;
1020 
1022  S_IRUSR | S_IWUSR);
1023  if (fd >= 0)
1024  {
1025  (void) pg_fsync(fd);
1026  close(fd);
1027  }
1029  }
1030  else if (stat(RECOVERY_SIGNAL_FILE, &stat_buf) == 0)
1031  {
1032  int fd;
1033 
1035  S_IRUSR | S_IWUSR);
1036  if (fd >= 0)
1037  {
1038  (void) pg_fsync(fd);
1039  close(fd);
1040  }
1042  }
1043 
1044  StandbyModeRequested = false;
1045  ArchiveRecoveryRequested = false;
1047  {
1048  StandbyModeRequested = true;
1049  ArchiveRecoveryRequested = true;
1050  }
1051  else if (recovery_signal_file_found)
1052  {
1053  StandbyModeRequested = false;
1054  ArchiveRecoveryRequested = true;
1055  }
1056  else
1057  return;
1058 
1059  /*
1060  * We don't support standby mode in standalone backends; that requires
1061  * other processes such as the WAL receiver to be alive.
1062  */
1064  ereport(FATAL,
1065  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1066  errmsg("standby mode is not supported by single-user servers")));
1067 }
#define PG_BINARY
Definition: c.h:1283
int BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition: fd.c:1061
int pg_fsync(int fd)
Definition: fd.c:361
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:414
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:290
#define RECOVERY_SIGNAL_FILE
Definition: xlog.h:289
#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 2898 of file xlogrecovery.c.

2899 {
2900  uint8 xact_info;
2901  TimestampTz xtime;
2902  TimestampTz delayUntil;
2903  long msecs;
2904 
2905  /* nothing to do if no delay configured */
2906  if (recovery_min_apply_delay <= 0)
2907  return false;
2908 
2909  /* no delay is applied on a database not yet consistent */
2910  if (!reachedConsistency)
2911  return false;
2912 
2913  /* nothing to do if crash recovery is requested */
2915  return false;
2916 
2917  /*
2918  * Is it a COMMIT record?
2919  *
2920  * We deliberately choose not to delay aborts since they have no effect on
2921  * MVCC. We already allow replay of records that don't have a timestamp,
2922  * so there is already opportunity for issues caused by early conflicts on
2923  * standbys.
2924  */
2925  if (XLogRecGetRmid(record) != RM_XACT_ID)
2926  return false;
2927 
2928  xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
2929 
2930  if (xact_info != XLOG_XACT_COMMIT &&
2931  xact_info != XLOG_XACT_COMMIT_PREPARED)
2932  return false;
2933 
2934  if (!getRecordTimestamp(record, &xtime))
2935  return false;
2936 
2938 
2939  /*
2940  * Exit without arming the latch if it's already past time to apply this
2941  * record
2942  */
2944  if (msecs <= 0)
2945  return false;
2946 
2947  while (true)
2948  {
2950 
2951  /* This might change recovery_min_apply_delay. */
2953 
2954  if (CheckForStandbyTrigger())
2955  break;
2956 
2957  /*
2958  * Recalculate delayUntil as recovery_min_apply_delay could have
2959  * changed while waiting in this loop.
2960  */
2962 
2963  /*
2964  * Wait for difference between GetCurrentTimestamp() and delayUntil.
2965  */
2967  delayUntil);
2968 
2969  if (msecs <= 0)
2970  break;
2971 
2972  elog(DEBUG2, "recovery apply delay %ld milliseconds", msecs);
2973 
2976  msecs,
2977  WAIT_EVENT_RECOVERY_APPLY_DELAY);
2978  }
2979  return true;
2980 }
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition: timestamp.c:1695
void ResetLatch(Latch *latch)
Definition: latch.c:697
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition: latch.c:490
#define WL_TIMEOUT
Definition: latch.h:128
#define WL_EXIT_ON_PM_DEATH
Definition: latch.h:130
#define WL_LATCH_SET
Definition: latch.h:125
#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 2841 of file xlogrecovery.c.

2842 {
2843  /* Don't pause unless users can connect! */
2844  if (!LocalHotStandbyActive)
2845  return;
2846 
2847  /* Don't pause after standby promotion has been triggered */
2849  return;
2850 
2851  if (endOfRecovery)
2852  ereport(LOG,
2853  (errmsg("pausing at the end of recovery"),
2854  errhint("Execute pg_wal_replay_resume() to promote.")));
2855  else
2856  ereport(LOG,
2857  (errmsg("recovery has paused"),
2858  errhint("Execute pg_wal_replay_resume() to continue.")));
2859 
2860  /* loop until recoveryPauseState is set to RECOVERY_NOT_PAUSED */
2862  {
2864  if (CheckForStandbyTrigger())
2865  return;
2866 
2867  /*
2868  * If recovery pause is requested then set it paused. While we are in
2869  * the loop, user might resume and pause again so set this every time.
2870  */
2872 
2873  /*
2874  * We wait on a condition variable that will wake us as soon as the
2875  * pause ends, but we use a timeout so we can check the above exit
2876  * condition periodically too.
2877  */
2879  WAIT_EVENT_RECOVERY_PAUSE);
2880  }
2882 }
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 4575 of file xlogrecovery.c.

4576 {
4577  if (currValue < minValue)
4578  {
4580  {
4581  bool warned_for_promote = false;
4582 
4583  ereport(WARNING,
4584  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4585  errmsg("hot standby is not possible because of insufficient parameter settings"),
4586  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4587  param_name,
4588  currValue,
4589  minValue)));
4590 
4591  SetRecoveryPause(true);
4592 
4593  ereport(LOG,
4594  (errmsg("recovery has paused"),
4595  errdetail("If recovery is unpaused, the server will shut down."),
4596  errhint("You can then restart the server after making the necessary configuration changes.")));
4597 
4599  {
4601 
4602  if (CheckForStandbyTrigger())
4603  {
4604  if (!warned_for_promote)
4605  ereport(WARNING,
4606  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4607  errmsg("promotion is not possible because of insufficient parameter settings"),
4608 
4609  /*
4610  * Repeat the detail from above so it's easy to find
4611  * in the log.
4612  */
4613  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4614  param_name,
4615  currValue,
4616  minValue),
4617  errhint("Restart the server after making the necessary configuration changes.")));
4618  warned_for_promote = true;
4619  }
4620 
4621  /*
4622  * If recovery pause is requested then set it paused. While
4623  * we are in the loop, user might resume and pause again so
4624  * set this every time.
4625  */
4627 
4628  /*
4629  * We wait on a condition variable that will wake us as soon
4630  * as the pause ends, but we use a timeout so we can check the
4631  * above conditions periodically too.
4632  */
4634  WAIT_EVENT_RECOVERY_PAUSE);
4635  }
4637  }
4638 
4639  ereport(FATAL,
4640  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4641  errmsg("recovery aborted because of insufficient parameter settings"),
4642  /* Repeat the detail from above so it's easy to find in the log. */
4643  errdetail("%s = %d is a lower setting than on the primary server, where its value was %d.",
4644  param_name,
4645  currValue,
4646  minValue),
4647  errhint("You can restart the server after making the necessary configuration changes.")));
4648  }
4649 }
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 2642 of file xlogrecovery.c.

2643 {
2644  uint8 info;
2645  uint8 xact_info;
2646  uint8 rmid;
2647  TimestampTz recordXtime = 0;
2648 
2649  /*
2650  * Ignore recovery target settings when not in archive recovery (meaning
2651  * we are in crash recovery).
2652  */
2654  return false;
2655 
2656  info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2657  rmid = XLogRecGetRmid(record);
2658 
2659  /*
2660  * There can be many restore points that share the same name; we stop at
2661  * the first one.
2662  */
2664  rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2665  {
2666  xl_restore_point *recordRestorePointData;
2667 
2668  recordRestorePointData = (xl_restore_point *) XLogRecGetData(record);
2669 
2670  if (strcmp(recordRestorePointData->rp_name, recoveryTargetName) == 0)
2671  {
2672  recoveryStopAfter = true;
2675  (void) getRecordTimestamp(record, &recoveryStopTime);
2676  strlcpy(recoveryStopName, recordRestorePointData->rp_name, MAXFNAMELEN);
2677 
2678  ereport(LOG,
2679  (errmsg("recovery stopping at restore point \"%s\", time %s",
2682  return true;
2683  }
2684  }
2685 
2686  /* Check if the target LSN has been reached */
2689  record->ReadRecPtr >= recoveryTargetLSN)
2690  {
2691  recoveryStopAfter = true;
2693  recoveryStopLSN = record->ReadRecPtr;
2694  recoveryStopTime = 0;
2695  recoveryStopName[0] = '\0';
2696  ereport(LOG,
2697  (errmsg("recovery stopping after WAL location (LSN) \"%X/%X\"",
2699  return true;
2700  }
2701 
2702  if (rmid != RM_XACT_ID)
2703  return false;
2704 
2705  xact_info = info & XLOG_XACT_OPMASK;
2706 
2707  if (xact_info == XLOG_XACT_COMMIT ||
2708  xact_info == XLOG_XACT_COMMIT_PREPARED ||
2709  xact_info == XLOG_XACT_ABORT ||
2710  xact_info == XLOG_XACT_ABORT_PREPARED)
2711  {
2712  TransactionId recordXid;
2713 
2714  /* Update the last applied transaction timestamp */
2715  if (getRecordTimestamp(record, &recordXtime))
2716  SetLatestXTime(recordXtime);
2717 
2718  /* Extract the XID of the committed/aborted transaction */
2719  if (xact_info == XLOG_XACT_COMMIT_PREPARED)
2720  {
2721  xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
2722  xl_xact_parsed_commit parsed;
2723 
2725  xlrec,
2726  &parsed);
2727  recordXid = parsed.twophase_xid;
2728  }
2729  else if (xact_info == XLOG_XACT_ABORT_PREPARED)
2730  {
2731  xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
2732  xl_xact_parsed_abort parsed;
2733 
2735  xlrec,
2736  &parsed);
2737  recordXid = parsed.twophase_xid;
2738  }
2739  else
2740  recordXid = XLogRecGetXid(record);
2741 
2742  /*
2743  * There can be only one transaction end record with this exact
2744  * transactionid
2745  *
2746  * when testing for an xid, we MUST test for equality only, since
2747  * transactions are numbered in the order they start, not the order
2748  * they complete. A higher numbered xid will complete before you about
2749  * 50% of the time...
2750  */
2752  recordXid == recoveryTargetXid)
2753  {
2754  recoveryStopAfter = true;
2755  recoveryStopXid = recordXid;
2756  recoveryStopTime = recordXtime;
2758  recoveryStopName[0] = '\0';
2759 
2760  if (xact_info == XLOG_XACT_COMMIT ||
2761  xact_info == XLOG_XACT_COMMIT_PREPARED)
2762  {
2763  ereport(LOG,
2764  (errmsg("recovery stopping after commit of transaction %u, time %s",
2767  }
2768  else if (xact_info == XLOG_XACT_ABORT ||
2769  xact_info == XLOG_XACT_ABORT_PREPARED)
2770  {
2771  ereport(LOG,
2772  (errmsg("recovery stopping after abort of transaction %u, time %s",
2775  }
2776  return true;
2777  }
2778  }
2779 
2780  /* Check if we should stop as soon as reaching consistency */
2782  {
2783  ereport(LOG,
2784  (errmsg("recovery stopping after reaching consistency")));
2785 
2786  recoveryStopAfter = true;
2788  recoveryStopTime = 0;
2790  recoveryStopName[0] = '\0';
2791  return true;
2792  }
2793 
2794  return false;
2795 }
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 2489 of file xlogrecovery.c.

2490 {
2491  bool stopsHere = false;
2492  uint8 xact_info;
2493  bool isCommit;
2494  TimestampTz recordXtime = 0;
2495  TransactionId recordXid;
2496 
2497  /*
2498  * Ignore recovery target settings when not in archive recovery (meaning
2499  * we are in crash recovery).
2500  */
2502  return false;
2503 
2504  /* Check if we should stop as soon as reaching consistency */
2506  {
2507  ereport(LOG,
2508  (errmsg("recovery stopping after reaching consistency")));
2509 
2510  recoveryStopAfter = false;
2513  recoveryStopTime = 0;
2514  recoveryStopName[0] = '\0';
2515  return true;
2516  }
2517 
2518  /* Check if target LSN has been reached */
2521  record->ReadRecPtr >= recoveryTargetLSN)
2522  {
2523  recoveryStopAfter = false;
2525  recoveryStopLSN = record->ReadRecPtr;
2526  recoveryStopTime = 0;
2527  recoveryStopName[0] = '\0';
2528  ereport(LOG,
2529  (errmsg("recovery stopping before WAL location (LSN) \"%X/%X\"",
2531  return true;
2532  }
2533 
2534  /* Otherwise we only consider stopping before COMMIT or ABORT records. */
2535  if (XLogRecGetRmid(record) != RM_XACT_ID)
2536  return false;
2537 
2538  xact_info = XLogRecGetInfo(record) & XLOG_XACT_OPMASK;
2539 
2540  if (xact_info == XLOG_XACT_COMMIT)
2541  {
2542  isCommit = true;
2543  recordXid = XLogRecGetXid(record);
2544  }
2545  else if (xact_info == XLOG_XACT_COMMIT_PREPARED)
2546  {
2547  xl_xact_commit *xlrec = (xl_xact_commit *) XLogRecGetData(record);
2548  xl_xact_parsed_commit parsed;
2549 
2550  isCommit = true;
2552  xlrec,
2553  &parsed);
2554  recordXid = parsed.twophase_xid;
2555  }
2556  else if (xact_info == XLOG_XACT_ABORT)
2557  {
2558  isCommit = false;
2559  recordXid = XLogRecGetXid(record);
2560  }
2561  else if (xact_info == XLOG_XACT_ABORT_PREPARED)
2562  {
2563  xl_xact_abort *xlrec = (xl_xact_abort *) XLogRecGetData(record);
2564  xl_xact_parsed_abort parsed;
2565 
2566  isCommit = false;
2568  xlrec,
2569  &parsed);
2570  recordXid = parsed.twophase_xid;
2571  }
2572  else
2573  return false;
2574 
2576  {
2577  /*
2578  * There can be only one transaction end record with this exact
2579  * transactionid
2580  *
2581  * when testing for an xid, we MUST test for equality only, since
2582  * transactions are numbered in the order they start, not the order
2583  * they complete. A higher numbered xid will complete before you about
2584  * 50% of the time...
2585  */
2586  stopsHere = (recordXid == recoveryTargetXid);
2587  }
2588 
2589  /*
2590  * Note: we must fetch recordXtime regardless of recoveryTarget setting.
2591  * We don't expect getRecordTimestamp ever to fail, since we already know
2592  * this is a commit or abort record; but test its result anyway.
2593  */
2594  if (getRecordTimestamp(record, &recordXtime) &&
2596  {
2597  /*
2598  * There can be many transactions that share the same commit time, so
2599  * we stop after the last one, if we are inclusive, or stop at the
2600  * first one if we are exclusive
2601  */
2603  stopsHere = (recordXtime > recoveryTargetTime);
2604  else
2605  stopsHere = (recordXtime >= recoveryTargetTime);
2606  }
2607 
2608  if (stopsHere)
2609  {
2610  recoveryStopAfter = false;
2611  recoveryStopXid = recordXid;
2612  recoveryStopTime = recordXtime;
2614  recoveryStopName[0] = '\0';
2615 
2616  if (isCommit)
2617  {
2618  ereport(LOG,
2619  (errmsg("recovery stopping before commit of transaction %u, time %s",
2622  }
2623  else
2624  {
2625  ereport(LOG,
2626  (errmsg("recovery stopping before abort of transaction %u, time %s",
2629  }
2630  }
2631 
2632  return stopsHere;
2633 }

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

4371 {
4372  unlink(PROMOTE_SIGNAL_FILE);
4373 }

References PROMOTE_SIGNAL_FILE.

Referenced by CheckForStandbyTrigger(), and PostmasterMain().

◆ rescanLatestTimeLine()

static bool rescanLatestTimeLine ( TimeLineID  replayTLI,
XLogRecPtr  replayLSN 
)
static

Definition at line 4020 of file xlogrecovery.c.

4021 {
4022  List *newExpectedTLEs;
4023  bool found;
4024  ListCell *cell;
4025  TimeLineID newtarget;
4026  TimeLineID oldtarget = recoveryTargetTLI;
4027  TimeLineHistoryEntry *currentTle = NULL;
4028 
4030  if (newtarget == recoveryTargetTLI)
4031  {
4032  /* No new timelines found */
4033  return false;
4034  }
4035 
4036  /*
4037  * Determine the list of expected TLIs for the new TLI
4038  */
4039 
4040  newExpectedTLEs = readTimeLineHistory(newtarget);
4041 
4042  /*
4043  * If the current timeline is not part of the history of the new timeline,
4044  * we cannot proceed to it.
4045  */
4046  found = false;
4047  foreach(cell, newExpectedTLEs)
4048  {
4049  currentTle = (TimeLineHistoryEntry *) lfirst(cell);
4050 
4051  if (currentTle->tli == recoveryTargetTLI)
4052  {
4053  found = true;
4054  break;
4055  }
4056  }
4057  if (!found)
4058  {
4059  ereport(LOG,
4060  (errmsg("new timeline %u is not a child of database system timeline %u",
4061  newtarget,
4062  replayTLI)));
4063  return false;
4064  }
4065 
4066  /*
4067  * The current timeline was found in the history file, but check that the
4068  * next timeline was forked off from it *after* the current recovery
4069  * location.
4070  */
4071  if (currentTle->end < replayLSN)
4072  {
4073  ereport(LOG,
4074  (errmsg("new timeline %u forked off current database system timeline %u before current recovery point %X/%X",
4075  newtarget,
4076  replayTLI,
4077  LSN_FORMAT_ARGS(replayLSN))));
4078  return false;
4079  }
4080 
4081  /* The new timeline history seems valid. Switch target */
4082  recoveryTargetTLI = newtarget;
4084  expectedTLEs = newExpectedTLEs;
4085 
4086  /*
4087  * As in StartupXLOG(), try to ensure we have all the history files
4088  * between the old target and new target in pg_wal.
4089  */
4090  restoreTimeLineHistoryFiles(oldtarget + 1, newtarget);
4091 
4092  ereport(LOG,
4093  (errmsg("new target timeline is %u",
4094  recoveryTargetTLI)));
4095 
4096  return true;
4097 }
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:1559
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 2191 of file xlogrecovery.c.

2192 {
2193  XLogReaderState *record = (XLogReaderState *) arg;
2195 
2196  initStringInfo(&buf);
2197  xlog_outdesc(&buf, record);
2198  xlog_block_info(&buf, record);
2199 
2200  /* translator: %s is a WAL record description */
2201  errcontext("WAL redo at %X/%X for %s",
2202  LSN_FORMAT_ARGS(record->ReadRecPtr),
2203  buf.data);
2204 
2205  pfree(buf.data);
2206 }
#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 4328 of file xlogrecovery.c.

4329 {
4333 
4334  /*
4335  * Mark the recovery pause state as 'not paused' because the paused state
4336  * ends and promotion continues if a promotion is triggered while recovery
4337  * is paused. Otherwise pg_get_wal_replay_pause_state() can mistakenly
4338  * return 'paused' while a promotion is ongoing.
4339  */
4340  SetRecoveryPause(false);
4341 
4342  LocalPromoteIsTriggered = true;
4343 }

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

Referenced by CheckForStandbyTrigger().

◆ SetRecoveryPause()

◆ ShutdownWalRecovery()

void ShutdownWalRecovery ( void  )

Definition at line 1541 of file xlogrecovery.c.

1542 {
1543  char recoveryPath[MAXPGPATH];
1544 
1545  /* Final update of pg_stat_recovery_prefetch. */
1547 
1548  /* Shut down xlogreader */
1549  if (readFile >= 0)
1550  {
1551  close(readFile);
1552  readFile = -1;
1553  }
1556 
1558  {
1559  /*
1560  * Since there might be a partial WAL segment named RECOVERYXLOG, get
1561  * rid of it.
1562  */
1563  snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYXLOG");
1564  unlink(recoveryPath); /* ignore any error */
1565 
1566  /* Get rid of any remaining recovered timeline-history file, too */
1567  snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYHISTORY");
1568  unlink(recoveryPath); /* ignore any error */
1569  }
1570 
1571  /*
1572  * We don't need the latch anymore. It's not strictly necessary to disown
1573  * it, but let's do it for the sake of tidiness.
1574  */
1577 }
void DisownLatch(Latch *latch)
Definition: latch.c:462
#define XLOGDIR
void XLogPrefetcherComputeStats(XLogPrefetcher *prefetcher)
void XLogPrefetcherFree(XLogPrefetcher *prefetcher)
void XLogReaderFree(XLogReaderState *state)
Definition: xlogreader.c:170

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

4292 {
4294  {
4295  ereport(LOG,
4296  (errmsg("WAL receiver process shutdown requested")));
4297 
4298  pendingWalRcvRestart = true;
4299  }
4300 }
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 1070 of file xlogrecovery.c.

1071 {
1073  return;
1074 
1075  /*
1076  * Check for compulsory parameters
1077  */
1079  {
1080  if ((PrimaryConnInfo == NULL || strcmp(PrimaryConnInfo, "") == 0) &&
1081  (recoveryRestoreCommand == NULL || strcmp(recoveryRestoreCommand, "") == 0))
1082  ereport(WARNING,
1083  (errmsg("specified neither primary_conninfo nor restore_command"),
1084  errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
1085  }
1086  else
1087  {
1088  if (recoveryRestoreCommand == NULL ||
1089  strcmp(recoveryRestoreCommand, "") == 0)
1090  ereport(FATAL,
1091  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1092  errmsg("must specify restore_command when standby mode is not enabled")));
1093  }
1094 
1095  /*
1096  * Override any inconsistent requests. Note that this is a change of
1097  * behaviour in 9.5; prior to this we simply ignored a request to pause if
1098  * hot_standby = off, which was surprising behaviour.
1099  */
1103 
1104  /*
1105  * Final parsing of recovery_target_time string; see also
1106  * check_recovery_target_time().
1107  */
1109  {
1113  Int32GetDatum(-1)));
1114  }
1115 
1116  /*
1117  * If user specified recovery_target_timeline, validate it or compute the
1118  * "latest" value. We can't do this until after we've gotten the restore
1119  * command and set InArchiveRecovery, because we need to fetch timeline
1120  * history files from the archive.
1121  */
1123  {
1125 
1126  /* Timeline 1 does not have a history file, all else should */
1127  if (rtli != 1 && !existsTimeLineHistory(rtli))
1128  ereport(FATAL,
1129  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1130  errmsg("recovery target timeline %u does not exist",
1131  rtli)));
1132  recoveryTargetTLI = rtli;
1133  }
1135  {
1136  /* We start the "latest" search from pg_control's timeline */
1138  }
1139  else
1140  {
1141  /*
1142  * else we just use the recoveryTargetTLI as already read from
1143  * ControlFile
1144  */
1146  }
1147 }
bool existsTimeLineHistory(TimeLineID probeTLI)
Definition: timeline.c:222
Datum timestamptz_in(PG_FUNCTION_ARGS)
Definition: timestamp.c:400
#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:124
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 2377 of file xlogrecovery.c.

2378 {
2379  RmgrData rmgr = GetRmgr(XLogRecGetRmid(record));
2380  RelFileLocator rlocator;
2381  ForkNumber forknum;
2382  BlockNumber blkno;
2383  int block_id;
2384 
2385  /* Records with no backup blocks have no need for consistency checks. */
2386  if (!XLogRecHasAnyBlockRefs(record))
2387  return;
2388 
2389  Assert((XLogRecGetInfo(record) & XLR_CHECK_CONSISTENCY) != 0);
2390 
2391  for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
2392  {
2393  Buffer buf;
2394  Page page;
2395 
2396  if (!XLogRecGetBlockTagExtended(record, block_id,
2397  &rlocator, &forknum, &blkno, NULL))
2398  {
2399  /*
2400  * WAL record doesn't contain a block reference with the given id.
2401  * Do nothing.
2402  */
2403  continue;
2404  }
2405 
2406  Assert(XLogRecHasBlockImage(record, block_id));
2407 
2408  if (XLogRecBlockImageApply(record, block_id))
2409  {
2410  /*
2411  * WAL record has already applied the page, so bypass the
2412  * consistency check as that would result in comparing the full
2413  * page stored in the record with itself.
2414  */
2415  continue;
2416  }
2417 
2418  /*
2419  * Read the contents from the current buffer and store it in a
2420  * temporary page.
2421  */
2422  buf = XLogReadBufferExtended(rlocator, forknum, blkno,
2424  InvalidBuffer);
2425  if (!BufferIsValid(buf))
2426  continue;
2427 
2429  page = BufferGetPage(buf);
2430 
2431  /*
2432  * Take a copy of the local page where WAL has been applied to have a
2433  * comparison base before masking it...
2434  */
2435  memcpy(replay_image_masked, page, BLCKSZ);
2436 
2437  /* No need for this page anymore now that a copy is in. */
2439 
2440  /*
2441  * If the block LSN is already ahead of this WAL record, we can't
2442  * expect contents to match. This can happen if recovery is
2443  * restarted.
2444  */
2445  if (PageGetLSN(replay_image_masked) > record->EndRecPtr)
2446  continue;
2447 
2448  /*
2449  * Read the contents from the backup copy, stored in WAL record and
2450  * store it in a temporary page. There is no need to allocate a new
2451  * page here, a local buffer is fine to hold its contents and a mask
2452  * can be directly applied on it.
2453  */
2454  if (!RestoreBlockImage(record, block_id, primary_image_masked))
2455  ereport(ERROR,
2456  (errcode(ERRCODE_INTERNAL_ERROR),
2457  errmsg_internal("%s", record->errormsg_buf)));
2458 
2459  /*
2460  * If masking function is defined, mask both the primary and replay
2461  * images
2462  */
2463  if (rmgr.rm_mask != NULL)
2464  {
2465  rmgr.rm_mask(replay_image_masked, blkno);
2466  rmgr.rm_mask(primary_image_masked, blkno);
2467  }
2468 
2469  /* Time to compare the primary and replay images. */
2470  if (memcmp(replay_image_masked, primary_image_masked, BLCKSZ) != 0)
2471  {
2472  elog(FATAL,
2473  "inconsistent page found, rel %u/%u/%u, forknum %u, blkno %u",
2474  rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
2475  forknum, blkno);
2476  }
2477  }
2478 }
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:4497
void LockBuffer(Buffer buffer, int mode)
Definition: bufmgr.c:4715
static Page BufferGetPage(Buffer buffer)
Definition: bufmgr.h:350
#define BUFFER_LOCK_EXCLUSIVE
Definition: bufmgr.h:159
@ RBM_NORMAL_NO_LOG
Definition: bufmgr.h:50
static bool BufferIsValid(Buffer bufnum)
Definition: bufmgr.h:301
Pointer Page
Definition: bufpage.h:78
static XLogRecPtr PageGetLSN(Page page)
Definition: bufpage.h:383
ForkNumber
Definition: relpath.h:48
RelFileNumber relNumber
void(* rm_mask)(char *pagedata, BlockNumber blkno)
char * errormsg_buf
Definition: xlogreader.h:311
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
Definition: xlogreader.c:2005
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
Definition: xlogreader.c:2064
#define XLogRecBlockImageApply(decoder, block_id)
Definition: xlogreader.h:425
#define XLogRecMaxBlockId(decoder)
Definition: xlogreader.h:418
#define XLogRecHasBlockImage(decoder, block_id)
Definition: xlogreader.h:423
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:417
Buffer XLogReadBufferExtended(RelFileLocator rlocator, ForkNumber forknum, BlockNumber blkno, ReadBufferMode mode, Buffer recent_buffer)
Definition: xlogutils.c:474

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

Referenced by ApplyWalRecord().

◆ WaitForWALToBecomeAvailable()

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

Definition at line 3457 of file xlogrecovery.c.

3461 {
3462  static TimestampTz last_fail_time = 0;
3463  TimestampTz now;
3464  bool streaming_reply_sent = false;
3465 
3466  /*-------
3467  * Standby mode is implemented by a state machine:
3468  *
3469  * 1. Read from either archive or pg_wal (XLOG_FROM_ARCHIVE), or just
3470  * pg_wal (XLOG_FROM_PG_WAL)
3471  * 2. Check for promotion trigger request
3472  * 3. Read from primary server via walreceiver (XLOG_FROM_STREAM)
3473  * 4. Rescan timelines
3474  * 5. Sleep wal_retrieve_retry_interval milliseconds, and loop back to 1.
3475  *
3476  * Failure to read from the current source advances the state machine to
3477  * the next state.
3478  *
3479  * 'currentSource' indicates the current state. There are no currentSource
3480  * values for "check trigger", "rescan timelines", and "sleep" states,
3481  * those actions are taken when reading from the previous source fails, as
3482  * part of advancing to the next state.
3483  *
3484  * If standby mode is turned off while reading WAL from stream, we move
3485  * to XLOG_FROM_ARCHIVE and reset lastSourceFailed, to force fetching
3486  * the files (which would be required at end of recovery, e.g., timeline
3487  * history file) from archive or pg_wal. We don't need to kill WAL receiver
3488  * here because it's already stopped when standby mode is turned off at
3489  * the end of recovery.
3490  *-------
3491  */
3492  if (!InArchiveRecovery)
3494  else if (currentSource == XLOG_FROM_ANY ||
3496  {
3497  lastSourceFailed = false;
3499  }
3500 
3501  for (;;)
3502  {
3503  XLogSource oldSource = currentSource;
3504  bool startWalReceiver = false;
3505 
3506  /*
3507  * First check if we failed to read from the current source, and
3508  * advance the state machine if so. The failure to read might've
3509  * happened outside this function, e.g when a CRC check fails on a
3510  * record, or within this loop.
3511  */
3512  if (lastSourceFailed)
3513  {
3514  /*
3515  * Don't allow any retry loops to occur during nonblocking
3516  * readahead. Let the caller process everything that has been
3517  * decoded already first.
3518  */
3519  if (nonblocking)
3520  return XLREAD_WOULDBLOCK;
3521 
3522  switch (currentSource)
3523  {
3524  case XLOG_FROM_ARCHIVE:
3525  case XLOG_FROM_PG_WAL:
3526 
3527  /*
3528  * Check to see if promotion is requested. Note that we do
3529  * this only after failure, so when you promote, we still
3530  * finish replaying as much as we can from archive and
3531  * pg_wal before failover.
3532  */
3534  {
3536  return XLREAD_FAIL;
3537  }
3538 
3539  /*
3540  * Not in standby mode, and we've now tried the archive
3541  * and pg_wal.
3542  */
3543  if (!StandbyMode)
3544  return XLREAD_FAIL;
3545 
3546  /*
3547  * Move to XLOG_FROM_STREAM state, and set to start a
3548  * walreceiver if necessary.
3549  */
3551  startWalReceiver = true;
3552  break;
3553 
3554  case XLOG_FROM_STREAM:
3555 
3556  /*
3557  * Failure while streaming. Most likely, we got here
3558  * because streaming replication was terminated, or
3559  * promotion was triggered. But we also get here if we
3560  * find an invalid record in the WAL streamed from the
3561  * primary, in which case something is seriously wrong.
3562  * There's little chance that the problem will just go
3563  * away, but PANIC is not good for availability either,
3564  * especially in hot standby mode. So, we treat that the
3565  * same as disconnection, and retry from archive/pg_wal
3566  * again. The WAL in the archive should be identical to
3567  * what was streamed, so it's unlikely that it helps, but
3568  * one can hope...
3569  */
3570 
3571  /*
3572  * We should be able to move to XLOG_FROM_STREAM only in
3573  * standby mode.
3574  */
3576 
3577  /*
3578  * Before we leave XLOG_FROM_STREAM state, make sure that
3579  * walreceiver is not active, so that it won't overwrite
3580  * WAL that we restore from archive.
3581  */
3583 
3584  /*
3585  * Before we sleep, re-scan for possible new timelines if
3586  * we were requested to recover to the latest timeline.
3587  */
3589  {
3590  if (rescanLatestTimeLine(replayTLI, replayLSN))
3591  {
3593  break;
3594  }
3595  }
3596 
3597  /*
3598  * XLOG_FROM_STREAM is the last state in our state
3599  * machine, so we've exhausted all the options for
3600  * obtaining the requested WAL. We're going to loop back
3601  * and retry from the archive, but if it hasn't been long
3602  * since last attempt, sleep wal_retrieve_retry_interval
3603  * milliseconds to avoid busy-waiting.
3604  */
3606  if (!TimestampDifferenceExceeds(last_fail_time, now,
3608  {
3609  long wait_time;
3610 
3611  wait_time = wal_retrieve_retry_interval -
3612  TimestampDifferenceMilliseconds(last_fail_time, now);
3613 
3614  elog(LOG, "waiting for WAL to become available at %X/%X",
3615  LSN_FORMAT_ARGS(RecPtr));
3616 
3617  /* Do background tasks that might benefit us later. */
3619 
3623  wait_time,
3624  WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL);
3627 
3628  /* Handle interrupt signals of startup process */
3630  }
3631  last_fail_time = now;
3633  break;
3634 
3635  default:
3636  elog(ERROR, "unexpected WAL source %d", currentSource);
3637  }
3638  }
3639  else if (currentSource == XLOG_FROM_PG_WAL)
3640  {
3641  /*
3642  * We just successfully read a file in pg_wal. We prefer files in
3643  * the archive over ones in pg_wal, so try the next file again
3644  * from the archive first.
3645  */
3646  if (InArchiveRecovery)
3648  }
3649 
3650  if (currentSource != oldSource)
3651  elog(DEBUG2, "switched WAL source from %s to %s after %s",
3653  lastSourceFailed ? "failure" : "success");
3654 
3655  /*
3656  * We've now handled possible failure. Try to read from the chosen
3657  * source.
3658  */
3659  lastSourceFailed = false;
3660 
3661  switch (currentSource)
3662  {
3663  case XLOG_FROM_ARCHIVE:
3664  case XLOG_FROM_PG_WAL:
3665 
3666  /*
3667  * WAL receiver must not be running when reading WAL from
3668  * archive or pg_wal.
3669  */
3670  Assert(!WalRcvStreaming());
3671 
3672  /* Close any old file we might have open. */
3673  if (readFile >= 0)
3674  {
3675  close(readFile);
3676  readFile = -1;
3677  }
3678  /* Reset curFileTLI if random fetch. */
3679  if (randAccess)
3680  curFileTLI = 0;
3681 
3682  /*
3683  * Try to restore the file from archive, or read an existing
3684  * file from pg_wal.
3685  */
3688  currentSource);
3689  if (readFile >= 0)
3690  return XLREAD_SUCCESS; /* success! */
3691 
3692  /*
3693  * Nope, not found in archive or pg_wal.
3694  */
3695  lastSourceFailed = true;
3696  break;
3697 
3698  case XLOG_FROM_STREAM:
3699  {
3700  bool havedata;
3701 
3702  /*
3703  * We should be able to move to XLOG_FROM_STREAM only in
3704  * standby mode.
3705  */
3707 
3708  /*
3709  * First, shutdown walreceiver if its restart has been
3710  * requested -- but no point if we're already slated for
3711  * starting it.
3712  */
3713  if (pendingWalRcvRestart && !startWalReceiver)
3714  {
3716 
3717  /*
3718  * Re-scan for possible new timelines if we were
3719  * requested to recover to the latest timeline.
3720  */
3723  rescanLatestTimeLine(replayTLI, replayLSN);
3724 
3725  startWalReceiver = true;
3726  }
3727  pendingWalRcvRestart = false;
3728 
3729  /*
3730  * Launch walreceiver if needed.
3731  *
3732  * If fetching_ckpt is true, RecPtr points to the initial
3733  * checkpoint location. In that case, we use RedoStartLSN
3734  * as the streaming start position instead of RecPtr, so
3735  * that when we later jump backwards to start redo at
3736  * RedoStartLSN, we will have the logs streamed already.
3737  */
3738  if (startWalReceiver &&
3739  PrimaryConnInfo && strcmp(PrimaryConnInfo, "") != 0)
3740  {
3741  XLogRecPtr ptr;
3742  TimeLineID tli;
3743 
3744  if (fetching_ckpt)
3745  {
3746  ptr = RedoStartLSN;
3747  tli = RedoStartTLI;
3748  }
3749  else
3750  {
3751  ptr = RecPtr;
3752 
3753  /*
3754  * Use the record begin position to determine the
3755  * TLI, rather than the position we're reading.
3756  */
3757  tli = tliOfPointInHistory(tliRecPtr, expectedTLEs);
3758 
3759  if (curFileTLI > 0 && tli < curFileTLI)
3760  elog(ERROR, "according to history file, WAL location %X/%X belongs to timeline %u, but previous recovered WAL file came from timeline %u",
3761  LSN_FORMAT_ARGS(tliRecPtr),
3762  tli, curFileTLI);
3763  }
3764  curFileTLI = tli;
3769  flushedUpto = 0;
3770  }
3771 
3772  /*
3773  * Check if WAL receiver is active or wait to start up.
3774  */
3775  if (!WalRcvStreaming())
3776  {
3777  lastSourceFailed = true;
3778  break;
3779  }
3780 
3781  /*
3782  * Walreceiver is active, so see if new data has arrived.
3783  *
3784  * We only advance XLogReceiptTime when we obtain fresh
3785  * WAL from walreceiver and observe that we had already
3786  * processed everything before the most recent "chunk"
3787  * that it flushed to disk. In steady state where we are
3788  * keeping up with the incoming data, XLogReceiptTime will
3789  * be updated on each cycle. When we are behind,
3790  * XLogReceiptTime will not advance, so the grace time
3791  * allotted to conflicting queries will decrease.
3792  */
3793  if (RecPtr < flushedUpto)
3794  havedata = true;
3795  else
3796  {
3797  XLogRecPtr latestChunkStart;
3798 
3799  flushedUpto = GetWalRcvFlushRecPtr(&latestChunkStart, &receiveTLI);
3800  if (RecPtr < flushedUpto && receiveTLI == curFileTLI)
3801  {
3802  havedata = true;
3803  if (latestChunkStart <= RecPtr)
3804  {
3807  }
3808  }
3809  else
3810  havedata = false;
3811  }
3812  if (havedata)
3813  {
3814  /*
3815  * Great, streamed far enough. Open the file if it's
3816  * not open already. Also read the timeline history
3817  * file if we haven't initialized timeline history
3818  * yet; it should be streamed over and present in
3819  * pg_wal by now. Use XLOG_FROM_STREAM so that source
3820  * info is set correctly and XLogReceiptTime isn't
3821  * changed.
3822  *
3823  * NB: We must set readTimeLineHistory based on
3824  * recoveryTargetTLI, not receiveTLI. Normally they'll
3825  * be the same, but if recovery_target_timeline is
3826  * 'latest' and archiving is configured, then it's
3827  * possible that we managed to retrieve one or more
3828  * new timeline history files from the archive,
3829  * updating recoveryTargetTLI.
3830  */
3831  if (readFile < 0)
3832  {
3833  if (!expectedTLEs)
3836  receiveTLI,
3837  XLOG_FROM_STREAM, false);
3838  Assert(readFile >= 0);
3839  }
3840  else
3841  {
3842  /* just make sure source info is correct... */
3845  return XLREAD_SUCCESS;
3846  }
3847  break;
3848  }
3849 
3850  /* In nonblocking mode, return rather than sleeping. */
3851  if (nonblocking)
3852  return XLREAD_WOULDBLOCK;
3853 
3854  /*
3855  * Data not here yet. Check for trigger, then wait for
3856  * walreceiver to wake us up when new WAL arrives.
3857  */
3858  if (CheckForStandbyTrigger())
3859  {
3860  /*
3861  * Note that we don't return XLREAD_FAIL immediately
3862  * here. After being triggered, we still want to
3863  * replay all the WAL that was already streamed. It's
3864  * in pg_wal now, so we just treat this as a failure,
3865  * and the state machine will move on to replay the
3866  * streamed WAL from pg_wal, and then recheck the
3867  * trigger and exit replay.
3868  */
3869  lastSourceFailed = true;
3870  break;
3871  }
3872 
3873  /*
3874  * Since we have replayed everything we have received so
3875  * far and are about to start waiting for more WAL, let's
3876  * tell the upstream server our replay location now so
3877  * that pg_stat_replication doesn't show stale
3878  * information.
3879  */
3880  if (!streaming_reply_sent)
3881  {
3882  WalRcvForceReply();
3883  streaming_reply_sent = true;
3884  }
3885 
3886  /* Do any background tasks that might benefit us later. */
3888 
3889  /* Update pg_stat_recovery_prefetch before sleeping. */
3891 
3892  /*
3893  * Wait for more WAL to arrive, when we will be woken
3894  * immediately by the WAL receiver.
3895  */
3898  -1L,
3899  WAIT_EVENT_RECOVERY_WAL_STREAM);
3901  break;
3902  }
3903 
3904  default:
3905  elog(ERROR, "unexpected WAL source %d", currentSource);
3906  }
3907 
3908  /*
3909  * Check for recovery pause here so that we can confirm more quickly
3910  * that a requested pause has actually taken effect.
3911  */
3912  if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
3914  recoveryPausesHere(false);
3915 
3916  /*
3917  * This possibly-long loop needs to handle interrupts of startup
3918  * process.
3919  */
3921  }
3922 
3923  return XLREAD_FAIL; /* not reached */
3924 }
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1719
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547
void KnownAssignedTransactionIdsIdleMaintenance(void)
Definition: procarray.c:4474
XLogRecPtr GetWalRcvFlushRecPtr(XLogRecPtr *latestChunkStart, TimeLineID *receiveTLI)
void RequestXLogStreaming(TimeLineID tli, XLogRecPtr recptr, const char *conninfo, const char *slotname, bool create_temp_slot)
void SetInstallXLogFileSegmentActive(void)
Definition: xlog.c:8974
int wal_retrieve_retry_interval
Definition: xlog.c:137
@ XLREAD_WOULDBLOCK
Definition: xlogreader.h:353
@ XLREAD_SUCCESS
Definition: xlogreader.h:351
@ XLREAD_FAIL