PostgreSQL Source Code git master
Loading...
Searching...
No Matches
standby.h File Reference
Include dependency graph for standby.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  RunningTransactionsData
 

Macros

#define NUM_RECOVERY_CONFLICT_REASONS   (RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK + 1)
 
#define MinSizeOfXactRunningXacts   offsetof(xl_running_xacts, xids)
 

Typedefs

typedef struct PGPROC PGPROC
 
typedef struct VirtualTransactionId VirtualTransactionId
 
typedef struct RunningTransactionsData RunningTransactionsData
 
typedef RunningTransactionsDataRunningTransactions
 

Enumerations

enum  RecoveryConflictReason {
  RECOVERY_CONFLICT_DATABASE , RECOVERY_CONFLICT_TABLESPACE , RECOVERY_CONFLICT_LOCK , RECOVERY_CONFLICT_SNAPSHOT ,
  RECOVERY_CONFLICT_LOGICALSLOT , RECOVERY_CONFLICT_BUFFERPIN , RECOVERY_CONFLICT_STARTUP_DEADLOCK , RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK
}
 
enum  subxids_array_status { SUBXIDS_IN_ARRAY , SUBXIDS_MISSING , SUBXIDS_IN_SUBTRANS }
 

Functions

void InitRecoveryTransactionEnvironment (void)
 
void ShutdownRecoveryTransactionEnvironment (void)
 
void ResolveRecoveryConflictWithSnapshot (TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
 
void ResolveRecoveryConflictWithSnapshotFullXid (FullTransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
 
void ResolveRecoveryConflictWithTablespace (Oid tsid)
 
void ResolveRecoveryConflictWithDatabase (Oid dbid)
 
void ResolveRecoveryConflictWithLock (LOCKTAG locktag, bool logging_conflict)
 
void ResolveRecoveryConflictWithBufferPin (void)
 
void CheckRecoveryConflictDeadlock (void)
 
void StandbyDeadLockHandler (void)
 
void StandbyTimeoutHandler (void)
 
void StandbyLockTimeoutHandler (void)
 
void LogRecoveryConflict (RecoveryConflictReason reason, TimestampTz wait_start, TimestampTz now, VirtualTransactionId *wait_list, bool still_waiting)
 
void StandbyAcquireAccessExclusiveLock (TransactionId xid, Oid dbOid, Oid relOid)
 
void StandbyReleaseLockTree (TransactionId xid, int nsubxids, TransactionId *subxids)
 
void StandbyReleaseAllLocks (void)
 
void StandbyReleaseOldLocks (TransactionId oldxid)
 
void LogAccessExclusiveLock (Oid dbOid, Oid relOid)
 
void LogAccessExclusiveLockPrepare (void)
 
XLogRecPtr LogStandbySnapshot (Oid dbid)
 
void LogStandbyInvalidations (int nmsgs, SharedInvalidationMessage *msgs, bool relcacheInitFileInval)
 

Variables

PGDLLIMPORT int max_standby_archive_delay
 
PGDLLIMPORT int max_standby_streaming_delay
 
PGDLLIMPORT bool log_recovery_conflict_waits
 

Macro Definition Documentation

◆ MinSizeOfXactRunningXacts

#define MinSizeOfXactRunningXacts   offsetof(xl_running_xacts, xids)

Definition at line 104 of file standby.h.

◆ NUM_RECOVERY_CONFLICT_REASONS

#define NUM_RECOVERY_CONFLICT_REASONS   (RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK + 1)

Definition at line 67 of file standby.h.

Typedef Documentation

◆ PGPROC

Definition at line 22 of file standby.h.

◆ RunningTransactions

◆ RunningTransactionsData

◆ VirtualTransactionId

Definition at line 23 of file standby.h.

Enumeration Type Documentation

◆ RecoveryConflictReason

Enumerator
RECOVERY_CONFLICT_DATABASE 
RECOVERY_CONFLICT_TABLESPACE 
RECOVERY_CONFLICT_LOCK 
RECOVERY_CONFLICT_SNAPSHOT 
RECOVERY_CONFLICT_LOGICALSLOT 
RECOVERY_CONFLICT_BUFFERPIN 
RECOVERY_CONFLICT_STARTUP_DEADLOCK 
RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK 

Definition at line 31 of file standby.h.

32{
33 /* Backend is connected to a database that is being dropped */
35
36 /* Backend is using a tablespace that is being dropped */
38
39 /* Backend is holding a lock that is blocking recovery */
41
42 /* Backend is holding a snapshot that is blocking recovery */
44
45 /* Backend is using a logical replication slot that must be invalidated */
47
48 /* Backend is holding a pin on a buffer that is blocking recovery */
50
51 /*
52 * The backend is requested to check for deadlocks. The startup process
53 * doesn't check for deadlock directly, because we want to kill one of the
54 * other backends instead of the startup process.
55 */
57
58 /*
59 * Like RECOVERY_CONFLICT_STARTUP_DEADLOCK is, but the suspected deadlock
60 * involves a buffer pin that some other backend is holding. That needs
61 * special checking because the normal deadlock detector doesn't track the
62 * buffer pins.
63 */
RecoveryConflictReason
Definition standby.h:32
@ RECOVERY_CONFLICT_TABLESPACE
Definition standby.h:37
@ RECOVERY_CONFLICT_SNAPSHOT
Definition standby.h:43
@ RECOVERY_CONFLICT_LOCK
Definition standby.h:40
@ RECOVERY_CONFLICT_DATABASE
Definition standby.h:34
@ RECOVERY_CONFLICT_STARTUP_DEADLOCK
Definition standby.h:56
@ RECOVERY_CONFLICT_BUFFERPIN
Definition standby.h:49
@ RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK
Definition standby.h:64
@ RECOVERY_CONFLICT_LOGICALSLOT
Definition standby.h:46

◆ subxids_array_status

Enumerator
SUBXIDS_IN_ARRAY 
SUBXIDS_MISSING 
SUBXIDS_IN_SUBTRANS 

Definition at line 119 of file standby.h.

120{
121 SUBXIDS_IN_ARRAY, /* xids array includes all running subxids */
122 SUBXIDS_MISSING, /* snapshot overflowed, subxids are missing */
123 SUBXIDS_IN_SUBTRANS, /* subxids are not included in 'xids', but
124 * pg_subtrans is fully up-to-date */
subxids_array_status
Definition standby.h:120
@ SUBXIDS_IN_SUBTRANS
Definition standby.h:123
@ SUBXIDS_MISSING
Definition standby.h:122
@ SUBXIDS_IN_ARRAY
Definition standby.h:121

Function Documentation

◆ CheckRecoveryConflictDeadlock()

void CheckRecoveryConflictDeadlock ( void  )
extern

Definition at line 907 of file standby.c.

908{
909 Assert(!InRecovery); /* do not call in Startup process */
910
912 return;
913
914 /*
915 * Error message should match ProcessInterrupts() but we avoid calling
916 * that because we aren't handling an interrupt at this point. Note that
917 * we only cancel the current transaction here, so if we are in a
918 * subtransaction and the pin is held by a parent, then the Startup
919 * process will continue to wait even though we have avoided deadlock.
920 */
923 errmsg("canceling statement due to conflict with recovery"),
924 errdetail("User transaction caused buffer deadlock with recovery.")));
925}
bool HoldingBufferPinThatDelaysRecovery(void)
Definition bufmgr.c:6817
#define Assert(condition)
Definition c.h:943
int errcode(int sqlerrcode)
Definition elog.c:874
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:151
static char * errmsg
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition pgbench.c:78
bool InRecovery
Definition xlogutils.c:50

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

Referenced by ProcSleep().

◆ InitRecoveryTransactionEnvironment()

void InitRecoveryTransactionEnvironment ( void  )
extern

Definition at line 96 of file standby.c.

97{
100
101 Assert(RecoveryLockHash == NULL); /* don't run this twice */
102
103 /*
104 * Initialize the hash tables for tracking the locks held by each
105 * transaction.
106 */
107 hash_ctl.keysize = sizeof(xl_standby_lock);
108 hash_ctl.entrysize = sizeof(RecoveryLockEntry);
109 RecoveryLockHash = hash_create("RecoveryLockHash",
110 64,
111 &hash_ctl,
113 hash_ctl.keysize = sizeof(TransactionId);
114 hash_ctl.entrysize = sizeof(RecoveryLockXidEntry);
115 RecoveryLockXidHash = hash_create("RecoveryLockXidHash",
116 64,
117 &hash_ctl,
119
120 /*
121 * Initialize shared invalidation management for Startup process, being
122 * careful to register ourselves as a sendOnly process so we don't need to
123 * read messages, nor will we get signaled when the queue starts filling
124 * up.
125 */
127
128 /*
129 * Lock a virtual transaction id for Startup process.
130 *
131 * We need to do GetNextLocalTransactionId() because
132 * SharedInvalBackendInit() leaves localTransactionId invalid and the lock
133 * manager doesn't like that at all.
134 *
135 * Note that we don't need to run XactLockTableInsert() because nobody
136 * needs to wait on xids. That sounds a little strange, but table locks
137 * are held by vxids and row level locks are held by xids. All queries
138 * hold AccessShareLocks so never block while we write or lock new rows.
139 */
144
146}
uint32 TransactionId
Definition c.h:736
HTAB * hash_create(const char *tabname, int64 nelem, const HASHCTL *info, int flags)
Definition dynahash.c:360
ProcNumber MyProcNumber
Definition globals.c:92
#define HASH_ELEM
Definition hsearch.h:90
#define HASH_BLOBS
Definition hsearch.h:92
void VirtualXactLockTableInsert(VirtualTransactionId vxid)
Definition lock.c:4603
static int fb(int x)
void SharedInvalBackendInit(bool sendOnly)
Definition sinvaladt.c:274
LocalTransactionId GetNextLocalTransactionId(void)
Definition sinvaladt.c:703
PGPROC * MyProc
Definition proc.c:71
static HTAB * RecoveryLockXidHash
Definition standby.c:67
static HTAB * RecoveryLockHash
Definition standby.c:66
ProcNumber procNumber
Definition proc.h:226
struct PGPROC::@136 vxid
LocalTransactionId localTransactionId
Definition lock.h:65
ProcNumber procNumber
Definition lock.h:64
HotStandbyState standbyState
Definition xlogutils.c:53
@ STANDBY_INITIALIZED
Definition xlogutils.h:53

References Assert, fb(), GetNextLocalTransactionId(), HASH_BLOBS, hash_create(), HASH_ELEM, VirtualTransactionId::localTransactionId, MyProc, MyProcNumber, VirtualTransactionId::procNumber, PGPROC::procNumber, RecoveryLockHash, RecoveryLockXidHash, SharedInvalBackendInit(), STANDBY_INITIALIZED, standbyState, VirtualXactLockTableInsert(), and PGPROC::vxid.

Referenced by StartupXLOG().

◆ LogAccessExclusiveLock()

void LogAccessExclusiveLock ( Oid  dbOid,
Oid  relOid 
)
extern

Definition at line 1454 of file standby.c.

1455{
1457
1459
1460 xlrec.dbOid = dbOid;
1461 xlrec.relOid = relOid;
1462
1465}
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition standby.c:1436
TransactionId xid
Definition lockdefs.h:53
TransactionId GetCurrentTransactionId(void)
Definition xact.c:456
int MyXactFlags
Definition xact.c:138
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK
Definition xact.h:109

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

Referenced by LockAcquireExtended().

◆ LogAccessExclusiveLockPrepare()

void LogAccessExclusiveLockPrepare ( void  )
extern

Definition at line 1471 of file standby.c.

1472{
1473 /*
1474 * Ensure that a TransactionId has been assigned to this transaction, for
1475 * two reasons, both related to lock release on the standby. First, we
1476 * must assign an xid so that RecordTransactionCommit() and
1477 * RecordTransactionAbort() do not optimise away the transaction
1478 * completion record which recovery relies upon to release locks. It's a
1479 * hack, but for a corner case not worth adding code for into the main
1480 * commit path. Second, we must assign an xid before the lock is recorded
1481 * in shared memory, otherwise a concurrently executing
1482 * GetRunningTransactionLocks() might see a lock associated with an
1483 * InvalidTransactionId which we later assert cannot happen.
1484 */
1486}

References fb(), and GetCurrentTransactionId().

Referenced by LockAcquireExtended().

◆ LogRecoveryConflict()

void LogRecoveryConflict ( RecoveryConflictReason  reason,
TimestampTz  wait_start,
TimestampTz  now,
VirtualTransactionId wait_list,
bool  still_waiting 
)
extern

Definition at line 275 of file standby.c.

278{
279 long secs;
280 int usecs;
281 long msecs;
283 int nprocs = 0;
284
285 /*
286 * There must be no conflicting processes when the recovery conflict has
287 * already been resolved.
288 */
290
292 msecs = secs * 1000 + usecs / 1000;
293 usecs = usecs % 1000;
294
295 if (wait_list)
296 {
298
299 /* Construct a string of list of the conflicting processes */
302 {
303 PGPROC *proc = ProcNumberGetProc(vxids->procNumber);
304
305 /* proc can be NULL if the target backend is not active */
306 if (proc)
307 {
308 if (nprocs == 0)
309 {
311 appendStringInfo(&buf, "%d", proc->pid);
312 }
313 else
314 appendStringInfo(&buf, ", %d", proc->pid);
315
316 nprocs++;
317 }
318
319 vxids++;
320 }
321 }
322
323 /*
324 * If wait_list is specified, report the list of PIDs of active
325 * conflicting backends in a detail message. Note that if all the backends
326 * in the list are not active, no detail message is logged.
327 */
328 if (still_waiting)
329 {
330 ereport(LOG,
331 errmsg("recovery still waiting after %ld.%03d ms: %s",
333 nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.",
334 "Conflicting processes: %s.",
335 nprocs, buf.data) : 0);
336 }
337 else
338 {
339 ereport(LOG,
340 errmsg("recovery finished waiting after %ld.%03d ms: %s",
342 }
343
344 if (nprocs > 0)
345 pfree(buf.data);
346}
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition timestamp.c:1715
Datum now(PG_FUNCTION_ARGS)
Definition timestamp.c:1603
#define LOG
Definition elog.h:31
int int int int errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
#define VirtualTransactionIdIsValid(vxid)
Definition lock.h:70
void pfree(void *pointer)
Definition mcxt.c:1616
static char buf[DEFAULT_XLOG_SEG_SIZE]
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition procarray.c:3111
static const char * get_recovery_conflict_desc(RecoveryConflictReason reason)
Definition standby.c:1515
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Definition proc.h:179
int pid
Definition proc.h:197

References appendStringInfo(), Assert, buf, ereport, errdetail_log_plural(), errmsg, fb(), get_recovery_conflict_desc(), initStringInfo(), LOG, now(), pfree(), PGPROC::pid, ProcNumberGetProc(), TimestampDifference(), and VirtualTransactionIdIsValid.

Referenced by LockBufferForCleanup(), ProcSleep(), and ResolveRecoveryConflictWithVirtualXIDs().

◆ LogStandbyInvalidations()

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

Definition at line 1493 of file standby.c.

1495{
1497
1498 /* prepare record */
1499 memset(&xlrec, 0, sizeof(xlrec));
1500 xlrec.dbId = MyDatabaseId;
1502 xlrec.relcacheInitFileInval = relcacheInitFileInval;
1503 xlrec.nmsgs = nmsgs;
1504
1505 /* perform insertion */
1508 XLogRegisterData(msgs,
1509 nmsgs * sizeof(SharedInvalidationMessage));
1511}
Oid MyDatabaseTableSpace
Definition globals.c:98
Oid MyDatabaseId
Definition globals.c:96
#define XLOG_INVALIDATIONS
Definition standbydefs.h:36
#define MinSizeOfInvalidations
Definition standbydefs.h:73
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:482
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:372
void XLogBeginInsert(void)
Definition xloginsert.c:153

References fb(), MinSizeOfInvalidations, MyDatabaseId, MyDatabaseTableSpace, XLOG_INVALIDATIONS, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

Referenced by RecordTransactionCommit().

◆ LogStandbySnapshot()

XLogRecPtr LogStandbySnapshot ( Oid  dbid)
extern

Definition at line 1303 of file standby.c.

1304{
1306 RunningTransactions running;
1307 xl_standby_lock *locks;
1308 int nlocks;
1309 bool logical_decoding_enabled = IsLogicalDecodingEnabled();
1310
1312
1313#ifdef USE_INJECTION_POINTS
1314 if (IS_INJECTION_POINT_ATTACHED("skip-log-running-xacts"))
1315 {
1316 /*
1317 * This record could move slot's xmin forward during decoding, leading
1318 * to unpredictable results, so skip it when requested by the test.
1319 */
1320 return GetInsertRecPtr();
1321 }
1322#endif
1323
1324 /*
1325 * Get details of any AccessExclusiveLocks being held at the moment.
1326 */
1327 locks = GetRunningTransactionLocks(&nlocks);
1328 if (nlocks > 0)
1329 LogAccessExclusiveLocks(nlocks, locks);
1330 pfree(locks);
1331
1332 /*
1333 * Log details of all in-progress transactions. This should be the last
1334 * record we write, because standby will open up when it sees this.
1335 */
1336 running = GetRunningTransactionData(dbid);
1337
1338 /*
1339 * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
1340 * For Hot Standby this can be done before inserting the WAL record
1341 * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
1342 * the clog. For logical decoding, though, the lock can't be released
1343 * early because the clog might be "in the future" from the POV of the
1344 * historic snapshot. This would allow for situations where we're waiting
1345 * for the end of a transaction listed in the xl_running_xacts record
1346 * which, according to the WAL, has committed before the xl_running_xacts
1347 * record. Fortunately this routine isn't executed frequently, and it's
1348 * only a shared lock.
1349 */
1350 if (!logical_decoding_enabled)
1352
1353 recptr = LogCurrentRunningXacts(running);
1354
1355 /* Release lock if we kept it longer ... */
1356 if (logical_decoding_enabled)
1358
1359 /* GetRunningTransactionData() acquired XidGenLock, we must release it */
1361
1362 return recptr;
1363}
#define IS_INJECTION_POINT_ATTACHED(name)
xl_standby_lock * GetRunningTransactionLocks(int *nlocks)
Definition lock.c:4154
bool IsLogicalDecodingEnabled(void)
Definition logicalctl.c:202
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
RunningTransactions GetRunningTransactionData(Oid dbid)
Definition procarray.c:2630
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
Definition standby.c:1375
XLogRecPtr GetInsertRecPtr(void)
Definition xlog.c:6978
#define XLogStandbyInfoActive()
Definition xlog.h:126
uint64 XLogRecPtr
Definition xlogdefs.h:21

References Assert, fb(), GetInsertRecPtr(), GetRunningTransactionData(), GetRunningTransactionLocks(), IS_INJECTION_POINT_ATTACHED, IsLogicalDecodingEnabled(), LogAccessExclusiveLocks(), LogCurrentRunningXacts(), LWLockRelease(), pfree(), and XLogStandbyInfoActive.

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

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )
extern

Definition at line 795 of file standby.c.

796{
798
800
802
803 if (GetCurrentTimestamp() >= ltime && ltime != 0)
804 {
805 /*
806 * We're already behind, so clear a path as quickly as possible.
807 */
809 }
810 else
811 {
812 /*
813 * Wake up at ltime, and check for deadlocks as well if we will be
814 * waiting longer than deadlock_timeout
815 */
817 int cnt = 0;
818
819 if (ltime != 0)
820 {
822 timeouts[cnt].type = TMPARAM_AT;
823 timeouts[cnt].fin_time = ltime;
824 cnt++;
825 }
826
829 timeouts[cnt].type = TMPARAM_AFTER;
830 timeouts[cnt].delay_ms = DeadlockTimeout;
831 cnt++;
832
834 }
835
836 /*
837 * Wait to be signaled by UnpinBuffer() or for the wait to be interrupted
838 * by one of the timeouts established above.
839 *
840 * We assume that only UnpinBuffer() and the timeout requests established
841 * above can wake us up here. WakeupRecovery() called by walreceiver or
842 * SIGHUP signal handler, etc cannot do that because it uses the different
843 * latch from that ProcWaitForSignal() waits on.
844 */
846
850 {
851 /*
852 * Send out a request for hot-standby backends to check themselves for
853 * deadlocks.
854 *
855 * XXX The subsequent ResolveRecoveryConflictWithBufferPin() will wait
856 * to be signaled by UnpinBuffer() again and send a request for
857 * deadlocks check if deadlock_timeout happens. This causes the
858 * request to continue to be sent every deadlock_timeout until the
859 * buffer is unpinned or ltime is reached. This would increase the
860 * workload in the startup process and backends. In practice it may
861 * not be so harmful because the period that the buffer is kept pinned
862 * is basically no so long. But we should fix this?
863 */
865 }
866
867 /*
868 * Clear any timeout requests established above. We assume here that the
869 * Startup process doesn't have any other timeouts than what this function
870 * uses. If that stops being true, we could cancel the timeouts
871 * individually, but that'd be slower.
872 */
876}
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1639
int64 TimestampTz
Definition timestamp.h:39
int DeadlockTimeout
Definition proc.c:62
void ProcWaitForSignal(uint32 wait_event_info)
Definition proc.c:2015
static volatile sig_atomic_t got_standby_deadlock_timeout
Definition standby.c:70
static TimestampTz GetStandbyLimitTime(void)
Definition standby.c:202
static volatile sig_atomic_t got_standby_delay_timeout
Definition standby.c:71
static void SendRecoveryConflictWithBufferPin(RecoveryConflictReason reason)
Definition standby.c:879
void disable_all_timeouts(bool keep_indicators)
Definition timeout.c:751
void enable_timeouts(const EnableTimeoutParams *timeouts, int count)
Definition timeout.c:630
@ STANDBY_DEADLOCK_TIMEOUT
Definition timeout.h:30
@ STANDBY_TIMEOUT
Definition timeout.h:31
@ TMPARAM_AT
Definition timeout.h:54
@ TMPARAM_AFTER
Definition timeout.h:53
#define InHotStandby
Definition xlogutils.h:60

References Assert, DeadlockTimeout, disable_all_timeouts(), enable_timeouts(), fb(), GetCurrentTimestamp(), GetStandbyLimitTime(), got_standby_deadlock_timeout, got_standby_delay_timeout, EnableTimeoutParams::id, InHotStandby, ProcWaitForSignal(), RECOVERY_CONFLICT_BUFFERPIN, RECOVERY_CONFLICT_BUFFERPIN_DEADLOCK, SendRecoveryConflictWithBufferPin(), STANDBY_DEADLOCK_TIMEOUT, STANDBY_TIMEOUT, TMPARAM_AFTER, and TMPARAM_AT.

Referenced by LockBufferForCleanup().

◆ ResolveRecoveryConflictWithDatabase()

void ResolveRecoveryConflictWithDatabase ( Oid  dbid)
extern

Definition at line 572 of file standby.c.

573{
574 /*
575 * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that
576 * only waits for transactions and completely idle sessions would block
577 * us. This is rare enough that we do this as simply as possible: no wait,
578 * just force them off immediately.
579 *
580 * No locking is required here because we already acquired
581 * AccessExclusiveLock. Anybody trying to connect while we do this will
582 * block during InitPostgres() and then disconnect when they see the
583 * database has been removed.
584 */
585 while (CountDBBackends(dbid) > 0)
586 {
588
589 /*
590 * Wait awhile for them to die so that we avoid flooding an
591 * unresponsive backend when system is heavily loaded.
592 */
593 pg_usleep(10000);
594 }
595}
void SignalRecoveryConflictWithDatabase(Oid databaseid, RecoveryConflictReason reason)
Definition procarray.c:3542
int CountDBBackends(Oid databaseid)
Definition procarray.c:3642
void pg_usleep(long microsec)
Definition signal.c:53

References CountDBBackends(), pg_usleep(), RECOVERY_CONFLICT_DATABASE, and SignalRecoveryConflictWithDatabase().

Referenced by dbase_redo().

◆ ResolveRecoveryConflictWithLock()

void ResolveRecoveryConflictWithLock ( LOCKTAG  locktag,
bool  logging_conflict 
)
extern

Definition at line 626 of file standby.c.

627{
630
632
635
636 /*
637 * Update waitStart if first time through after the startup process
638 * started waiting for the lock. It should not be updated every time
639 * ResolveRecoveryConflictWithLock() is called during the wait.
640 *
641 * Use the current time obtained for comparison with ltime as waitStart
642 * (i.e., the time when this process started waiting for the lock). Since
643 * getting the current time newly can cause overhead, we reuse the
644 * already-obtained time to avoid that overhead.
645 *
646 * Note that waitStart is updated without holding the lock table's
647 * partition lock, to avoid the overhead by additional lock acquisition.
648 * This can cause "waitstart" in pg_locks to become NULL for a very short
649 * period of time after the wait started even though "granted" is false.
650 * This is OK in practice because we can assume that users are likely to
651 * look at "waitstart" when waiting for the lock for a long time.
652 */
655
656 if (now >= ltime && ltime != 0)
657 {
658 /*
659 * We're already behind, so clear a path as quickly as possible.
660 */
662
664
665 /*
666 * Prevent ResolveRecoveryConflictWithVirtualXIDs() from reporting
667 * "waiting" in PS display by disabling its argument report_waiting
668 * because the caller, WaitOnLock(), has already reported that.
669 */
672 PG_WAIT_LOCK | locktag.locktag_type,
673 false);
674 }
675 else
676 {
677 /*
678 * Wait (or wait again) until ltime, and check for deadlocks as well
679 * if we will be waiting longer than deadlock_timeout
680 */
682 int cnt = 0;
683
684 if (ltime != 0)
685 {
688 timeouts[cnt].type = TMPARAM_AT;
689 timeouts[cnt].fin_time = ltime;
690 cnt++;
691 }
692
695 timeouts[cnt].type = TMPARAM_AFTER;
696 timeouts[cnt].delay_ms = DeadlockTimeout;
697 cnt++;
698
700 }
701
702 /* Wait to be signaled by the release of the Relation Lock */
704
705 /*
706 * Exit if ltime is reached. Then all the backends holding conflicting
707 * locks will be canceled in the next ResolveRecoveryConflictWithLock()
708 * call.
709 */
711 goto cleanup;
712
714 {
716
718
719 /* Quick exit if there's no work to be done */
721 goto cleanup;
722
723 /*
724 * Send signals to all the backends holding the conflicting locks, to
725 * ask them to check themselves for deadlocks.
726 */
728 {
731 backends++;
732 }
733
734 /*
735 * Exit if the recovery conflict has not been logged yet even though
736 * logging is enabled, so that the caller can log that. Then
737 * RecoveryConflictWithLock() is called again and we will wait again
738 * for the lock to be released.
739 */
741 goto cleanup;
742
743 /*
744 * Wait again here to be signaled by the release of the Relation Lock,
745 * to prevent the subsequent RecoveryConflictWithLock() from causing
746 * deadlock_timeout and sending a request for deadlocks check again.
747 * Otherwise the request continues to be sent every deadlock_timeout
748 * until the relation locks are released or ltime is reached.
749 */
752 }
753
754cleanup:
755
756 /*
757 * Clear any timeout requests established above. We assume here that the
758 * Startup process doesn't have any other outstanding timeouts than those
759 * used by this function. If that stops being true, we could cancel the
760 * timeouts individually, but that'd be slower.
761 */
765}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:485
static uint64 pg_atomic_read_u64(volatile pg_atomic_uint64 *ptr)
Definition atomics.h:467
static void cleanup(void)
Definition bootstrap.c:886
VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
Definition lock.c:3078
#define AccessExclusiveLock
Definition lockdefs.h:43
bool SignalRecoveryConflictWithVirtualXID(VirtualTransactionId vxid, RecoveryConflictReason reason)
Definition procarray.c:3497
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, RecoveryConflictReason reason, uint32 wait_event_info, bool report_waiting)
Definition standby.c:361
static volatile sig_atomic_t got_standby_lock_timeout
Definition standby.c:72
uint8 locktag_type
Definition locktag.h:70
pg_atomic_uint64 waitStart
Definition proc.h:311
@ STANDBY_LOCK_TIMEOUT
Definition timeout.h:32
#define PG_WAIT_LOCK

References AccessExclusiveLock, Assert, cleanup(), DeadlockTimeout, disable_all_timeouts(), enable_timeouts(), fb(), GetCurrentTimestamp(), GetLockConflicts(), GetStandbyLimitTime(), got_standby_deadlock_timeout, got_standby_lock_timeout, EnableTimeoutParams::id, InHotStandby, LOCKTAG::locktag_type, MyProc, now(), pg_atomic_read_u64(), pg_atomic_write_u64(), PG_WAIT_LOCK, ProcWaitForSignal(), RECOVERY_CONFLICT_LOCK, RECOVERY_CONFLICT_STARTUP_DEADLOCK, ResolveRecoveryConflictWithVirtualXIDs(), SignalRecoveryConflictWithVirtualXID(), STANDBY_DEADLOCK_TIMEOUT, STANDBY_LOCK_TIMEOUT, TMPARAM_AFTER, TMPARAM_AT, VirtualTransactionIdIsValid, and PGPROC::waitStart.

Referenced by ProcSleep().

◆ ResolveRecoveryConflictWithSnapshot()

void ResolveRecoveryConflictWithSnapshot ( TransactionId  snapshotConflictHorizon,
bool  isCatalogRel,
RelFileLocator  locator 
)
extern

Definition at line 470 of file standby.c.

473{
475
476 /*
477 * If we get passed InvalidTransactionId then we do nothing (no conflict).
478 *
479 * This can happen whenever the changes in the WAL record do not affect
480 * visibility on a standby. For example: a record that only freezes an
481 * xmax from a locker.
482 *
483 * It's also quite common with records generated during index deletion
484 * (original execution of the deletion can reason that a recovery conflict
485 * which is sufficient for the deletion operation must take place before
486 * replay of the deletion record itself).
487 */
488 if (!TransactionIdIsValid(snapshotConflictHorizon))
489 return;
490
491 Assert(TransactionIdIsNormal(snapshotConflictHorizon));
492 backends = GetConflictingVirtualXIDs(snapshotConflictHorizon,
493 locator.dbOid);
497 true);
498
499 /*
500 * Note that WaitExceedsMaxStandbyDelay() is not taken into account here
501 * (as opposed to ResolveRecoveryConflictWithVirtualXIDs() above). That
502 * seems OK, given that this kind of conflict should not normally be
503 * reached, e.g. due to using a physical replication slot.
504 */
505 if (IsLogicalDecodingEnabled() && isCatalogRel)
507 snapshotConflictHorizon);
508}
VirtualTransactionId * GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
Definition procarray.c:3389
bool InvalidateObsoleteReplicationSlots(uint32 possible_causes, XLogSegNo oldestSegno, Oid dboid, TransactionId snapshotConflictHorizon)
Definition slot.c:2220
@ RS_INVAL_HORIZON
Definition slot.h:64
#define TransactionIdIsValid(xid)
Definition transam.h:41
#define TransactionIdIsNormal(xid)
Definition transam.h:42

References Assert, RelFileLocator::dbOid, fb(), GetConflictingVirtualXIDs(), InvalidateObsoleteReplicationSlots(), IsLogicalDecodingEnabled(), RECOVERY_CONFLICT_SNAPSHOT, ResolveRecoveryConflictWithVirtualXIDs(), RS_INVAL_HORIZON, TransactionIdIsNormal, and TransactionIdIsValid.

Referenced by btree_xlog_delete(), gistRedoDeleteRecord(), hash_xlog_vacuum_one_page(), heap_xlog_prune_freeze(), ResolveRecoveryConflictWithSnapshotFullXid(), and spgRedoVacuumRedirect().

◆ ResolveRecoveryConflictWithSnapshotFullXid()

void ResolveRecoveryConflictWithSnapshotFullXid ( FullTransactionId  snapshotConflictHorizon,
bool  isCatalogRel,
RelFileLocator  locator 
)
extern

Definition at line 515 of file standby.c.

518{
519 /*
520 * ResolveRecoveryConflictWithSnapshot operates on 32-bit TransactionIds,
521 * so truncate the logged FullTransactionId. If the logged value is very
522 * old, so that XID wrap-around already happened on it, there can't be any
523 * snapshots that still see it.
524 */
526 uint64 diff;
527
528 diff = U64FromFullTransactionId(nextXid) -
529 U64FromFullTransactionId(snapshotConflictHorizon);
530 if (diff < MaxTransactionId / 2)
531 {
532 TransactionId truncated;
533
534 truncated = XidFromFullTransactionId(snapshotConflictHorizon);
536 isCatalogRel,
537 locator);
538 }
539}
uint64_t uint64
Definition c.h:625
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition standby.c:470
#define U64FromFullTransactionId(x)
Definition transam.h:49
#define XidFromFullTransactionId(x)
Definition transam.h:48
#define MaxTransactionId
Definition transam.h:35
FullTransactionId ReadNextFullTransactionId(void)
Definition varsup.c:283

References fb(), MaxTransactionId, ReadNextFullTransactionId(), ResolveRecoveryConflictWithSnapshot(), U64FromFullTransactionId, and XidFromFullTransactionId.

Referenced by btree_xlog_reuse_page(), and gistRedoPageReuse().

◆ ResolveRecoveryConflictWithTablespace()

void ResolveRecoveryConflictWithTablespace ( Oid  tsid)
extern

Definition at line 542 of file standby.c.

543{
545
546 /*
547 * Standby users may be currently using this tablespace for their
548 * temporary files. We only care about current users because
549 * temp_tablespace parameter will just ignore tablespaces that no longer
550 * exist.
551 *
552 * Ask everybody to cancel their queries immediately so we can ensure no
553 * temp files remain and we can remove the tablespace. Nuke the entire
554 * site from orbit, it's the only way to be sure.
555 *
556 * XXX: We could work out the pids of active backends using this
557 * tablespace by examining the temp filenames in the directory. We would
558 * then convert the pids into VirtualXIDs before attempting to cancel
559 * them.
560 *
561 * We don't wait for commit because drop tablespace is non-transactional.
562 */
564 InvalidOid);
568 true);
569}
#define InvalidOid
#define InvalidTransactionId
Definition transam.h:31

References fb(), GetConflictingVirtualXIDs(), InvalidOid, InvalidTransactionId, RECOVERY_CONFLICT_TABLESPACE, and ResolveRecoveryConflictWithVirtualXIDs().

Referenced by tblspc_redo().

◆ ShutdownRecoveryTransactionEnvironment()

void ShutdownRecoveryTransactionEnvironment ( void  )
extern

Definition at line 162 of file standby.c.

163{
164 /*
165 * Do nothing if RecoveryLockHash is NULL because that means that
166 * transaction tracking has not yet been initialized or has already been
167 * shut down. This makes it safe to have possibly-redundant calls of this
168 * function during process exit.
169 */
170 if (RecoveryLockHash == NULL)
171 return;
172
173 /* Mark all tracked in-progress transactions as finished. */
175
176 /* Release all locks the tracked transactions were holding */
178
179 /* Destroy the lock hash tables. */
184
185 /* Cleanup our VirtualTransaction */
187}
void hash_destroy(HTAB *hashp)
Definition dynahash.c:802
void VirtualXactLockTableCleanup(void)
Definition lock.c:4626
void ExpireAllKnownAssignedTransactionIds(void)
Definition procarray.c:4551
void StandbyReleaseAllLocks(void)
Definition standby.c:1108

References ExpireAllKnownAssignedTransactionIds(), fb(), hash_destroy(), RecoveryLockHash, RecoveryLockXidHash, StandbyReleaseAllLocks(), and VirtualXactLockTableCleanup().

Referenced by StartupProcExit(), and StartupXLOG().

◆ StandbyAcquireAccessExclusiveLock()

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

Definition at line 988 of file standby.c.

989{
993 LOCKTAG locktag;
994 bool found;
995
996 /* Already processed? */
997 if (!TransactionIdIsValid(xid) ||
1000 return;
1001
1002 elog(DEBUG4, "adding recovery lock: db %u rel %u", dbOid, relOid);
1003
1004 /* dbOid is InvalidOid when we are locking a shared relation. */
1005 Assert(OidIsValid(relOid));
1006
1007 /* Create a hash entry for this xid, if we don't have one already. */
1009 if (!found)
1010 {
1011 Assert(xidentry->xid == xid); /* dynahash should have set this */
1012 xidentry->head = NULL;
1013 }
1014
1015 /* Create a hash entry for this lock, unless we have one already. */
1016 key.xid = xid;
1017 key.dbOid = dbOid;
1018 key.relOid = relOid;
1020 if (!found)
1021 {
1022 /* It's new, so link it into the XID's list ... */
1023 lockentry->next = xidentry->head;
1024 xidentry->head = lockentry;
1025
1026 /* ... and acquire the lock locally. */
1027 SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
1028
1029 (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
1030 }
1031}
#define OidIsValid(objectId)
Definition c.h:858
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:889
#define elog(elevel,...)
Definition elog.h:227
#define DEBUG4
Definition elog.h:27
@ HASH_ENTER
Definition hsearch.h:109
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition lock.c:807
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition locktag.h:81
bool TransactionIdDidCommit(TransactionId transactionId)
Definition transam.c:126
bool TransactionIdDidAbort(TransactionId transactionId)
Definition transam.c:188

References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, fb(), HASH_ENTER, hash_search(), RecoveryLockEntry::key, LockAcquire(), OidIsValid, RecoveryLockHash, RecoveryLockXidHash, xl_standby_lock::relOid, SET_LOCKTAG_RELATION, TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsValid, and xl_standby_lock::xid.

Referenced by lock_twophase_standby_recover(), and standby_redo().

◆ StandbyDeadLockHandler()

void StandbyDeadLockHandler ( void  )
extern

Definition at line 938 of file standby.c.

939{
941}

References got_standby_deadlock_timeout.

Referenced by StartupProcessMain().

◆ StandbyLockTimeoutHandler()

void StandbyLockTimeoutHandler ( void  )
extern

Definition at line 956 of file standby.c.

957{
959}

References got_standby_lock_timeout.

Referenced by StartupProcessMain().

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )
extern

Definition at line 1108 of file standby.c.

1109{
1110 HASH_SEQ_STATUS status;
1111 RecoveryLockXidEntry *entry;
1112
1113 elog(DEBUG2, "release all standby locks");
1114
1116 while ((entry = hash_seq_search(&status)))
1117 {
1120 }
1121}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1352
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1317
#define DEBUG2
Definition elog.h:29
@ HASH_REMOVE
Definition hsearch.h:110
static void StandbyReleaseXidEntryLocks(RecoveryLockXidEntry *xidentry)
Definition standby.c:1037

References DEBUG2, elog, fb(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), RecoveryLockXidHash, and StandbyReleaseXidEntryLocks().

Referenced by ShutdownRecoveryTransactionEnvironment(), and StandbyReleaseLocks().

◆ StandbyReleaseLockTree()

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

Definition at line 1094 of file standby.c.

1095{
1096 int i;
1097
1099
1100 for (i = 0; i < nsubxids; i++)
1101 StandbyReleaseLocks(subxids[i]);
1102}
int i
Definition isn.c:77
static void StandbyReleaseLocks(TransactionId xid)
Definition standby.c:1070

References fb(), i, and StandbyReleaseLocks().

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

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)
extern

Definition at line 1132 of file standby.c.

1133{
1134 HASH_SEQ_STATUS status;
1135 RecoveryLockXidEntry *entry;
1136
1138 while ((entry = hash_seq_search(&status)))
1139 {
1141
1142 /* Skip if prepared transaction. */
1144 continue;
1145
1146 /* Skip if >= oldxid. */
1147 if (!TransactionIdPrecedes(entry->xid, oldxid))
1148 continue;
1149
1150 /* Remove all locks and hash table entry. */
1153 }
1154}
TransactionId xid
Definition standby.c:62
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition twophase.c:1473

References Assert, fb(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), RecoveryLockXidHash, StandbyReleaseXidEntryLocks(), StandbyTransactionIdIsPrepared(), TransactionIdIsValid, TransactionIdPrecedes(), and RecoveryLockXidEntry::xid.

Referenced by ProcArrayApplyRecoveryInfo().

◆ StandbyTimeoutHandler()

void StandbyTimeoutHandler ( void  )
extern

Definition at line 947 of file standby.c.

948{
950}

References got_standby_delay_timeout.

Referenced by StartupProcessMain().

Variable Documentation

◆ log_recovery_conflict_waits

PGDLLIMPORT bool log_recovery_conflict_waits
extern

◆ max_standby_archive_delay

PGDLLIMPORT int max_standby_archive_delay
extern

Definition at line 41 of file standby.c.

Referenced by GetStandbyLimitTime().

◆ max_standby_streaming_delay

PGDLLIMPORT int max_standby_streaming_delay
extern

Definition at line 42 of file standby.c.

Referenced by GetStandbyLimitTime().