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, 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 (void)
 
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 178 of file standby.c.

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

Typedef Documentation

◆ RecoveryLockListsEntry

Function Documentation

◆ CheckRecoveryConflictDeadlock()

void CheckRecoveryConflictDeadlock ( void  )

Definition at line 556 of file standby.c.

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

Referenced by ProcSleep().

557 {
558  Assert(!InRecovery); /* do not call in Startup process */
559 
561  return;
562 
563  /*
564  * Error message should match ProcessInterrupts() but we avoid calling
565  * that because we aren't handling an interrupt at this point. Note that
566  * we only cancel the current transaction here, so if we are in a
567  * subtransaction and the pin is held by a parent, then the Startup
568  * process will continue to wait even though we have avoided deadlock.
569  */
570  ereport(ERROR,
571  (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
572  errmsg("canceling statement due to conflict with recovery"),
573  errdetail("User transaction caused buffer deadlock with recovery.")));
574 }
bool InRecovery
Definition: xlog.c:202
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:738
bool HoldingBufferPinThatDelaysRecovery(void)
Definition: bufmgr.c:3728
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ GetStandbyLimitTime()

static TimestampTz GetStandbyLimitTime ( void  )
static

Definition at line 154 of file standby.c.

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

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

155 {
156  TimestampTz rtime;
157  bool fromStream;
158 
159  /*
160  * The cutoff time is the last WAL data receipt time plus the appropriate
161  * delay variable. Delay of -1 means wait forever.
162  */
163  GetXLogReceiptTime(&rtime, &fromStream);
164  if (fromStream)
165  {
167  return 0; /* wait forever */
169  }
170  else
171  {
173  return 0; /* wait forever */
175  }
176 }
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:6224
int max_standby_streaming_delay
Definition: standby.c:41

◆ InitRecoveryTransactionEnvironment()

void InitRecoveryTransactionEnvironment ( void  )

Definition at line 73 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().

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

◆ LogAccessExclusiveLock()

void LogAccessExclusiveLock ( Oid  dbOid,
Oid  relOid 
)

Definition at line 1053 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().

1054 {
1055  xl_standby_lock xlrec;
1056 
1057  xlrec.xid = GetCurrentTransactionId();
1058 
1059  xlrec.dbOid = dbOid;
1060  xlrec.relOid = relOid;
1061 
1062  LogAccessExclusiveLocks(1, &xlrec);
1064 }
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition: standby.c:1035
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK
Definition: xact.h:103
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:422
int MyXactFlags
Definition: xact.c:118
TransactionId xid
Definition: lockdefs.h:54

◆ LogAccessExclusiveLockPrepare()

void LogAccessExclusiveLockPrepare ( void  )

Definition at line 1070 of file standby.c.

References GetCurrentTransactionId().

Referenced by LockAcquireExtended().

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

◆ LogAccessExclusiveLocks()

static void LogAccessExclusiveLocks ( int  nlocks,
xl_standby_lock locks 
)
static

Definition at line 1035 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().

1036 {
1037  xl_standby_locks xlrec;
1038 
1039  xlrec.nlocks = nlocks;
1040 
1041  XLogBeginInsert();
1042  XLogRegisterData((char *) &xlrec, offsetof(xl_standby_locks, locks));
1043  XLogRegisterData((char *) locks, nlocks * sizeof(xl_standby_lock));
1045 
1046  (void) XLogInsert(RM_STANDBY_ID, XLOG_STANDBY_LOCK);
1047 }
#define XLOG_STANDBY_LOCK
Definition: standbydefs.h:34
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:230
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define offsetof(type, field)
Definition: c.h:661

◆ LogCurrentRunningXacts()

static XLogRecPtr LogCurrentRunningXacts ( RunningTransactions  CurrRunningXacts)
static

Definition at line 975 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().

976 {
977  xl_running_xacts xlrec;
978  XLogRecPtr recptr;
979 
980  xlrec.xcnt = CurrRunningXacts->xcnt;
981  xlrec.subxcnt = CurrRunningXacts->subxcnt;
982  xlrec.subxid_overflow = CurrRunningXacts->subxid_overflow;
983  xlrec.nextXid = CurrRunningXacts->nextXid;
984  xlrec.oldestRunningXid = CurrRunningXacts->oldestRunningXid;
985  xlrec.latestCompletedXid = CurrRunningXacts->latestCompletedXid;
986 
987  /* Header */
988  XLogBeginInsert();
990  XLogRegisterData((char *) (&xlrec), MinSizeOfXactRunningXacts);
991 
992  /* array of TransactionIds */
993  if (xlrec.xcnt > 0)
994  XLogRegisterData((char *) CurrRunningXacts->xids,
995  (xlrec.xcnt + xlrec.subxcnt) * sizeof(TransactionId));
996 
997  recptr = XLogInsert(RM_STANDBY_ID, XLOG_RUNNING_XACTS);
998 
999  if (CurrRunningXacts->subxid_overflow)
1001  "snapshot of %u running transactions overflowed (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
1002  CurrRunningXacts->xcnt,
1003  (uint32) (recptr >> 32), (uint32) recptr,
1004  CurrRunningXacts->oldestRunningXid,
1005  CurrRunningXacts->latestCompletedXid,
1006  CurrRunningXacts->nextXid);
1007  else
1009  "snapshot of %u+%u running transaction ids (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
1010  CurrRunningXacts->xcnt, CurrRunningXacts->subxcnt,
1011  (uint32) (recptr >> 32), (uint32) recptr,
1012  CurrRunningXacts->oldestRunningXid,
1013  CurrRunningXacts->latestCompletedXid,
1014  CurrRunningXacts->nextXid);
1015 
1016  /*
1017  * Ensure running_xacts information is synced to disk not too far in the
1018  * future. We don't want to stall anything though (i.e. use XLogFlush()),
1019  * so we let the wal writer do it during normal operation.
1020  * XLogSetAsyncXactLSN() conveniently will mark the LSN as to-be-synced
1021  * and nudge the WALWriter into action if sleeping. Check
1022  * XLogBackgroundFlush() for details why a record might not be flushed
1023  * without it.
1024  */
1025  XLogSetAsyncXactLSN(recptr);
1026 
1027  return recptr;
1028 }
TransactionId oldestRunningXid
Definition: standby.h:76
uint32 TransactionId
Definition: c.h:513
TransactionId * xids
Definition: standby.h:79
int trace_recovery(int trace_level)
Definition: elog.c:3505
TransactionId latestCompletedXid
Definition: standby.h:77
TransactionId latestCompletedXid
Definition: standbydefs.h:54
#define DEBUG2
Definition: elog.h:24
unsigned int uint32
Definition: c.h:367
void XLogSetRecordFlags(uint8 flags)
Definition: xloginsert.c:397
#define MinSizeOfXactRunningXacts
Definition: standby.h:55
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void XLogSetAsyncXactLSN(XLogRecPtr asyncXactLSN)
Definition: xlog.c:2672
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:230
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:120

◆ LogStandbyInvalidations()

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

Definition at line 1092 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().

1094 {
1095  xl_invalidations xlrec;
1096 
1097  /* prepare record */
1098  memset(&xlrec, 0, sizeof(xlrec));
1099  xlrec.dbId = MyDatabaseId;
1100  xlrec.tsId = MyDatabaseTableSpace;
1101  xlrec.relcacheInitFileInval = relcacheInitFileInval;
1102  xlrec.nmsgs = nmsgs;
1103 
1104  /* perform insertion */
1105  XLogBeginInsert();
1106  XLogRegisterData((char *) (&xlrec), MinSizeOfInvalidations);
1107  XLogRegisterData((char *) msgs,
1108  nmsgs * sizeof(SharedInvalidationMessage));
1109  XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
1110 }
#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:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
Oid MyDatabaseId
Definition: globals.c:85
void XLogBeginInsert(void)
Definition: xloginsert.c:120

◆ LogStandbySnapshot()

XLogRecPtr LogStandbySnapshot ( void  )

Definition at line 915 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().

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

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )

Definition at line 475 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().

476 {
477  TimestampTz ltime;
478 
480 
481  ltime = GetStandbyLimitTime();
482 
483  if (ltime == 0)
484  {
485  /*
486  * We're willing to wait forever for conflicts, so set timeout for
487  * deadlock check only
488  */
490  }
491  else if (GetCurrentTimestamp() >= ltime)
492  {
493  /*
494  * We're already behind, so clear a path as quickly as possible.
495  */
497  }
498  else
499  {
500  /*
501  * Wake up at ltime, and check for deadlocks as well if we will be
502  * waiting longer than deadlock_timeout
503  */
504  EnableTimeoutParams timeouts[2];
505 
506  timeouts[0].id = STANDBY_TIMEOUT;
507  timeouts[0].type = TMPARAM_AT;
508  timeouts[0].fin_time = ltime;
509  timeouts[1].id = STANDBY_DEADLOCK_TIMEOUT;
510  timeouts[1].type = TMPARAM_AFTER;
511  timeouts[1].delay_ms = DeadlockTimeout;
512  enable_timeouts(timeouts, 2);
513  }
514 
515  /* Wait to be signaled by UnpinBuffer() */
517 
518  /*
519  * Clear any timeout requests established above. We assume here that the
520  * Startup process doesn't have any other timeouts than what this function
521  * uses. If that stops being true, we could cancel the timeouts
522  * individually, but that'd be slower.
523  */
524  disable_all_timeouts(false);
525 }
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:154
TimeoutId id
Definition: timeout.h:54
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
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:528
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1800
#define PG_WAIT_BUFFER_PIN
Definition: pgstat.h:739
void enable_timeout_after(TimeoutId id, int delay_ms)
Definition: timeout.c:435
#define Assert(condition)
Definition: c.h:738
TimestampTz fin_time
Definition: timeout.h:57
int DeadlockTimeout
Definition: proc.c:60

◆ ResolveRecoveryConflictWithDatabase()

void ResolveRecoveryConflictWithDatabase ( Oid  dbid)

Definition at line 353 of file standby.c.

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

Referenced by dbase_redo().

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

◆ ResolveRecoveryConflictWithLock()

void ResolveRecoveryConflictWithLock ( LOCKTAG  locktag)

Definition at line 396 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().

397 {
398  TimestampTz ltime;
399 
401 
402  ltime = GetStandbyLimitTime();
403 
404  if (GetCurrentTimestamp() >= ltime)
405  {
406  /*
407  * We're already behind, so clear a path as quickly as possible.
408  */
409  VirtualTransactionId *backends;
410 
411  backends = GetLockConflicts(&locktag, AccessExclusiveLock, NULL);
412 
413  /*
414  * Prevent ResolveRecoveryConflictWithVirtualXIDs() from reporting
415  * "waiting" in PS display by disabling its argument report_waiting
416  * because the caller, WaitOnLock(), has already reported that.
417  */
420  false);
421  }
422  else
423  {
424  /*
425  * Wait (or wait again) until ltime
426  */
427  EnableTimeoutParams timeouts[1];
428 
429  timeouts[0].id = STANDBY_LOCK_TIMEOUT;
430  timeouts[0].type = TMPARAM_AT;
431  timeouts[0].fin_time = ltime;
432  enable_timeouts(timeouts, 1);
433  }
434 
435  /* Wait to be signaled by the release of the Relation Lock */
437 
438  /*
439  * Clear any timeout requests established above. We assume here that the
440  * Startup process doesn't have any other outstanding timeouts than those
441  * used by this function. If that stops being true, we could cancel the
442  * timeouts individually, but that'd be slower.
443  */
444  disable_all_timeouts(false);
445 }
#define PG_WAIT_LOCK
Definition: pgstat.h:738
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:154
TimeoutId id
Definition: timeout.h:54
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
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:1800
VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
Definition: lock.c:2907
uint8 locktag_type
Definition: lock.h:169
#define Assert(condition)
Definition: c.h:738
TimestampTz fin_time
Definition: timeout.h:57
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, bool report_waiting)
Definition: standby.c:225
#define AccessExclusiveLock
Definition: lockdefs.h:45

◆ ResolveRecoveryConflictWithSnapshot()

void ResolveRecoveryConflictWithSnapshot ( TransactionId  latestRemovedXid,
RelFileNode  node 
)

Definition at line 299 of file standby.c.

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

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().

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

◆ ResolveRecoveryConflictWithTablespace()

void ResolveRecoveryConflictWithTablespace ( Oid  tsid)

Definition at line 324 of file standby.c.

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

Referenced by tblspc_redo().

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

◆ ResolveRecoveryConflictWithVirtualXIDs()

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

Definition at line 225 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().

227 {
228  TimestampTz waitStart = 0;
229  char *new_status;
230 
231  /* Fast exit, to avoid a kernel call if there's no work to be done. */
232  if (!VirtualTransactionIdIsValid(*waitlist))
233  return;
234 
235  if (report_waiting)
236  waitStart = GetCurrentTimestamp();
237  new_status = NULL; /* we haven't changed the ps display */
238 
239  while (VirtualTransactionIdIsValid(*waitlist))
240  {
241  /* reset standbyWait_us for each xact we wait for */
243 
244  /* wait until the virtual xid is gone */
245  while (!VirtualXactLock(*waitlist, false))
246  {
247  /*
248  * Report via ps if we have been waiting for more than 500 msec
249  * (should that be configurable?)
250  */
251  if (update_process_title && new_status == NULL && report_waiting &&
253  500))
254  {
255  const char *old_status;
256  int len;
257 
258  old_status = get_ps_display(&len);
259  new_status = (char *) palloc(len + 8 + 1);
260  memcpy(new_status, old_status, len);
261  strcpy(new_status + len, " waiting");
262  set_ps_display(new_status);
263  new_status[len] = '\0'; /* truncate off " waiting" */
264  }
265 
266  /* Is it time to kill it? */
268  {
269  pid_t pid;
270 
271  /*
272  * Now find out who to throw out of the balloon.
273  */
275  pid = CancelVirtualTransaction(*waitlist, reason);
276 
277  /*
278  * Wait a little bit for it to die so that we avoid flooding
279  * an unresponsive backend when system is heavily loaded.
280  */
281  if (pid != 0)
282  pg_usleep(5000L);
283  }
284  }
285 
286  /* The virtual transaction is gone now, wait for the next one */
287  waitlist++;
288  }
289 
290  /* Reset ps display if we changed it */
291  if (new_status)
292  {
293  set_ps_display(new_status);
294  pfree(new_status);
295  }
296 }
pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
Definition: procarray.c:2657
bool update_process_title
Definition: ps_status.c:36
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
int64 TimestampTz
Definition: timestamp.h:39
static int standbyWait_us
Definition: standby.c:179
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1682
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4459
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:1056
#define STANDBY_INITIAL_WAIT_US
Definition: standby.c:178
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:738
void * palloc(Size size)
Definition: mcxt.c:949
static bool WaitExceedsMaxStandbyDelay(void)
Definition: standby.c:187

◆ SendRecoveryConflictWithBufferPin()

static void SendRecoveryConflictWithBufferPin ( ProcSignalReason  reason)
static

Definition at line 528 of file standby.c.

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

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

529 {
532 
533  /*
534  * We send signal to all backends to ask them if they are holding the
535  * buffer pin which is delaying the Startup process. We must not set the
536  * conflict flag yet, since most backends will be innocent. Let the
537  * SIGUSR1 handling in each backend decide their own fate.
538  */
539  CancelDBBackends(InvalidOid, reason, false);
540 }
void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:2820
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:738

◆ ShutdownRecoveryTransactionEnvironment()

void ShutdownRecoveryTransactionEnvironment ( void  )

Definition at line 125 of file standby.c.

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

Referenced by StartupXLOG().

126 {
127  /* Mark all tracked in-progress transactions as finished. */
129 
130  /* Release all locks the tracked transactions were holding */
132 
133  /* Destroy the hash table of locks. */
135  RecoveryLockLists = NULL;
136 
137  /* Cleanup our VirtualTransaction */
139 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:815
void VirtualXactLockTableCleanup(void)
Definition: lock.c:4412
static HTAB * RecoveryLockLists
Definition: standby.c:43
void ExpireAllKnownAssignedTransactionIds(void)
Definition: procarray.c:3407
void StandbyReleaseAllLocks(void)
Definition: standby.c:744

◆ standby_redo()

void standby_redo ( XLogReaderState record)

Definition at line 798 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.

799 {
800  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
801 
802  /* Backup blocks are not used in standby records */
803  Assert(!XLogRecHasAnyBlockRefs(record));
804 
805  /* Do nothing if we're not in hot standby mode */
807  return;
808 
809  if (info == XLOG_STANDBY_LOCK)
810  {
811  xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record);
812  int i;
813 
814  for (i = 0; i < xlrec->nlocks; i++)
816  xlrec->locks[i].dbOid,
817  xlrec->locks[i].relOid);
818  }
819  else if (info == XLOG_RUNNING_XACTS)
820  {
821  xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
822  RunningTransactionsData running;
823 
824  running.xcnt = xlrec->xcnt;
825  running.subxcnt = xlrec->subxcnt;
826  running.subxid_overflow = xlrec->subxid_overflow;
827  running.nextXid = xlrec->nextXid;
828  running.latestCompletedXid = xlrec->latestCompletedXid;
829  running.oldestRunningXid = xlrec->oldestRunningXid;
830  running.xids = xlrec->xids;
831 
832  ProcArrayApplyRecoveryInfo(&running);
833  }
834  else if (info == XLOG_INVALIDATIONS)
835  {
836  xl_invalidations *xlrec = (xl_invalidations *) XLogRecGetData(record);
837 
839  xlrec->nmsgs,
840  xlrec->relcacheInitFileInval,
841  xlrec->dbId,
842  xlrec->tsId);
843  }
844  else
845  elog(PANIC, "standby_redo: unknown op code %u", info);
846 }
void ProcArrayApplyRecoveryInfo(RunningTransactions running)
Definition: procarray.c:665
TransactionId oldestRunningXid
Definition: standby.h:76
#define XLOG_INVALIDATIONS
Definition: standbydefs.h:36
unsigned char uint8
Definition: c.h:365
#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:288
TransactionId latestCompletedXid
Definition: standbydefs.h:54
bool relcacheInitFileInval
Definition: standbydefs.h:67
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:284
TransactionId xid
Definition: lockdefs.h:54
void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid)
Definition: inval.c:884
#define Assert(condition)
Definition: c.h:738
#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:643
#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:290
HotStandbyState standbyState
Definition: xlog.c:205

◆ StandbyAcquireAccessExclusiveLock()

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

Definition at line 643 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().

644 {
645  RecoveryLockListsEntry *entry;
646  xl_standby_lock *newlock;
647  LOCKTAG locktag;
648  bool found;
649 
650  /* Already processed? */
651  if (!TransactionIdIsValid(xid) ||
652  TransactionIdDidCommit(xid) ||
654  return;
655 
657  "adding recovery lock: db %u rel %u", dbOid, relOid);
658 
659  /* dbOid is InvalidOid when we are locking a shared relation. */
660  Assert(OidIsValid(relOid));
661 
662  /* Create a new list for this xid, if we don't have one already. */
663  entry = hash_search(RecoveryLockLists, &xid, HASH_ENTER, &found);
664  if (!found)
665  {
666  entry->xid = xid;
667  entry->locks = NIL;
668  }
669 
670  newlock = palloc(sizeof(xl_standby_lock));
671  newlock->xid = xid;
672  newlock->dbOid = dbOid;
673  newlock->relOid = relOid;
674  entry->locks = lappend(entry->locks, newlock);
675 
676  SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);
677 
678  (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
679 }
#define NIL
Definition: pg_list.h:65
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition: lock.c:735
static HTAB * RecoveryLockLists
Definition: standby.c:43
Definition: lock.h:163
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:907
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
#define DEBUG4
Definition: elog.h:22
#define OidIsValid(objectId)
Definition: c.h:644
TransactionId xid
Definition: standby.c:56
int trace_recovery(int trace_level)
Definition: elog.c:3505
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:180
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
List * lappend(List *list, void *datum)
Definition: list.c:322
TransactionId xid
Definition: lockdefs.h:54
#define Assert(condition)
Definition: c.h:738
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:949
#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 612 of file standby.c.

Referenced by StartupProcessMain().

613 {
614 }

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )

Definition at line 744 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().

745 {
747  RecoveryLockListsEntry *entry;
748 
749  elog(trace_recovery(DEBUG2), "release all standby locks");
750 
752  while ((entry = hash_seq_search(&status)))
753  {
756  }
757 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:682
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:907
int trace_recovery(int trace_level)
Definition: elog.c:3505
#define DEBUG2
Definition: elog.h:24
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1390
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1380
#define elog(elevel,...)
Definition: elog.h:214
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ StandbyReleaseLockList()

static void StandbyReleaseLockList ( List locks)
static

Definition at line 682 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().

683 {
684  while (locks)
685  {
686  xl_standby_lock *lock = (xl_standby_lock *) linitial(locks);
687  LOCKTAG locktag;
688 
690  "releasing recovery lock: xid %u db %u rel %u",
691  lock->xid, lock->dbOid, lock->relOid);
692  SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid);
693  if (!LockRelease(&locktag, AccessExclusiveLock, true))
694  {
695  elog(LOG,
696  "RecoveryLockLists contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
697  lock->xid, lock->dbOid, lock->relOid);
698  Assert(false);
699  }
700  pfree(lock);
701  locks = list_delete_first(locks);
702  }
703 }
Definition: lock.h:163
#define LOG
Definition: elog.h:26
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3505
void pfree(void *pointer)
Definition: mcxt.c:1056
#define linitial(l)
Definition: pg_list.h:195
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:180
TransactionId xid
Definition: lockdefs.h:54
#define Assert(condition)
Definition: c.h:738
#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:1969
List * list_delete_first(List *list)
Definition: list.c:861

◆ StandbyReleaseLocks()

static void StandbyReleaseLocks ( TransactionId  xid)
static

Definition at line 706 of file standby.c.

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

Referenced by StandbyReleaseLockTree().

707 {
708  RecoveryLockListsEntry *entry;
709 
710  if (TransactionIdIsValid(xid))
711  {
712  if ((entry = hash_search(RecoveryLockLists, &xid, HASH_FIND, NULL)))
713  {
716  }
717  }
718  else
720 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:682
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:907
void StandbyReleaseAllLocks(void)
Definition: standby.c:744
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ StandbyReleaseLockTree()

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

Definition at line 730 of file standby.c.

References i, and StandbyReleaseLocks().

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

731 {
732  int i;
733 
734  StandbyReleaseLocks(xid);
735 
736  for (i = 0; i < nsubxids; i++)
737  StandbyReleaseLocks(subxids[i]);
738 }
static void StandbyReleaseLocks(TransactionId xid)
Definition: standby.c:706
int i

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)

Definition at line 765 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().

766 {
768  RecoveryLockListsEntry *entry;
769 
771  while ((entry = hash_seq_search(&status)))
772  {
774 
775  /* Skip if prepared transaction. */
777  continue;
778 
779  /* Skip if >= oldxid. */
780  if (!TransactionIdPrecedes(entry->xid, oldxid))
781  continue;
782 
783  /* Remove all locks and hash table entry. */
786  }
787 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:682
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:907
TransactionId xid
Definition: standby.c:56
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1372
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:738
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1390
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1380
#define TransactionIdIsValid(xid)
Definition: transam.h:41
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:225

◆ StandbyTimeoutHandler()

void StandbyTimeoutHandler ( void  )

Definition at line 599 of file standby.c.

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

Referenced by StartupProcessMain().

600 {
601  /* forget any pending STANDBY_DEADLOCK_TIMEOUT request */
603 
605 }
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition: standby.c:528
void disable_timeout(TimeoutId id, bool keep_indicator)
Definition: timeout.c:532

◆ WaitExceedsMaxStandbyDelay()

static bool WaitExceedsMaxStandbyDelay ( void  )
static

Definition at line 187 of file standby.c.

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

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

188 {
189  TimestampTz ltime;
190 
192 
193  /* Are we past the limit time? */
194  ltime = GetStandbyLimitTime();
195  if (ltime && GetCurrentTimestamp() >= ltime)
196  return true;
197 
198  /*
199  * Sleep a bit (this is essential to avoid busy-waiting).
200  */
202 
203  /*
204  * Progressively increase the sleep times, but not to more than 1s, since
205  * pg_usleep isn't interruptible on some platforms.
206  */
207  standbyWait_us *= 2;
208  if (standbyWait_us > 1000000)
209  standbyWait_us = 1000000;
210 
211  return false;
212 }
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:154
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
int64 TimestampTz
Definition: timestamp.h:39
static int standbyWait_us
Definition: standby.c:179
void pg_usleep(long microsec)
Definition: signal.c:53
#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 GetOldestXmin(), and GetSnapshotData().