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

Go to the source code of this file.

Data Structures

struct  XLogPageReadPrivate
 

Macros

#define RECOVERY_COMMAND_FILE   "recovery.conf"
 
#define RECOVERY_COMMAND_DONE   "recovery.done"
 
#define ADD_TARGET_IF_SET(gucname, kind)
 

Typedefs

typedef struct XLogPageReadPrivate XLogPageReadPrivate
 

Enumerations

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

Functions

static void XLogRecoveryShmemRequest (void *arg)
 
static void XLogRecoveryShmemInit (void *arg)
 
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 chargetRecoveryStopReason (void)
 
static void recoveryPausesHere (bool endOfRecovery)
 
static bool recoveryApplyDelay (XLogReaderState *record)
 
static void ConfirmRecoveryPaused (void)
 
static XLogRecordReadRecord (XLogPrefetcher *xlogprefetcher, int emode, bool fetching_ckpt, TimeLineID replayTLI)
 
static int XLogPageRead (XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen, XLogRecPtr targetRecPtr, char *readBuf)
 
static XLogPageReadResult WaitForWALToBecomeAvailable (XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr, TimeLineID replayTLI, XLogRecPtr replayLSN, bool nonblocking)
 
static int emode_for_corrupt_record (int emode, XLogRecPtr RecPtr)
 
static XLogRecordReadCheckpointRecord (XLogPrefetcher *xlogprefetcher, XLogRecPtr RecPtr, TimeLineID replayTLI)
 
static bool rescanLatestTimeLine (TimeLineID replayTLI, XLogRecPtr replayLSN)
 
static int XLogFileRead (XLogSegNo segno, TimeLineID tli, XLogSource source, bool notfoundOk)
 
static int XLogFileReadAnyTLI (XLogSegNo segno, XLogSource source)
 
static bool CheckForStandbyTrigger (void)
 
static void SetPromoteIsTriggered (void)
 
static bool HotStandbyActiveInReplay (void)
 
static void SetCurrentChunkStartTime (TimestampTz xtime)
 
static void SetLatestXTime (TimestampTz xtime)
 
static RecoveryTargetType DetermineRecoveryTargetType (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)
 
bool check_recovery_target (char **newval, void **extra, GucSource source)
 
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)
 
bool check_recovery_target_time (char **newval, void **extra, GucSource source)
 
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 []
 
charrecoveryRestoreCommand = NULL
 
charrecoveryEndCommand = NULL
 
chararchiveCleanupCommand = NULL
 
RecoveryTargetType recoveryTarget = RECOVERY_TARGET_UNSET
 
bool recoveryTargetInclusive = true
 
int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE
 
TransactionId recoveryTargetXid
 
charrecovery_target_time_string
 
TimestampTz recoveryTargetTime
 
charrecoveryTargetName
 
XLogRecPtr recoveryTargetLSN
 
int recovery_min_apply_delay = 0
 
charPrimaryConnInfo = NULL
 
charPrimarySlotName = 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 = InvalidXLogRecPtr
 
static TimeLineID receiveTLI = 0
 
static XLogRecPtr minRecoveryPoint
 
static TimeLineID minRecoveryPointTLI
 
static XLogRecPtr backupStartPoint
 
static XLogRecPtr backupEndPoint
 
static bool backupEndRequired = false
 
bool reachedConsistency = false
 
static charreplay_image_masked = NULL
 
static charprimary_image_masked = NULL
 
XLogRecoveryCtlDataXLogRecoveryCtl = NULL
 
const ShmemCallbacks XLogRecoveryShmemCallbacks
 
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

◆ ADD_TARGET_IF_SET

#define ADD_TARGET_IF_SET (   gucname,
  kind 
)
Value:
do { \
val = GetConfigOption(gucname, false, false); \
if (val[0] != '\0') \
{ \
ntargets++; \
target = (kind); \
if (buf.len == 0) \
appendStringInfo(&buf, _("\"%s\""), gucname); \
appendStringInfo(&buf, _(", \"%s\""), gucname); \
} \
} while (0)
#define _(x)
Definition elog.c:96
const char * GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged)
Definition guc.c:4257
long val
Definition informix.c:689
static char buf[DEFAULT_XLOG_SEG_SIZE]
static int fb(int x)

◆ RECOVERY_COMMAND_DONE

#define RECOVERY_COMMAND_DONE   "recovery.done"

Definition at line 74 of file xlogrecovery.c.

◆ RECOVERY_COMMAND_FILE

#define RECOVERY_COMMAND_FILE   "recovery.conf"

Definition at line 73 of file xlogrecovery.c.

Typedef Documentation

◆ XLogPageReadPrivate

Enumeration Type Documentation

◆ XLogSource

Enumerator
XLOG_FROM_ANY 
XLOG_FROM_ARCHIVE 
XLOG_FROM_PG_WAL 
XLOG_FROM_STREAM 

Definition at line 214 of file xlogrecovery.c.

215{
216 XLOG_FROM_ANY = 0, /* request to read WAL from any source */
217 XLOG_FROM_ARCHIVE, /* restored using restore_command */
218 XLOG_FROM_PG_WAL, /* existing file in pg_wal */
219 XLOG_FROM_STREAM, /* streamed from primary */
220} XLogSource;
XLogSource
@ XLOG_FROM_PG_WAL
@ XLOG_FROM_STREAM
@ XLOG_FROM_ARCHIVE
@ XLOG_FROM_ANY

Function Documentation

◆ ApplyWalRecord()

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

Definition at line 1888 of file xlogrecovery.c.

1889{
1890 ErrorContextCallback errcallback;
1891 bool switchedTLI = false;
1892
1893 /* Setup error traceback support for ereport() */
1894 errcallback.callback = rm_redo_error_callback;
1895 errcallback.arg = xlogreader;
1896 errcallback.previous = error_context_stack;
1897 error_context_stack = &errcallback;
1898
1899 /*
1900 * TransamVariables->nextXid must be beyond record's xid.
1901 */
1903
1904 /*
1905 * Before replaying this record, check if this record causes the current
1906 * timeline to change. The record is already considered to be part of the
1907 * new timeline, so we update replayTLI before replaying it. That's
1908 * important so that replayEndTLI, which is recorded as the minimum
1909 * recovery point's TLI if recovery stops after this record, is set
1910 * correctly.
1911 */
1912 if (record->xl_rmid == RM_XLOG_ID)
1913 {
1914 TimeLineID newReplayTLI = *replayTLI;
1915 TimeLineID prevReplayTLI = *replayTLI;
1916 uint8 info = record->xl_info & ~XLR_INFO_MASK;
1917
1918 if (info == XLOG_CHECKPOINT_SHUTDOWN)
1919 {
1920 CheckPoint checkPoint;
1921
1922 memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
1923 newReplayTLI = checkPoint.ThisTimeLineID;
1924 prevReplayTLI = checkPoint.PrevTimeLineID;
1925 }
1926 else if (info == XLOG_END_OF_RECOVERY)
1927 {
1929
1931 newReplayTLI = xlrec.ThisTimeLineID;
1932 prevReplayTLI = xlrec.PrevTimeLineID;
1933 }
1934
1935 if (newReplayTLI != *replayTLI)
1936 {
1937 /* Check that it's OK to switch to this TLI */
1939 newReplayTLI, prevReplayTLI, *replayTLI);
1940
1941 /* Following WAL records should be run with new TLI */
1942 *replayTLI = newReplayTLI;
1943 switchedTLI = true;
1944 }
1945 }
1946
1947 /*
1948 * Update shared replayEndRecPtr before replaying this record, so that
1949 * XLogFlush will update minRecoveryPoint correctly.
1950 */
1953 XLogRecoveryCtl->replayEndTLI = *replayTLI;
1955
1956 /*
1957 * If we are attempting to enter Hot Standby mode, process XIDs we see
1958 */
1962
1963 /*
1964 * Some XLOG record types that are related to recovery are processed
1965 * directly here, rather than in xlog_redo()
1966 */
1967 if (record->xl_rmid == RM_XLOG_ID)
1968 xlogrecovery_redo(xlogreader, *replayTLI);
1969
1970 /* Now apply the WAL record itself */
1972
1973 /*
1974 * After redo, check whether the backup pages associated with the WAL
1975 * record are consistent with the existing pages. This check is done only
1976 * if consistency check is enabled for this record.
1977 */
1978 if ((record->xl_info & XLR_CHECK_CONSISTENCY) != 0)
1980
1981 /* Pop the error context stack */
1982 error_context_stack = errcallback.previous;
1983
1984 /*
1985 * Update lastReplayedEndRecPtr after this record has been successfully
1986 * replayed.
1987 */
1991 XLogRecoveryCtl->lastReplayedTLI = *replayTLI;
1993
1994 /* ------
1995 * Wakeup walsenders:
1996 *
1997 * On the standby, the WAL is flushed first (which will only wake up
1998 * physical walsenders) and then applied, which will only wake up logical
1999 * walsenders.
2000 *
2001 * Indeed, logical walsenders on standby can't decode and send data until
2002 * it's been applied.
2003 *
2004 * Physical walsenders don't need to be woken up during replay unless
2005 * cascading replication is allowed and time line change occurred (so that
2006 * they can notice that they are on a new time line).
2007 *
2008 * That's why the wake up conditions are for:
2009 *
2010 * - physical walsenders in case of new time line and cascade
2011 * replication is allowed
2012 * - logical walsenders in case cascade replication is allowed (could not
2013 * be created otherwise)
2014 * ------
2015 */
2018
2019 /*
2020 * If rm_redo called XLogRequestWalReceiverReply, then we wake up the
2021 * receiver so that it notices the updated lastReplayedEndRecPtr and sends
2022 * a reply to the primary.
2023 */
2025 {
2028 }
2029
2030 /* Allow read-only connections if we're consistent now */
2032
2033 /* Is this a timeline switch? */
2034 if (switchedTLI)
2035 {
2036 /*
2037 * Before we continue on the new timeline, clean up any (possibly
2038 * bogus) future WAL segments on the old timeline.
2039 */
2041
2042 /* Reset the prefetcher. */
2044 }
2045}
uint8_t uint8
Definition c.h:681
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
ErrorContextCallback * error_context_stack
Definition elog.c:100
#define XLOG_CHECKPOINT_SHUTDOWN
Definition pg_control.h:72
#define XLOG_END_OF_RECOVERY
Definition pg_control.h:81
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition procarray.c:4443
static void SpinLockRelease(volatile slock_t *lock)
Definition spin.h:62
static void SpinLockAcquire(volatile slock_t *lock)
Definition spin.h:56
TimeLineID PrevTimeLineID
Definition pg_control.h:40
TimeLineID ThisTimeLineID
Definition pg_control.h:39
struct ErrorContextCallback * previous
Definition elog.h:299
void(* callback)(void *arg)
Definition elog.h:300
void(* rm_redo)(XLogReaderState *record)
XLogRecPtr EndRecPtr
Definition xlogreader.h:206
XLogRecPtr ReadRecPtr
Definition xlogreader.h:205
uint8 xl_info
Definition xlogrecord.h:46
TransactionId xl_xid
Definition xlogrecord.h:44
RmgrId xl_rmid
Definition xlogrecord.h:47
XLogRecPtr lastReplayedEndRecPtr
TimeLineID replayEndTLI
TimeLineID lastReplayedTLI
XLogRecPtr replayEndRecPtr
XLogRecPtr lastReplayedReadRecPtr
#define TransactionIdIsValid(xid)
Definition transam.h:41
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition varsup.c:299
void WalRcvRequestApplyReply(void)
#define AllowCascadeReplication()
Definition walreceiver.h:40
void WalSndWakeup(bool physical, bool logical)
Definition walsender.c:4050
void RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
Definition xlog.c:3990
static RmgrData GetRmgr(RmgrId rmid)
uint32 TimeLineID
Definition xlogdefs.h:63
void XLogPrefetchReconfigure(void)
#define XLogRecGetData(decoder)
Definition xlogreader.h:415
#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)
XLogRecoveryCtlData * XLogRecoveryCtl
static bool doRequestWalReceiverReply
static XLogReaderState * xlogreader
HotStandbyState standbyState
Definition xlogutils.c:53
@ STANDBY_INITIALIZED
Definition xlogutils.h:53

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

Referenced by PerformWalRecovery().

◆ assign_recovery_target_lsn()

void assign_recovery_target_lsn ( const char newval,
void extra 
)

Definition at line 4866 of file xlogrecovery.c.

4867{
4868 if (newval && strcmp(newval, "") != 0)
4869 recoveryTargetLSN = *((XLogRecPtr *) extra);
4870}
#define newval
uint64 XLogRecPtr
Definition xlogdefs.h:21
XLogRecPtr recoveryTargetLSN

References fb(), newval, and recoveryTargetLSN.

◆ assign_recovery_target_timeline()

void assign_recovery_target_timeline ( const char newval,
void extra 
)

Definition at line 5000 of file xlogrecovery.c.

5001{
5005 else
5007}
RecoveryTargetTimeLineGoal recoveryTargetTimeLineGoal
TimeLineID recoveryTargetTLIRequested
RecoveryTargetTimeLineGoal
@ RECOVERY_TARGET_TIMELINE_NUMERIC

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

5066{
5067 if (newval && strcmp(newval, "") != 0)
5068 recoveryTargetXid = *((TransactionId *) extra);
5069}
uint32 TransactionId
Definition c.h:795
TransactionId recoveryTargetXid

References fb(), newval, and recoveryTargetXid.

◆ check_primary_slot_name()

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

Definition at line 4756 of file xlogrecovery.c.

4757{
4758 int err_code;
4759 char *err_msg = NULL;
4760 char *err_hint = NULL;
4761
4762 if (*newval && strcmp(*newval, "") != 0 &&
4764 &err_msg, &err_hint))
4765 {
4767 GUC_check_errdetail("%s", err_msg);
4768 if (err_hint != NULL)
4770 return false;
4771 }
4772
4773 return true;
4774}
void GUC_check_errcode(int sqlerrcode)
Definition guc.c:6666
#define GUC_check_errdetail
Definition guc.h:508
#define GUC_check_errhint
Definition guc.h:512
bool ReplicationSlotValidateNameInternal(const char *name, bool allow_reserved_name, int *err_code, char **err_msg, char **err_hint)
Definition slot.c:310

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

◆ check_recovery_target()

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

Definition at line 4827 of file xlogrecovery.c.

4828{
4829 if (strcmp(*newval, "immediate") != 0 && strcmp(*newval, "") != 0)
4830 {
4831 GUC_check_errdetail("The only allowed value is \"immediate\".");
4832 return false;
4833 }
4834 return true;
4835}

References fb(), GUC_check_errdetail, and newval.

◆ check_recovery_target_lsn()

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

Definition at line 4841 of file xlogrecovery.c.

4842{
4843 if (strcmp(*newval, "") != 0)
4844 {
4845 XLogRecPtr lsn;
4848
4849 lsn = pg_lsn_in_safe(*newval, (Node *) &escontext);
4850 if (escontext.error_occurred)
4851 return false;
4852
4853 myextra = (XLogRecPtr *) guc_malloc(LOG, sizeof(XLogRecPtr));
4854 if (!myextra)
4855 return false;
4856 *myextra = lsn;
4857 *extra = myextra;
4858 }
4859 return true;
4860}
#define LOG
Definition elog.h:32
void * guc_malloc(int elevel, size_t size)
Definition guc.c:637
XLogRecPtr pg_lsn_in_safe(const char *str, Node *escontext)
Definition pg_lsn.c:32
Definition nodes.h:133

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

◆ check_recovery_target_name()

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

Definition at line 4876 of file xlogrecovery.c.

4877{
4878 /* Use the value of newval directly */
4879 if (strlen(*newval) >= MAXFNAMELEN)
4880 {
4881 GUC_check_errdetail("\"%s\" is too long (maximum %d characters).",
4882 "recovery_target_name", MAXFNAMELEN - 1);
4883 return false;
4884 }
4885 return true;
4886}
#define MAXFNAMELEN

References fb(), GUC_check_errdetail, MAXFNAMELEN, and newval.

◆ check_recovery_target_time()

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

Definition at line 4898 of file xlogrecovery.c.

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

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

◆ check_recovery_target_timeline()

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

Definition at line 4953 of file xlogrecovery.c.

4954{
4957
4958 if (strcmp(*newval, "current") == 0)
4960 else if (strcmp(*newval, "latest") == 0)
4962 else
4963 {
4964 char *endp;
4965 uint64 timeline;
4966
4968
4969 errno = 0;
4970 timeline = strtou64(*newval, &endp, 0);
4971
4972 if (*endp != '\0' || errno == EINVAL || errno == ERANGE)
4973 {
4974 GUC_check_errdetail("\"%s\" is not a valid number.",
4975 "recovery_target_timeline");
4976 return false;
4977 }
4978
4980 {
4981 GUC_check_errdetail("\"%s\" must be between %u and %u.",
4982 "recovery_target_timeline", 1, PG_UINT32_MAX);
4983 return false;
4984 }
4985 }
4986
4988 if (!myextra)
4989 return false;
4990 *myextra = rttg;
4991 *extra = myextra;
4992
4993 return true;
4994}
#define PG_UINT32_MAX
Definition c.h:733
uint64_t uint64
Definition c.h:684
#define EINVAL
Definition private.h:69
@ RECOVERY_TARGET_TIMELINE_CONTROLFILE
@ RECOVERY_TARGET_TIMELINE_LATEST

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

◆ check_recovery_target_xid()

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

Definition at line 5013 of file xlogrecovery.c.

5014{
5015 if (strcmp(*newval, "") != 0)
5016 {
5017 TransactionId xid;
5019 char *endp;
5020 char *val;
5021
5022 errno = 0;
5023
5024 /*
5025 * Consume leading whitespace to determine if number is negative
5026 */
5027 val = *newval;
5028
5029 while (isspace((unsigned char) *val))
5030 val++;
5031
5032 /*
5033 * This cast will remove the epoch, if any
5034 */
5035 xid = (TransactionId) strtou64(val, &endp, 0);
5036
5037 if (*endp != '\0' || errno == EINVAL || errno == ERANGE || *val == '-')
5038 {
5039 GUC_check_errdetail("\"%s\" is not a valid number.",
5040 "recovery_target_xid");
5041 return false;
5042 }
5043
5044 if (xid < FirstNormalTransactionId)
5045 {
5046 GUC_check_errdetail("\"%s\" without epoch must be greater than or equal to %u.",
5047 "recovery_target_xid",
5049 return false;
5050 }
5051
5053 if (!myextra)
5054 return false;
5055 *myextra = xid;
5056 *extra = myextra;
5057 }
5058 return true;
5059}
#define FirstNormalTransactionId
Definition transam.h:34

References EINVAL, fb(), FirstNormalTransactionId, GUC_check_errdetail, guc_malloc(), LOG, newval, and val.

◆ CheckForStandbyTrigger()

static bool CheckForStandbyTrigger ( void  )
static

Definition at line 4449 of file xlogrecovery.c.

4450{
4452 return true;
4453
4455 {
4456 ereport(LOG, (errmsg("received promote request")));
4460 return true;
4461 }
4462
4463 return false;
4464}
bool IsPromoteSignaled(void)
Definition startup.c:287
void ResetPromoteSignaled(void)
Definition startup.c:293
#define ereport(elevel,...)
Definition elog.h:152
static char * errmsg
bool CheckPromoteSignal(void)
static bool LocalPromoteIsTriggered
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 4479 of file xlogrecovery.c.

4480{
4481 struct stat stat_buf;
4482
4483 if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
4484 return true;
4485
4486 return false;
4487}
#define stat
Definition win32_port.h:74
#define PROMOTE_SIGNAL_FILE
Definition xlog.h:341

References fb(), PROMOTE_SIGNAL_FILE, and stat.

Referenced by CheckForStandbyTrigger(), and process_pm_pmsignal().

◆ CheckRecoveryConsistency()

static void CheckRecoveryConsistency ( void  )
static

Definition at line 2156 of file xlogrecovery.c.

2157{
2158 XLogRecPtr lastReplayedEndRecPtr;
2159 TimeLineID lastReplayedTLI;
2160
2161 /*
2162 * During crash recovery, we don't reach a consistent state until we've
2163 * replayed all the WAL.
2164 */
2166 return;
2167
2169
2170 /*
2171 * assume that we are called in the startup process, and hence don't need
2172 * a lock to read lastReplayedEndRecPtr
2173 */
2174 lastReplayedEndRecPtr = XLogRecoveryCtl->lastReplayedEndRecPtr;
2175 lastReplayedTLI = XLogRecoveryCtl->lastReplayedTLI;
2176
2177 /*
2178 * Have we reached the point where our base backup was completed?
2179 */
2181 backupEndPoint <= lastReplayedEndRecPtr)
2182 {
2185
2186 elog(DEBUG1, "end of backup reached");
2187
2188 /*
2189 * We have reached the end of base backup, as indicated by pg_control.
2190 * Update the control file accordingly.
2191 */
2192 ReachedEndOfBackup(lastReplayedEndRecPtr, lastReplayedTLI);
2195 backupEndRequired = false;
2196
2197 ereport(LOG,
2198 errmsg("completed backup recovery with redo LSN %X/%08X and end LSN %X/%08X",
2201 }
2202
2203 /*
2204 * Have we passed our safe starting point? Note that minRecoveryPoint is
2205 * known to be incorrectly set if recovering from a backup, until the
2206 * XLOG_BACKUP_END arrives to advise us of the correct minRecoveryPoint.
2207 * All we know prior to that is that we're not consistent yet.
2208 */
2210 minRecoveryPoint <= lastReplayedEndRecPtr)
2211 {
2212 /*
2213 * Check to see if the XLOG sequence contained any unresolved
2214 * references to uninitialized pages.
2215 */
2217
2218 /*
2219 * Check that pg_tblspc doesn't contain any real directories. Replay
2220 * of Database/CREATE_* records may have created fictitious tablespace
2221 * directories that should have been removed by the time consistency
2222 * was reached.
2223 */
2225
2226 reachedConsistency = true;
2228 ereport(LOG,
2229 errmsg("consistent recovery state reached at %X/%08X",
2230 LSN_FORMAT_ARGS(lastReplayedEndRecPtr)));
2231 }
2232
2233 /*
2234 * Have we got a valid starting snapshot that will allow queries to be
2235 * run? If so, we can tell postmaster that the database is consistent now,
2236 * enabling connections.
2237 */
2242 {
2246
2247 LocalHotStandbyActive = true;
2248
2250 }
2251}
#define Assert(condition)
Definition c.h:1002
#define DEBUG1
Definition elog.h:31
#define elog(elevel,...)
Definition elog.h:228
bool IsUnderPostmaster
Definition globals.c:122
void SendPostmasterSignal(PMSignalReason reason)
Definition pmsignal.c:164
@ PMSIGNAL_BEGIN_HOT_STANDBY
Definition pmsignal.h:37
@ PMSIGNAL_RECOVERY_CONSISTENT
Definition pmsignal.h:36
void ReachedEndOfBackup(XLogRecPtr EndRecPtr, TimeLineID tli)
Definition xlog.c:6748
#define XLogRecPtrIsValid(r)
Definition xlogdefs.h:29
#define LSN_FORMAT_ARGS(lsn)
Definition xlogdefs.h:47
#define InvalidXLogRecPtr
Definition xlogdefs.h:28
bool reachedConsistency
static bool backupEndRequired
static XLogRecPtr minRecoveryPoint
static XLogRecPtr backupEndPoint
bool InArchiveRecovery
static bool LocalHotStandbyActive
static void CheckTablespaceDirectory(void)
static XLogRecPtr backupStartPoint
void XLogCheckInvalidPages(void)
Definition xlogutils.c:234
@ STANDBY_SNAPSHOT_READY
Definition xlogutils.h:55

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

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

◆ CheckTablespaceDirectory()

static void CheckTablespaceDirectory ( void  )
static

Definition at line 2123 of file xlogrecovery.c.

2124{
2125 DIR *dir;
2126 struct dirent *de;
2127
2129 while ((de = ReadDir(dir, PG_TBLSPC_DIR)) != NULL)
2130 {
2131 char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR)];
2132
2133 /* Skip entries of non-oid names */
2134 if (strspn(de->d_name, "0123456789") != strlen(de->d_name))
2135 continue;
2136
2137 snprintf(path, sizeof(path), "%s/%s", PG_TBLSPC_DIR, de->d_name);
2138
2139 if (get_dirent_type(path, de, false, ERROR) != PGFILETYPE_LNK)
2142 errmsg("unexpected directory entry \"%s\" found in %s",
2144 errdetail("All directory entries in %s/ should be symbolic links.",
2146 errhint("Remove those directories, or set \"allow_in_place_tablespaces\" to ON transiently to let recovery complete.")));
2147 }
2148}
bool allow_in_place_tablespaces
Definition tablespace.c:87
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
#define PANIC
Definition elog.h:44
#define ERROR
Definition elog.h:40
DIR * AllocateDir(const char *dirname)
Definition fd.c:2891
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition fd.c:2957
PGFileType get_dirent_type(const char *path, const struct dirent *de, bool look_through_symlinks, int elevel)
Definition file_utils.c:547
@ PGFILETYPE_LNK
Definition file_utils.h:24
#define ERRCODE_DATA_CORRUPTED
#define MAXPGPATH
#define snprintf
Definition port.h:261
#define PG_TBLSPC_DIR
Definition relpath.h:41
Definition dirent.c:26
char d_name[MAX_PATH]
Definition dirent.h:15

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

Referenced by CheckRecoveryConsistency().

◆ checkTimeLineSwitch()

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

Definition at line 2359 of file xlogrecovery.c.

2361{
2362 /* Check that the record agrees on what the current (old) timeline is */
2363 if (prevTLI != replayTLI)
2364 ereport(PANIC,
2365 (errmsg("unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record",
2366 prevTLI, replayTLI)));
2367
2368 /*
2369 * The new timeline better be in the list of timelines we expect to see,
2370 * according to the timeline history. It should also not decrease.
2371 */
2372 if (newTLI < replayTLI || !tliInHistory(newTLI, expectedTLEs))
2373 ereport(PANIC,
2374 (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
2375 newTLI, replayTLI)));
2376
2377 /*
2378 * If we have not yet reached min recovery point, and we're about to
2379 * switch to a timeline greater than the timeline of the min recovery
2380 * point: trouble. After switching to the new timeline, we could not
2381 * possibly visit the min recovery point on the correct timeline anymore.
2382 * This can happen if there is a newer timeline in the archive that
2383 * branched before the timeline the min recovery point is on, and you
2384 * attempt to do PITR to the new timeline.
2385 */
2387 lsn < minRecoveryPoint &&
2389 ereport(PANIC,
2390 errmsg("unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%08X on timeline %u",
2391 newTLI,
2394
2395 /* Looks good */
2396}
bool tliInHistory(TimeLineID tli, List *expectedTLEs)
Definition timeline.c:527
static List * expectedTLEs
static TimeLineID minRecoveryPointTLI

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

Referenced by ApplyWalRecord().

◆ ConfirmRecoveryPaused()

◆ DetermineRecoveryTargetType()

static RecoveryTargetType DetermineRecoveryTargetType ( void  )
static

Definition at line 4781 of file xlogrecovery.c.

4782{
4783 int ntargets = 0;
4785 const char *val;
4787
4789
4790#define ADD_TARGET_IF_SET(gucname, kind) \
4791 do { \
4792 val = GetConfigOption(gucname, false, false); \
4793 if (val[0] != '\0') \
4794 { \
4795 ntargets++; \
4796 target = (kind); \
4797 if (buf.len == 0) \
4798 appendStringInfo(&buf, _("\"%s\""), gucname); \
4799 else \
4800 appendStringInfo(&buf, _(", \"%s\""), gucname); \
4801 } \
4802 } while (0)
4803
4804 ADD_TARGET_IF_SET("recovery_target", RECOVERY_TARGET_IMMEDIATE);
4805 ADD_TARGET_IF_SET("recovery_target_lsn", RECOVERY_TARGET_LSN);
4806 ADD_TARGET_IF_SET("recovery_target_name", RECOVERY_TARGET_NAME);
4807 ADD_TARGET_IF_SET("recovery_target_time", RECOVERY_TARGET_TIME);
4808 ADD_TARGET_IF_SET("recovery_target_xid", RECOVERY_TARGET_XID);
4809#undef ADD_TARGET_IF_SET
4810
4811 if (ntargets > 1)
4812 ereport(FATAL,
4814 errmsg("cannot specify more than one recovery target"),
4815 errdetail("Parameters set are: %s.",
4816 buf.data));
4817
4818 pfree(buf.data);
4819
4820 return target;
4821}
#define FATAL
Definition elog.h:42
void pfree(void *pointer)
Definition mcxt.c:1619
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
#define ADD_TARGET_IF_SET(gucname, kind)
RecoveryTargetType
@ RECOVERY_TARGET_IMMEDIATE
@ RECOVERY_TARGET_TIME
@ RECOVERY_TARGET_UNSET
@ RECOVERY_TARGET_XID
@ RECOVERY_TARGET_LSN
@ RECOVERY_TARGET_NAME

References ADD_TARGET_IF_SET, buf, ereport, errcode(), errdetail(), errmsg, FATAL, fb(), initStringInfo(), pfree(), RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_LSN, RECOVERY_TARGET_NAME, RECOVERY_TARGET_TIME, RECOVERY_TARGET_UNSET, RECOVERY_TARGET_XID, and val.

Referenced by validateRecoveryParameters().

◆ emode_for_corrupt_record()

static int emode_for_corrupt_record ( int  emode,
XLogRecPtr  RecPtr 
)
static

Definition at line 4048 of file xlogrecovery.c.

4049{
4051
4052 if (readSource == XLOG_FROM_PG_WAL && emode == LOG)
4053 {
4054 if (RecPtr == lastComplaint)
4055 emode = DEBUG1;
4056 else
4058 }
4059 return emode;
4060}
static XLogSource readSource

References DEBUG1, fb(), InvalidXLogRecPtr, LOG, readSource, and XLOG_FROM_PG_WAL.

Referenced by ReadRecord(), and XLogPageRead().

◆ EnableStandbyMode()

static void EnableStandbyMode ( void  )
static

Definition at line 425 of file xlogrecovery.c.

426{
427 StandbyMode = true;
428
429 /*
430 * To avoid server log bloat, we don't report recovery progress in a
431 * standby as it will always be in recovery unless promoted. We disable
432 * startup progress timeout in standby mode to avoid calling
433 * startup_progress_timeout_handler() unnecessarily.
434 */
436}
void disable_startup_progress_timeout(void)
Definition startup.c:308
bool StandbyMode

References disable_startup_progress_timeout(), and StandbyMode.

Referenced by InitWalRecovery(), and ReadRecord().

◆ FinishWalRecovery()

EndOfWalRecoveryInfo * FinishWalRecovery ( void  )

Definition at line 1422 of file xlogrecovery.c.

1423{
1425 XLogRecPtr lastRec;
1426 TimeLineID lastRecTLI;
1427 XLogRecPtr endOfLog;
1428
1429 /*
1430 * Kill WAL receiver, if it's still running, before we continue to write
1431 * the startup checkpoint and aborted-contrecord records. It will trump
1432 * over these records and subsequent ones if it's still alive when we
1433 * start writing WAL.
1434 */
1436
1437 /*
1438 * Shutdown the slot sync worker to drop any temporary slots acquired by
1439 * it and to prevent it from keep trying to fetch the failover slots.
1440 *
1441 * We do not update the 'synced' column in 'pg_replication_slots' system
1442 * view from true to false here, as any failed update could leave 'synced'
1443 * column false for some slots. This could cause issues during slot sync
1444 * after restarting the server as a standby. While updating the 'synced'
1445 * column after switching to the new timeline is an option, it does not
1446 * simplify the handling for the 'synced' column. Therefore, we retain the
1447 * 'synced' column as true after promotion as it may provide useful
1448 * information about the slot origin.
1449 */
1451
1452 /*
1453 * We are now done reading the xlog from stream. Turn off streaming
1454 * recovery to force fetching the files (which would be required at end of
1455 * recovery, e.g., timeline history file) from archive or pg_wal.
1456 *
1457 * Note that standby mode must be turned off after killing WAL receiver,
1458 * i.e., calling XLogShutdownWalRcv().
1459 */
1461 StandbyMode = false;
1462
1463 /*
1464 * Determine where to start writing WAL next.
1465 *
1466 * Re-fetch the last valid or last applied record, so we can identify the
1467 * exact endpoint of what we consider the valid portion of WAL. There may
1468 * be an incomplete continuation record after that, in which case
1469 * 'abortedRecPtr' and 'missingContrecPtr' are set and the caller will
1470 * write a special OVERWRITE_CONTRECORD message to mark that the rest of
1471 * it is intentionally missing. See CreateOverwriteContrecordRecord().
1472 *
1473 * An important side-effect of this is to load the last page into
1474 * xlogreader. The caller uses it to initialize the WAL for writing.
1475 */
1476 if (!InRecovery)
1477 {
1478 lastRec = CheckPointLoc;
1479 lastRecTLI = CheckPointTLI;
1480 }
1481 else
1482 {
1484 lastRecTLI = XLogRecoveryCtl->lastReplayedTLI;
1485 }
1487 (void) ReadRecord(xlogprefetcher, PANIC, false, lastRecTLI);
1488 endOfLog = xlogreader->EndRecPtr;
1489
1490 /*
1491 * Remember the TLI in the filename of the XLOG segment containing the
1492 * end-of-log. It could be different from the timeline that endOfLog
1493 * nominally belongs to, if there was a timeline switch in that segment,
1494 * and we were reading the old WAL from a segment belonging to a higher
1495 * timeline.
1496 */
1497 result->endOfLogTLI = xlogreader->seg.ws_tli;
1498
1500 {
1501 /*
1502 * We are no longer in archive recovery state.
1503 *
1504 * We are now done reading the old WAL. Turn off archive fetching if
1505 * it was active.
1506 */
1508 InArchiveRecovery = false;
1509
1510 /*
1511 * If the ending log segment is still open, close it (to avoid
1512 * problems on Windows with trying to rename or delete an open file).
1513 */
1514 if (readFile >= 0)
1515 {
1516 close(readFile);
1517 readFile = -1;
1518 }
1519 }
1520
1521 /*
1522 * Copy the last partial block to the caller, for initializing the WAL
1523 * buffer for appending new WAL.
1524 */
1525 if (endOfLog % XLOG_BLCKSZ != 0)
1526 {
1527 char *page;
1528 int len;
1530
1531 pageBeginPtr = endOfLog - (endOfLog % XLOG_BLCKSZ);
1533
1534 /* Copy the valid part of the last block */
1535 len = endOfLog % XLOG_BLCKSZ;
1536 page = palloc(len);
1537 memcpy(page, xlogreader->readBuf, len);
1538
1539 result->lastPageBeginPtr = pageBeginPtr;
1540 result->lastPage = page;
1541 }
1542 else
1543 {
1544 /* There is no partial block to copy. */
1545 result->lastPageBeginPtr = endOfLog;
1546 result->lastPage = NULL;
1547 }
1548
1549 /*
1550 * Create a comment for the history file to explain why and where timeline
1551 * changed.
1552 */
1553 result->recoveryStopReason = getRecoveryStopReason();
1554
1555 result->lastRec = lastRec;
1556 result->lastRecTLI = lastRecTLI;
1557 result->endOfLog = endOfLog;
1558
1559 result->abortedRecPtr = abortedRecPtr;
1560 result->missingContrecPtr = missingContrecPtr;
1561
1562 result->standby_signal_file_found = standby_signal_file_found;
1563 result->recovery_signal_file_found = recovery_signal_file_found;
1564
1565 return result;
1566}
uint32 result
#define palloc_object(type)
Definition fe_memutils.h:89
#define close(a)
Definition win32.h:12
void * palloc(Size size)
Definition mcxt.c:1390
const void size_t len
void ShutDownSlotSync(void)
Definition slotsync.c:1830
TimeLineID ws_tli
Definition xlogreader.h:49
WALOpenSegment seg
Definition xlogreader.h:271
bool WalRcvStreaming(void)
int wal_segment_size
Definition xlog.c:150
void XLogShutdownWalRcv(void)
Definition xlog.c:10149
#define XLogSegmentOffset(xlogptr, wal_segsz_bytes)
void XLogPrefetcherBeginRead(XLogPrefetcher *prefetcher, XLogRecPtr recPtr)
static char * getRecoveryStopReason(void)
bool ArchiveRecoveryRequested
static XLogRecPtr missingContrecPtr
static uint32 readOff
static bool standby_signal_file_found
static int readFile
static XLogRecPtr abortedRecPtr
static XLogRecord * ReadRecord(XLogPrefetcher *xlogprefetcher, int emode, bool fetching_ckpt, TimeLineID replayTLI)
static XLogRecPtr CheckPointLoc
static bool recovery_signal_file_found
static XLogPrefetcher * xlogprefetcher
static TimeLineID CheckPointTLI
bool InRecovery
Definition xlogutils.c:50

References abortedRecPtr, ArchiveRecoveryRequested, Assert, CheckPointLoc, CheckPointTLI, close, XLogReaderState::EndRecPtr, fb(), getRecoveryStopReason(), InArchiveRecovery, InRecovery, XLogRecoveryCtlData::lastReplayedReadRecPtr, XLogRecoveryCtlData::lastReplayedTLI, len, memcpy(), missingContrecPtr, palloc(), palloc_object, PANIC, XLogReaderState::readBuf, readFile, readOff, ReadRecord(), recovery_signal_file_found, result, XLogReaderState::seg, ShutDownSlotSync(), standby_signal_file_found, StandbyMode, wal_segment_size, WalRcvStreaming(), WALOpenSegment::ws_tli, xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, XLogRecoveryCtl, XLogSegmentOffset, and XLogShutdownWalRcv().

Referenced by StartupXLOG().

◆ GetCurrentChunkReplayStartTime()

◆ GetCurrentReplayRecPtr()

XLogRecPtr GetCurrentReplayRecPtr ( TimeLineID replayEndTLI)

◆ GetLatestXTime()

◆ getRecordTimestamp()

static bool getRecordTimestamp ( XLogReaderState record,
TimestampTz recordXtime 
)
static

Definition at line 2408 of file xlogrecovery.c.

2409{
2410 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2412 uint8 rmid = XLogRecGetRmid(record);
2413
2414 if (rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2415 {
2416 *recordXtime = ((xl_restore_point *) XLogRecGetData(record))->rp_time;
2417 return true;
2418 }
2419 if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_COMMIT ||
2421 {
2422 *recordXtime = ((xl_xact_commit *) XLogRecGetData(record))->xact_time;
2423 return true;
2424 }
2425 if (rmid == RM_XACT_ID && (xact_info == XLOG_XACT_ABORT ||
2427 {
2428 *recordXtime = ((xl_xact_abort *) XLogRecGetData(record))->xact_time;
2429 return true;
2430 }
2431 return false;
2432}
#define XLOG_RESTORE_POINT
Definition pg_control.h:79
#define XLOG_XACT_COMMIT_PREPARED
Definition xact.h:173
#define XLOG_XACT_COMMIT
Definition xact.h:170
#define XLOG_XACT_OPMASK
Definition xact.h:180
#define XLOG_XACT_ABORT
Definition xact.h:172
#define XLOG_XACT_ABORT_PREPARED
Definition xact.h:174
#define XLogRecGetInfo(decoder)
Definition xlogreader.h:410
#define XLogRecGetRmid(decoder)
Definition xlogreader.h:411

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

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

◆ GetRecoveryPauseState()

◆ getRecoveryStopReason()

static char * getRecoveryStopReason ( void  )
static

Definition at line 2868 of file xlogrecovery.c.

2869{
2870 char reason[200];
2871
2873 snprintf(reason, sizeof(reason),
2874 "%s transaction %u",
2875 recoveryStopAfter ? "after" : "before",
2878 snprintf(reason, sizeof(reason),
2879 "%s %s\n",
2880 recoveryStopAfter ? "after" : "before",
2883 snprintf(reason, sizeof(reason),
2884 "%s LSN %X/%08X\n",
2885 recoveryStopAfter ? "after" : "before",
2888 snprintf(reason, sizeof(reason),
2889 "at restore point \"%s\"",
2892 snprintf(reason, sizeof(reason), "reached consistency");
2893 else
2894 snprintf(reason, sizeof(reason), "no recovery target specified");
2895
2896 return pstrdup(reason);
2897}
const char * timestamptz_to_str(TimestampTz t)
Definition timestamp.c:1870
char * pstrdup(const char *in)
Definition mcxt.c:1910
static XLogRecPtr recoveryStopLSN
static TimestampTz recoveryStopTime
static char recoveryStopName[MAXFNAMELEN]
static bool recoveryStopAfter
RecoveryTargetType recoveryTarget
static TransactionId recoveryStopXid

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

4659{
4660 /*
4661 * This must be executed in the startup process, since we don't export the
4662 * relevant state to shared memory.
4663 */
4665
4668}
static XLogSource XLogReceiptSource
static TimestampTz XLogReceiptTime

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

Referenced by GetStandbyLimitTime().

◆ GetXLogReplayRecPtr()

◆ HotStandbyActive()

bool HotStandbyActive ( void  )

Definition at line 4518 of file xlogrecovery.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ HotStandbyActiveInReplay()

static bool HotStandbyActiveInReplay ( void  )
static

Definition at line 4543 of file xlogrecovery.c.

4544{
4546 return LocalHotStandbyActive;
4547}
bool IsPostmasterEnvironment
Definition globals.c:121
#define AmStartupProcess()
Definition miscadmin.h:396

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

461{
462 XLogPageReadPrivate *private;
463 struct stat st;
464 bool wasShutdown;
465 XLogRecord *record;
467 bool haveTblspcMap = false;
468 bool haveBackupLabel = false;
469 CheckPoint checkPoint;
470 bool backupFromStandby = false;
471
473
474 /*
475 * Initialize on the assumption we want to recover to the latest timeline
476 * that's active according to pg_control.
477 */
481 else
483
484 /*
485 * Check for signal files, and if so set up state for offline recovery
486 */
489
490 /*
491 * Take ownership of the wakeup latch if we're going to sleep during
492 * recovery, if required.
493 */
496
497 /*
498 * Set the WAL reading processor now, as it will be needed when reading
499 * the checkpoint record required (backup_label or not).
500 */
502 xlogreader =
504 XL_ROUTINE(.page_read = &XLogPageRead,
505 .segment_open = NULL,
506 .segment_close = wal_segment_close),
507 private);
508 if (!xlogreader)
511 errmsg("out of memory"),
512 errdetail("Failed while allocating a WAL reading processor.")));
514
515 /*
516 * Set the WAL decode buffer size. This limits how far ahead we can read
517 * in the WAL.
518 */
520
521 /* Create a WAL prefetcher. */
523
524 /*
525 * Allocate two page buffers dedicated to WAL consistency checks. We do
526 * it this way, rather than just making static arrays, for two reasons:
527 * (1) no need to waste the storage in most instantiations of the backend;
528 * (2) a static char array isn't guaranteed to have any particular
529 * alignment, whereas palloc() will provide MAXALIGN'd storage.
530 */
533
534 /*
535 * Read the backup_label file. We want to run this part of the recovery
536 * process after checking for signal files and after performing validation
537 * of the recovery parameters.
538 */
541 {
542 List *tablespaces = NIL;
543
544 /*
545 * Archive recovery was requested, and thanks to the backup label
546 * file, we know how far we need to replay to reach consistency. Enter
547 * archive recovery directly.
548 */
549 InArchiveRecovery = true;
552
553 /*
554 * Omitting backup_label when creating a new replica, PITR node etc.
555 * unfortunately is a common cause of corruption. Logging that
556 * backup_label was used makes it a bit easier to exclude that as the
557 * cause of observed corruption.
558 *
559 * Do so before we try to read the checkpoint record (which can fail),
560 * as otherwise it can be hard to understand why a checkpoint other
561 * than ControlFile->checkPoint is used.
562 */
563 ereport(LOG,
564 errmsg("starting backup recovery with redo LSN %X/%08X, checkpoint LSN %X/%08X, on timeline ID %u",
568
569 /*
570 * When a backup_label file is present, we want to roll forward from
571 * the checkpoint it identifies, rather than using pg_control.
572 */
575 if (record != NULL)
576 {
577 memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
580 errmsg_internal("checkpoint record is at %X/%08X",
582 InRecovery = true; /* force recovery even if SHUTDOWNED */
583
584 /*
585 * Make sure that REDO location exists. This may not be the case
586 * if there was a crash during an online backup, which left a
587 * backup_label around that references a WAL segment that's
588 * already been archived.
589 */
590 if (checkPoint.redo < CheckPointLoc)
591 {
593 if (!ReadRecord(xlogprefetcher, LOG, false,
594 checkPoint.ThisTimeLineID))
596 errmsg("could not find redo location %X/%08X referenced by checkpoint record at %X/%08X",
598 errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
599 "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
600 "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
602 }
603 }
604 else
605 {
607 errmsg("could not locate required checkpoint record at %X/%08X",
609 errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" or \"%s/standby.signal\" and add required recovery options.\n"
610 "If you are not restoring from a backup, try removing the file \"%s/backup_label\".\n"
611 "Be careful: removing \"%s/backup_label\" will result in a corrupt cluster if restoring from a backup.",
613 wasShutdown = false; /* keep compiler quiet */
614 }
615
616 /* Read the tablespace_map file if present and create symlinks. */
617 if (read_tablespace_map(&tablespaces))
618 {
619 ListCell *lc;
620
621 foreach(lc, tablespaces)
622 {
624 char *linkloc;
625
626 linkloc = psprintf("%s/%u", PG_TBLSPC_DIR, ti->oid);
627
628 /*
629 * Remove the existing symlink if any and Create the symlink
630 * under PGDATA.
631 */
633
634 if (symlink(ti->path, linkloc) < 0)
637 errmsg("could not create symbolic link \"%s\": %m",
638 linkloc)));
639
640 pfree(ti->path);
641 pfree(ti);
642 }
643
644 /* tell the caller to delete it later */
645 haveTblspcMap = true;
646 }
647
648 /* tell the caller to delete it later */
649 haveBackupLabel = true;
650 }
651 else
652 {
653 /* No backup_label file has been found if we are here. */
654
655 /*
656 * If tablespace_map file is present without backup_label file, there
657 * is no use of such file. There is no harm in retaining it, but it
658 * is better to get rid of the map file so that we don't have any
659 * redundant file in data directory and it will avoid any sort of
660 * confusion. It seems prudent though to just rename the file out of
661 * the way rather than delete it completely, also we ignore any error
662 * that occurs in rename operation as even if map file is present
663 * without backup_label file, it is harmless.
664 */
665 if (stat(TABLESPACE_MAP, &st) == 0)
666 {
669 ereport(LOG,
670 (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
672 errdetail("File \"%s\" was renamed to \"%s\".",
674 else
675 ereport(LOG,
676 (errmsg("ignoring file \"%s\" because no file \"%s\" exists",
678 errdetail("Could not rename file \"%s\" to \"%s\": %m.",
680 }
681
682 /*
683 * It's possible that archive recovery was requested, but we don't
684 * know how far we need to replay the WAL before we reach consistency.
685 * This can happen for example if a base backup is taken from a
686 * running server using an atomic filesystem snapshot, without calling
687 * pg_backup_start/stop. Or if you just kill a running primary server
688 * and put it into archive recovery by creating a recovery signal
689 * file.
690 *
691 * Our strategy in that case is to perform crash recovery first,
692 * replaying all the WAL present in pg_wal, and only enter archive
693 * recovery after that.
694 *
695 * But usually we already know how far we need to replay the WAL (up
696 * to minRecoveryPoint, up to backupEndPoint, or until we see an
697 * end-of-backup record), and we can enter archive recovery directly.
698 */
704 {
705 InArchiveRecovery = true;
708 }
709
710 /*
711 * For the same reason as when starting up with backup_label present,
712 * emit a log message when we continue initializing from a base
713 * backup.
714 */
716 ereport(LOG,
717 errmsg("restarting backup recovery with redo LSN %X/%08X",
719
720 /* Get the last valid checkpoint record. */
727 if (record != NULL)
728 {
730 errmsg_internal("checkpoint record is at %X/%08X",
732 }
733 else
734 {
735 /*
736 * We used to attempt to go back to a secondary checkpoint record
737 * here, but only when not in standby mode. We now just fail if we
738 * can't read the last checkpoint because this allows us to
739 * simplify processing around checkpoints.
740 */
742 errmsg("could not locate a valid checkpoint record at %X/%08X",
744 }
745 memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
747
748 /* Make sure that REDO location exists. */
749 if (checkPoint.redo < CheckPointLoc)
750 {
752 if (!ReadRecord(xlogprefetcher, LOG, false, checkPoint.ThisTimeLineID))
754 errmsg("could not find redo location %X/%08X referenced by checkpoint record at %X/%08X",
756 }
757 }
758
760 {
762 ereport(LOG,
763 (errmsg("entering standby mode")));
765 ereport(LOG,
766 (errmsg("starting point-in-time recovery to XID %u",
769 ereport(LOG,
770 (errmsg("starting point-in-time recovery to %s",
773 ereport(LOG,
774 (errmsg("starting point-in-time recovery to \"%s\"",
777 ereport(LOG,
778 errmsg("starting point-in-time recovery to WAL location (LSN) \"%X/%08X\"",
781 ereport(LOG,
782 (errmsg("starting point-in-time recovery to earliest consistent point")));
783 else
784 ereport(LOG,
785 (errmsg("starting archive recovery")));
786 }
787
788 /*
789 * If the location of the checkpoint record is not on the expected
790 * timeline in the history of the requested timeline, we cannot proceed:
791 * the backup is not part of the history of the requested timeline.
792 */
793 Assert(expectedTLEs); /* was initialized by reading checkpoint
794 * record */
797 {
799
800 /*
801 * tliSwitchPoint will throw an error if the checkpoint's timeline is
802 * not in expectedTLEs at all.
803 */
806 (errmsg("requested timeline %u is not a child of this server's history",
808 /* translator: %s is a backup_label file or a pg_control file */
809 errdetail("Latest checkpoint in file \"%s\" is at %X/%08X on timeline %u, but in the history of the requested timeline, the server forked off from that timeline at %X/%08X.",
810 haveBackupLabel ? "backup_label" : "pg_control",
814 }
815
816 /*
817 * The min recovery point should be part of the requested timeline's
818 * history, too.
819 */
824 errmsg("requested timeline %u does not contain minimum recovery point %X/%08X on timeline %u",
828
830 errmsg_internal("redo record is at %X/%08X; shutdown %s",
831 LSN_FORMAT_ARGS(checkPoint.redo),
832 wasShutdown ? "true" : "false"));
834 (errmsg_internal("next transaction ID: " UINT64_FORMAT "; next OID: %u",
836 checkPoint.nextOid)));
838 (errmsg_internal("next MultiXactId: %u; next MultiXactOffset: %" PRIu64,
839 checkPoint.nextMulti, checkPoint.nextMultiOffset)));
841 (errmsg_internal("oldest unfrozen transaction ID: %u, in database %u",
842 checkPoint.oldestXid, checkPoint.oldestXidDB)));
844 (errmsg_internal("oldest MultiXactId: %u, in database %u",
845 checkPoint.oldestMulti, checkPoint.oldestMultiDB)));
847 (errmsg_internal("commit timestamp Xid oldest/newest: %u/%u",
848 checkPoint.oldestCommitTsXid,
849 checkPoint.newestCommitTsXid)));
852 (errmsg("invalid next transaction ID")));
853
854 /* sanity check */
855 if (checkPoint.redo > CheckPointLoc)
857 (errmsg("invalid redo in checkpoint record")));
858
859 /*
860 * Check whether we need to force recovery from WAL. If it appears to
861 * have been a clean shutdown and we did not have a recovery signal file,
862 * then assume no recovery needed.
863 */
864 if (checkPoint.redo < CheckPointLoc)
865 {
866 if (wasShutdown)
868 (errmsg("invalid redo record in shutdown checkpoint")));
869 InRecovery = true;
870 }
871 else if (ControlFile->state != DB_SHUTDOWNED)
872 InRecovery = true;
874 {
875 /* force recovery due to presence of recovery signal file */
876 InRecovery = true;
877 }
878
879 /*
880 * If recovery is needed, update our in-memory copy of pg_control to show
881 * that we are recovering and to show the selected checkpoint as the place
882 * we are starting from. We also mark pg_control with any minimum recovery
883 * stop point obtained from a backup history file.
884 *
885 * We don't write the changes to disk yet, though. Only do that after
886 * initializing various subsystems.
887 */
888 if (InRecovery)
889 {
891 {
893 }
894 else
895 {
896 ereport(LOG,
897 (errmsg("database system was not properly shut down; "
898 "automatic recovery in progress")));
900 ereport(LOG,
901 (errmsg("crash recovery starts in timeline %u "
902 "and has target timeline %u",
906 }
908 ControlFile->checkPointCopy = checkPoint;
910 {
911 /* initialize minRecoveryPoint if not set yet */
912 if (ControlFile->minRecoveryPoint < checkPoint.redo)
913 {
914 ControlFile->minRecoveryPoint = checkPoint.redo;
916 }
917 }
918
919 /*
920 * Set backupStartPoint if we're starting recovery from a base backup.
921 *
922 * Also set backupEndPoint and use minRecoveryPoint as the backup end
923 * location if we're starting recovery from a base backup which was
924 * taken from a standby. In this case, the database system status in
925 * pg_control must indicate that the database was already in recovery.
926 * Usually that will be DB_IN_ARCHIVE_RECOVERY but also can be
927 * DB_SHUTDOWNED_IN_RECOVERY if recovery previously was interrupted
928 * before reaching this point; e.g. because restore_command or
929 * primary_conninfo were faulty.
930 *
931 * Any other state indicates that the backup somehow became corrupted
932 * and we can't sensibly continue with recovery.
933 */
934 if (haveBackupLabel)
935 {
936 ControlFile->backupStartPoint = checkPoint.redo;
938
940 {
944 (errmsg("backup_label contains data inconsistent with control file"),
945 errhint("This means that the backup is corrupted and you will "
946 "have to use another backup for recovery.")));
948 }
949 }
950 }
951
952 /* remember these, so that we know when we have reached consistency */
957 {
960 }
961 else
962 {
965 }
966
967 /*
968 * Start recovery assuming that the final record isn't lost.
969 */
972
976}
TimeLineID tliOfPointInHistory(XLogRecPtr ptr, List *history)
Definition timeline.c:545
XLogRecPtr tliSwitchPoint(TimeLineID tli, List *history, TimeLineID *nextTLI)
Definition timeline.c:573
void remove_tablespace_symlink(const char *linkloc)
Definition tablespace.c:891
#define UINT64_FORMAT
Definition c.h:694
int errcode_for_file_access(void)
Definition elog.c:898
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition fd.c:783
#define palloc0_object(type)
Definition fe_memutils.h:90
char * DataDir
Definition globals.c:73
void OwnLatch(Latch *latch)
Definition latch.c:126
DBState
Definition pg_control.h:98
@ DB_IN_ARCHIVE_RECOVERY
Definition pg_control.h:104
@ DB_SHUTDOWNED_IN_RECOVERY
Definition pg_control.h:101
@ DB_SHUTDOWNED
Definition pg_control.h:100
@ DB_IN_CRASH_RECOVERY
Definition pg_control.h:103
#define lfirst(lc)
Definition pg_list.h:172
#define NIL
Definition pg_list.h:68
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
Oid oldestMultiDB
Definition pg_control.h:52
MultiXactId oldestMulti
Definition pg_control.h:51
MultiXactOffset nextMultiOffset
Definition pg_control.h:48
TransactionId newestCommitTsXid
Definition pg_control.h:56
TransactionId oldestXid
Definition pg_control.h:49
MultiXactId nextMulti
Definition pg_control.h:47
FullTransactionId nextXid
Definition pg_control.h:45
TransactionId oldestCommitTsXid
Definition pg_control.h:54
XLogRecPtr redo
Definition pg_control.h:37
Oid oldestXidDB
Definition pg_control.h:50
XLogRecPtr backupStartPoint
Definition pg_control.h:178
CheckPoint checkPointCopy
Definition pg_control.h:143
XLogRecPtr backupEndPoint
Definition pg_control.h:179
XLogRecPtr minRecoveryPoint
Definition pg_control.h:176
XLogRecPtr checkPoint
Definition pg_control.h:141
uint64 system_identifier
Definition pg_control.h:118
TimeLineID minRecoveryPointTLI
Definition pg_control.h:177
Definition pg_list.h:54
uint64 system_identifier
Definition xlogreader.h:190
#define U64FromFullTransactionId(x)
Definition transam.h:49
#define XidFromFullTransactionId(x)
Definition transam.h:48
#define TransactionIdIsNormal(xid)
Definition transam.h:42
#define symlink(oldpath, newpath)
Definition win32_port.h:242
int wal_decode_buffer_size
Definition xlog.c:143
static ControlFileData * ControlFile
Definition xlog.c:584
#define TABLESPACE_MAP_OLD
Definition xlog.h:338
#define TABLESPACE_MAP
Definition xlog.h:337
#define BACKUP_LABEL_FILE
Definition xlog.h:334
XLogPrefetcher * XLogPrefetcherAllocate(XLogReaderState *reader)
XLogReaderState * XLogReaderAllocate(int wal_segment_size, const char *waldir, XLogReaderRoutine *routine, void *private_data)
Definition xlogreader.c:108
void XLogReaderSetDecodeBuffer(XLogReaderState *state, void *buffer, size_t size)
Definition xlogreader.c:92
#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
static void readRecoverySignalFile(void)
static bool read_tablespace_map(List **tablespaces)
static bool read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI, bool *backupEndRequired, bool *backupFromStandby)
static char * primary_image_masked
static char * replay_image_masked
TimeLineID recoveryTargetTLI
static XLogRecPtr RedoStartLSN
static void EnableStandbyMode(void)
TimestampTz recoveryTargetTime
char * recoveryTargetName
static bool StandbyModeRequested
void wal_segment_close(XLogReaderState *state)
Definition xlogutils.c:855

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, fb(), InArchiveRecovery, InRecovery, InvalidXLogRecPtr, lfirst, LOG, LSN_FORMAT_ARGS, memcpy(), minRecoveryPoint, ControlFileData::minRecoveryPoint, minRecoveryPointTLI, ControlFileData::minRecoveryPointTLI, missingContrecPtr, CheckPoint::newestCommitTsXid, CheckPoint::nextMulti, CheckPoint::nextMultiOffset, CheckPoint::nextOid, CheckPoint::nextXid, NIL, CheckPoint::oldestCommitTsXid, CheckPoint::oldestMulti, CheckPoint::oldestMultiDB, CheckPoint::oldestXid, CheckPoint::oldestXidDB, OwnLatch(), palloc(), palloc0_object, PANIC, pfree(), PG_TBLSPC_DIR, primary_image_masked, psprintf(), read_backup_label(), read_tablespace_map(), ReadCheckpointRecord(), ReadRecord(), readRecoverySignalFile(), RECOVERY_TARGET_IMMEDIATE, RECOVERY_TARGET_LSN, RECOVERY_TARGET_NAME, RECOVERY_TARGET_TIME, RECOVERY_TARGET_XID, recoveryTarget, recoveryTargetLSN, recoveryTargetName, recoveryTargetTime, recoveryTargetTLI, recoveryTargetXid, XLogRecoveryCtlData::recoveryWakeupLatch, CheckPoint::redo, RedoStartLSN, RedoStartTLI, remove_tablespace_symlink(), replay_image_masked, StandbyModeRequested, stat, ControlFileData::state, symlink, XLogReaderState::system_identifier, ControlFileData::system_identifier, TABLESPACE_MAP, TABLESPACE_MAP_OLD, CheckPoint::ThisTimeLineID, timestamptz_to_str(), tliOfPointInHistory(), tliSwitchPoint(), TransactionIdIsNormal, U64FromFullTransactionId, UINT64_FORMAT, validateRecoveryParameters(), wal_decode_buffer_size, wal_segment_close(), wal_segment_size, XidFromFullTransactionId, XLogRecord::xl_info, XL_ROUTINE, XLOG_CHECKPOINT_SHUTDOWN, XLogPageRead(), xlogprefetcher, XLogPrefetcherAllocate(), XLogPrefetcherBeginRead(), xlogreader, XLogReaderAllocate(), XLogReaderSetDecodeBuffer(), XLogRecGetData, XLogRecoveryCtl, and XLogRecPtrIsValid.

Referenced by StartupXLOG().

◆ PerformWalRecovery()

void PerformWalRecovery ( void  )

Definition at line 1617 of file xlogrecovery.c.

1618{
1619 XLogRecord *record;
1620 bool reachedRecoveryTarget = false;
1621 TimeLineID replayTLI;
1622
1623 /*
1624 * Initialize shared variables for tracking progress of WAL replay, as if
1625 * we had just replayed the record before the REDO location (or the
1626 * checkpoint record itself, if it's a shutdown checkpoint).
1627 */
1630 {
1634 }
1635 else
1636 {
1640 }
1647
1648 /* Also ensure XLogReceiptTime has a sane value */
1650
1651 /*
1652 * Let postmaster know we've started redo now, so that it can launch the
1653 * archiver if necessary.
1654 */
1657
1658 /*
1659 * Allow read-only connections immediately if we're consistent already.
1660 */
1662
1663 /*
1664 * Find the first record that logically follows the checkpoint --- it
1665 * might physically precede it, though.
1666 */
1668 {
1669 /* back up to find the record */
1670 replayTLI = RedoStartTLI;
1672 record = ReadRecord(xlogprefetcher, PANIC, false, replayTLI);
1673
1674 /*
1675 * If a checkpoint record's redo pointer points back to an earlier
1676 * LSN, the record at that LSN should be an XLOG_CHECKPOINT_REDO
1677 * record.
1678 */
1679 if (record->xl_rmid != RM_XLOG_ID ||
1681 ereport(FATAL,
1682 errmsg("unexpected record type found at redo point %X/%08X",
1684 }
1685 else
1686 {
1687 /* just have to read next record after CheckPoint */
1689 replayTLI = CheckPointTLI;
1690 record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1691 }
1692
1693 if (record != NULL)
1694 {
1696 PGRUsage ru0;
1697
1699
1700 InRedo = true;
1701
1702 RmgrStartup();
1703
1704 ereport(LOG,
1705 errmsg("redo starts at %X/%08X",
1707
1708 /* Prepare to report progress of the redo phase. */
1709 if (!StandbyMode)
1711
1712 /*
1713 * main redo apply loop
1714 */
1715 do
1716 {
1717 if (!StandbyMode)
1718 ereport_startup_progress("redo in progress, elapsed time: %ld.%02d s, current LSN: %X/%08X",
1720
1721#ifdef WAL_DEBUG
1722 if (XLOG_DEBUG)
1723 {
1725
1727 appendStringInfo(&buf, "REDO @ %X/%08X; LSN %X/%08X: ",
1731 appendStringInfoString(&buf, " - ");
1733 elog(LOG, "%s", buf.data);
1734 pfree(buf.data);
1735 }
1736#endif
1737
1738 /* Handle interrupt signals of startup process */
1740
1741 /*
1742 * Pause WAL replay, if requested by a hot-standby session via
1743 * SetRecoveryPause().
1744 *
1745 * Note that we intentionally don't take the info_lck spinlock
1746 * here. We might therefore read a slightly stale value of the
1747 * recoveryPause flag, but it can't be very stale (no worse than
1748 * the last spinlock we did acquire). Since a pause request is a
1749 * pretty asynchronous thing anyway, possibly responding to it one
1750 * WAL record later than we otherwise would is a minor issue, so
1751 * it doesn't seem worth adding another spinlock cycle to prevent
1752 * that.
1753 */
1754 if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1756 recoveryPausesHere(false);
1757
1758 /*
1759 * Have we reached our recovery target?
1760 */
1762 {
1763 reachedRecoveryTarget = true;
1764 break;
1765 }
1766
1767 /*
1768 * If we've been asked to lag the primary, wait on latch until
1769 * enough time has passed.
1770 */
1772 {
1773 /*
1774 * We test for paused recovery again here. If user sets
1775 * delayed apply, it may be because they expect to pause
1776 * recovery in case of problems, so we must test again here
1777 * otherwise pausing during the delay-wait wouldn't work.
1778 */
1779 if (((volatile XLogRecoveryCtlData *) XLogRecoveryCtl)->recoveryPauseState !=
1781 recoveryPausesHere(false);
1782 }
1783
1784 /*
1785 * Apply the record
1786 */
1787 ApplyWalRecord(xlogreader, record, &replayTLI);
1788
1789 /*
1790 * Wake up processes waiting for standby replay, write, or flush
1791 * LSN to reach current replay position. Replay implies that the
1792 * WAL was already written and flushed to disk, so write and flush
1793 * waiters can be woken at the replay position too.
1794 */
1801
1802 /* Exit loop if we reached inclusive recovery target */
1804 {
1805 reachedRecoveryTarget = true;
1806 break;
1807 }
1808
1809 /* Else, try to fetch the next WAL record */
1810 record = ReadRecord(xlogprefetcher, LOG, false, replayTLI);
1811 } while (record != NULL);
1812
1813 /*
1814 * end of main redo apply loop
1815 */
1816
1818 {
1819 if (!reachedConsistency)
1820 ereport(FATAL,
1821 (errmsg("requested recovery stop point is before consistent recovery point")));
1822
1823 /*
1824 * This is the last point where we can restart recovery with a new
1825 * recovery target, if we shutdown and begin again. After this,
1826 * Resource Managers may choose to do permanent corrective actions
1827 * at end of recovery.
1828 */
1829 switch (recoveryTargetAction)
1830 {
1832
1833 /*
1834 * exit with special return code to request shutdown of
1835 * postmaster. Log messages issued from postmaster.
1836 */
1837 proc_exit(3);
1838
1840 SetRecoveryPause(true);
1841 recoveryPausesHere(true);
1842
1843 /* drop into promote */
1845
1847 break;
1848 }
1849 }
1850
1851 RmgrCleanup();
1852
1853 ereport(LOG,
1854 errmsg("redo done at %X/%08X system usage: %s",
1856 pg_rusage_show(&ru0)));
1858 if (xtime)
1859 ereport(LOG,
1860 (errmsg("last completed transaction was at log time %s",
1862
1863 InRedo = false;
1864 }
1865 else
1866 {
1867 /* there are no WAL records following the checkpoint */
1868 ereport(LOG,
1869 (errmsg("redo is not required")));
1870 }
1871
1872 /*
1873 * This check is intentionally after the above log messages that indicate
1874 * how far recovery went.
1875 */
1879 ereport(FATAL,
1881 errmsg("recovery ended before configured recovery target was reached")));
1882}
void begin_startup_progress_phase(void)
Definition startup.c:342
void ProcessStartupProcInterrupts(void)
Definition startup.c:154
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1649
#define pg_fallthrough
Definition c.h:220
void proc_exit(int code)
Definition ipc.c:105
#define XLOG_CHECKPOINT_REDO
Definition pg_control.h:86
const char * pg_rusage_show(const PGRUsage *ru0)
Definition pg_rusage.c:40
void pg_rusage_init(PGRUsage *ru0)
Definition pg_rusage.c:27
@ PMSIGNAL_RECOVERY_STARTED
Definition pmsignal.h:35
void RmgrStartup(void)
Definition rmgr.c:58
void RmgrCleanup(void)
Definition rmgr.c:74
#define ereport_startup_progress(msg,...)
Definition startup.h:18
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
#define XLR_INFO_MASK
Definition xlogrecord.h:62
static bool recoveryStopsBefore(XLogReaderState *record)
int recoveryTargetAction
static bool recoveryApplyDelay(XLogReaderState *record)
static bool recoveryStopsAfter(XLogReaderState *record)
void SetRecoveryPause(bool recoveryPause)
void xlog_outdesc(StringInfo buf, XLogReaderState *record)
static bool InRedo
static void ApplyWalRecord(XLogReaderState *xlogreader, XLogRecord *record, TimeLineID *replayTLI)
static void recoveryPausesHere(bool endOfRecovery)
TimestampTz GetLatestXTime(void)
@ RECOVERY_TARGET_ACTION_PAUSE
@ RECOVERY_TARGET_ACTION_PROMOTE
@ RECOVERY_TARGET_ACTION_SHUTDOWN
@ RECOVERY_NOT_PAUSED
void WaitLSNWakeup(WaitLSNType lsnType, XLogRecPtr currentLSN)
Definition xlogwait.c:344
@ WAIT_LSN_TYPE_STANDBY_REPLAY
Definition xlogwait.h:39
@ WAIT_LSN_TYPE_STANDBY_FLUSH
Definition xlogwait.h:41
@ WAIT_LSN_TYPE_STANDBY_WRITE
Definition xlogwait.h:40

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

Referenced by StartupXLOG().

◆ PromoteIsTriggered()

bool PromoteIsTriggered ( void  )

Definition at line 4410 of file xlogrecovery.c.

4411{
4412 /*
4413 * We check shared state each time only until a standby promotion is
4414 * triggered. We can't trigger a promotion again, so there's no need to
4415 * keep checking after the shared variable has once been seen true.
4416 */
4418 return true;
4419
4423
4425}

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

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

◆ read_backup_label()

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

Definition at line 1172 of file xlogrecovery.c.

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

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

Referenced by InitWalRecovery().

◆ read_tablespace_map()

static bool read_tablespace_map ( List **  tablespaces)
static

Definition at line 1318 of file xlogrecovery.c.

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

References AllocateFile(), EINVAL, ereport, errcode(), errcode_for_file_access(), errmsg, FATAL, fb(), FreeFile(), i, lappend(), MAXPGPATH, palloc0_object, pstrdup(), str, and TABLESPACE_MAP.

Referenced by InitWalRecovery().

◆ ReadCheckpointRecord()

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

Definition at line 4067 of file xlogrecovery.c.

4069{
4070 XLogRecord *record;
4071 uint8 info;
4072
4074
4075 if (!XRecOffIsValid(RecPtr))
4076 {
4077 ereport(LOG,
4078 (errmsg("invalid checkpoint location")));
4079 return NULL;
4080 }
4081
4083 record = ReadRecord(xlogprefetcher, LOG, true, replayTLI);
4084
4085 if (record == NULL)
4086 {
4087 ereport(LOG,
4088 (errmsg("invalid checkpoint record")));
4089 return NULL;
4090 }
4091 if (record->xl_rmid != RM_XLOG_ID)
4092 {
4093 ereport(LOG,
4094 (errmsg("invalid resource manager ID in checkpoint record")));
4095 return NULL;
4096 }
4097 info = record->xl_info & ~XLR_INFO_MASK;
4098 if (info != XLOG_CHECKPOINT_SHUTDOWN &&
4099 info != XLOG_CHECKPOINT_ONLINE)
4100 {
4101 ereport(LOG,
4102 (errmsg("invalid xl_info in checkpoint record")));
4103 return NULL;
4104 }
4106 {
4107 ereport(LOG,
4108 (errmsg("invalid length of checkpoint record")));
4109 return NULL;
4110 }
4111 return record;
4112}
#define XLOG_CHECKPOINT_ONLINE
Definition pg_control.h:73
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, fb(), LOG, ReadRecord(), SizeOfXLogRecord, SizeOfXLogRecordDataHeaderShort, XLogRecord::xl_info, XLogRecord::xl_rmid, XLogRecord::xl_tot_len, XLOG_CHECKPOINT_ONLINE, XLOG_CHECKPOINT_SHUTDOWN, xlogprefetcher, XLogPrefetcherBeginRead(), xlogreader, and XRecOffIsValid.

Referenced by InitWalRecovery().

◆ ReadRecord()

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

Definition at line 3113 of file xlogrecovery.c.

3115{
3116 XLogRecord *record;
3119
3121
3122 /* Pass through parameters to XLogPageRead */
3123 private->fetching_ckpt = fetching_ckpt;
3124 private->emode = emode;
3125 private->randAccess = !XLogRecPtrIsValid(xlogreader->ReadRecPtr);
3126 private->replayTLI = replayTLI;
3127
3128 /* This is the first attempt to read this page. */
3129 lastSourceFailed = false;
3130
3131 for (;;)
3132 {
3133 char *errormsg;
3134
3135 record = XLogPrefetcherReadRecord(xlogprefetcher, &errormsg);
3136 if (record == NULL)
3137 {
3138 /*
3139 * When we find that WAL ends in an incomplete record, keep track
3140 * of that record. After recovery is done, we'll write a record
3141 * to indicate to downstream WAL readers that that portion is to
3142 * be ignored.
3143 *
3144 * However, when ArchiveRecoveryRequested = true, we're going to
3145 * switch to a new timeline at the end of recovery. We will only
3146 * copy WAL over to the new timeline up to the end of the last
3147 * complete record, so if we did this, we would later create an
3148 * overwrite contrecord in the wrong place, breaking everything.
3149 */
3152 {
3155 }
3156
3157 if (readFile >= 0)
3158 {
3159 close(readFile);
3160 readFile = -1;
3161 }
3162
3163 /*
3164 * We only end up here without a message when XLogPageRead()
3165 * failed - in that case we already logged something. In
3166 * StandbyMode that only happens if we have been triggered, so we
3167 * shouldn't loop anymore in that case.
3168 */
3169 if (errormsg)
3171 (errmsg_internal("%s", errormsg) /* already translated */ ));
3172 }
3173
3174 /*
3175 * Check page TLI is one of the expected values.
3176 */
3178 {
3179 char fname[MAXFNAMELEN];
3180 XLogSegNo segno;
3181 int32 offset;
3182
3186 XLogFileName(fname, xlogreader->seg.ws_tli, segno,
3189 errmsg("unexpected timeline ID %u in WAL segment %s, LSN %X/%08X, offset %u",
3191 fname,
3193 offset));
3194 record = NULL;
3195 }
3196
3197 if (record)
3198 {
3199 /* Great, got a record */
3200 return record;
3201 }
3202 else
3203 {
3204 /* No valid record available from this source */
3205 lastSourceFailed = true;
3206
3207 /*
3208 * If archive recovery was requested, but we were still doing
3209 * crash recovery, switch to archive recovery and retry using the
3210 * offline archive. We have now replayed all the valid WAL in
3211 * pg_wal, so we are presumably now consistent.
3212 *
3213 * We require that there's at least some valid WAL present in
3214 * pg_wal, however (!fetching_ckpt). We could recover using the
3215 * WAL from the archive, even if pg_wal is completely empty, but
3216 * we'd have no idea how far we'd have to replay to reach
3217 * consistency. So err on the safe side and give up.
3218 */
3220 !fetching_ckpt)
3221 {
3223 (errmsg_internal("reached end of WAL in pg_wal, entering archive recovery")));
3224 InArchiveRecovery = true;
3227
3230 minRecoveryPointTLI = replayTLI;
3231
3233
3234 /*
3235 * Before we retry, reset lastSourceFailed and currentSource
3236 * so that we will check the archive next.
3237 */
3238 lastSourceFailed = false;
3240
3241 continue;
3242 }
3243
3244 /* In standby mode, loop back to retry. Otherwise, give up. */
3246 continue;
3247 else
3248 return NULL;
3249 }
3250 }
3251}
int32_t int32
Definition c.h:679
XLogRecPtr missingContrecPtr
Definition xlogreader.h:214
XLogRecPtr abortedRecPtr
Definition xlogreader.h:213
TimeLineID latestPageTLI
Definition xlogreader.h:279
XLogRecPtr latestPagePtr
Definition xlogreader.h:278
void * private_data
Definition xlogreader.h:195
void SwitchIntoArchiveRecovery(XLogRecPtr EndRecPtr, TimeLineID replayTLI)
Definition xlog.c:6710
#define XLByteToSeg(xlrp, logSegNo, wal_segsz_bytes)
static void XLogFileName(char *fname, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
uint64 XLogSegNo
Definition xlogdefs.h:52
XLogRecord * XLogPrefetcherReadRecord(XLogPrefetcher *prefetcher, char **errmsg)
XLogReaderState * XLogPrefetcherGetReader(XLogPrefetcher *prefetcher)
static bool CheckForStandbyTrigger(void)
static bool lastSourceFailed
static XLogSource currentSource
static int emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)

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

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

◆ readRecoverySignalFile()

static void readRecoverySignalFile ( void  )
static

Definition at line 986 of file xlogrecovery.c.

987{
988 struct stat stat_buf;
989
991 return;
992
993 /*
994 * Check for old recovery API file: recovery.conf
995 */
999 errmsg("using recovery command file \"%s\" is not supported",
1001
1002 /*
1003 * Remove unused .done file, if present. Ignore if absent.
1004 */
1006
1007 /*
1008 * Check for recovery signal files and if found, fsync them since they
1009 * represent server state information. We don't sweat too much about the
1010 * possibility of fsync failure, however.
1011 */
1012 if (stat(STANDBY_SIGNAL_FILE, &stat_buf) == 0)
1013 {
1014 int fd;
1015
1017 S_IRUSR | S_IWUSR);
1018 if (fd >= 0)
1019 {
1020 (void) pg_fsync(fd);
1021 close(fd);
1022 }
1024 }
1025
1027 {
1028 int fd;
1029
1031 S_IRUSR | S_IWUSR);
1032 if (fd >= 0)
1033 {
1034 (void) pg_fsync(fd);
1035 close(fd);
1036 }
1038 }
1039
1040 /*
1041 * If both signal files are present, standby signal file takes precedence.
1042 * If neither is present then we won't enter archive recovery.
1043 */
1044 StandbyModeRequested = false;
1047 {
1048 StandbyModeRequested = true;
1050 }
1052 {
1053 StandbyModeRequested = false;
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,
1066 errmsg("standby mode is not supported by single-user servers")));
1067}
#define PG_BINARY
Definition c.h:1431
int BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
Definition fd.c:1112
int pg_fsync(int fd)
Definition fd.c:390
#define IsBootstrapProcessingMode()
Definition miscadmin.h:486
static int fd(const char *x, int i)
#define S_IRUSR
Definition win32_port.h:296
#define S_IWUSR
Definition win32_port.h:299
#define STANDBY_SIGNAL_FILE
Definition xlog.h:333
#define RECOVERY_SIGNAL_FILE
Definition xlog.h:332
#define RECOVERY_COMMAND_FILE
#define RECOVERY_COMMAND_DONE

References ArchiveRecoveryRequested, BasicOpenFilePerm(), close, ereport, errcode(), errcode_for_file_access(), errmsg, FATAL, fb(), 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 2964 of file xlogrecovery.c.

2965{
2969 long msecs;
2970
2971 /* nothing to do if no delay configured */
2972 if (recovery_min_apply_delay <= 0)
2973 return false;
2974
2975 /* no delay is applied on a database not yet consistent */
2976 if (!reachedConsistency)
2977 return false;
2978
2979 /* nothing to do if crash recovery is requested */
2981 return false;
2982
2983 /*
2984 * Is it a COMMIT record?
2985 *
2986 * We deliberately choose not to delay aborts since they have no effect on
2987 * MVCC. We already allow replay of records that don't have a timestamp,
2988 * so there is already opportunity for issues caused by early conflicts on
2989 * standbys.
2990 */
2991 if (XLogRecGetRmid(record) != RM_XACT_ID)
2992 return false;
2993
2995
2996 if (xact_info != XLOG_XACT_COMMIT &&
2998 return false;
2999
3000 if (!getRecordTimestamp(record, &xtime))
3001 return false;
3002
3004
3005 /*
3006 * Exit without arming the latch if it's already past time to apply this
3007 * record
3008 */
3010 if (msecs <= 0)
3011 return false;
3012
3013 while (true)
3014 {
3016
3017 /* This might change recovery_min_apply_delay. */
3019
3021 break;
3022
3023 /*
3024 * Recalculate delayUntil as recovery_min_apply_delay could have
3025 * changed while waiting in this loop.
3026 */
3028
3029 /*
3030 * Wait for difference between GetCurrentTimestamp() and delayUntil.
3031 */
3033 delayUntil);
3034
3035 if (msecs <= 0)
3036 break;
3037
3038 elog(DEBUG2, "recovery apply delay %ld milliseconds", msecs);
3039
3042 msecs,
3044 }
3045 return true;
3046}
long TimestampDifferenceMilliseconds(TimestampTz start_time, TimestampTz stop_time)
Definition timestamp.c:1765
#define DEBUG2
Definition elog.h:30
void ResetLatch(Latch *latch)
Definition latch.c:374
int WaitLatch(Latch *latch, int wakeEvents, long timeout, uint32 wait_event_info)
Definition latch.c:172
#define TimestampTzPlusMilliseconds(tz, ms)
Definition timestamp.h:85
#define WL_TIMEOUT
#define WL_EXIT_ON_PM_DEATH
#define WL_LATCH_SET
static bool getRecordTimestamp(XLogReaderState *record, TimestampTz *recordXtime)
int recovery_min_apply_delay

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

Referenced by PerformWalRecovery().

◆ recoveryPausesHere()

static void recoveryPausesHere ( bool  endOfRecovery)
static

Definition at line 2907 of file xlogrecovery.c.

2908{
2909 /* Don't pause unless users can connect! */
2911 return;
2912
2913 /* Don't pause after standby promotion has been triggered */
2915 return;
2916
2917 if (endOfRecovery)
2918 ereport(LOG,
2919 (errmsg("pausing at the end of recovery"),
2920 errhint("Execute pg_wal_replay_resume() to promote.")));
2921 else
2922 ereport(LOG,
2923 (errmsg("recovery has paused"),
2924 errhint("Execute pg_wal_replay_resume() to continue.")));
2925
2926 /* loop until recoveryPauseState is set to RECOVERY_NOT_PAUSED */
2928 {
2931 return;
2932
2933 /*
2934 * If recovery pause is requested then set it paused. While we are in
2935 * the loop, user might resume and pause again so set this every time.
2936 */
2938
2939 /*
2940 * We wait on a condition variable that will wake us as soon as the
2941 * pause ends, but we use a timeout so we can check the above exit
2942 * condition periodically too.
2943 */
2946 }
2948}
bool ConditionVariableCancelSleep(void)
bool ConditionVariableTimedSleep(ConditionVariable *cv, long timeout, uint32 wait_event_info)
ConditionVariable recoveryNotPausedCV
static void ConfirmRecoveryPaused(void)
RecoveryPauseState GetRecoveryPauseState(void)

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

Referenced by PerformWalRecovery(), and WaitForWALToBecomeAvailable().

◆ RecoveryRequiresIntParameter()

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

Definition at line 4675 of file xlogrecovery.c.

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

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

Referenced by CheckRequiredParameterValues().

◆ recoveryStopsAfter()

static bool recoveryStopsAfter ( XLogReaderState record)
static

Definition at line 2708 of file xlogrecovery.c.

2709{
2710 uint8 info;
2712 uint8 rmid;
2714
2715 /*
2716 * Ignore recovery target settings when not in archive recovery (meaning
2717 * we are in crash recovery).
2718 */
2720 return false;
2721
2722 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2723 rmid = XLogRecGetRmid(record);
2724
2725 /*
2726 * There can be many restore points that share the same name; we stop at
2727 * the first one.
2728 */
2730 rmid == RM_XLOG_ID && info == XLOG_RESTORE_POINT)
2731 {
2733
2735
2737 {
2738 recoveryStopAfter = true;
2743
2744 ereport(LOG,
2745 (errmsg("recovery stopping at restore point \"%s\", time %s",
2748 return true;
2749 }
2750 }
2751
2752 /* Check if the target LSN has been reached */
2755 record->ReadRecPtr >= recoveryTargetLSN)
2756 {
2757 recoveryStopAfter = true;
2759 recoveryStopLSN = record->ReadRecPtr;
2760 recoveryStopTime = 0;
2761 recoveryStopName[0] = '\0';
2762 ereport(LOG,
2763 errmsg("recovery stopping after WAL location (LSN) \"%X/%08X\"",
2765 return true;
2766 }
2767
2768 if (rmid != RM_XACT_ID)
2769 return false;
2770
2771 xact_info = info & XLOG_XACT_OPMASK;
2772
2773 if (xact_info == XLOG_XACT_COMMIT ||
2777 {
2779
2780 /* Update the last applied transaction timestamp */
2781 if (getRecordTimestamp(record, &recordXtime))
2783
2784 /* Extract the XID of the committed/aborted transaction */
2786 {
2789
2791 xlrec,
2792 &parsed);
2793 recordXid = parsed.twophase_xid;
2794 }
2796 {
2799
2801 xlrec,
2802 &parsed);
2803 recordXid = parsed.twophase_xid;
2804 }
2805 else
2806 recordXid = XLogRecGetXid(record);
2807
2808 /*
2809 * There can be only one transaction end record with this exact
2810 * transactionid
2811 *
2812 * when testing for an xid, we MUST test for equality only, since
2813 * transactions are numbered in the order they start, not the order
2814 * they complete. A higher numbered xid will complete before you about
2815 * 50% of the time...
2816 */
2819 {
2820 recoveryStopAfter = true;
2824 recoveryStopName[0] = '\0';
2825
2826 if (xact_info == XLOG_XACT_COMMIT ||
2828 {
2829 ereport(LOG,
2830 (errmsg("recovery stopping after commit of transaction %u, time %s",
2833 }
2834 else if (xact_info == XLOG_XACT_ABORT ||
2836 {
2837 ereport(LOG,
2838 (errmsg("recovery stopping after abort of transaction %u, time %s",
2841 }
2842 return true;
2843 }
2844 }
2845
2846 /* Check if we should stop as soon as reaching consistency */
2848 {
2849 ereport(LOG,
2850 (errmsg("recovery stopping after reaching consistency")));
2851
2852 recoveryStopAfter = true;
2854 recoveryStopTime = 0;
2856 recoveryStopName[0] = '\0';
2857 return true;
2858 }
2859
2860 return false;
2861}
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition strlcpy.c:45
#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
static void SetLatestXTime(TimestampTz xtime)

References ArchiveRecoveryRequested, ereport, errmsg, fb(), 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, SetLatestXTime(), strlcpy(), timestamptz_to_str(), XLOG_RESTORE_POINT, XLOG_XACT_ABORT, XLOG_XACT_ABORT_PREPARED, XLOG_XACT_COMMIT, XLOG_XACT_COMMIT_PREPARED, XLOG_XACT_OPMASK, XLogRecGetData, XLogRecGetInfo, XLogRecGetRmid, and XLogRecGetXid.

Referenced by PerformWalRecovery().

◆ recoveryStopsBefore()

static bool recoveryStopsBefore ( XLogReaderState record)
static

Definition at line 2555 of file xlogrecovery.c.

2556{
2557 bool stopsHere = false;
2559 bool isCommit;
2562
2563 /*
2564 * Ignore recovery target settings when not in archive recovery (meaning
2565 * we are in crash recovery).
2566 */
2568 return false;
2569
2570 /* Check if we should stop as soon as reaching consistency */
2572 {
2573 ereport(LOG,
2574 (errmsg("recovery stopping after reaching consistency")));
2575
2576 recoveryStopAfter = false;
2579 recoveryStopTime = 0;
2580 recoveryStopName[0] = '\0';
2581 return true;
2582 }
2583
2584 /* Check if target LSN has been reached */
2587 record->ReadRecPtr >= recoveryTargetLSN)
2588 {
2589 recoveryStopAfter = false;
2591 recoveryStopLSN = record->ReadRecPtr;
2592 recoveryStopTime = 0;
2593 recoveryStopName[0] = '\0';
2594 ereport(LOG,
2595 errmsg("recovery stopping before WAL location (LSN) \"%X/%08X\"",
2597 return true;
2598 }
2599
2600 /* Otherwise we only consider stopping before COMMIT or ABORT records. */
2601 if (XLogRecGetRmid(record) != RM_XACT_ID)
2602 return false;
2603
2605
2607 {
2608 isCommit = true;
2609 recordXid = XLogRecGetXid(record);
2610 }
2612 {
2615
2616 isCommit = true;
2618 xlrec,
2619 &parsed);
2620 recordXid = parsed.twophase_xid;
2621 }
2622 else if (xact_info == XLOG_XACT_ABORT)
2623 {
2624 isCommit = false;
2625 recordXid = XLogRecGetXid(record);
2626 }
2628 {
2631
2632 isCommit = false;
2634 xlrec,
2635 &parsed);
2636 recordXid = parsed.twophase_xid;
2637 }
2638 else
2639 return false;
2640
2642 {
2643 /*
2644 * There can be only one transaction end record with this exact
2645 * transactionid
2646 *
2647 * when testing for an xid, we MUST test for equality only, since
2648 * transactions are numbered in the order they start, not the order
2649 * they complete. A higher numbered xid will complete before you about
2650 * 50% of the time...
2651 */
2653 }
2654
2655 /*
2656 * Note: we must fetch recordXtime regardless of recoveryTarget setting.
2657 * We don't expect getRecordTimestamp ever to fail, since we already know
2658 * this is a commit or abort record; but test its result anyway.
2659 */
2660 if (getRecordTimestamp(record, &recordXtime) &&
2662 {
2663 /*
2664 * There can be many transactions that share the same commit time, so
2665 * we stop after the last one, if we are inclusive, or stop at the
2666 * first one if we are exclusive
2667 */
2670 else
2672 }
2673
2674 if (stopsHere)
2675 {
2676 recoveryStopAfter = false;
2680 recoveryStopName[0] = '\0';
2681
2682 if (isCommit)
2683 {
2684 ereport(LOG,
2685 (errmsg("recovery stopping before commit of transaction %u, time %s",
2688 }
2689 else
2690 {
2691 ereport(LOG,
2692 (errmsg("recovery stopping before abort of transaction %u, time %s",
2695 }
2696 }
2697
2698 return stopsHere;
2699}

References ArchiveRecoveryRequested, ereport, errmsg, fb(), 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(), 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 4470 of file xlogrecovery.c.

4471{
4473}

References fb(), and PROMOTE_SIGNAL_FILE.

Referenced by CheckForStandbyTrigger(), and PostmasterMain().

◆ rescanLatestTimeLine()

static bool rescanLatestTimeLine ( TimeLineID  replayTLI,
XLogRecPtr  replayLSN 
)
static

Definition at line 4122 of file xlogrecovery.c.

4123{
4125 bool found;
4126 ListCell *cell;
4130
4133 {
4134 /* No new timelines found */
4135 return false;
4136 }
4137
4138 /*
4139 * Determine the list of expected TLIs for the new TLI
4140 */
4141
4143
4144 /*
4145 * If the current timeline is not part of the history of the new timeline,
4146 * we cannot proceed to it.
4147 */
4148 found = false;
4149 foreach(cell, newExpectedTLEs)
4150 {
4152
4153 if (currentTle->tli == recoveryTargetTLI)
4154 {
4155 found = true;
4156 break;
4157 }
4158 }
4159 if (!found)
4160 {
4161 ereport(LOG,
4162 (errmsg("new timeline %u is not a child of database system timeline %u",
4163 newtarget,
4164 replayTLI)));
4165 return false;
4166 }
4167
4168 /*
4169 * The current timeline was found in the history file, but check that the
4170 * next timeline was forked off from it *after* the current recovery
4171 * location.
4172 */
4173 if (currentTle->end < replayLSN)
4174 {
4175 ereport(LOG,
4176 errmsg("new timeline %u forked off current database system timeline %u before current recovery point %X/%08X",
4177 newtarget,
4178 replayTLI,
4180 return false;
4181 }
4182
4183 /* The new timeline history seems valid. Switch target */
4187
4188 /*
4189 * As in StartupXLOG(), try to ensure we have all the history files
4190 * between the old target and new target in pg_wal.
4191 */
4193
4194 ereport(LOG,
4195 (errmsg("new target timeline is %u",
4197
4198 return true;
4199}
List * readTimeLineHistory(TimeLineID targetTLI)
Definition timeline.c:77
TimeLineID findNewestTimeLine(TimeLineID startTLI)
Definition timeline.c:265
void restoreTimeLineHistoryFiles(TimeLineID begin, TimeLineID end)
Definition timeline.c:51
void list_free_deep(List *list)
Definition list.c:1560

References ereport, errmsg, expectedTLEs, fb(), findNewestTimeLine(), lfirst, list_free_deep(), LOG, LSN_FORMAT_ARGS, readTimeLineHistory(), recoveryTargetTLI, and restoreTimeLineHistoryFiles().

Referenced by WaitForWALToBecomeAvailable().

◆ rm_redo_error_callback()

static void rm_redo_error_callback ( void arg)
static

Definition at line 2257 of file xlogrecovery.c.

2258{
2259 XLogReaderState *record = (XLogReaderState *) arg;
2261
2263 xlog_outdesc(&buf, record);
2264 xlog_block_info(&buf, record);
2265
2266 /* translator: %s is a WAL record description */
2267 errcontext("WAL redo at %X/%08X for %s",
2268 LSN_FORMAT_ARGS(record->ReadRecPtr),
2269 buf.data);
2270
2271 pfree(buf.data);
2272}
Datum arg
Definition elog.c:1323
#define errcontext
Definition elog.h:200
static void xlog_block_info(StringInfo buf, XLogReaderState *record)

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

Referenced by ApplyWalRecord().

◆ SetCurrentChunkStartTime()

◆ SetLatestXTime()

◆ SetPromoteIsTriggered()

static void SetPromoteIsTriggered ( void  )
static

Definition at line 4428 of file xlogrecovery.c.

4429{
4433
4434 /*
4435 * Mark the recovery pause state as 'not paused' because the paused state
4436 * ends and promotion continues if a promotion is triggered while recovery
4437 * is paused. Otherwise pg_get_wal_replay_pause_state() can mistakenly
4438 * return 'paused' while a promotion is ongoing.
4439 */
4440 SetRecoveryPause(false);
4441
4443}

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

Referenced by CheckForStandbyTrigger().

◆ SetRecoveryPause()

◆ ShutdownWalRecovery()

void ShutdownWalRecovery ( void  )

Definition at line 1572 of file xlogrecovery.c.

1573{
1574 char recoveryPath[MAXPGPATH];
1575
1576 /* Final update of pg_stat_recovery_prefetch. */
1578
1579 /* Shut down xlogreader */
1580 if (readFile >= 0)
1581 {
1582 close(readFile);
1583 readFile = -1;
1584 }
1588
1590 {
1591 /*
1592 * Since there might be a partial WAL segment named RECOVERYXLOG, get
1593 * rid of it.
1594 */
1595 snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYXLOG");
1596 unlink(recoveryPath); /* ignore any error */
1597
1598 /* Get rid of any remaining recovered timeline-history file, too */
1599 snprintf(recoveryPath, MAXPGPATH, XLOGDIR "/RECOVERYHISTORY");
1600 unlink(recoveryPath); /* ignore any error */
1601 }
1602
1603 /*
1604 * We don't need the latch anymore. It's not strictly necessary to disown
1605 * it, but let's do it for the sake of tidiness.
1606 */
1609}
void DisownLatch(Latch *latch)
Definition latch.c:144
#define XLOGDIR
void XLogPrefetcherComputeStats(XLogPrefetcher *prefetcher)
void XLogPrefetcherFree(XLogPrefetcher *prefetcher)
void XLogReaderFree(XLogReaderState *state)
Definition xlogreader.c:163

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

Referenced by StartupXLOG().

◆ StartupRequestWalReceiverRestart()

void StartupRequestWalReceiverRestart ( void  )

Definition at line 4391 of file xlogrecovery.c.

4392{
4394 {
4395 ereport(LOG,
4396 (errmsg("WAL receiver process shutdown requested")));
4397
4398 pendingWalRcvRestart = true;
4399 }
4400}
bool WalRcvRunning(void)
static bool pendingWalRcvRestart

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{
1072 /* Reject conflicting targets even when recovery was not requested */
1074
1076 return;
1077
1078 /*
1079 * Check for compulsory parameters
1080 */
1082 {
1083 if ((PrimaryConnInfo == NULL || strcmp(PrimaryConnInfo, "") == 0) &&
1086 (errmsg("specified neither \"primary_conninfo\" nor \"restore_command\""),
1087 errhint("The database server will regularly poll the pg_wal subdirectory to check for files placed there.")));
1088 }
1089 else
1090 {
1093 ereport(FATAL,
1095 errmsg("must specify \"restore_command\" when standby mode is not enabled")));
1096 }
1097
1098 /*
1099 * Override any inconsistent requests. Note that this is a change of
1100 * behaviour in 9.5; prior to this we simply ignored a request to pause if
1101 * hot_standby = off, which was surprising behaviour.
1102 */
1106
1107 /*
1108 * Final parsing of recovery_target_time string; see also
1109 * check_recovery_target_time().
1110 */
1112 {
1116 Int32GetDatum(-1)));
1117 }
1118
1119 /*
1120 * If user specified recovery_target_timeline, validate it or compute the
1121 * "latest" value. We can't do this until after we've gotten the restore
1122 * command and set InArchiveRecovery, because we need to fetch timeline
1123 * history files from the archive.
1124 */
1126 {
1128
1129 /* Timeline 1 does not have a history file, all else should */
1130 if (rtli != 1 && !existsTimeLineHistory(rtli))
1131 ereport(FATAL,
1133 errmsg("recovery target timeline %u does not exist",
1134 rtli)));
1136 }
1138 {
1139 /* We start the "latest" search from pg_control's timeline */
1141 }
1142 else
1143 {
1144 /*
1145 * else we just use the recoveryTargetTLI as already read from
1146 * ControlFile
1147 */
1149 }
1150}
bool existsTimeLineHistory(TimeLineID probeTLI)
Definition timeline.c:223
Datum timestamptz_in(PG_FUNCTION_ARGS)
Definition timestamp.c:414
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition fmgr.h:692
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212
#define InvalidOid
static TimestampTz DatumGetTimestampTz(Datum X)
Definition timestamp.h:34
bool EnableHotStandby
Definition xlog.c:128
char * recoveryRestoreCommand
char * recovery_target_time_string
static RecoveryTargetType DetermineRecoveryTargetType(void)
char * PrimaryConnInfo

References ArchiveRecoveryRequested, Assert, CStringGetDatum(), DatumGetTimestampTz(), DetermineRecoveryTargetType(), DirectFunctionCall3, EnableHotStandby, ereport, errcode(), errhint(), errmsg, existsTimeLineHistory(), FATAL, fb(), 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 2443 of file xlogrecovery.c.

2444{
2446 RelFileLocator rlocator;
2447 ForkNumber forknum;
2448 BlockNumber blkno;
2449 int block_id;
2450
2451 /* Records with no backup blocks have no need for consistency checks. */
2452 if (!XLogRecHasAnyBlockRefs(record))
2453 return;
2454
2456
2457 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
2458 {
2459 Buffer buf;
2460 Page page;
2461
2463 &rlocator, &forknum, &blkno, NULL))
2464 {
2465 /*
2466 * WAL record doesn't contain a block reference with the given id.
2467 * Do nothing.
2468 */
2469 continue;
2470 }
2471
2473
2474 if (XLogRecBlockImageApply(record, block_id))
2475 {
2476 /*
2477 * WAL record has already applied the page, so bypass the
2478 * consistency check as that would result in comparing the full
2479 * page stored in the record with itself.
2480 */
2481 continue;
2482 }
2483
2484 /*
2485 * Read the contents from the current buffer and store it in a
2486 * temporary page.
2487 */
2488 buf = XLogReadBufferExtended(rlocator, forknum, blkno,
2491 if (!BufferIsValid(buf))
2492 continue;
2493
2495 page = BufferGetPage(buf);
2496
2497 /*
2498 * Take a copy of the local page where WAL has been applied to have a
2499 * comparison base before masking it...
2500 */
2502
2503 /* No need for this page anymore now that a copy is in. */
2505
2506 /*
2507 * If the block LSN is already ahead of this WAL record, we can't
2508 * expect contents to match. This can happen if recovery is
2509 * restarted.
2510 */
2512 continue;
2513
2514 /*
2515 * Read the contents from the backup copy, stored in WAL record and
2516 * store it in a temporary page. There is no need to allocate a new
2517 * page here, a local buffer is fine to hold its contents and a mask
2518 * can be directly applied on it.
2519 */
2521 ereport(ERROR,
2523 errmsg_internal("%s", record->errormsg_buf)));
2524
2525 /*
2526 * If masking function is defined, mask both the primary and replay
2527 * images
2528 */
2529 if (rmgr.rm_mask != NULL)
2530 {
2531 rmgr.rm_mask(replay_image_masked, blkno);
2532 rmgr.rm_mask(primary_image_masked, blkno);
2533 }
2534
2535 /* Time to compare the primary and replay images. */
2537 {
2538 elog(FATAL,
2539 "inconsistent page found, rel %u/%u/%u, forknum %u, blkno %u",
2540 rlocator.spcOid, rlocator.dbOid, rlocator.relNumber,
2541 forknum, blkno);
2542 }
2543 }
2544}
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:5626
static Page BufferGetPage(Buffer buffer)
Definition bufmgr.h:468
@ BUFFER_LOCK_EXCLUSIVE
Definition bufmgr.h:222
static void LockBuffer(Buffer buffer, BufferLockMode mode)
Definition bufmgr.h:334
@ RBM_NORMAL_NO_LOG
Definition bufmgr.h:52
static bool BufferIsValid(Buffer bufnum)
Definition bufmgr.h:419
PageData * Page
Definition bufpage.h:81
static XLogRecPtr PageGetLSN(const PageData *page)
Definition bufpage.h:410
ForkNumber
Definition relpath.h:56
RelFileNumber relNumber
char * errormsg_buf
Definition xlogreader.h:310
bool XLogRecGetBlockTagExtended(XLogReaderState *record, uint8 block_id, RelFileLocator *rlocator, ForkNumber *forknum, BlockNumber *blknum, Buffer *prefetch_buffer)
bool RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
#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:484

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

Referenced by ApplyWalRecord().

◆ WaitForWALToBecomeAvailable()

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

Definition at line 3541 of file xlogrecovery.c.

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

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

Referenced by XLogPageRead().

◆ WakeupRecovery()

◆ xlog_block_info()

static void xlog_block_info ( StringInfo  buf,
XLogReaderState record 
)
static

Definition at line 2318 of file xlogrecovery.c.

2319{
2320 int block_id;
2321
2322 /* decode block references */
2323 for (block_id = 0; block_id <= XLogRecMaxBlockId(record); block_id++)
2324 {
2325 RelFileLocator rlocator;
2326 ForkNumber forknum;
2328
2330 &rlocator, &forknum, &blk, NULL))
2331 continue;
2332
2333 if (forknum != MAIN_FORKNUM)
2334 appendStringInfo(buf, "; blkref #%d: rel %u/%u/%u, fork %u, blk %u",
2335 block_id,
2336 rlocator.spcOid, rlocator.dbOid,
2337 rlocator.relNumber,
2338 forknum,
2339 blk);
2340 else
2341 appendStringInfo(buf, "; blkref #%d: rel %u/%u/%u, blk %u",
2342 block_id,
2343 rlocator.spcOid, rlocator.dbOid,
2344 rlocator.relNumber,
2345 blk);
2346 if (XLogRecHasBlockImage(record, block_id))
2347 appendStringInfoString(buf, " FPW");
2348 }
2349}
@ MAIN_FORKNUM
Definition relpath.h:58

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

Referenced by rm_redo_error_callback().

◆ xlog_outdesc()

void xlog_outdesc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 2279 of file xlogrecovery.c.

2280{
2282 uint8 info = XLogRecGetInfo(record);
2283 const char *id;
2284
2287
2288 id = rmgr.rm_identify(info);
2289 if (id == NULL)
2290 appendStringInfo(buf, "UNKNOWN (%X): ", info & ~XLR_INFO_MASK);
2291 else
2292 appendStringInfo(buf, "%s: ", id);
2293
2294 rmgr.rm_desc(buf, record);
2295}
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), buf, fb(), GetRmgr(), XLogRecGetInfo, XLogRecGetRmid, and XLR_INFO_MASK.

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

◆ XLogFileRead()

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

Definition at line 4209 of file xlogrecovery.c.

4211{
4212 char xlogfname[MAXFNAMELEN];
4213 char activitymsg[MAXFNAMELEN + 16];
4214 char path[MAXPGPATH];
4215 int fd;
4216
4218
4219 switch (source)
4220 {
4221 case XLOG_FROM_ARCHIVE:
4222 /* Report recovery progress in PS display */
4223 snprintf(activitymsg, sizeof(activitymsg), "waiting for %s",
4224 xlogfname);
4226
4227 if (!RestoreArchivedFile(path, xlogfname,
4228 "RECOVERYXLOG",
4230 InRedo))
4231 return -1;
4232 break;
4233
4234 case XLOG_FROM_PG_WAL:
4235 case XLOG_FROM_STREAM:
4236 XLogFilePath(path, tli, segno, wal_segment_size);
4237 break;
4238
4239 default:
4240 elog(ERROR, "invalid XLogFileRead source %d", source);
4241 }
4242
4243 /*
4244 * If the segment was fetched from archival storage, replace the existing
4245 * xlog segment (if any) with the archival version.
4246 */
4248 {
4251
4252 /*
4253 * Set path to point at the new file in pg_wal.
4254 */
4255 snprintf(path, MAXPGPATH, XLOGDIR "/%s", xlogfname);
4256 }
4257
4259 if (fd >= 0)
4260 {
4261 /* Success! */
4262 curFileTLI = tli;
4263
4264 /* Report recovery progress in PS display */
4265 snprintf(activitymsg, sizeof(activitymsg), "recovering %s",
4266 xlogfname);
4268
4269 /* Track source of data in assorted state variables */
4272 /* In FROM_STREAM case, caller tracks receipt time, not me */
4273 if (source != XLOG_FROM_STREAM)
4275
4276 return fd;
4277 }
4278 if (errno != ENOENT || !notfoundOk) /* unexpected failure? */
4279 ereport(PANIC,
4281 errmsg("could not open file \"%s\": %m", path)));
4282 return -1;
4283}
int BasicOpenFile(const char *fileName, int fileFlags)
Definition fd.c:1090
static rewind_source * source
Definition pg_rewind.c:89
static void set_ps_display(const char *activity)
Definition ps_status.h:40
bool IsInstallXLogFileSegmentActive(void)
Definition xlog.c:10176
static void XLogFilePath(char *path, TimeLineID tli, XLogSegNo logSegNo, int wal_segsz_bytes)
bool RestoreArchivedFile(char *path, const char *xlogfname, const char *recovername, off_t expectedSize, bool cleanupEnabled)
Definition xlogarchive.c:55
void KeepFileRestoredFromArchive(const char *path, const char *xlogfname)

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

Referenced by WaitForWALToBecomeAvailable(), and XLogFileReadAnyTLI().

◆ XLogFileReadAnyTLI()

static int XLogFileReadAnyTLI ( XLogSegNo  segno,
XLogSource  source 
)
static

Definition at line 4291 of file xlogrecovery.c.

4292{
4293 char path[MAXPGPATH];
4294 ListCell *cell;
4295 int fd;
4296 List *tles;
4297
4298 /*
4299 * Loop looking for a suitable timeline ID: we might need to read any of
4300 * the timelines listed in expectedTLEs.
4301 *
4302 * We expect curFileTLI on entry to be the TLI of the preceding file in
4303 * sequence, or 0 if there was no predecessor. We do not allow curFileTLI
4304 * to go backwards; this prevents us from picking up the wrong file when a
4305 * parent timeline extends to higher segment numbers than the child we
4306 * want to read.
4307 *
4308 * If we haven't read the timeline history file yet, read it now, so that
4309 * we know which TLIs to scan. We don't save the list in expectedTLEs,
4310 * however, unless we actually find a valid segment. That way if there is
4311 * neither a timeline history file nor a WAL segment in the archive, and
4312 * streaming replication is set up, we'll read the timeline history file
4313 * streamed from the primary when we start streaming, instead of
4314 * recovering with a dummy history generated here.
4315 */
4316 if (expectedTLEs)
4318 else
4320
4321 foreach(cell, tles)
4322 {
4324 TimeLineID tli = hent->tli;
4325
4326 if (tli < curFileTLI)
4327 break; /* don't bother looking at too-old TLIs */
4328
4329 /*
4330 * Skip scanning the timeline ID that the logfile segment to read
4331 * doesn't belong to
4332 */
4333 if (XLogRecPtrIsValid(hent->begin))
4334 {
4335 XLogSegNo beginseg = 0;
4336
4338
4339 /*
4340 * The logfile segment that doesn't belong to the timeline is
4341 * older or newer than the segment that the timeline started or
4342 * ended at, respectively. It's sufficient to check only the
4343 * starting segment of the timeline here. Since the timelines are
4344 * scanned in descending order in this loop, any segments newer
4345 * than the ending segment should belong to newer timeline and
4346 * have already been read before. So it's not necessary to check
4347 * the ending segment of the timeline here.
4348 */
4349 if (segno < beginseg)
4350 continue;
4351 }
4352
4354 {
4355 fd = XLogFileRead(segno, tli, XLOG_FROM_ARCHIVE, true);
4356 if (fd != -1)
4357 {
4358 elog(DEBUG1, "got WAL segment from archive");
4359 if (!expectedTLEs)
4361 return fd;
4362 }
4363 }
4364
4366 {
4367 fd = XLogFileRead(segno, tli, XLOG_FROM_PG_WAL, true);
4368 if (fd != -1)
4369 {
4370 if (!expectedTLEs)
4372 return fd;
4373 }
4374 }
4375 }
4376
4377 /* Couldn't find it. For simplicity, complain about front timeline */
4379 errno = ENOENT;
4382 errmsg("could not open file \"%s\": %m", path)));
4383 return -1;
4384}

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

Referenced by WaitForWALToBecomeAvailable().

◆ XLogPageRead()

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

Definition at line 3282 of file xlogrecovery.c.

3284{
3285 XLogPageReadPrivate *private =
3287 int emode = private->emode;
3290 ssize_t r;
3292
3294
3297
3298 /*
3299 * See if we need to switch to a new segment because the requested record
3300 * is not in the currently open one.
3301 */
3302 if (readFile >= 0 &&
3304 {
3305 /*
3306 * Request a restartpoint if we've replayed too much xlog since the
3307 * last one.
3308 */
3310 {
3312 {
3313 (void) GetRedoRecPtr();
3316 }
3317 }
3318
3319 close(readFile);
3320 readFile = -1;
3322 }
3323
3325
3326retry:
3327 /* See if we need to retrieve more data */
3328 if (readFile < 0 ||
3331 {
3332 if (readFile >= 0 &&
3336 return XLREAD_WOULDBLOCK;
3337
3339 private->randAccess,
3340 private->fetching_ckpt,
3342 private->replayTLI,
3345 {
3346 case XLREAD_WOULDBLOCK:
3347 return XLREAD_WOULDBLOCK;
3348 case XLREAD_FAIL:
3349 if (readFile >= 0)
3350 close(readFile);
3351 readFile = -1;
3352 readLen = 0;
3354 return XLREAD_FAIL;
3355 case XLREAD_SUCCESS:
3356 break;
3357 }
3358 }
3359
3360 /*
3361 * At this point, we have the right segment open and if we're streaming we
3362 * know the requested record is in it.
3363 */
3364 Assert(readFile != -1);
3365
3366 /*
3367 * If the current segment is being streamed from the primary, calculate
3368 * how much of the current page we have received already. We know the
3369 * requested record has been received, but this is for the benefit of
3370 * future calls, to allow quick exit at the top of this function.
3371 */
3373 {
3376 else
3379 }
3380 else
3382
3383 /* Read the requested page */
3385
3386 /* Measure I/O timing when reading segment */
3388
3390 r = pg_pread(readFile, readBuf, XLOG_BLCKSZ, (pgoff_t) readOff);
3391 if (r != XLOG_BLCKSZ)
3392 {
3393 char fname[MAXFNAMELEN];
3394 int save_errno = errno;
3395
3397
3398 /* Count I/O stats only for successful short reads */
3399 if (r > 0)
3401 io_start, 1, r);
3402
3404 if (r < 0)
3405 {
3406 errno = save_errno;
3409 errmsg("could not read from WAL segment %s, LSN %X/%08X, offset %u: %m",
3411 readOff)));
3412 }
3413 else
3416 errmsg("could not read from WAL segment %s, LSN %X/%08X, offset %u: read %zd of %zu",
3418 readOff, r, (Size) XLOG_BLCKSZ)));
3420 }
3422
3424 io_start, 1, r);
3425
3428 Assert(reqLen <= readLen);
3429
3431
3432 /*
3433 * Check the page header immediately, so that we can retry immediately if
3434 * it's not valid. This may seem unnecessary, because ReadPageInternal()
3435 * validates the page header anyway, and would propagate the failure up to
3436 * ReadRecord(), which would retry. However, there's a corner case with
3437 * continuation records, if a record is split across two pages such that
3438 * we would need to read the two pages from different sources across two
3439 * WAL segments.
3440 *
3441 * The first page is only available locally, in pg_wal, because it's
3442 * already been recycled on the primary. The second page, however, is not
3443 * present in pg_wal, and we should stream it from the primary. There is a
3444 * recycled WAL segment present in pg_wal, with garbage contents, however.
3445 * We would read the first page from the local WAL segment, but when
3446 * reading the second page, we would read the bogus, recycled, WAL
3447 * segment. If we didn't catch that case here, we would never recover,
3448 * because ReadRecord() would retry reading the whole record from the
3449 * beginning.
3450 *
3451 * Of course, this only catches errors in the page header, which is what
3452 * happens in the case of a recycled WAL segment. Other kinds of errors or
3453 * corruption still has the same problem. But this at least fixes the
3454 * common case, which can happen as part of normal operation.
3455 *
3456 * Validating the page header is cheap enough that doing it twice
3457 * shouldn't be a big deal from a performance point of view.
3458 *
3459 * When not in standby mode, an invalid page header should cause recovery
3460 * to end, not retry reading the page, so we don't need to validate the
3461 * page header here for the retry. Instead, ReadPageInternal() is
3462 * responsible for the validation.
3463 */
3464 if (StandbyMode &&
3467 {
3468 /*
3469 * Emit this error right now then retry this page immediately. Use
3470 * errmsg_internal() because the message was already translated.
3471 */
3472 if (xlogreader->errormsg_buf[0])
3475
3476 /* reset any error XLogReaderValidatePageHeader() might have set */
3479 }
3480
3481 return readLen;
3482
3484
3485 /*
3486 * If we're reading ahead, give up fast. Retries and error reporting will
3487 * be handled by a later read when recovery catches up to this point.
3488 */
3490 return XLREAD_WOULDBLOCK;
3491
3492 lastSourceFailed = true;
3493
3494 if (readFile >= 0)
3495 close(readFile);
3496 readFile = -1;
3497 readLen = 0;
3499
3500 /* In standby-mode, keep trying */
3501 if (StandbyMode)
3502 goto retry;
3503 else
3504 return XLREAD_FAIL;
3505}
#define PG_USED_FOR_ASSERTS_ONLY
Definition c.h:308
size_t Size
Definition c.h:748
void RequestCheckpoint(int flags)
@ IOOBJECT_WAL
Definition pgstat.h:283
@ IOCONTEXT_NORMAL
Definition pgstat.h:293
@ IOOP_READ
Definition pgstat.h:319
instr_time pgstat_prepare_io_time(bool track_io_guc)
Definition pgstat_io.c:91
void pgstat_count_io_op_time(IOObject io_object, IOContext io_context, IOOp io_op, instr_time start_time, uint32 cnt, uint64 bytes)
Definition pgstat_io.c:122
#define pg_pread
Definition port.h:248
off_t pgoff_t
Definition port.h:422
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition wait_event.h:67
static void pgstat_report_wait_end(void)
Definition wait_event.h:83
XLogRecPtr GetRedoRecPtr(void)
Definition xlog.c:6938
bool track_wal_io_timing
Definition xlog.c:144
bool XLogCheckpointNeeded(XLogSegNo new_segno)
Definition xlog.c:2301
#define CHECKPOINT_CAUSE_XLOG
Definition xlog.h:160
#define XLByteInSeg(xlrp, logSegNo, wal_segsz_bytes)
void XLogReaderResetError(XLogReaderState *state)
bool XLogReaderValidatePageHeader(XLogReaderState *state, XLogRecPtr recptr, char *phdr)
static XLogPageReadResult WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess, bool fetching_ckpt, XLogRecPtr tliRecPtr, TimeLineID replayTLI, XLogRecPtr replayLSN, bool nonblocking)
static uint32 readLen

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

Referenced by InitWalRecovery().

◆ xlogrecovery_redo()

static void xlogrecovery_redo ( XLogReaderState record,
TimeLineID  replayTLI 
)
static

Definition at line 2052 of file xlogrecovery.c.

2053{
2054 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2055 XLogRecPtr lsn = record->EndRecPtr;
2056
2057 Assert(XLogRecGetRmid(record) == RM_XLOG_ID);
2058
2059 if (info == XLOG_OVERWRITE_CONTRECORD)
2060 {
2061 /* Verify the payload of a XLOG_OVERWRITE_CONTRECORD record. */
2063
2065 if (xlrec.overwritten_lsn != record->overwrittenRecPtr)
2066 elog(FATAL, "mismatching overwritten LSN %X/%08X -> %X/%08X",
2067 LSN_FORMAT_ARGS(xlrec.overwritten_lsn),
2069
2070 /* We have safely skipped the aborted record */
2073
2074 ereport(LOG,
2075 errmsg("successfully skipped missing contrecord at %X/%08X, overwritten at %s",
2076 LSN_FORMAT_ARGS(xlrec.overwritten_lsn),
2077 timestamptz_to_str(xlrec.overwrite_time)));
2078
2079 /* Verifying the record should only happen once */
2081 }
2082 else if (info == XLOG_BACKUP_END)
2083 {
2084 XLogRecPtr startpoint;
2085
2086 memcpy(&startpoint, XLogRecGetData(record), sizeof(startpoint));
2087
2088 if (backupStartPoint == startpoint)
2089 {
2090 /*
2091 * We have reached the end of base backup, the point where
2092 * pg_backup_stop() was done. The data on disk is now consistent
2093 * (assuming we have also reached minRecoveryPoint). Set
2094 * backupEndPoint to the current LSN, so that the next call to
2095 * CheckRecoveryConsistency() will notice it and do the
2096 * end-of-backup processing.
2097 */
2098 elog(DEBUG1, "end of backup record reached");
2099
2100 backupEndPoint = lsn;
2101 }
2102 else
2103 elog(DEBUG1, "saw end-of-backup record for backup starting at %X/%08X, waiting for %X/%08X",
2105 }
2106}
#define XLOG_OVERWRITE_CONTRECORD
Definition pg_control.h:85
#define XLOG_BACKUP_END
Definition pg_control.h:77
XLogRecPtr overwrittenRecPtr
Definition xlogreader.h:216

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

Referenced by ApplyWalRecord().

◆ XLogRecoveryShmemInit()

static void XLogRecoveryShmemInit ( void arg)
static

◆ XLogRecoveryShmemRequest()

static void XLogRecoveryShmemRequest ( void arg)
static

Definition at line 402 of file xlogrecovery.c.

403{
404 ShmemRequestStruct(.name = "XLOG Recovery Ctl",
405 .size = sizeof(XLogRecoveryCtlData),
406 .ptr = (void **) &XLogRecoveryCtl,
407 );
408}
#define ShmemRequestStruct(...)
Definition shmem.h:176
const char * name

References name, ShmemRequestStruct, and XLogRecoveryCtl.

◆ XLogRequestWalReceiverReply()

void XLogRequestWalReceiverReply ( void  )

Definition at line 4503 of file xlogrecovery.c.

4504{
4506}

References doRequestWalReceiverReply.

Referenced by xact_redo_commit().

Variable Documentation

◆ abortedRecPtr

XLogRecPtr abortedRecPtr
static

◆ archiveCleanupCommand

char* archiveCleanupCommand = NULL

Definition at line 89 of file xlogrecovery.c.

Referenced by CreateRestartPoint().

◆ ArchiveRecoveryRequested

◆ backupEndPoint

XLogRecPtr backupEndPoint
static

Definition at line 287 of file xlogrecovery.c.

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

◆ backupEndRequired

bool backupEndRequired = false
static

Definition at line 288 of file xlogrecovery.c.

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

◆ backupStartPoint

XLogRecPtr backupStartPoint
static

Definition at line 286 of file xlogrecovery.c.

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

◆ CheckPointLoc

XLogRecPtr CheckPointLoc = InvalidXLogRecPtr
static

Definition at line 172 of file xlogrecovery.c.

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

◆ CheckPointTLI

TimeLineID CheckPointTLI = 0
static

Definition at line 173 of file xlogrecovery.c.

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

◆ curFileTLI

TimeLineID curFileTLI
static

◆ currentSource

XLogSource currentSource = XLOG_FROM_ANY
static

◆ doRequestWalReceiverReply

bool doRequestWalReceiverReply
static

Definition at line 190 of file xlogrecovery.c.

Referenced by ApplyWalRecord(), and XLogRequestWalReceiverReply().

◆ expectedTLEs

◆ flushedUpto

XLogRecPtr flushedUpto = InvalidXLogRecPtr
static

Definition at line 267 of file xlogrecovery.c.

Referenced by WaitForWALToBecomeAvailable(), and XLogPageRead().

◆ InArchiveRecovery

◆ InRedo

bool InRedo = false
static

Definition at line 208 of file xlogrecovery.c.

Referenced by PerformWalRecovery(), and XLogFileRead().

◆ lastSourceFailed

bool lastSourceFailed = false
static

Definition at line 252 of file xlogrecovery.c.

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

◆ LocalHotStandbyActive

bool LocalHotStandbyActive = false
static

◆ LocalPromoteIsTriggered

bool LocalPromoteIsTriggered = false
static

◆ minRecoveryPoint

XLogRecPtr minRecoveryPoint
static

◆ minRecoveryPointTLI

TimeLineID minRecoveryPointTLI
static

Definition at line 284 of file xlogrecovery.c.

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

◆ missingContrecPtr

XLogRecPtr missingContrecPtr
static

◆ pendingWalRcvRestart

bool pendingWalRcvRestart = false
static

◆ primary_image_masked

char* primary_image_masked = NULL
static

Definition at line 308 of file xlogrecovery.c.

Referenced by InitWalRecovery(), and verifyBackupPageConsistency().

◆ PrimaryConnInfo

◆ PrimarySlotName

◆ reachedConsistency

◆ readFile

int readFile = -1
static

◆ readLen

uint32 readLen = 0
static

Definition at line 238 of file xlogrecovery.c.

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

◆ readOff

uint32 readOff = 0
static

Definition at line 237 of file xlogrecovery.c.

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

◆ readSegNo

XLogSegNo readSegNo = 0
static

Definition at line 236 of file xlogrecovery.c.

Referenced by WaitForWALToBecomeAvailable(), and XLogPageRead().

◆ readSource

◆ receiveTLI

TimeLineID receiveTLI = 0
static

◆ recovery_min_apply_delay

int recovery_min_apply_delay = 0

Definition at line 98 of file xlogrecovery.c.

Referenced by recoveryApplyDelay().

◆ recovery_signal_file_found

bool recovery_signal_file_found = false
static

Definition at line 156 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), and readRecoverySignalFile().

◆ recovery_target_action_options

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

Definition at line 79 of file xlogrecovery.c.

79 {
80 {"pause", RECOVERY_TARGET_ACTION_PAUSE, false},
81 {"promote", RECOVERY_TARGET_ACTION_PROMOTE, false},
82 {"shutdown", RECOVERY_TARGET_ACTION_SHUTDOWN, false},
83 {NULL, 0, false}
84};

◆ recovery_target_time_string

char* recovery_target_time_string

Definition at line 94 of file xlogrecovery.c.

Referenced by validateRecoveryParameters().

◆ recoveryEndCommand

char* recoveryEndCommand = NULL

Definition at line 88 of file xlogrecovery.c.

Referenced by CleanupAfterArchiveRecovery().

◆ recoveryRestoreCommand

char* recoveryRestoreCommand = NULL

Definition at line 87 of file xlogrecovery.c.

Referenced by RestoreArchivedFile(), and validateRecoveryParameters().

◆ recoveryStopAfter

bool recoveryStopAfter
static

Definition at line 337 of file xlogrecovery.c.

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

◆ recoveryStopLSN

XLogRecPtr recoveryStopLSN
static

Definition at line 335 of file xlogrecovery.c.

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

◆ recoveryStopName

char recoveryStopName[MAXFNAMELEN]
static

Definition at line 336 of file xlogrecovery.c.

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

◆ recoveryStopTime

TimestampTz recoveryStopTime
static

Definition at line 334 of file xlogrecovery.c.

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

◆ recoveryStopXid

TransactionId recoveryStopXid
static

Definition at line 333 of file xlogrecovery.c.

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

◆ recoveryTarget

◆ recoveryTargetAction

int recoveryTargetAction = RECOVERY_TARGET_ACTION_PAUSE

Definition at line 92 of file xlogrecovery.c.

Referenced by PerformWalRecovery(), and validateRecoveryParameters().

◆ recoveryTargetInclusive

bool recoveryTargetInclusive = true

Definition at line 91 of file xlogrecovery.c.

Referenced by recoveryStopsAfter(), and recoveryStopsBefore().

◆ recoveryTargetLSN

XLogRecPtr recoveryTargetLSN

◆ recoveryTargetName

char* recoveryTargetName

Definition at line 96 of file xlogrecovery.c.

Referenced by InitWalRecovery(), and recoveryStopsAfter().

◆ recoveryTargetTime

TimestampTz recoveryTargetTime

Definition at line 95 of file xlogrecovery.c.

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

◆ recoveryTargetTimeLineGoal

◆ recoveryTargetTLI

◆ recoveryTargetTLIRequested

TimeLineID recoveryTargetTLIRequested = 0

Definition at line 126 of file xlogrecovery.c.

Referenced by assign_recovery_target_timeline(), and validateRecoveryParameters().

◆ recoveryTargetXid

◆ RedoStartLSN

◆ RedoStartTLI

TimeLineID RedoStartTLI = 0
static

◆ replay_image_masked

char* replay_image_masked = NULL
static

Definition at line 307 of file xlogrecovery.c.

Referenced by InitWalRecovery(), and verifyBackupPageConsistency().

◆ standby_signal_file_found

bool standby_signal_file_found = false
static

Definition at line 155 of file xlogrecovery.c.

Referenced by FinishWalRecovery(), and readRecoverySignalFile().

◆ StandbyMode

◆ StandbyModeRequested

bool StandbyModeRequested = false
static

◆ wal_receiver_create_temp_slot

bool wal_receiver_create_temp_slot = false

Definition at line 103 of file xlogrecovery.c.

Referenced by StartupRereadConfig(), and WaitForWALToBecomeAvailable().

◆ xlogprefetcher

◆ xlogreader

◆ XLogReceiptSource

XLogSource XLogReceiptSource = XLOG_FROM_ANY
static

Definition at line 264 of file xlogrecovery.c.

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

◆ XLogReceiptTime

TimestampTz XLogReceiptTime = 0
static

◆ XLogRecoveryCtl

◆ XLogRecoveryShmemCallbacks

const ShmemCallbacks XLogRecoveryShmemCallbacks
Initial value:
= {
.request_fn = XLogRecoveryShmemRequest,
}
static void XLogRecoveryShmemInit(void *arg)
static void XLogRecoveryShmemRequest(void *arg)

Definition at line 315 of file xlogrecovery.c.

315 {
316 .request_fn = XLogRecoveryShmemRequest,
317 .init_fn = XLogRecoveryShmemInit,
318};

◆ xlogSourceNames

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

Definition at line 223 of file xlogrecovery.c.

223{"any", "archive", "pg_wal", "stream"};

Referenced by WaitForWALToBecomeAvailable().