PostgreSQL Source Code  git master
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
 

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

Definition at line 92 of file standby.h.

◆ RunningTransactionsData

Function Documentation

◆ CheckRecoveryConflictDeadlock()

void CheckRecoveryConflictDeadlock ( void  )

Definition at line 904 of file standby.c.

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

Definition at line 94 of file standby.c.

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

References Assert, HASHCTL::entrysize, GetNextLocalTransactionId(), HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, 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 
)

Definition at line 1423 of file standby.c.

1424 {
1425  xl_standby_lock xlrec;
1426 
1427  xlrec.xid = GetCurrentTransactionId();
1428 
1429  xlrec.dbOid = dbOid;
1430  xlrec.relOid = relOid;
1431 
1432  LogAccessExclusiveLocks(1, &xlrec);
1434 }
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition: standby.c:1405
TransactionId xid
Definition: lockdefs.h:51
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:451
int MyXactFlags
Definition: xact.c:134
#define XACT_FLAGS_ACQUIREDACCESSEXCLUSIVELOCK
Definition: xact.h:108

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

Referenced by LockAcquireExtended().

◆ LogAccessExclusiveLockPrepare()

void LogAccessExclusiveLockPrepare ( void  )

Definition at line 1440 of file standby.c.

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

References GetCurrentTransactionId().

Referenced by LockAcquireExtended().

◆ LogRecoveryConflict()

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

Definition at line 273 of file standby.c.

276 {
277  long secs;
278  int usecs;
279  long msecs;
281  int nprocs = 0;
282 
283  /*
284  * There must be no conflicting processes when the recovery conflict has
285  * already been resolved.
286  */
287  Assert(still_waiting || wait_list == NULL);
288 
289  TimestampDifference(wait_start, now, &secs, &usecs);
290  msecs = secs * 1000 + usecs / 1000;
291  usecs = usecs % 1000;
292 
293  if (wait_list)
294  {
295  VirtualTransactionId *vxids;
296 
297  /* Construct a string of list of the conflicting processes */
298  vxids = wait_list;
299  while (VirtualTransactionIdIsValid(*vxids))
300  {
301  PGPROC *proc = ProcNumberGetProc(vxids->procNumber);
302 
303  /* proc can be NULL if the target backend is not active */
304  if (proc)
305  {
306  if (nprocs == 0)
307  {
309  appendStringInfo(&buf, "%d", proc->pid);
310  }
311  else
312  appendStringInfo(&buf, ", %d", proc->pid);
313 
314  nprocs++;
315  }
316 
317  vxids++;
318  }
319  }
320 
321  /*
322  * If wait_list is specified, report the list of PIDs of active
323  * conflicting backends in a detail message. Note that if all the backends
324  * in the list are not active, no detail message is logged.
325  */
326  if (still_waiting)
327  {
328  ereport(LOG,
329  errmsg("recovery still waiting after %ld.%03d ms: %s",
330  msecs, usecs, get_recovery_conflict_desc(reason)),
331  nprocs > 0 ? errdetail_log_plural("Conflicting process: %s.",
332  "Conflicting processes: %s.",
333  nprocs, buf.data) : 0);
334  }
335  else
336  {
337  ereport(LOG,
338  errmsg("recovery finished waiting after %ld.%03d ms: %s",
339  msecs, usecs, get_recovery_conflict_desc(reason)));
340  }
341 
342  if (nprocs > 0)
343  pfree(buf.data);
344 }
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1730
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1618
int errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1272
#define LOG
Definition: elog.h:31
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
void pfree(void *pointer)
Definition: mcxt.c:1520
static char * buf
Definition: pg_test_fsync.c:73
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
Definition: procarray.c:3125
static const char * get_recovery_conflict_desc(ProcSignalReason reason)
Definition: standby.c:1484
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: proc.h:157
int pid
Definition: proc.h:178

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

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

◆ LogStandbyInvalidations()

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

Definition at line 1462 of file standby.c.

1464 {
1465  xl_invalidations xlrec;
1466 
1467  /* prepare record */
1468  memset(&xlrec, 0, sizeof(xlrec));
1469  xlrec.dbId = MyDatabaseId;
1470  xlrec.tsId = MyDatabaseTableSpace;
1471  xlrec.relcacheInitFileInval = relcacheInitFileInval;
1472  xlrec.nmsgs = nmsgs;
1473 
1474  /* perform insertion */
1475  XLogBeginInsert();
1476  XLogRegisterData((char *) (&xlrec), MinSizeOfInvalidations);
1477  XLogRegisterData((char *) msgs,
1478  nmsgs * sizeof(SharedInvalidationMessage));
1479  XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
1480 }
Oid MyDatabaseTableSpace
Definition: globals.c:93
Oid MyDatabaseId
Definition: globals.c:91
#define XLOG_INVALIDATIONS
Definition: standbydefs.h:36
#define MinSizeOfInvalidations
Definition: standbydefs.h:72
bool relcacheInitFileInval
Definition: standbydefs.h:67
void XLogRegisterData(char *data, uint32 len)
Definition: xloginsert.c:364
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:474
void XLogBeginInsert(void)
Definition: xloginsert.c:149

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

◆ LogStandbySnapshot()

XLogRecPtr LogStandbySnapshot ( void  )

Definition at line 1285 of file standby.c.

1286 {
1287  XLogRecPtr recptr;
1288  RunningTransactions running;
1289  xl_standby_lock *locks;
1290  int nlocks;
1291 
1293 
1294  /*
1295  * Get details of any AccessExclusiveLocks being held at the moment.
1296  */
1297  locks = GetRunningTransactionLocks(&nlocks);
1298  if (nlocks > 0)
1299  LogAccessExclusiveLocks(nlocks, locks);
1300  pfree(locks);
1301 
1302  /*
1303  * Log details of all in-progress transactions. This should be the last
1304  * record we write, because standby will open up when it sees this.
1305  */
1306  running = GetRunningTransactionData();
1307 
1308  /*
1309  * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
1310  * For Hot Standby this can be done before inserting the WAL record
1311  * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
1312  * the clog. For logical decoding, though, the lock can't be released
1313  * early because the clog might be "in the future" from the POV of the
1314  * historic snapshot. This would allow for situations where we're waiting
1315  * for the end of a transaction listed in the xl_running_xacts record
1316  * which, according to the WAL, has committed before the xl_running_xacts
1317  * record. Fortunately this routine isn't executed frequently, and it's
1318  * only a shared lock.
1319  */
1321  LWLockRelease(ProcArrayLock);
1322 
1323  recptr = LogCurrentRunningXacts(running);
1324 
1325  /* Release lock if we kept it longer ... */
1327  LWLockRelease(ProcArrayLock);
1328 
1329  /* GetRunningTransactionData() acquired XidGenLock, we must release it */
1330  LWLockRelease(XidGenLock);
1331 
1332  return recptr;
1333 }
xl_standby_lock * GetRunningTransactionLocks(int *nlocks)
Definition: lock.c:3956
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
RunningTransactions GetRunningTransactionData(void)
Definition: procarray.c:2681
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
Definition: standby.c:1345
int wal_level
Definition: xlog.c:131
@ WAL_LEVEL_LOGICAL
Definition: xlog.h:74
#define XLogStandbyInfoActive()
Definition: xlog.h:121
uint64 XLogRecPtr
Definition: xlogdefs.h:21

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

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

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )

Definition at line 792 of file standby.c.

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

References Assert, DeadlockTimeout, EnableTimeoutParams::delay_ms, disable_all_timeouts(), enable_timeouts(), EnableTimeoutParams::fin_time, 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, TMPARAM_AT, and EnableTimeoutParams::type.

Referenced by LockBufferForCleanup().

◆ ResolveRecoveryConflictWithDatabase()

void ResolveRecoveryConflictWithDatabase ( Oid  dbid)

Definition at line 568 of file standby.c.

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

Definition at line 622 of file standby.c.

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

References AccessExclusiveLock, Assert, cleanup(), DeadlockTimeout, EnableTimeoutParams::delay_ms, disable_all_timeouts(), enable_timeouts(), EnableTimeoutParams::fin_time, 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, EnableTimeoutParams::type, VirtualTransactionIdIsValid, and PGPROC::waitStart.

Referenced by ProcSleep().

◆ ResolveRecoveryConflictWithSnapshot()

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

Definition at line 467 of file standby.c.

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

References Assert, RelFileLocator::dbOid, GetConflictingVirtualXIDs(), InvalidateObsoleteReplicationSlots(), PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, ResolveRecoveryConflictWithVirtualXIDs(), RS_INVAL_HORIZON, TransactionIdIsNormal, TransactionIdIsValid, wal_level, and WAL_LEVEL_LOGICAL.

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 
)

Definition at line 511 of file standby.c.

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

Referenced by btree_xlog_reuse_page(), and gistRedoPageReuse().

◆ ResolveRecoveryConflictWithTablespace()

void ResolveRecoveryConflictWithTablespace ( Oid  tsid)

Definition at line 538 of file standby.c.

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

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

Referenced by tblspc_redo().

◆ ShutdownRecoveryTransactionEnvironment()

void ShutdownRecoveryTransactionEnvironment ( void  )

Definition at line 160 of file standby.c.

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

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

Referenced by StartupProcExit(), and StartupXLOG().

◆ StandbyAcquireAccessExclusiveLock()

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

Definition at line 985 of file standby.c.

986 {
987  RecoveryLockXidEntry *xidentry;
988  RecoveryLockEntry *lockentry;
990  LOCKTAG locktag;
991  bool found;
992 
993  /* Already processed? */
994  if (!TransactionIdIsValid(xid) ||
995  TransactionIdDidCommit(xid) ||
997  return;
998 
999  elog(DEBUG4, "adding recovery lock: db %u rel %u", dbOid, relOid);
1000 
1001  /* dbOid is InvalidOid when we are locking a shared relation. */
1002  Assert(OidIsValid(relOid));
1003 
1004  /* Create a hash entry for this xid, if we don't have one already. */
1005  xidentry = hash_search(RecoveryLockXidHash, &xid, HASH_ENTER, &found);
1006  if (!found)
1007  {
1008  Assert(xidentry->xid == xid); /* dynahash should have set this */
1009  xidentry->head = NULL;
1010  }
1011 
1012  /* Create a hash entry for this lock, unless we have one already. */
1013  key.xid = xid;
1014  key.dbOid = dbOid;
1015  key.relOid = relOid;
1016  lockentry = hash_search(RecoveryLockHash, &key, HASH_ENTER, &found);
1017  if (!found)
1018  {
1019  /* It's new, so link it into the XID's list ... */
1020  lockentry->next = xidentry->head;
1021  xidentry->head = lockentry;
1022 
1023  /* ... and acquire the lock locally. */
1024  SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
1025 
1026  (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
1027  }
1028 }
#define OidIsValid(objectId)
Definition: c.h:775
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
#define elog(elevel,...)
Definition: elog.h:224
#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:734
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
Definition: lock.h:165
struct RecoveryLockEntry * next
Definition: standby.c:55
TransactionId xid
Definition: standby.c:60
struct RecoveryLockEntry * head
Definition: standby.c:61
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:188

References AccessExclusiveLock, Assert, DEBUG4, elog, HASH_ENTER, hash_search(), RecoveryLockXidEntry::head, sort-test::key, LockAcquire(), RecoveryLockEntry::next, OidIsValid, RecoveryLockHash, RecoveryLockXidHash, SET_LOCKTAG_RELATION, TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsValid, and RecoveryLockXidEntry::xid.

Referenced by lock_twophase_standby_recover(), and standby_redo().

◆ StandbyDeadLockHandler()

void StandbyDeadLockHandler ( void  )

Definition at line 935 of file standby.c.

936 {
938 }

References got_standby_deadlock_timeout.

Referenced by StartupProcessMain().

◆ StandbyLockTimeoutHandler()

void StandbyLockTimeoutHandler ( void  )

Definition at line 953 of file standby.c.

954 {
956 }

References got_standby_lock_timeout.

Referenced by StartupProcessMain().

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )

Definition at line 1105 of file standby.c.

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

References DEBUG2, elog, 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 
)

Definition at line 1091 of file standby.c.

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

References i, and StandbyReleaseLocks().

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

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)

Definition at line 1126 of file standby.c.

1127 {
1128  HASH_SEQ_STATUS status;
1129  RecoveryLockXidEntry *entry;
1130 
1132  while ((entry = hash_seq_search(&status)))
1133  {
1134  Assert(TransactionIdIsValid(entry->xid));
1135 
1136  /* Skip if prepared transaction. */
1137  if (StandbyTransactionIdIsPrepared(entry->xid))
1138  continue;
1139 
1140  /* Skip if >= oldxid. */
1141  if (!TransactionIdPrecedes(entry->xid, oldxid))
1142  continue;
1143 
1144  /* Remove all locks and hash table entry. */
1147  }
1148 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1475

References Assert, 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  )

Definition at line 944 of file standby.c.

945 {
947 }

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

Referenced by GetStandbyLimitTime().

◆ max_standby_streaming_delay

PGDLLIMPORT int max_standby_streaming_delay
extern

Definition at line 40 of file standby.c.

Referenced by GetStandbyLimitTime().