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)
 
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 542 of file standby.c.

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

Referenced by ProcSleep().

543 {
544  Assert(!InRecovery); /* do not call in Startup process */
545 
547  return;
548 
549  /*
550  * Error message should match ProcessInterrupts() but we avoid calling
551  * that because we aren't handling an interrupt at this point. Note that
552  * we only cancel the current transaction here, so if we are in a
553  * subtransaction and the pin is held by a parent, then the Startup
554  * process will continue to wait even though we have avoided deadlock.
555  */
556  ereport(ERROR,
557  (errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
558  errmsg("canceling statement due to conflict with recovery"),
559  errdetail("User transaction caused buffer deadlock with recovery.")));
560 }
bool InRecovery
Definition: xlog.c:194
int errcode(int sqlerrcode)
Definition: elog.c:572
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:862
#define ereport(elevel, rest)
Definition: elog.h:141
#define Assert(condition)
Definition: c.h:732
bool HoldingBufferPinThatDelaysRecovery(void)
Definition: bufmgr.c:3692
int errmsg(const char *fmt,...)
Definition: elog.c:786

◆ 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:6285
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:80
static HTAB * RecoveryLockLists
Definition: standby.c:43
#define HASH_ELEM
Definition: hsearch.h:87
uint32 TransactionId
Definition: c.h:507
void SharedInvalBackendInit(bool sendOnly)
Definition: sinvaladt.c:258
Size entrysize
Definition: hsearch.h:73
LocalTransactionId localTransactionId
Definition: lock.h:66
LocalTransactionId GetNextLocalTransactionId(void)
Definition: sinvaladt.c:769
void VirtualXactLockTableInsert(VirtualTransactionId vxid)
Definition: lock.c:4296
#define HASH_BLOBS
Definition: hsearch.h:88
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72
BackendId backendId
Definition: lock.h:65
struct RecoveryLockListsEntry RecoveryLockListsEntry
HotStandbyState standbyState
Definition: xlog.c:197

◆ LogAccessExclusiveLock()

void LogAccessExclusiveLock ( Oid  dbOid,
Oid  relOid 
)

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

1040 {
1041  xl_standby_lock xlrec;
1042 
1043  xlrec.xid = GetCurrentTransactionId();
1044 
1045  xlrec.dbOid = dbOid;
1046  xlrec.relOid = relOid;
1047 
1048  LogAccessExclusiveLocks(1, &xlrec);
1050 }
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition: standby.c:1021
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK
Definition: xact.h:99
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:399
int MyXactFlags
Definition: xact.c:118
TransactionId xid
Definition: lockdefs.h:54

◆ LogAccessExclusiveLockPrepare()

void LogAccessExclusiveLockPrepare ( void  )

Definition at line 1056 of file standby.c.

References GetCurrentTransactionId().

Referenced by LockAcquireExtended().

1057 {
1058  /*
1059  * Ensure that a TransactionId has been assigned to this transaction, for
1060  * two reasons, both related to lock release on the standby. First, we
1061  * must assign an xid so that RecordTransactionCommit() and
1062  * RecordTransactionAbort() do not optimise away the transaction
1063  * completion record which recovery relies upon to release locks. It's a
1064  * hack, but for a corner case not worth adding code for into the main
1065  * commit path. Second, we must assign an xid before the lock is recorded
1066  * in shared memory, otherwise a concurrently executing
1067  * GetRunningTransactionLocks() might see a lock associated with an
1068  * InvalidTransactionId which we later assert cannot happen.
1069  */
1070  (void) GetCurrentTransactionId();
1071 }
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:399

◆ LogAccessExclusiveLocks()

static void LogAccessExclusiveLocks ( int  nlocks,
xl_standby_lock locks 
)
static

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

1022 {
1023  xl_standby_locks xlrec;
1024 
1025  xlrec.nlocks = nlocks;
1026 
1027  XLogBeginInsert();
1028  XLogRegisterData((char *) &xlrec, offsetof(xl_standby_locks, locks));
1029  XLogRegisterData((char *) locks, nlocks * sizeof(xl_standby_lock));
1031 
1032  (void) XLogInsert(RM_STANDBY_ID, XLOG_STANDBY_LOCK);
1033 }
#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:193
void XLogBeginInsert(void)
Definition: xloginsert.c:120
#define offsetof(type, field)
Definition: c.h:655

◆ LogCurrentRunningXacts()

static XLogRecPtr LogCurrentRunningXacts ( RunningTransactions  CurrRunningXacts)
static

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

962 {
963  xl_running_xacts xlrec;
964  XLogRecPtr recptr;
965 
966  xlrec.xcnt = CurrRunningXacts->xcnt;
967  xlrec.subxcnt = CurrRunningXacts->subxcnt;
968  xlrec.subxid_overflow = CurrRunningXacts->subxid_overflow;
969  xlrec.nextXid = CurrRunningXacts->nextXid;
970  xlrec.oldestRunningXid = CurrRunningXacts->oldestRunningXid;
971  xlrec.latestCompletedXid = CurrRunningXacts->latestCompletedXid;
972 
973  /* Header */
974  XLogBeginInsert();
976  XLogRegisterData((char *) (&xlrec), MinSizeOfXactRunningXacts);
977 
978  /* array of TransactionIds */
979  if (xlrec.xcnt > 0)
980  XLogRegisterData((char *) CurrRunningXacts->xids,
981  (xlrec.xcnt + xlrec.subxcnt) * sizeof(TransactionId));
982 
983  recptr = XLogInsert(RM_STANDBY_ID, XLOG_RUNNING_XACTS);
984 
985  if (CurrRunningXacts->subxid_overflow)
987  "snapshot of %u running transactions overflowed (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
988  CurrRunningXacts->xcnt,
989  (uint32) (recptr >> 32), (uint32) recptr,
990  CurrRunningXacts->oldestRunningXid,
991  CurrRunningXacts->latestCompletedXid,
992  CurrRunningXacts->nextXid);
993  else
995  "snapshot of %u+%u running transaction ids (lsn %X/%X oldest xid %u latest complete %u next xid %u)",
996  CurrRunningXacts->xcnt, CurrRunningXacts->subxcnt,
997  (uint32) (recptr >> 32), (uint32) recptr,
998  CurrRunningXacts->oldestRunningXid,
999  CurrRunningXacts->latestCompletedXid,
1000  CurrRunningXacts->nextXid);
1001 
1002  /*
1003  * Ensure running_xacts information is synced to disk not too far in the
1004  * future. We don't want to stall anything though (i.e. use XLogFlush()),
1005  * so we let the wal writer do it during normal operation.
1006  * XLogSetAsyncXactLSN() conveniently will mark the LSN as to-be-synced
1007  * and nudge the WALWriter into action if sleeping. Check
1008  * XLogBackgroundFlush() for details why a record might not be flushed
1009  * without it.
1010  */
1011  XLogSetAsyncXactLSN(recptr);
1012 
1013  return recptr;
1014 }
TransactionId oldestRunningXid
Definition: standby.h:76
uint32 TransactionId
Definition: c.h:507
TransactionId * xids
Definition: standby.h:79
int trace_recovery(int trace_level)
Definition: elog.c:3481
TransactionId latestCompletedXid
Definition: standby.h:77
TransactionId latestCompletedXid
Definition: standbydefs.h:54
#define DEBUG2
Definition: elog.h:24
unsigned int uint32
Definition: c.h:358
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:2647
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLOG_MARK_UNIMPORTANT
Definition: xlog.h:193
TransactionId nextXid
Definition: standbydefs.h:52
TransactionId nextXid
Definition: standby.h:75
#define elog(elevel,...)
Definition: elog.h:226
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 1078 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().

1080 {
1081  xl_invalidations xlrec;
1082 
1083  /* prepare record */
1084  memset(&xlrec, 0, sizeof(xlrec));
1085  xlrec.dbId = MyDatabaseId;
1086  xlrec.tsId = MyDatabaseTableSpace;
1087  xlrec.relcacheInitFileInval = relcacheInitFileInval;
1088  xlrec.nmsgs = nmsgs;
1089 
1090  /* perform insertion */
1091  XLogBeginInsert();
1092  XLogRegisterData((char *) (&xlrec), MinSizeOfInvalidations);
1093  XLogRegisterData((char *) msgs,
1094  nmsgs * sizeof(SharedInvalidationMessage));
1095  XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
1096 }
#define XLOG_INVALIDATIONS
Definition: standbydefs.h:36
Oid MyDatabaseTableSpace
Definition: globals.c:86
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:84
void XLogBeginInsert(void)
Definition: xloginsert.c:120

◆ LogStandbySnapshot()

XLogRecPtr LogStandbySnapshot ( void  )

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

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

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )

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

462 {
463  TimestampTz ltime;
464 
466 
467  ltime = GetStandbyLimitTime();
468 
469  if (ltime == 0)
470  {
471  /*
472  * We're willing to wait forever for conflicts, so set timeout for
473  * deadlock check only
474  */
476  }
477  else if (GetCurrentTimestamp() >= ltime)
478  {
479  /*
480  * We're already behind, so clear a path as quickly as possible.
481  */
483  }
484  else
485  {
486  /*
487  * Wake up at ltime, and check for deadlocks as well if we will be
488  * waiting longer than deadlock_timeout
489  */
490  EnableTimeoutParams timeouts[2];
491 
492  timeouts[0].id = STANDBY_TIMEOUT;
493  timeouts[0].type = TMPARAM_AT;
494  timeouts[0].fin_time = ltime;
495  timeouts[1].id = STANDBY_DEADLOCK_TIMEOUT;
496  timeouts[1].type = TMPARAM_AFTER;
497  timeouts[1].delay_ms = DeadlockTimeout;
498  enable_timeouts(timeouts, 2);
499  }
500 
501  /* Wait to be signaled by UnpinBuffer() */
503 
504  /*
505  * Clear any timeout requests established above. We assume here that the
506  * Startup process doesn't have any other timeouts than what this function
507  * uses. If that stops being true, we could cancel the timeouts
508  * individually, but that'd be slower.
509  */
510  disable_all_timeouts(false);
511 }
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:154
TimeoutId id
Definition: timeout.h:54
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1570
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:476
void disable_all_timeouts(bool keep_indicators)
Definition: timeout.c:596
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition: standby.c:514
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1777
#define PG_WAIT_BUFFER_PIN
Definition: pgstat.h:739
void enable_timeout_after(TimeoutId id, int delay_ms)
Definition: timeout.c:428
#define Assert(condition)
Definition: c.h:732
TimestampTz fin_time
Definition: timeout.h:57
int DeadlockTimeout
Definition: proc.c:60

◆ ResolveRecoveryConflictWithDatabase()

void ResolveRecoveryConflictWithDatabase ( Oid  dbid)

Definition at line 346 of file standby.c.

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

Referenced by dbase_redo().

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

◆ ResolveRecoveryConflictWithLock()

void ResolveRecoveryConflictWithLock ( LOCKTAG  locktag)

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

390 {
391  TimestampTz ltime;
392 
394 
395  ltime = GetStandbyLimitTime();
396 
397  if (GetCurrentTimestamp() >= ltime)
398  {
399  /*
400  * We're already behind, so clear a path as quickly as possible.
401  */
402  VirtualTransactionId *backends;
403 
404  backends = GetLockConflicts(&locktag, AccessExclusiveLock);
407  }
408  else
409  {
410  /*
411  * Wait (or wait again) until ltime
412  */
413  EnableTimeoutParams timeouts[1];
414 
415  timeouts[0].id = STANDBY_LOCK_TIMEOUT;
416  timeouts[0].type = TMPARAM_AT;
417  timeouts[0].fin_time = ltime;
418  enable_timeouts(timeouts, 1);
419  }
420 
421  /* Wait to be signaled by the release of the Relation Lock */
423 
424  /*
425  * Clear any timeout requests established above. We assume here that the
426  * Startup process doesn't have any other outstanding timeouts than those
427  * used by this function. If that stops being true, we could cancel the
428  * timeouts individually, but that'd be slower.
429  */
430  disable_all_timeouts(false);
431 }
#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:1570
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:476
void disable_all_timeouts(bool keep_indicators)
Definition: timeout.c:596
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason)
Definition: standby.c:221
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1777
uint8 locktag_type
Definition: lock.h:184
#define Assert(condition)
Definition: c.h:732
TimestampTz fin_time
Definition: timeout.h:57
#define AccessExclusiveLock
Definition: lockdefs.h:45
VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode)
Definition: lock.c:2820

◆ ResolveRecoveryConflictWithSnapshot()

void ResolveRecoveryConflictWithSnapshot ( TransactionId  latestRemovedXid,
RelFileNode  node 
)

Definition at line 294 of file standby.c.

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

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

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

◆ ResolveRecoveryConflictWithTablespace()

void ResolveRecoveryConflictWithTablespace ( Oid  tsid)

Definition at line 318 of file standby.c.

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

Referenced by tblspc_redo().

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

◆ ResolveRecoveryConflictWithVirtualXIDs()

static void ResolveRecoveryConflictWithVirtualXIDs ( VirtualTransactionId waitlist,
ProcSignalReason  reason 
)
static

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

223 {
224  TimestampTz waitStart;
225  char *new_status;
226 
227  /* Fast exit, to avoid a kernel call if there's no work to be done. */
228  if (!VirtualTransactionIdIsValid(*waitlist))
229  return;
230 
231  waitStart = GetCurrentTimestamp();
232  new_status = NULL; /* we haven't changed the ps display */
233 
234  while (VirtualTransactionIdIsValid(*waitlist))
235  {
236  /* reset standbyWait_us for each xact we wait for */
238 
239  /* wait until the virtual xid is gone */
240  while (!VirtualXactLock(*waitlist, false))
241  {
242  /*
243  * Report via ps if we have been waiting for more than 500 msec
244  * (should that be configurable?)
245  */
246  if (update_process_title && new_status == NULL &&
248  500))
249  {
250  const char *old_status;
251  int len;
252 
253  old_status = get_ps_display(&len);
254  new_status = (char *) palloc(len + 8 + 1);
255  memcpy(new_status, old_status, len);
256  strcpy(new_status + len, " waiting");
257  set_ps_display(new_status, false);
258  new_status[len] = '\0'; /* truncate off " waiting" */
259  }
260 
261  /* Is it time to kill it? */
263  {
264  pid_t pid;
265 
266  /*
267  * Now find out who to throw out of the balloon.
268  */
270  pid = CancelVirtualTransaction(*waitlist, reason);
271 
272  /*
273  * Wait a little bit for it to die so that we avoid flooding
274  * an unresponsive backend when system is heavily loaded.
275  */
276  if (pid != 0)
277  pg_usleep(5000L);
278  }
279  }
280 
281  /* The virtual transaction is gone now, wait for the next one */
282  waitlist++;
283  }
284 
285  /* Reset ps display if we changed it */
286  if (new_status)
287  {
288  set_ps_display(new_status, false);
289  pfree(new_status);
290  }
291 }
pid_t CancelVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode)
Definition: procarray.c:2656
bool update_process_title
Definition: ps_status.c:35
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1570
int64 TimestampTz
Definition: timestamp.h:39
static int standbyWait_us
Definition: standby.c:179
void set_ps_display(const char *activity, bool force)
Definition: ps_status.c:331
bool TimestampDifferenceExceeds(TimestampTz start_time, TimestampTz stop_time, int msec)
Definition: timestamp.c:1669
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
Definition: lock.c:4366
void pg_usleep(long microsec)
Definition: signal.c:53
void pfree(void *pointer)
Definition: mcxt.c:1031
#define STANDBY_INITIAL_WAIT_US
Definition: standby.c:178
const char * get_ps_display(int *displen)
Definition: ps_status.c:412
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
#define Assert(condition)
Definition: c.h:732
void * palloc(Size size)
Definition: mcxt.c:924
static bool WaitExceedsMaxStandbyDelay(void)
Definition: standby.c:187

◆ SendRecoveryConflictWithBufferPin()

static void SendRecoveryConflictWithBufferPin ( ProcSignalReason  reason)
static

Definition at line 514 of file standby.c.

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

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

515 {
518 
519  /*
520  * We send signal to all backends to ask them if they are holding the
521  * buffer pin which is delaying the Startup process. We must not set the
522  * conflict flag yet, since most backends will be innocent. Let the
523  * SIGUSR1 handling in each backend decide their own fate.
524  */
525  CancelDBBackends(InvalidOid, reason, false);
526 }
void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:2819
#define InvalidOid
Definition: postgres_ext.h:36
#define Assert(condition)
Definition: c.h:732

◆ 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:814
void VirtualXactLockTableCleanup(void)
Definition: lock.c:4319
static HTAB * RecoveryLockLists
Definition: standby.c:43
void ExpireAllKnownAssignedTransactionIds(void)
Definition: procarray.c:3290
void StandbyReleaseAllLocks(void)
Definition: standby.c:730

◆ standby_redo()

void standby_redo ( XLogReaderState record)

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

785 {
786  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
787 
788  /* Backup blocks are not used in standby records */
789  Assert(!XLogRecHasAnyBlockRefs(record));
790 
791  /* Do nothing if we're not in hot standby mode */
793  return;
794 
795  if (info == XLOG_STANDBY_LOCK)
796  {
797  xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record);
798  int i;
799 
800  for (i = 0; i < xlrec->nlocks; i++)
802  xlrec->locks[i].dbOid,
803  xlrec->locks[i].relOid);
804  }
805  else if (info == XLOG_RUNNING_XACTS)
806  {
807  xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record);
808  RunningTransactionsData running;
809 
810  running.xcnt = xlrec->xcnt;
811  running.subxcnt = xlrec->subxcnt;
812  running.subxid_overflow = xlrec->subxid_overflow;
813  running.nextXid = xlrec->nextXid;
814  running.latestCompletedXid = xlrec->latestCompletedXid;
815  running.oldestRunningXid = xlrec->oldestRunningXid;
816  running.xids = xlrec->xids;
817 
818  ProcArrayApplyRecoveryInfo(&running);
819  }
820  else if (info == XLOG_INVALIDATIONS)
821  {
822  xl_invalidations *xlrec = (xl_invalidations *) XLogRecGetData(record);
823 
825  xlrec->nmsgs,
826  xlrec->relcacheInitFileInval,
827  xlrec->dbId,
828  xlrec->tsId);
829  }
830  else
831  elog(PANIC, "standby_redo: unknown op code %u", info);
832 }
void ProcArrayApplyRecoveryInfo(RunningTransactions running)
Definition: procarray.c:662
TransactionId oldestRunningXid
Definition: standby.h:76
#define XLOG_INVALIDATIONS
Definition: standbydefs.h:36
unsigned char uint8
Definition: c.h:356
#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:230
TransactionId latestCompletedXid
Definition: standbydefs.h:54
bool relcacheInitFileInval
Definition: standbydefs.h:67
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:226
TransactionId xid
Definition: lockdefs.h:54
void ProcessCommittedInvalidationMessages(SharedInvalidationMessage *msgs, int nmsgs, bool RelcacheInitFileInval, Oid dbid, Oid tsid)
Definition: inval.c:882
#define Assert(condition)
Definition: c.h:732
#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:629
#define elog(elevel,...)
Definition: elog.h:226
int i
TransactionId oldestRunningXid
Definition: standbydefs.h:53
#define XLOG_RUNNING_XACTS
Definition: standbydefs.h:35
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:232
HotStandbyState standbyState
Definition: xlog.c:197

◆ StandbyAcquireAccessExclusiveLock()

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

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

630 {
631  RecoveryLockListsEntry *entry;
632  xl_standby_lock *newlock;
633  LOCKTAG locktag;
634  bool found;
635 
636  /* Already processed? */
637  if (!TransactionIdIsValid(xid) ||
638  TransactionIdDidCommit(xid) ||
640  return;
641 
643  "adding recovery lock: db %u rel %u", dbOid, relOid);
644 
645  /* dbOid is InvalidOid when we are locking a shared relation. */
646  Assert(OidIsValid(relOid));
647 
648  /* Create a new list for this xid, if we don't have one already. */
649  entry = hash_search(RecoveryLockLists, &xid, HASH_ENTER, &found);
650  if (!found)
651  {
652  entry->xid = xid;
653  entry->locks = NIL;
654  }
655 
656  newlock = palloc(sizeof(xl_standby_lock));
657  newlock->xid = xid;
658  newlock->dbOid = dbOid;
659  newlock->relOid = relOid;
660  entry->locks = lappend(entry->locks, newlock);
661 
662  SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid);
663 
664  (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
665 }
#define NIL
Definition: pg_list.h:69
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition: lock.c:708
static HTAB * RecoveryLockLists
Definition: standby.c:43
Definition: lock.h:178
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
#define DEBUG4
Definition: elog.h:22
#define OidIsValid(objectId)
Definition: c.h:638
TransactionId xid
Definition: standby.c:56
int trace_recovery(int trace_level)
Definition: elog.c:3481
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:193
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
List * lappend(List *list, void *datum)
Definition: list.c:128
TransactionId xid
Definition: lockdefs.h:54
#define Assert(condition)
Definition: c.h:732
#define AccessExclusiveLock
Definition: lockdefs.h:45
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ StandbyDeadLockHandler()

void StandbyDeadLockHandler ( void  )

◆ StandbyLockTimeoutHandler()

void StandbyLockTimeoutHandler ( void  )

Definition at line 598 of file standby.c.

Referenced by StartupProcessMain().

599 {
600 }

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )

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

731 {
733  RecoveryLockListsEntry *entry;
734 
735  elog(trace_recovery(DEBUG2), "release all standby locks");
736 
738  while ((entry = hash_seq_search(&status)))
739  {
742  }
743 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:668
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
int trace_recovery(int trace_level)
Definition: elog.c:3481
#define DEBUG2
Definition: elog.h:24
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#define elog(elevel,...)
Definition: elog.h:226
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 668 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().

669 {
670  while (locks)
671  {
672  xl_standby_lock *lock = (xl_standby_lock *) linitial(locks);
673  LOCKTAG locktag;
674 
676  "releasing recovery lock: xid %u db %u rel %u",
677  lock->xid, lock->dbOid, lock->relOid);
678  SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid);
679  if (!LockRelease(&locktag, AccessExclusiveLock, true))
680  {
681  elog(LOG,
682  "RecoveryLockLists contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u",
683  lock->xid, lock->dbOid, lock->relOid);
684  Assert(false);
685  }
686  pfree(lock);
687  locks = list_delete_first(locks);
688  }
689 }
Definition: lock.h:178
#define LOG
Definition: elog.h:26
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3481
void pfree(void *pointer)
Definition: mcxt.c:1031
#define linitial(l)
Definition: pg_list.h:111
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:193
TransactionId xid
Definition: lockdefs.h:54
#define Assert(condition)
Definition: c.h:732
#define AccessExclusiveLock
Definition: lockdefs.h:45
#define elog(elevel,...)
Definition: elog.h:226
bool LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
Definition: lock.c:1884
List * list_delete_first(List *list)
Definition: list.c:666

◆ StandbyReleaseLocks()

static void StandbyReleaseLocks ( TransactionId  xid)
static

Definition at line 692 of file standby.c.

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

Referenced by StandbyReleaseLockTree().

693 {
694  RecoveryLockListsEntry *entry;
695 
696  if (TransactionIdIsValid(xid))
697  {
698  if ((entry = hash_search(RecoveryLockLists, &xid, HASH_FIND, NULL)))
699  {
702  }
703  }
704  else
706 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:668
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
void StandbyReleaseAllLocks(void)
Definition: standby.c:730
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ StandbyReleaseLockTree()

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

Definition at line 716 of file standby.c.

References i, and StandbyReleaseLocks().

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

717 {
718  int i;
719 
720  StandbyReleaseLocks(xid);
721 
722  for (i = 0; i < nsubxids; i++)
723  StandbyReleaseLocks(subxids[i]);
724 }
static void StandbyReleaseLocks(TransactionId xid)
Definition: standby.c:692
int i

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)

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

752 {
754  RecoveryLockListsEntry *entry;
755 
757  while ((entry = hash_seq_search(&status)))
758  {
760 
761  /* Skip if prepared transaction. */
763  continue;
764 
765  /* Skip if >= oldxid. */
766  if (!TransactionIdPrecedes(entry->xid, oldxid))
767  continue;
768 
769  /* Remove all locks and hash table entry. */
772  }
773 }
static void StandbyReleaseLockList(List *locks)
Definition: standby.c:668
static HTAB * RecoveryLockLists
Definition: standby.c:43
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
TransactionId xid
Definition: standby.c:56
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1411
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:732
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
#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 585 of file standby.c.

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

Referenced by StartupProcessMain().

586 {
587  /* forget any pending STANDBY_DEADLOCK_TIMEOUT request */
589 
591 }
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition: standby.c:514
void disable_timeout(TimeoutId id, bool keep_indicator)
Definition: timeout.c:525

◆ 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 interruptable 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:1570
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:98

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