PostgreSQL Source Code  git master
standby.c File Reference
#include "postgres.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/sinvaladt.h"
#include "storage/standby.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
Include dependency graph for standby.c:

Go to the source code of this file.

Data Structures

struct  RecoveryLockListsEntry
 

Macros

#define STANDBY_INITIAL_WAIT_US   1000
 

Typedefs

typedef struct RecoveryLockListsEntry RecoveryLockListsEntry
 

Functions

static void ResolveRecoveryConflictWithVirtualXIDs (VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info, bool report_waiting)
 
static void SendRecoveryConflictWithBufferPin (ProcSignalReason reason)
 
static XLogRecPtr LogCurrentRunningXacts (RunningTransactions CurrRunningXacts)
 
static void LogAccessExclusiveLocks (int nlocks, xl_standby_lock *locks)
 
void InitRecoveryTransactionEnvironment (void)
 
void ShutdownRecoveryTransactionEnvironment (void)
 
static TimestampTz GetStandbyLimitTime (void)
 
static bool WaitExceedsMaxStandbyDelay (uint32 wait_event_info)
 
void ResolveRecoveryConflictWithSnapshot (TransactionId latestRemovedXid, RelFileNode node)
 
void ResolveRecoveryConflictWithTablespace (Oid tsid)
 
void ResolveRecoveryConflictWithDatabase (Oid dbid)
 
void ResolveRecoveryConflictWithLock (LOCKTAG locktag)
 
void ResolveRecoveryConflictWithBufferPin (void)
 
void CheckRecoveryConflictDeadlock (void)
 
void StandbyDeadLockHandler (void)
 
void StandbyTimeoutHandler (void)
 
void StandbyLockTimeoutHandler (void)
 
void StandbyAcquireAccessExclusiveLock (TransactionId xid, Oid dbOid, Oid relOid)
 
static void StandbyReleaseLockList (List *locks)
 
static void StandbyReleaseLocks (TransactionId xid)
 
void StandbyReleaseLockTree (TransactionId xid, int nsubxids, TransactionId *subxids)
 
void StandbyReleaseAllLocks (void)
 
void StandbyReleaseOldLocks (TransactionId oldxid)
 
void standby_redo (XLogReaderState *record)
 
XLogRecPtr LogStandbySnapshot (void)
 
void LogAccessExclusiveLock (Oid dbOid, Oid relOid)
 
void LogAccessExclusiveLockPrepare (void)
 
void LogStandbyInvalidations (int nmsgs, SharedInvalidationMessage *msgs, bool relcacheInitFileInval)
 

Variables

int vacuum_defer_cleanup_age
 
int max_standby_archive_delay = 30 * 1000
 
int max_standby_streaming_delay = 30 * 1000
 
static HTABRecoveryLockLists
 
static int standbyWait_us = STANDBY_INITIAL_WAIT_US
 

Macro Definition Documentation

◆ STANDBY_INITIAL_WAIT_US

#define STANDBY_INITIAL_WAIT_US   1000

Definition at line 180 of file standby.c.

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

Typedef Documentation

◆ RecoveryLockListsEntry

Function Documentation

◆ CheckRecoveryConflictDeadlock()

void CheckRecoveryConflictDeadlock ( void  )

Definition at line 564 of file standby.c.

References Assert, ereport, errcode(), errdetail(), errmsg(), ERROR, HoldingBufferPinThatDelaysRecovery(), and InRecovery.

Referenced by ProcSleep().

565 {
566  Assert(!InRecovery); /* do not call in Startup process */
567 
569  return;
570 
571  /*
572  * Error message should match ProcessInterrupts() but we avoid calling
573  * that because we aren't handling an interrupt at this point. Note that
574  * we only cancel the current transaction here, so if we are in a
575  * subtransaction and the pin is held by a parent, then the Startup
576  * process will continue to wait even though we have avoided deadlock.
577  */
578  ereport(ERROR,
579  (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
580  errmsg("canceling statement due to conflict with recovery"),
581  errdetail("User transaction caused buffer deadlock with recovery.")));
582 }
bool InRecovery
Definition: xlog.c:205
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:957
#define ereport(elevel,...)
Definition: elog.h:144
#define Assert(condition)
Definition: c.h:745
bool HoldingBufferPinThatDelaysRecovery(void)
Definition: bufmgr.c:3918
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ GetStandbyLimitTime()

static TimestampTz GetStandbyLimitTime ( void  )
static

Definition at line 156 of file standby.c.

References GetXLogReceiptTime(), max_standby_archive_delay, max_standby_streaming_delay, and TimestampTzPlusMilliseconds.

Referenced by ResolveRecoveryConflictWithBufferPin(), ResolveRecoveryConflictWithLock(), and WaitExceedsMaxStandbyDelay().

157 {
158  TimestampTz rtime;
159  bool fromStream;
160 
161  /*
162  * The cutoff time is the last WAL data receipt time plus the appropriate
163  * delay variable. Delay of -1 means wait forever.
164  */
165  GetXLogReceiptTime(&rtime, &fromStream);
166  if (fromStream)
167  {
169  return 0; /* wait forever */
171  }
172  else
173  {
175  return 0; /* wait forever */
177  }
178 }
int max_standby_archive_delay
Definition: standby.c:40
int64 TimestampTz
Definition: timestamp.h:39
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:56
void GetXLogReceiptTime(TimestampTz *rtime, bool *fromStream)
Definition: xlog.c:6220
int max_standby_streaming_delay
Definition: standby.c:41

◆ InitRecoveryTransactionEnvironment()

void InitRecoveryTransactionEnvironment ( void  )

Definition at line 75 of file standby.c.

References VirtualTransactionId::backendId, HASHCTL::entrysize, GetNextLocalTransactionId(), HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, VirtualTransactionId::localTransactionId, MyBackendId, SharedInvalBackendInit(), STANDBY_INITIALIZED, standbyState, and VirtualXactLockTableInsert().

Referenced by StartupXLOG().

76 {
78  HASHCTL hash_ctl;
79 
80  /*
81  * Initialize the hash table for tracking the list of locks held by each
82  * transaction.
83  */
84  memset(&hash_ctl, 0, sizeof(hash_ctl));
85  hash_ctl.keysize = sizeof(TransactionId);
86  hash_ctl.entrysize = sizeof(RecoveryLockListsEntry);
87  RecoveryLockLists = hash_create("RecoveryLockLists",
88  64,
89  &hash_ctl,
91 
92  /*
93  * Initialize shared invalidation management for Startup process, being
94  * careful to register ourselves as a sendOnly process so we don't need to
95  * read messages, nor will we get signaled when the queue starts filling
96  * up.
97  */
99 
100  /*
101  * Lock a virtual transaction id for Startup process.
102  *
103  * We need to do GetNextLocalTransactionId() because
104  * SharedInvalBackendInit() leaves localTransactionId invalid and the lock
105  * manager doesn't like that at all.
106  *
107  * Note that we don't need to run XactLockTableInsert() because nobody
108  * needs to wait on xids. That sounds a little strange, but table locks
109  * are held by vxids and row level locks are held by xids. All queries
110  * hold AccessShareLocks so never block while we write or lock new rows.
111  */
112  vxid.backendId = MyBackendId;
115 
117 }
BackendId MyBackendId
Definition: globals.c:81
static HTAB * RecoveryLockLists
Definition: standby.c:43
#define HASH_ELEM
Definition: hsearch.h:85
uint32 TransactionId
Definition: c.h:520
void SharedInvalBackendInit(bool sendOnly)
Definition: sinvaladt.c:257
Size entrysize
Definition: hsearch.h:72
LocalTransactionId localTransactionId
Definition: lock.h:65
LocalTransactionId GetNextLocalTransactionId(void)
Definition: sinvaladt.c:766
void VirtualXactLockTableInsert(VirtualTransactionId vxid)
Definition: lock.c:4391
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
BackendId backendId
Definition: lock.h:64
struct RecoveryLockListsEntry RecoveryLockListsEntry
HotStandbyState standbyState
Definition: xlog.c:208

◆ LogAccessExclusiveLock()

void LogAccessExclusiveLock ( Oid  dbOid,
Oid  relOid 
)

Definition at line 1061 of file standby.c.

References xl_standby_lock::dbOid, GetCurrentTransactionId(), LogAccessExclusiveLocks(), MyXactFlags, xl_standby_lock::relOid, XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK, and xl_standby_lock::xid.

Referenced by LockAcquireExtended().

1062 {
1063  xl_standby_lock xlrec;
1064 
1065  xlrec.xid = GetCurrentTransactionId();
1066 
1067  xlrec.dbOid = dbOid;
1068  xlrec.relOid = relOid;
1069 
1070  LogAccessExclusiveLocks(1, &xlrec);
1072 }
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition: standby.c:1043
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK
Definition: xact.h:107
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:438
int MyXactFlags
Definition: xact.c:132
TransactionId xid
Definition: lockdefs.h:54

◆ LogAccessExclusiveLockPrepare()

void LogAccessExclusiveLockPrepare ( void  )

Definition at line 1078 of file standby.c.

References GetCurrentTransactionId().

Referenced by LockAcquireExtended().

1079 {
1080  /*
1081  * Ensure that a TransactionId has been assigned to this transaction, for
1082  * two reasons, both related to lock release on the standby. First, we
1083  * must assign an xid so that RecordTransactionCommit() and
1084  * RecordTransactionAbort() do not optimise away the transaction
1085  * completion record which recovery relies upon to release locks. It's a
1086  * hack, but for a corner case not worth adding code for into the main
1087  * commit path. Second, we must assign an xid before the lock is recorded
1088  * in shared memory, otherwise a concurrently executing
1089  * GetRunningTransactionLocks() might see a lock associated with an
1090  * InvalidTransactionId which we later assert cannot happen.
1091  */
1092  (void) GetCurrentTransactionId();
1093 }
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:438

◆ LogAccessExclusiveLocks()

static void LogAccessExclusiveLocks ( int  nlocks,
xl_standby_lock locks 
)
static

Definition at line 1043 of file standby.c.

References xl_standby_locks::nlocks, offsetof, XLOG_MARK_UNIMPORTANT, XLOG_STANDBY_LOCK, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), and XLogSetRecordFlags().

Referenced by LogAccessExclusiveLock(), and LogStandbySnapshot().

1044 {
1045  xl_standby_locks xlrec;
1046 
1047  xlrec.nlocks = nlocks;
1048 
1049  XLogBeginInsert();
1050  XLogRegisterData((char *) &xlrec, offsetof(xl_standby_locks, locks));
1051  XLogRegisterData((char *) locks, nlocks * sizeof(xl_standby_lock));
1053 
1054  (void) XLogInsert(RM_STANDBY_ID, XLOG_STANDBY_LOCK);
1055 }
#define XLOG_STANDBY_LOCK
Definition: standbydefs.h:34
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:404
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:239
void XLogBeginInsert(void)
Definition: xloginsert.c:123
#define offsetof(type, field)
Definition: c.h:668

◆ LogCurrentRunningXacts()

static XLogRecPtr LogCurrentRunningXacts ( RunningTransactions  CurrRunningXacts)
static

Definition at line 983 of file standby.c.

References DEBUG2, elog, xl_running_xacts::latestCompletedXid, RunningTransactionsData::latestCompletedXid, MinSizeOfXactRunningXacts, xl_running_xacts::nextXid, RunningTransactionsData::nextXid, xl_running_xacts::oldestRunningXid, RunningTransactionsData::oldestRunningXid, xl_running_xacts::subxcnt, RunningTransactionsData::subxcnt, xl_running_xacts::subxid_overflow, RunningTransactionsData::subxid_overflow, trace_recovery(), xl_running_xacts::xcnt, RunningTransactionsData::xcnt, RunningTransactionsData::xids, XLOG_MARK_UNIMPORTANT, XLOG_RUNNING_XACTS, XLogBeginInsert(), XLogInsert(), XLogRegisterData(), XLogSetAsyncXactLSN(), and XLogSetRecordFlags().

Referenced by LogStandbySnapshot().

984 {
985  xl_running_xacts xlrec;
986  XLogRecPtr recptr;
987 
988  xlrec.xcnt = CurrRunningXacts->xcnt;
989  xlrec.subxcnt = CurrRunningXacts->subxcnt;
990  xlrec.subxid_overflow = CurrRunningXacts->subxid_overflow;
991  xlrec.nextXid = CurrRunningXacts->nextXid;
992  xlrec.oldestRunningXid = CurrRunningXacts->oldestRunningXid;
993  xlrec.latestCompletedXid = CurrRunningXacts->latestCompletedXid;
994 
995  /* Header */
996  XLogBeginInsert();
998  XLogRegisterData((char *) (&xlrec), MinSizeOfXactRunningXacts);
999 
1000  /* array of TransactionIds */
1001  if (xlrec.xcnt > 0)
1002  XLogRegisterData((char *) CurrRunningXacts->xids,
1003  (xlrec.xcnt + xlrec.subxcnt) * sizeof(TransactionId));
1004 
1005  recptr = XLogInsert(RM_STANDBY_ID, XLOG_RUNNING_XACTS);
1006 
1007  if (CurrRunningXacts->subxid_overflow)
1009  "snapshot of %u running transactions overflowed (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
1010  CurrRunningXacts->xcnt,
1011  (uint32) (recptr >> 32), (uint32) recptr,
1012  CurrRunningXacts->oldestRunningXid,
1013  CurrRunningXacts->latestCompletedXid,
1014  CurrRunningXacts->nextXid);
1015  else
1017  "snapshot of %u+%u running transaction ids (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
1018  CurrRunningXacts->xcnt, CurrRunningXacts->subxcnt,
1019  (uint32) (recptr >> 32), (uint32) recptr,
1020  CurrRunningXacts->oldestRunningXid,
1021  CurrRunningXacts->latestCompletedXid,
1022  CurrRunningXacts->nextXid);
1023 
1024  /*
1025  * Ensure running_xacts information is synced to disk not too far in the
1026  * future. We don't want to stall anything though (i.e. use XLogFlush()),
1027  * so we let the wal writer do it during normal operation.
1028  * XLogSetAsyncXactLSN() conveniently will mark the LSN as to-be-synced
1029  * and nudge the WALWriter into action if sleeping. Check
1030  * XLogBackgroundFlush() for details why a record might not be flushed
1031  * without it.
1032  */
1033  XLogSetAsyncXactLSN(recptr);
1034 
1035  return recptr;
1036 }
TransactionId oldestRunningXid
Definition: standby.h:76
uint32 TransactionId
Definition: c.h:520
TransactionId * xids
Definition: standby.h:79
int trace_recovery(int trace_level)
Definition: elog.c:3543
TransactionId latestCompletedXid
Definition: standby.h:77
TransactionId latestCompletedXid
Definition: standbydefs.h:54
#define DEBUG2
Definition: elog.h:24
unsigned int uint32
Definition: c.h:374
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:404
#define MinSizeOfXactRunningXacts
Definition: standby.h:55
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
void XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
Definition: xlog.c:2683
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:239
TransactionId nextXid
Definition: standbydefs.h:52
TransactionId nextXid
Definition: standby.h:75
#define elog(elevel,...)
Definition: elog.h:214
TransactionId oldestRunningXid
Definition: standbydefs.h:53
#define XLOG_RUNNING_XACTS
Definition: standbydefs.h:35
void XLogBeginInsert(void)
Definition: xloginsert.c:123

◆ LogStandbyInvalidations()

void LogStandbyInvalidations ( int  nmsgs,
SharedInvalidationMessage msgs,
bool  relcacheInitFileInval 
)

Definition at line 1100 of file standby.c.

References xl_invalidations::dbId, MinSizeOfInvalidations, MyDatabaseId, MyDatabaseTableSpace, xl_invalidations::nmsgs, xl_invalidations::relcacheInitFileInval, xl_invalidations::tsId, XLOG_INVALIDATIONS, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by RecordTransactionCommit().

1102 {
1103  xl_invalidations xlrec;
1104 
1105  /* prepare record */
1106  memset(&xlrec, 0, sizeof(xlrec));
1107  xlrec.dbId = MyDatabaseId;
1108  xlrec.tsId = MyDatabaseTableSpace;
1109  xlrec.relcacheInitFileInval = relcacheInitFileInval;
1110  xlrec.nmsgs = nmsgs;
1111 
1112  /* perform insertion */
1113  XLogBeginInsert();
1114  XLogRegisterData((char *) (&xlrec), MinSizeOfInvalidations);
1115  XLogRegisterData((char *) msgs,
1116  nmsgs * sizeof(SharedInvalidationMessage));
1117  XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
1118 }
#define XLOG_INVALIDATIONS
Definition: standbydefs.h:36
Oid MyDatabaseTableSpace
Definition: globals.c:87
bool relcacheInitFileInval
Definition: standbydefs.h:67
#define MinSizeOfInvalidations
Definition: standbydefs.h:72
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:330
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:422
Oid MyDatabaseId
Definition: globals.c:85
void XLogBeginInsert(void)
Definition: xloginsert.c:123

◆ LogStandbySnapshot()

XLogRecPtr LogStandbySnapshot ( void  )

Definition at line 923 of file standby.c.

References Assert, GetRunningTransactionData(), GetRunningTransactionLocks(), RecoveryLockListsEntry::locks, LogAccessExclusiveLocks(), LogCurrentRunningXacts(), LWLockRelease(), pfree(), wal_level, WAL_LEVEL_LOGICAL, and XLogStandbyInfoActive.

Referenced by BackgroundWriterMain(), CreateCheckPoint(), ReplicationSlotReserveWal(), and SnapBuildWaitSnapshot().

924 {
925  XLogRecPtr recptr;
926  RunningTransactions running;
927  xl_standby_lock *locks;
928  int nlocks;
929 
931 
932  /*
933  * Get details of any AccessExclusiveLocks being held at the moment.
934  */
935  locks = GetRunningTransactionLocks(&nlocks);
936  if (nlocks > 0)
937  LogAccessExclusiveLocks(nlocks, locks);
938  pfree(locks);
939 
940  /*
941  * Log details of all in-progress transactions. This should be the last
942  * record we write, because standby will open up when it sees this.
943  */
944  running = GetRunningTransactionData();
945 
946  /*
947  * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
948  * For Hot Standby this can be done before inserting the WAL record
949  * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
950  * the clog. For logical decoding, though, the lock can't be released
951  * early because the clog might be "in the future" from the POV of the
952  * historic snapshot. This would allow for situations where we're waiting
953  * for the end of a transaction listed in the xl_running_xacts record
954  * which, according to the WAL, has committed before the xl_running_xacts
955  * record. Fortunately this routine isn't executed frequently, and it's
956  * only a shared lock.
957  */
959  LWLockRelease(ProcArrayLock);
960 
961  recptr = LogCurrentRunningXacts(running);
962 
963  /* Release lock if we kept it longer ... */
965  LWLockRelease(ProcArrayLock);
966 
967  /* GetRunningTransactionData() acquired XidGenLock, we must release it */
968  LWLockRelease(XidGenLock);
969 
970  return recptr;
971 }
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition: standby.c:1043
int wal_level
Definition: xlog.c:107
xl_standby_lock * GetRunningTransactionLocks(int *nlocks)
Definition: lock.c:3933
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
void pfree(void *pointer)
Definition: mcxt.c:1057
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
Definition: standby.c:983
#define XLogStandbyInfoActive()
Definition: xlog.h:205
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define Assert(condition)
Definition: c.h:745
RunningTransactions GetRunningTransactionData(void)
Definition: procarray.c:2554

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )

Definition at line 483 of file standby.c.

References Assert, DeadlockTimeout, EnableTimeoutParams::delay_ms, disable_all_timeouts(), enable_timeout_after(), enable_timeouts(), EnableTimeoutParams::fin_time, GetCurrentTimestamp(), GetStandbyLimitTime(), EnableTimeoutParams::id, InHotStandby, PG_WAIT_BUFFER_PIN, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, ProcWaitForSignal(), SendRecoveryConflictWithBufferPin(), STANDBY_DEADLOCK_TIMEOUT, STANDBY_TIMEOUT, TMPARAM_AFTER, TMPARAM_AT, and EnableTimeoutParams::type.

Referenced by LockBufferForCleanup().

484 {
485  TimestampTz ltime;
486 
488 
489  ltime = GetStandbyLimitTime();
490 
491  if (ltime == 0)
492  {
493  /*
494  * We're willing to wait forever for conflicts, so set timeout for
495  * deadlock check only
496  */
498  }
499  else if (GetCurrentTimestamp() >= ltime)
500  {
501  /*
502  * We're already behind, so clear a path as quickly as possible.
503  */
505  }
506  else
507  {
508  /*
509  * Wake up at ltime, and check for deadlocks as well if we will be
510  * waiting longer than deadlock_timeout
511  */
512  EnableTimeoutParams timeouts[2];
513 
514  timeouts[0].id = STANDBY_TIMEOUT;
515  timeouts[0].type = TMPARAM_AT;
516  timeouts[0].fin_time = ltime;
517  timeouts[1].id = STANDBY_DEADLOCK_TIMEOUT;
518  timeouts[1].type = TMPARAM_AFTER;
519  timeouts[1].delay_ms = DeadlockTimeout;
520  enable_timeouts(timeouts, 2);
521  }
522 
523  /* Wait to be signaled by UnpinBuffer() */
525 
526  /*
527  * Clear any timeout requests established above. We assume here that the
528  * Startup process doesn't have any other timeouts than what this function
529  * uses. If that stops being true, we could cancel the timeouts
530  * individually, but that'd be slower.
531  */
532  disable_all_timeouts(false);
533 }
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:156
TimeoutId id
Definition: timeout.h:54
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1574
int64 TimestampTz
Definition: timestamp.h:39
TimeoutType type
Definition: timeout.h:55
#define InHotStandby
Definition: xlog.h:74
void enable_timeouts(const EnableTimeoutParams *timeouts, int count)
Definition: timeout.c:483
void disable_all_timeouts(bool keep_indicators)
Definition: timeout.c:598
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition: standby.c:536
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1796
#define PG_WAIT_BUFFER_PIN
Definition: pgstat.h:786
void enable_timeout_after(TimeoutId id, int delay_ms)
Definition: timeout.c:435
#define Assert(condition)
Definition: c.h:745
TimestampTz fin_time
Definition: timeout.h:57
int DeadlockTimeout
Definition: proc.c:60

◆ ResolveRecoveryConflictWithDatabase()

void ResolveRecoveryConflictWithDatabase ( Oid  dbid)

Definition at line 360 of file standby.c.

References CancelDBBackends(), CountDBBackends(), pg_usleep(), and PROCSIG_RECOVERY_CONFLICT_DATABASE.

Referenced by dbase_redo().

361 {
362  /*
363  * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that
364  * only waits for transactions and completely idle sessions would block
365  * us. This is rare enough that we do this as simply as possible: no wait,
366  * just force them off immediately.
367  *
368  * No locking is required here because we already acquired
369  * AccessExclusiveLock. Anybody trying to connect while we do this will
370  * block during InitPostgres() and then disconnect when they see the
371  * database has been removed.
372  */
373  while (CountDBBackends(dbid) > 0)
374  {
376 
377  /*
378  * Wait awhile for them to die so that we avoid flooding an
379  * unresponsive backend when system is heavily loaded.
380  */
381  pg_usleep(10000);
382  }
383 }
int CountDBBackends(Oid databaseid)
Definition: procarray.c:3371
void pg_usleep(long microsec)
Definition: signal.c:53
void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3432

◆ ResolveRecoveryConflictWithLock()

void ResolveRecoveryConflictWithLock ( LOCKTAG  locktag)

Definition at line 403 of file standby.c.

References AccessExclusiveLock, Assert, disable_all_timeouts(), enable_timeouts(), EnableTimeoutParams::fin_time, GetCurrentTimestamp(), GetLockConflicts(), GetStandbyLimitTime(), EnableTimeoutParams::id, InHotStandby, LOCKTAG::locktag_type, PG_WAIT_LOCK, PROCSIG_RECOVERY_CONFLICT_LOCK, ProcWaitForSignal(), ResolveRecoveryConflictWithVirtualXIDs(), STANDBY_LOCK_TIMEOUT, TMPARAM_AT, and EnableTimeoutParams::type.

Referenced by ProcSleep().

404 {
405  TimestampTz ltime;
406 
408 
409  ltime = GetStandbyLimitTime();
410 
411  if (GetCurrentTimestamp() >= ltime)
412  {
413  /*
414  * We're already behind, so clear a path as quickly as possible.
415  */
416  VirtualTransactionId *backends;
417 
418  backends = GetLockConflicts(&locktag, AccessExclusiveLock, NULL);
419 
420  /*
421  * Prevent ResolveRecoveryConflictWithVirtualXIDs() from reporting
422  * "waiting" in PS display by disabling its argument report_waiting
423  * because the caller, WaitOnLock(), has already reported that.
424  */
427  PG_WAIT_LOCK | locktag.locktag_type,
428  false);
429  }
430  else
431  {
432  /*
433  * Wait (or wait again) until ltime
434  */
435  EnableTimeoutParams timeouts[1];
436 
437  timeouts[0].id = STANDBY_LOCK_TIMEOUT;
438  timeouts[0].type = TMPARAM_AT;
439  timeouts[0].fin_time = ltime;
440  enable_timeouts(timeouts, 1);
441  }
442 
443  /* Wait to be signaled by the release of the Relation Lock */
445 
446  /*
447  * Clear any timeout requests established above. We assume here that the
448  * Startup process doesn't have any other outstanding timeouts than those
449  * used by this function. If that stops being true, we could cancel the
450  * timeouts individually, but that'd be slower.
451  */
452  disable_all_timeouts(false);
453 }
#define PG_WAIT_LOCK
Definition: pgstat.h:785
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:156
TimeoutId id
Definition: timeout.h:54
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info, bool report_waiting)
Definition: standby.c:229
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1574
int64 TimestampTz
Definition: timestamp.h:39
TimeoutType type
Definition: timeout.h:55
#define InHotStandby
Definition: xlog.h:74
void enable_timeouts(const EnableTimeoutParams *timeouts, int count)
Definition: timeout.c:483
void disable_all_timeouts(bool keep_indicators)
Definition: timeout.c:598
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1796
VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
Definition: lock.c:2912
uint8 locktag_type
Definition: lock.h:170
#define Assert(condition)
Definition: c.h:745
TimestampTz fin_time
Definition: timeout.h:57
#define AccessExclusiveLock
Definition: lockdefs.h:45

◆ ResolveRecoveryConflictWithSnapshot()

void ResolveRecoveryConflictWithSnapshot ( TransactionId  latestRemovedXid,
RelFileNode  node 
)

Definition at line 304 of file standby.c.

References RelFileNode::dbNode, GetConflictingVirtualXIDs(), PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, ResolveRecoveryConflictWithVirtualXIDs(), TransactionIdIsValid, and WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT.

Referenced by btree_xlog_delete(), btree_xlog_reuse_page(), gistRedoDeleteRecord(), gistRedoPageReuse(), hash_xlog_vacuum_one_page(), heap_xlog_clean(), heap_xlog_cleanup_info(), heap_xlog_freeze_page(), heap_xlog_visible(), and spgRedoVacuumRedirect().

305 {
306  VirtualTransactionId *backends;
307 
308  /*
309  * If we get passed InvalidTransactionId then we are a little surprised,
310  * but it is theoretically possible in normal running. It also happens
311  * when replaying already applied WAL records after a standby crash or
312  * restart, or when replaying an XLOG_HEAP2_VISIBLE record that marks as
313  * frozen a page which was already all-visible. If latestRemovedXid is
314  * invalid then there is no conflict. That rule applies across all record
315  * types that suffer from this conflict.
316  */
317  if (!TransactionIdIsValid(latestRemovedXid))
318  return;
319 
320  backends = GetConflictingVirtualXIDs(latestRemovedXid,
321  node.dbNode);
322 
326  true);
327 }
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info, bool report_waiting)
Definition: standby.c:229
VirtualTransactionId * GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
Definition: procarray.c:3196
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ ResolveRecoveryConflictWithTablespace()

void ResolveRecoveryConflictWithTablespace ( Oid  tsid)

Definition at line 330 of file standby.c.

References GetConflictingVirtualXIDs(), InvalidOid, InvalidTransactionId, PROCSIG_RECOVERY_CONFLICT_TABLESPACE, ResolveRecoveryConflictWithVirtualXIDs(), and WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE.

Referenced by tblspc_redo().

331 {
332  VirtualTransactionId *temp_file_users;
333 
334  /*
335  * Standby users may be currently using this tablespace for their
336  * temporary files. We only care about current users because
337  * temp_tablespace parameter will just ignore tablespaces that no longer
338  * exist.
339  *
340  * Ask everybody to cancel their queries immediately so we can ensure no
341  * temp files remain and we can remove the tablespace. Nuke the entire
342  * site from orbit, it's the only way to be sure.
343  *
344  * XXX: We could work out the pids of active backends using this
345  * tablespace by examining the temp filenames in the directory. We would
346  * then convert the pids into VirtualXIDs before attempting to cancel
347  * them.
348  *
349  * We don't wait for commit because drop tablespace is non-transactional.
350  */
352  InvalidOid);
356  true);
357 }
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info, bool report_waiting)
Definition: standby.c:229
VirtualTransactionId * GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
Definition: procarray.c:3196
#define InvalidTransactionId
Definition: transam.h:31
#define InvalidOid
Definition: postgres_ext.h:36

◆ ResolveRecoveryConflictWithVirtualXIDs()

static void ResolveRecoveryConflictWithVirtualXIDs ( VirtualTransactionId waitlist,
ProcSignalReason  reason,
uint32  wait_event_info,
bool  report_waiting 
)
static

Definition at line 229 of file standby.c.

References Assert, CancelVirtualTransaction(), get_ps_display(), GetCurrentTimestamp(), palloc(), pfree(), pg_usleep(), set_ps_display(), STANDBY_INITIAL_WAIT_US, standbyWait_us, TimestampDifferenceExceeds(), update_process_title, VirtualTransactionIdIsValid, VirtualXactLock(), and WaitExceedsMaxStandbyDelay().

Referenced by ResolveRecoveryConflictWithLock(), ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

232 {
233  TimestampTz waitStart = 0;
234  char *new_status;
235 
236  /* Fast exit, to avoid a kernel call if there's no work to be done. */
237  if (!VirtualTransactionIdIsValid(*waitlist))
238  return;
239 
240  if (report_waiting)
241  waitStart = GetCurrentTimestamp();
242  new_status = NULL; /* we haven't changed the ps display */
243 
244  while (VirtualTransactionIdIsValid(*waitlist))
245  {
246  /* reset standbyWait_us for each xact we wait for */
248 
249  /* wait until the virtual xid is gone */
250  while (!VirtualXactLock(*waitlist, false))
251  {
252  /*
253  * Report via ps if we have been waiting for more than 500 msec
254  * (should that be configurable?)
255  */
256  if (update_process_title && new_status == NULL && report_waiting &&
258  500))
259  {
260  const char *old_status;
261  int len;
262 
263  old_status = get_ps_display(&len);
264  new_status = (char *) palloc(len + 8 + 1);
265  memcpy(new_status, old_status, len);
266  strcpy(new_status + len, " waiting");
267  set_ps_display(new_status);
268  new_status[len] = '\0'; /* truncate off " waiting" */
269  }
270 
271  /* Is it time to kill it? */
272  if (WaitExceedsMaxStandbyDelay(wait_event_info))
273  {
274  pid_t pid;
275 
276  /*
277  * Now find out who to throw out of the balloon.
278  */
280  pid = CancelVirtualTransaction(*waitlist, reason);
281 
282  /*
283  * Wait a little bit for it to die so that we avoid flooding
284  * an unresponsive backend when system is heavily loaded.
285  */
286  if (pid != 0)
287  pg_usleep(5000L);
288  }
289  }
290 
291  /* The virtual transaction is gone now, wait for the next one */
292  waitlist++;
293  }
294 
295  /* Reset ps display if we changed it */
296  if (new_status)
297  {
298  set_ps_display(new_status);
299  pfree(new_status);
300  }
301 }
static bool WaitExceedsMaxStandbyDelay(uint32 wait_event_info)
Definition: standby.c:189
pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
Definition: procarray.c:3270
bool update_process_title
Definition: ps_status.c:36
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1574
int64 TimestampTz
Definition: timestamp.h:39
static int standbyWait_us
Definition: standby.c:181
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1673
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4461
void set_ps_display(const char *activity)
Definition: ps_status.c:349
void pg_usleep(long microsec)
Definition: signal.c:53
void pfree(void *pointer)
Definition: mcxt.c:1057
#define STANDBY_INITIAL_WAIT_US
Definition: standby.c:180
const char * get_ps_display(int *displen)
Definition: ps_status.c:430
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:70
#define Assert(condition)
Definition: c.h:745
void * palloc(Size size)
Definition: mcxt.c:950

◆ SendRecoveryConflictWithBufferPin()

static void SendRecoveryConflictWithBufferPin ( ProcSignalReason  reason)
static

Definition at line 536 of file standby.c.

References Assert, CancelDBBackends(), InvalidOid, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, and PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK.

Referenced by ResolveRecoveryConflictWithBufferPin(), StandbyDeadLockHandler(), and StandbyTimeoutHandler().

537 {
540 
541  /*
542  * We send signal to all backends to ask them if they are holding the
543  * buffer pin which is delaying the Startup process. We must not set the
544  * conflict flag yet, since most backends will be innocent. Let the
545  * SIGUSR1 handling in each backend decide their own fate.
546  */
547  CancelDBBackends(InvalidOid, reason, false);
548 }
void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3432
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:745

◆ ShutdownRecoveryTransactionEnvironment()

void ShutdownRecoveryTransactionEnvironment ( void  )

Definition at line 127 of file standby.c.

References ExpireAllKnownAssignedTransactionIds(), hash_destroy(), StandbyReleaseAllLocks(), and VirtualXactLockTableCleanup().

Referenced by StartupXLOG().

128 {
129  /* Mark all tracked in-progress transactions as finished. */
131 
132  /* Release all locks the tracked transactions were holding */
134 
135  /* Destroy the hash table of locks. */
137  RecoveryLockLists = NULL;
138 
139  /* Cleanup our VirtualTransaction */
141 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:827
void VirtualXactLockTableCleanup(void)
Definition: lock.c:4414
static HTAB * RecoveryLockLists
Definition: standby.c:43
void ExpireAllKnownAssignedTransactionIds(void)
Definition: procarray.c:4291
void StandbyReleaseAllLocks(void)
Definition: standby.c:752

◆ standby_redo()

void standby_redo ( XLogReaderState record)

Definition at line 806 of file standby.c.

References Assert, xl_invalidations::dbId, xl_standby_lock::dbOid, elog, i, xl_running_xacts::latestCompletedXid, RunningTransactionsData::latestCompletedXid, xl_standby_locks::locks, xl_invalidations::msgs, xl_running_xacts::nextXid, RunningTransactionsData::nextXid, xl_standby_locks::nlocks, xl_invalidations::nmsgs, xl_running_xacts::oldestRunningXid, RunningTransactionsData::oldestRunningXid, PANIC, ProcArrayApplyRecoveryInfo(), ProcessCommittedInvalidationMessages(), xl_invalidations::relcacheInitFileInval, xl_standby_lock::relOid, STANDBY_DISABLED, StandbyAcquireAccessExclusiveLock(), standbyState, xl_running_xacts::subxcnt, RunningTransactionsData::subxcnt, xl_running_xacts::subxid_overflow, RunningTransactionsData::subxid_overflow, xl_invalidations::tsId, xl_running_xacts::xcnt, RunningTransactionsData::xcnt, xl_standby_lock::xid, xl_running_xacts::xids, RunningTransactionsData::xids, XLOG_INVALIDATIONS, XLOG_RUNNING_XACTS, XLOG_STANDBY_LOCK, XLogRecGetData, XLogRecGetInfo, XLogRecHasAnyBlockRefs, and XLR_INFO_MASK.

807 {
808  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
809 
810  /* Backup blocks are not used in standby records */
811  Assert(!XLogRecHasAnyBlockRefs(record));
812 
813  /* Do nothing if we're not in hot standby mode */
815  return;
816 
817  if (info == XLOG_STANDBY_LOCK)
818  {
819  xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record);
820  int i;
821 
822  for (i = 0; i < xlrec->nlocks; i++)
824  xlrec->locks[i].dbOid,
825  xlrec->locks[i].relOid);
826  }
827  else if (info == XLOG_RUNNING_XACTS)
828  {
829  xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
830  RunningTransactionsData running;
831 
832  running.xcnt = xlrec->xcnt;
833  running.subxcnt = xlrec->subxcnt;
834  running.subxid_overflow = xlrec->subxid_overflow;
835  running.nextXid = xlrec->nextXid;
836  running.latestCompletedXid = xlrec->latestCompletedXid;
837  running.oldestRunningXid = xlrec->oldestRunningXid;
838  running.xids = xlrec->xids;
839 
840  ProcArrayApplyRecoveryInfo(&running);
841  }
842  else if (info == XLOG_INVALIDATIONS)
843  {
844  xl_invalidations *xlrec = (xl_invalidations *) XLogRecGetData(record);
845 
847  xlrec->nmsgs,
848  xlrec->relcacheInitFileInval,
849  xlrec->dbId,
850  xlrec->tsId);
851  }
852  else
853  elog(PANIC, "standby_redo: unknown op code %u", info);
854 }
void ProcArrayApplyRecoveryInfo(RunningTransactions running)
Definition: procarray.c:985
TransactionId oldestRunningXid
Definition: standby.h:76
#define XLOG_INVALIDATIONS
Definition: standbydefs.h:36
unsigned char uint8
Definition: c.h:372
#define XLOG_STANDBY_LOCK
Definition: standbydefs.h:34
TransactionId * xids
Definition: standby.h:79
#define PANIC
Definition: elog.h:53
TransactionId latestCompletedXid
Definition: standby.h:77
TransactionId xids[FLEXIBLE_ARRAY_MEMBER]
Definition: standbydefs.h:56
#define XLogRecGetData(decoder)
Definition: xlogreader.h:310
TransactionId latestCompletedXid
Definition: standbydefs.h:54
bool relcacheInitFileInval
Definition: standbydefs.h:67
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:305
TransactionId xid
Definition: lockdefs.h:54
void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid)
Definition: inval.c:887
#define Assert(condition)
Definition: c.h:745
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
SharedInvalidationMessage msgs[FLEXIBLE_ARRAY_MEMBER]
Definition: standbydefs.h:69
TransactionId nextXid
Definition: standbydefs.h:52
xl_standby_lock locks[FLEXIBLE_ARRAY_MEMBER]
Definition: standbydefs.h:41
TransactionId nextXid
Definition: standby.h:75
void StandbyAcquireAccessExclusiveLock(TransactionId xid, Oid dbOid, Oid relOid)
Definition: standby.c:651
#define elog(elevel,...)
Definition: elog.h:214
int i
TransactionId oldestRunningXid
Definition: standbydefs.h:53
#define XLOG_RUNNING_XACTS
Definition: standbydefs.h:35
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:312
HotStandbyState standbyState
Definition: xlog.c:208

◆ StandbyAcquireAccessExclusiveLock()

void StandbyAcquireAccessExclusiveLock ( TransactionId  xid,
Oid  dbOid,
Oid  relOid 
)

Definition at line 651 of file standby.c.

References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, HASH_ENTER, hash_search(), lappend(), LockAcquire(), RecoveryLockListsEntry::locks, NIL, OidIsValid, palloc(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, trace_recovery(), TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsValid, xl_standby_lock::xid, and RecoveryLockListsEntry::xid.

Referenced by lock_twophase_standby_recover(), and standby_redo().

652 {
653  RecoveryLockListsEntry *entry;
654  xl_standby_lock *newlock;
655  LOCKTAG locktag;
656  bool found;
657 
658  /* Already processed? */
659  if (!TransactionIdIsValid(xid) ||
660  TransactionIdDidCommit(xid) ||
662  return;
663 
665  "adding recovery lock: db %u rel %u", dbOid, relOid);
666 
667  /* dbOid is InvalidOid when we are locking a shared relation. */
668  Assert(OidIsValid(relOid));
669 
670  /* Create a new list for this xid, if we don't have one already. */
671  entry = hash_search(RecoveryLockLists, &xid, HASH_ENTER, &found);
672  if (!found)
673  {
674  entry->xid = xid;
675  entry->locks = NIL;
676  }
677 
678  newlock = palloc(sizeof(xl_standby_lock));
679  newlock->xid = xid;
680  newlock->dbOid = dbOid;
681  newlock->relOid = relOid;
682  entry->locks = lappend(entry->locks, newlock);
683 
684  SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);
685 
686  (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
687 }
#define NIL
Definition: pg_list.h:65
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition: lock.c:747
static HTAB * RecoveryLockLists
Definition: standby.c:43
Definition: lock.h:164
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
#define DEBUG4
Definition: elog.h:22
#define OidIsValid(objectId)
Definition: c.h:651
TransactionId xid
Definition: standby.c:58
int trace_recovery(int trace_level)
Definition: elog.c:3543
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
List * lappend(List *list, void *datum)
Definition: list.c:321
TransactionId xid
Definition: lockdefs.h:54
#define Assert(condition)
Definition: c.h:745
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:214
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ StandbyDeadLockHandler()

void StandbyDeadLockHandler ( void  )

◆ StandbyLockTimeoutHandler()

void StandbyLockTimeoutHandler ( void  )

Definition at line 620 of file standby.c.

Referenced by StartupProcessMain().

621 {
622 }

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )

Definition at line 752 of file standby.c.

References DEBUG2, elog, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), RecoveryLockListsEntry::locks, StandbyReleaseLockList(), status(), and trace_recovery().

Referenced by ShutdownRecoveryTransactionEnvironment(), and StandbyReleaseLocks().

753 {
755  RecoveryLockListsEntry *entry;
756 
757  elog(trace_recovery(DEBUG2), "release all standby locks");
758 
760  while ((entry = hash_seq_search(&status)))
761  {
764  }
765 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:690
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
int trace_recovery(int trace_level)
Definition: elog.c:3543
#define DEBUG2
Definition: elog.h:24
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
#define elog(elevel,...)
Definition: elog.h:214
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ StandbyReleaseLockList()

static void StandbyReleaseLockList ( List locks)
static

Definition at line 690 of file standby.c.

References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, linitial, list_delete_first(), LockRelease(), LOG, pfree(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, trace_recovery(), and xl_standby_lock::xid.

Referenced by StandbyReleaseAllLocks(), StandbyReleaseLocks(), and StandbyReleaseOldLocks().

691 {
692  while (locks)
693  {
694  xl_standby_lock *lock = (xl_standby_lock *) linitial(locks);
695  LOCKTAG locktag;
696 
698  "releasing recovery lock: xid %u db %u rel %u",
699  lock->xid, lock->dbOid, lock->relOid);
700  SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid);
701  if (!LockRelease(&locktag, AccessExclusiveLock, true))
702  {
703  elog(LOG,
704  "RecoveryLockLists contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
705  lock->xid, lock->dbOid, lock->relOid);
706  Assert(false);
707  }
708  pfree(lock);
709  locks = list_delete_first(locks);
710  }
711 }
Definition: lock.h:164
#define LOG
Definition: elog.h:26
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3543
void pfree(void *pointer)
Definition: mcxt.c:1057
#define linitial(l)
Definition: pg_list.h:195
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
TransactionId xid
Definition: lockdefs.h:54
#define Assert(condition)
Definition: c.h:745
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:214
bool LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
Definition: lock.c:1975
List * list_delete_first(List *list)
Definition: list.c:860

◆ StandbyReleaseLocks()

static void StandbyReleaseLocks ( TransactionId  xid)
static

Definition at line 714 of file standby.c.

References HASH_FIND, HASH_REMOVE, hash_search(), RecoveryLockListsEntry::locks, StandbyReleaseAllLocks(), StandbyReleaseLockList(), and TransactionIdIsValid.

Referenced by StandbyReleaseLockTree().

715 {
716  RecoveryLockListsEntry *entry;
717 
718  if (TransactionIdIsValid(xid))
719  {
720  if ((entry = hash_search(RecoveryLockLists, &xid, HASH_FIND, NULL)))
721  {
724  }
725  }
726  else
728 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:690
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
void StandbyReleaseAllLocks(void)
Definition: standby.c:752
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ StandbyReleaseLockTree()

void StandbyReleaseLockTree ( TransactionId  xid,
int  nsubxids,
TransactionId subxids 
)

Definition at line 738 of file standby.c.

References i, and StandbyReleaseLocks().

Referenced by RecoverPreparedTransactions(), xact_redo_abort(), and xact_redo_commit().

739 {
740  int i;
741 
742  StandbyReleaseLocks(xid);
743 
744  for (i = 0; i < nsubxids; i++)
745  StandbyReleaseLocks(subxids[i]);
746 }
static void StandbyReleaseLocks(TransactionId xid)
Definition: standby.c:714
int i

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)

Definition at line 773 of file standby.c.

References Assert, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), RecoveryLockListsEntry::locks, StandbyReleaseLockList(), StandbyTransactionIdIsPrepared(), status(), TransactionIdIsValid, TransactionIdPrecedes(), and RecoveryLockListsEntry::xid.

Referenced by ProcArrayApplyRecoveryInfo().

774 {
776  RecoveryLockListsEntry *entry;
777 
779  while ((entry = hash_seq_search(&status)))
780  {
782 
783  /* Skip if prepared transaction. */
785  continue;
786 
787  /* Skip if >= oldxid. */
788  if (!TransactionIdPrecedes(entry->xid, oldxid))
789  continue;
790 
791  /* Remove all locks and hash table entry. */
794  }
795 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:690
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
TransactionId xid
Definition: standby.c:58
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1369
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:745
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ StandbyTimeoutHandler()

void StandbyTimeoutHandler ( void  )

Definition at line 607 of file standby.c.

References disable_timeout(), PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, SendRecoveryConflictWithBufferPin(), and STANDBY_DEADLOCK_TIMEOUT.

Referenced by StartupProcessMain().

608 {
609  /* forget any pending STANDBY_DEADLOCK_TIMEOUT request */
611 
613 }
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition: standby.c:536
void disable_timeout(TimeoutId id, bool keep_indicator)
Definition: timeout.c:532

◆ WaitExceedsMaxStandbyDelay()

static bool WaitExceedsMaxStandbyDelay ( uint32  wait_event_info)
static

Definition at line 189 of file standby.c.

References CHECK_FOR_INTERRUPTS, GetCurrentTimestamp(), GetStandbyLimitTime(), pg_usleep(), pgstat_report_wait_end(), pgstat_report_wait_start(), and standbyWait_us.

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

190 {
191  TimestampTz ltime;
192 
194 
195  /* Are we past the limit time? */
196  ltime = GetStandbyLimitTime();
197  if (ltime && GetCurrentTimestamp() >= ltime)
198  return true;
199 
200  /*
201  * Sleep a bit (this is essential to avoid busy-waiting).
202  */
203  pgstat_report_wait_start(wait_event_info);
206 
207  /*
208  * Progressively increase the sleep times, but not to more than 1s, since
209  * pg_usleep isn't interruptible on some platforms.
210  */
211  standbyWait_us *= 2;
212  if (standbyWait_us > 1000000)
213  standbyWait_us = 1000000;
214 
215  return false;
216 }
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:156
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1574
int64 TimestampTz
Definition: timestamp.h:39
static int standbyWait_us
Definition: standby.c:181
void pg_usleep(long microsec)
Definition: signal.c:53
static void pgstat_report_wait_end(void)
Definition: pgstat.h:1386
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: pgstat.h:1362
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:99

Variable Documentation

◆ max_standby_archive_delay

int max_standby_archive_delay = 30 * 1000

Definition at line 40 of file standby.c.

Referenced by GetStandbyLimitTime().

◆ max_standby_streaming_delay

int max_standby_streaming_delay = 30 * 1000

Definition at line 41 of file standby.c.

Referenced by GetStandbyLimitTime().

◆ RecoveryLockLists

HTAB* RecoveryLockLists
static

Definition at line 43 of file standby.c.

◆ standbyWait_us

int standbyWait_us = STANDBY_INITIAL_WAIT_US
static

◆ vacuum_defer_cleanup_age

int vacuum_defer_cleanup_age

Definition at line 39 of file standby.c.

Referenced by ComputeXidHorizons(), and GetSnapshotData().