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 MinSizeOfXactRunningXacts   offsetof(xl_running_xacts, xids)
 

Typedefs

typedef struct RunningTransactionsData RunningTransactionsData
 
typedef RunningTransactionsDataRunningTransactions
 

Enumerations

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 (ProcSignalReason 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 (void)
 
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 63 of file standby.h.

Typedef Documentation

◆ RunningTransactions

◆ RunningTransactionsData

Enumeration Type Documentation

◆ subxids_array_status

Enumerator
SUBXIDS_IN_ARRAY 
SUBXIDS_MISSING 
SUBXIDS_IN_SUBTRANS 

Definition at line 78 of file standby.h.

79{
80 SUBXIDS_IN_ARRAY, /* xids array includes all running subxids */
81 SUBXIDS_MISSING, /* snapshot overflowed, subxids are missing */
82 SUBXIDS_IN_SUBTRANS, /* subxids are not included in 'xids', but
83 * pg_subtrans is fully up-to-date */
subxids_array_status
Definition standby.h:79
@ SUBXIDS_IN_SUBTRANS
Definition standby.h:82
@ SUBXIDS_MISSING
Definition standby.h:81
@ SUBXIDS_IN_ARRAY
Definition standby.h:80

Function Documentation

◆ CheckRecoveryConflictDeadlock()

void CheckRecoveryConflictDeadlock ( void  )
extern

Definition at line 905 of file standby.c.

906{
907 Assert(!InRecovery); /* do not call in Startup process */
908
910 return;
911
912 /*
913 * Error message should match ProcessInterrupts() but we avoid calling
914 * that because we aren't handling an interrupt at this point. Note that
915 * we only cancel the current transaction here, so if we are in a
916 * subtransaction and the pin is held by a parent, then the Startup
917 * process will continue to wait even though we have avoided deadlock.
918 */
921 errmsg("canceling statement due to conflict with recovery"),
922 errdetail("User transaction caused buffer deadlock with recovery.")));
923}
bool HoldingBufferPinThatDelaysRecovery(void)
Definition bufmgr.c:6664
#define Assert(condition)
Definition c.h:873
int errdetail(const char *fmt,...)
Definition elog.c:1216
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#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 95 of file standby.c.

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

1433{
1435
1437
1438 xlrec.dbOid = dbOid;
1439 xlrec.relOid = relOid;
1440
1443}
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition standby.c:1414
TransactionId xid
Definition lockdefs.h:53
TransactionId GetCurrentTransactionId(void)
Definition xact.c:455
int MyXactFlags
Definition xact.c:137
#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 1449 of file standby.c.

1450{
1451 /*
1452 * Ensure that a TransactionId has been assigned to this transaction, for
1453 * two reasons, both related to lock release on the standby. First, we
1454 * must assign an xid so that RecordTransactionCommit() and
1455 * RecordTransactionAbort() do not optimise away the transaction
1456 * completion record which recovery relies upon to release locks. It's a
1457 * hack, but for a corner case not worth adding code for into the main
1458 * commit path. Second, we must assign an xid before the lock is recorded
1459 * in shared memory, otherwise a concurrently executing
1460 * GetRunningTransactionLocks() might see a lock associated with an
1461 * InvalidTransactionId which we later assert cannot happen.
1462 */
1464}

References fb(), and GetCurrentTransactionId().

Referenced by LockAcquireExtended().

◆ LogRecoveryConflict()

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

Definition at line 274 of file standby.c.

277{
278 long secs;
279 int usecs;
280 long msecs;
282 int nprocs = 0;
283
284 /*
285 * There must be no conflicting processes when the recovery conflict has
286 * already been resolved.
287 */
289
291 msecs = secs * 1000 + usecs / 1000;
292 usecs = usecs % 1000;
293
294 if (wait_list)
295 {
297
298 /* Construct a string of list of the conflicting processes */
301 {
302 PGPROC *proc = ProcNumberGetProc(vxids->procNumber);
303
304 /* proc can be NULL if the target backend is not active */
305 if (proc)
306 {
307 if (nprocs == 0)
308 {
310 appendStringInfo(&buf, "%d", proc->pid);
311 }
312 else
313 appendStringInfo(&buf, ", %d", proc->pid);
314
315 nprocs++;
316 }
317
318 vxids++;
319 }
320 }
321
322 /*
323 * If wait_list is specified, report the list of PIDs of active
324 * conflicting backends in a detail message. Note that if all the backends
325 * in the list are not active, no detail message is logged.
326 */
327 if (still_waiting)
328 {
329 ereport(LOG,
330 errmsg("recovery still waiting after %ld.%03d ms: %s",
332 nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.",
333 "Conflicting processes: %s.",
334 nprocs, buf.data) : 0);
335 }
336 else
337 {
338 ereport(LOG,
339 errmsg("recovery finished waiting after %ld.%03d ms: %s",
341 }
342
343 if (nprocs > 0)
344 pfree(buf.data);
345}
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition timestamp.c:1721
Datum now(PG_FUNCTION_ARGS)
Definition timestamp.c:1609
int errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition elog.c:1285
#define LOG
Definition elog.h:31
#define VirtualTransactionIdIsValid(vxid)
Definition lock.h:69
void pfree(void *pointer)
Definition mcxt.c:1616
static char buf[DEFAULT_XLOG_SEG_SIZE]
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition procarray.c:3101
static const char * get_recovery_conflict_desc(ProcSignalReason reason)
Definition standby.c:1493
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:199

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

1473{
1475
1476 /* prepare record */
1477 memset(&xlrec, 0, sizeof(xlrec));
1478 xlrec.dbId = MyDatabaseId;
1480 xlrec.relcacheInitFileInval = relcacheInitFileInval;
1481 xlrec.nmsgs = nmsgs;
1482
1483 /* perform insertion */
1486 XLogRegisterData(msgs,
1487 nmsgs * sizeof(SharedInvalidationMessage));
1489}
Oid MyDatabaseTableSpace
Definition globals.c:96
Oid MyDatabaseId
Definition globals.c:94
#define XLOG_INVALIDATIONS
Definition standbydefs.h:36
#define MinSizeOfInvalidations
Definition standbydefs.h:72
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:478
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:368
void XLogBeginInsert(void)
Definition xloginsert.c:152

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

Referenced by RecordTransactionCommit().

◆ LogStandbySnapshot()

XLogRecPtr LogStandbySnapshot ( void  )
extern

Definition at line 1282 of file standby.c.

1283{
1285 RunningTransactions running;
1286 xl_standby_lock *locks;
1287 int nlocks;
1288 bool logical_decoding_enabled = IsLogicalDecodingEnabled();
1289
1291
1292#ifdef USE_INJECTION_POINTS
1293 if (IS_INJECTION_POINT_ATTACHED("skip-log-running-xacts"))
1294 {
1295 /*
1296 * This record could move slot's xmin forward during decoding, leading
1297 * to unpredictable results, so skip it when requested by the test.
1298 */
1299 return GetInsertRecPtr();
1300 }
1301#endif
1302
1303 /*
1304 * Get details of any AccessExclusiveLocks being held at the moment.
1305 */
1306 locks = GetRunningTransactionLocks(&nlocks);
1307 if (nlocks > 0)
1308 LogAccessExclusiveLocks(nlocks, locks);
1309 pfree(locks);
1310
1311 /*
1312 * Log details of all in-progress transactions. This should be the last
1313 * record we write, because standby will open up when it sees this.
1314 */
1315 running = GetRunningTransactionData();
1316
1317 /*
1318 * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
1319 * For Hot Standby this can be done before inserting the WAL record
1320 * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
1321 * the clog. For logical decoding, though, the lock can't be released
1322 * early because the clog might be "in the future" from the POV of the
1323 * historic snapshot. This would allow for situations where we're waiting
1324 * for the end of a transaction listed in the xl_running_xacts record
1325 * which, according to the WAL, has committed before the xl_running_xacts
1326 * record. Fortunately this routine isn't executed frequently, and it's
1327 * only a shared lock.
1328 */
1329 if (!logical_decoding_enabled)
1331
1332 recptr = LogCurrentRunningXacts(running);
1333
1334 /* Release lock if we kept it longer ... */
1335 if (logical_decoding_enabled)
1337
1338 /* GetRunningTransactionData() acquired XidGenLock, we must release it */
1340
1341 return recptr;
1342}
#define IS_INJECTION_POINT_ATTACHED(name)
xl_standby_lock * GetRunningTransactionLocks(int *nlocks)
Definition lock.c:4171
bool IsLogicalDecodingEnabled(void)
Definition logicalctl.c:204
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1793
RunningTransactions GetRunningTransactionData(void)
Definition procarray.c:2639
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
Definition standby.c:1354
XLogRecPtr GetInsertRecPtr(void)
Definition xlog.c:6608
#define XLogStandbyInfoActive()
Definition xlog.h:125
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(), and SnapBuildWaitSnapshot().

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )
extern

Definition at line 793 of file standby.c.

794{
796
798
800
801 if (GetCurrentTimestamp() >= ltime && ltime != 0)
802 {
803 /*
804 * We're already behind, so clear a path as quickly as possible.
805 */
807 }
808 else
809 {
810 /*
811 * Wake up at ltime, and check for deadlocks as well if we will be
812 * waiting longer than deadlock_timeout
813 */
815 int cnt = 0;
816
817 if (ltime != 0)
818 {
820 timeouts[cnt].type = TMPARAM_AT;
821 timeouts[cnt].fin_time = ltime;
822 cnt++;
823 }
824
827 timeouts[cnt].type = TMPARAM_AFTER;
828 timeouts[cnt].delay_ms = DeadlockTimeout;
829 cnt++;
830
832 }
833
834 /*
835 * Wait to be signaled by UnpinBuffer() or for the wait to be interrupted
836 * by one of the timeouts established above.
837 *
838 * We assume that only UnpinBuffer() and the timeout requests established
839 * above can wake us up here. WakeupRecovery() called by walreceiver or
840 * SIGHUP signal handler, etc cannot do that because it uses the different
841 * latch from that ProcWaitForSignal() waits on.
842 */
844
848 {
849 /*
850 * Send out a request for hot-standby backends to check themselves for
851 * deadlocks.
852 *
853 * XXX The subsequent ResolveRecoveryConflictWithBufferPin() will wait
854 * to be signaled by UnpinBuffer() again and send a request for
855 * deadlocks check if deadlock_timeout happens. This causes the
856 * request to continue to be sent every deadlock_timeout until the
857 * buffer is unpinned or ltime is reached. This would increase the
858 * workload in the startup process and backends. In practice it may
859 * not be so harmful because the period that the buffer is kept pinned
860 * is basically no so long. But we should fix this?
861 */
863 }
864
865 /*
866 * Clear any timeout requests established above. We assume here that the
867 * Startup process doesn't have any other timeouts than what this function
868 * uses. If that stops being true, we could cancel the timeouts
869 * individually, but that'd be slower.
870 */
874}
TimestampTz GetCurrentTimestamp(void)
Definition timestamp.c:1645
int64 TimestampTz
Definition timestamp.h:39
@ PROCSIG_RECOVERY_CONFLICT_BUFFERPIN
Definition procsignal.h:47
@ PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK
Definition procsignal.h:48
int DeadlockTimeout
Definition proc.c:58
void ProcWaitForSignal(uint32 wait_event_info)
Definition proc.c:1980
static volatile sig_atomic_t got_standby_deadlock_timeout
Definition standby.c:69
static TimestampTz GetStandbyLimitTime(void)
Definition standby.c:201
static volatile sig_atomic_t got_standby_delay_timeout
Definition standby.c:70
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition standby.c:877
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, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, ProcWaitForSignal(), SendRecoveryConflictWithBufferPin(), STANDBY_DEADLOCK_TIMEOUT, STANDBY_TIMEOUT, TMPARAM_AFTER, and TMPARAM_AT.

Referenced by LockBufferForCleanup().

◆ ResolveRecoveryConflictWithDatabase()

void ResolveRecoveryConflictWithDatabase ( Oid  dbid)
extern

Definition at line 569 of file standby.c.

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

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

Referenced by dbase_redo().

◆ ResolveRecoveryConflictWithLock()

void ResolveRecoveryConflictWithLock ( LOCKTAG  locktag,
bool  logging_conflict 
)
extern

Definition at line 623 of file standby.c.

624{
627
629
632
633 /*
634 * Update waitStart if first time through after the startup process
635 * started waiting for the lock. It should not be updated every time
636 * ResolveRecoveryConflictWithLock() is called during the wait.
637 *
638 * Use the current time obtained for comparison with ltime as waitStart
639 * (i.e., the time when this process started waiting for the lock). Since
640 * getting the current time newly can cause overhead, we reuse the
641 * already-obtained time to avoid that overhead.
642 *
643 * Note that waitStart is updated without holding the lock table's
644 * partition lock, to avoid the overhead by additional lock acquisition.
645 * This can cause "waitstart" in pg_locks to become NULL for a very short
646 * period of time after the wait started even though "granted" is false.
647 * This is OK in practice because we can assume that users are likely to
648 * look at "waitstart" when waiting for the lock for a long time.
649 */
652
653 if (now >= ltime && ltime != 0)
654 {
655 /*
656 * We're already behind, so clear a path as quickly as possible.
657 */
659
661
662 /*
663 * Prevent ResolveRecoveryConflictWithVirtualXIDs() from reporting
664 * "waiting" in PS display by disabling its argument report_waiting
665 * because the caller, WaitOnLock(), has already reported that.
666 */
669 PG_WAIT_LOCK | locktag.locktag_type,
670 false);
671 }
672 else
673 {
674 /*
675 * Wait (or wait again) until ltime, and check for deadlocks as well
676 * if we will be waiting longer than deadlock_timeout
677 */
679 int cnt = 0;
680
681 if (ltime != 0)
682 {
685 timeouts[cnt].type = TMPARAM_AT;
686 timeouts[cnt].fin_time = ltime;
687 cnt++;
688 }
689
692 timeouts[cnt].type = TMPARAM_AFTER;
693 timeouts[cnt].delay_ms = DeadlockTimeout;
694 cnt++;
695
697 }
698
699 /* Wait to be signaled by the release of the Relation Lock */
701
702 /*
703 * Exit if ltime is reached. Then all the backends holding conflicting
704 * locks will be canceled in the next ResolveRecoveryConflictWithLock()
705 * call.
706 */
708 goto cleanup;
709
711 {
713
715
716 /* Quick exit if there's no work to be done */
718 goto cleanup;
719
720 /*
721 * Send signals to all the backends holding the conflicting locks, to
722 * ask them to check themselves for deadlocks.
723 */
725 {
728 false);
729 backends++;
730 }
731
732 /*
733 * Exit if the recovery conflict has not been logged yet even though
734 * logging is enabled, so that the caller can log that. Then
735 * RecoveryConflictWithLock() is called again and we will wait again
736 * for the lock to be released.
737 */
739 goto cleanup;
740
741 /*
742 * Wait again here to be signaled by the release of the Relation Lock,
743 * to prevent the subsequent RecoveryConflictWithLock() from causing
744 * deadlock_timeout and sending a request for deadlocks check again.
745 * Otherwise the request continues to be sent every deadlock_timeout
746 * until the relation locks are released or ltime is reached.
747 */
750 }
751
752cleanup:
753
754 /*
755 * Clear any timeout requests established above. We assume here that the
756 * Startup process doesn't have any other outstanding timeouts than those
757 * used by this function. If that stops being true, we could cancel the
758 * timeouts individually, but that'd be slower.
759 */
763}
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:717
VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
Definition lock.c:3069
#define AccessExclusiveLock
Definition lockdefs.h:43
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition procarray.c:3459
@ PROCSIG_RECOVERY_CONFLICT_LOCK
Definition procsignal.h:44
static void ResolveRecoveryConflictWithVirtualXIDs(VirtualTransactionId *waitlist, ProcSignalReason reason, uint32 wait_event_info, bool report_waiting)
Definition standby.c:360
static volatile sig_atomic_t got_standby_lock_timeout
Definition standby.c:71
uint8 locktag_type
Definition lock.h:172
pg_atomic_uint64 waitStart
Definition proc.h:260
@ 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, PROCSIG_RECOVERY_CONFLICT_LOCK, PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, ProcWaitForSignal(), ResolveRecoveryConflictWithVirtualXIDs(), SignalVirtualTransaction(), 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 468 of file standby.c.

471{
473
474 /*
475 * If we get passed InvalidTransactionId then we do nothing (no conflict).
476 *
477 * This can happen when replaying already-applied WAL records after a
478 * standby crash or restart, or when replaying an XLOG_HEAP2_VISIBLE
479 * record that marks as frozen a page which was already all-visible. It's
480 * also quite common with records generated during index deletion
481 * (original execution of the deletion can reason that a recovery conflict
482 * which is sufficient for the deletion operation must take place before
483 * replay of the deletion record itself).
484 */
485 if (!TransactionIdIsValid(snapshotConflictHorizon))
486 return;
487
488 Assert(TransactionIdIsNormal(snapshotConflictHorizon));
489 backends = GetConflictingVirtualXIDs(snapshotConflictHorizon,
490 locator.dbOid);
494 true);
495
496 /*
497 * Note that WaitExceedsMaxStandbyDelay() is not taken into account here
498 * (as opposed to ResolveRecoveryConflictWithVirtualXIDs() above). That
499 * seems OK, given that this kind of conflict should not normally be
500 * reached, e.g. due to using a physical replication slot.
501 */
502 if (IsLogicalDecodingEnabled() && isCatalogRel)
504 snapshotConflictHorizon);
505}
VirtualTransactionId * GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
Definition procarray.c:3379
@ PROCSIG_RECOVERY_CONFLICT_SNAPSHOT
Definition procsignal.h:45
bool InvalidateObsoleteReplicationSlots(uint32 possible_causes, XLogSegNo oldestSegno, Oid dboid, TransactionId snapshotConflictHorizon)
Definition slot.c:2196
@ 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(), PROCSIG_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(), heap_xlog_visible(), ResolveRecoveryConflictWithSnapshotFullXid(), and spgRedoVacuumRedirect().

◆ ResolveRecoveryConflictWithSnapshotFullXid()

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

Definition at line 512 of file standby.c.

515{
516 /*
517 * ResolveRecoveryConflictWithSnapshot operates on 32-bit TransactionIds,
518 * so truncate the logged FullTransactionId. If the logged value is very
519 * old, so that XID wrap-around already happened on it, there can't be any
520 * snapshots that still see it.
521 */
523 uint64 diff;
524
525 diff = U64FromFullTransactionId(nextXid) -
526 U64FromFullTransactionId(snapshotConflictHorizon);
527 if (diff < MaxTransactionId / 2)
528 {
529 TransactionId truncated;
530
531 truncated = XidFromFullTransactionId(snapshotConflictHorizon);
533 isCatalogRel,
534 locator);
535 }
536}
uint64_t uint64
Definition c.h:547
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, bool isCatalogRel, RelFileLocator locator)
Definition standby.c:468
#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:288

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

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

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

Referenced by tblspc_redo().

◆ ShutdownRecoveryTransactionEnvironment()

void ShutdownRecoveryTransactionEnvironment ( void  )
extern

Definition at line 161 of file standby.c.

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

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

987{
991 LOCKTAG locktag;
992 bool found;
993
994 /* Already processed? */
995 if (!TransactionIdIsValid(xid) ||
998 return;
999
1000 elog(DEBUG4, "adding recovery lock: db %u rel %u", dbOid, relOid);
1001
1002 /* dbOid is InvalidOid when we are locking a shared relation. */
1003 Assert(OidIsValid(relOid));
1004
1005 /* Create a hash entry for this xid, if we don't have one already. */
1007 if (!found)
1008 {
1009 Assert(xidentry->xid == xid); /* dynahash should have set this */
1010 xidentry->head = NULL;
1011 }
1012
1013 /* Create a hash entry for this lock, unless we have one already. */
1014 key.xid = xid;
1015 key.dbOid = dbOid;
1016 key.relOid = relOid;
1018 if (!found)
1019 {
1020 /* It's new, so link it into the XID's list ... */
1021 lockentry->next = xidentry->head;
1022 xidentry->head = lockentry;
1023
1024 /* ... and acquire the lock locally. */
1025 SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
1026
1027 (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
1028 }
1029}
#define OidIsValid(objectId)
Definition c.h:788
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition dynahash.c:952
#define elog(elevel,...)
Definition elog.h:226
#define DEBUG4
Definition elog.h:27
@ HASH_ENTER
Definition hsearch.h:114
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
Definition lock.c:809
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition lock.h:183
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 936 of file standby.c.

937{
939}

References got_standby_deadlock_timeout.

Referenced by StartupProcessMain().

◆ StandbyLockTimeoutHandler()

void StandbyLockTimeoutHandler ( void  )
extern

Definition at line 954 of file standby.c.

955{
957}

References got_standby_lock_timeout.

Referenced by StartupProcessMain().

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )
extern

Definition at line 1106 of file standby.c.

1107{
1108 HASH_SEQ_STATUS status;
1109 RecoveryLockXidEntry *entry;
1110
1111 elog(DEBUG2, "release all standby locks");
1112
1114 while ((entry = hash_seq_search(&status)))
1115 {
1118 }
1119}
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition dynahash.c:1380
#define DEBUG2
Definition elog.h:29
@ HASH_REMOVE
Definition hsearch.h:115
static void StandbyReleaseXidEntryLocks(RecoveryLockXidEntry *xidentry)
Definition standby.c:1035

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

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

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

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

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)
extern

Definition at line 1130 of file standby.c.

1131{
1132 HASH_SEQ_STATUS status;
1133 RecoveryLockXidEntry *entry;
1134
1136 while ((entry = hash_seq_search(&status)))
1137 {
1139
1140 /* Skip if prepared transaction. */
1142 continue;
1143
1144 /* Skip if >= oldxid. */
1145 if (!TransactionIdPrecedes(entry->xid, oldxid))
1146 continue;
1147
1148 /* Remove all locks and hash table entry. */
1151 }
1152}
TransactionId xid
Definition standby.c:61
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition twophase.c:1467

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

946{
948}

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

Referenced by GetStandbyLimitTime().

◆ max_standby_streaming_delay

PGDLLIMPORT int max_standby_streaming_delay
extern

Definition at line 41 of file standby.c.

Referenced by GetStandbyLimitTime().