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, RelFileLocator locator)
 
void ResolveRecoveryConflictWithSnapshotFullXid (FullTransactionId snapshotConflictHorizon, 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 vacuum_defer_cleanup_age
 
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 62 of file standby.h.

Typedef Documentation

◆ RunningTransactions

Definition at line 89 of file standby.h.

◆ RunningTransactionsData

Function Documentation

◆ CheckRecoveryConflictDeadlock()

void CheckRecoveryConflictDeadlock ( void  )

Definition at line 891 of file standby.c.

892 {
893  Assert(!InRecovery); /* do not call in Startup process */
894 
896  return;
897 
898  /*
899  * Error message should match ProcessInterrupts() but we avoid calling
900  * that because we aren't handling an interrupt at this point. Note that
901  * we only cancel the current transaction here, so if we are in a
902  * subtransaction and the pin is held by a parent, then the Startup
903  * process will continue to wait even though we have avoided deadlock.
904  */
905  ereport(ERROR,
907  errmsg("canceling statement due to conflict with recovery"),
908  errdetail("User transaction caused buffer deadlock with recovery.")));
909 }
bool HoldingBufferPinThatDelaysRecovery(void)
Definition: bufmgr.c:4447
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
Assert(fmt[strlen(fmt) - 1] !='\n')
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:77
bool InRecovery
Definition: xlogutils.c:53

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

97 {
99  HASHCTL hash_ctl;
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  */
140  vxid.backendId = MyBackendId;
143 
145 }
uint32 TransactionId
Definition: c.h:636
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:350
BackendId MyBackendId
Definition: globals.c:85
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void VirtualXactLockTableInsert(VirtualTransactionId vxid)
Definition: lock.c:4411
struct xl_standby_lock xl_standby_lock
void SharedInvalBackendInit(bool sendOnly)
Definition: sinvaladt.c:266
LocalTransactionId GetNextLocalTransactionId(void)
Definition: sinvaladt.c:780
static HTAB * RecoveryLockXidHash
Definition: standby.c:67
struct RecoveryLockEntry RecoveryLockEntry
struct RecoveryLockXidEntry RecoveryLockXidEntry
static HTAB * RecoveryLockHash
Definition: standby.c:66
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
LocalTransactionId localTransactionId
Definition: lock.h:62
BackendId backendId
Definition: lock.h:61
HotStandbyState standbyState
Definition: xlogutils.c:56
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

References Assert(), VirtualTransactionId::backendId, HASHCTL::entrysize, GetNextLocalTransactionId(), HASH_BLOBS, hash_create(), HASH_ELEM, HASHCTL::keysize, VirtualTransactionId::localTransactionId, MyBackendId, RecoveryLockHash, RecoveryLockXidHash, SharedInvalBackendInit(), STANDBY_INITIALIZED, standbyState, and VirtualXactLockTableInsert().

Referenced by StartupXLOG().

◆ LogAccessExclusiveLock()

void LogAccessExclusiveLock ( Oid  dbOid,
Oid  relOid 
)

Definition at line 1402 of file standby.c.

1403 {
1404  xl_standby_lock xlrec;
1405 
1406  xlrec.xid = GetCurrentTransactionId();
1407 
1408  xlrec.dbOid = dbOid;
1409  xlrec.relOid = relOid;
1410 
1411  LogAccessExclusiveLocks(1, &xlrec);
1413 }
static void LogAccessExclusiveLocks(int nlocks, xl_standby_lock *locks)
Definition: standby.c:1384
TransactionId xid
Definition: lockdefs.h:51
TransactionId GetCurrentTransactionId(void)
Definition: xact.c:445
int MyXactFlags
Definition: xact.c:136
#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 1419 of file standby.c.

1420 {
1421  /*
1422  * Ensure that a TransactionId has been assigned to this transaction, for
1423  * two reasons, both related to lock release on the standby. First, we
1424  * must assign an xid so that RecordTransactionCommit() and
1425  * RecordTransactionAbort() do not optimise away the transaction
1426  * completion record which recovery relies upon to release locks. It's a
1427  * hack, but for a corner case not worth adding code for into the main
1428  * commit path. Second, we must assign an xid before the lock is recorded
1429  * in shared memory, otherwise a concurrently executing
1430  * GetRunningTransactionLocks() might see a lock associated with an
1431  * InvalidTransactionId which we later assert cannot happen.
1432  */
1433  (void) GetCurrentTransactionId();
1434 }

References GetCurrentTransactionId().

Referenced by LockAcquireExtended().

◆ LogRecoveryConflict()

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

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  */
288  Assert(still_waiting || wait_list == NULL);
289 
290  TimestampDifference(wait_start, now, &secs, &usecs);
291  msecs = secs * 1000 + usecs / 1000;
292  usecs = usecs % 1000;
293 
294  if (wait_list)
295  {
296  VirtualTransactionId *vxids;
297 
298  /* Construct a string of list of the conflicting processes */
299  vxids = wait_list;
300  while (VirtualTransactionIdIsValid(*vxids))
301  {
302  PGPROC *proc = BackendIdGetProc(vxids->backendId);
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",
331  msecs, usecs, get_recovery_conflict_desc(reason)),
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",
340  msecs, usecs, get_recovery_conflict_desc(reason)));
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:1667
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1546
int errdetail_log_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1271
#define LOG
Definition: elog.h:31
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
void pfree(void *pointer)
Definition: mcxt.c:1436
static char * buf
Definition: pg_test_fsync.c:67
PGPROC * BackendIdGetProc(int backendID)
Definition: sinvaladt.c:385
static const char * get_recovery_conflict_desc(ProcSignalReason reason)
Definition: standby.c:1463
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: proc.h:162
int pid
Definition: proc.h:186

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

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

◆ LogStandbyInvalidations()

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

Definition at line 1441 of file standby.c.

1443 {
1444  xl_invalidations xlrec;
1445 
1446  /* prepare record */
1447  memset(&xlrec, 0, sizeof(xlrec));
1448  xlrec.dbId = MyDatabaseId;
1449  xlrec.tsId = MyDatabaseTableSpace;
1450  xlrec.relcacheInitFileInval = relcacheInitFileInval;
1451  xlrec.nmsgs = nmsgs;
1452 
1453  /* perform insertion */
1454  XLogBeginInsert();
1455  XLogRegisterData((char *) (&xlrec), MinSizeOfInvalidations);
1456  XLogRegisterData((char *) msgs,
1457  nmsgs * sizeof(SharedInvalidationMessage));
1458  XLogInsert(RM_STANDBY_ID, XLOG_INVALIDATIONS);
1459 }
Oid MyDatabaseTableSpace
Definition: globals.c:91
Oid MyDatabaseId
Definition: globals.c:89
#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:351
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:451
void XLogBeginInsert(void)
Definition: xloginsert.c:150

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

1265 {
1266  XLogRecPtr recptr;
1267  RunningTransactions running;
1268  xl_standby_lock *locks;
1269  int nlocks;
1270 
1272 
1273  /*
1274  * Get details of any AccessExclusiveLocks being held at the moment.
1275  */
1276  locks = GetRunningTransactionLocks(&nlocks);
1277  if (nlocks > 0)
1278  LogAccessExclusiveLocks(nlocks, locks);
1279  pfree(locks);
1280 
1281  /*
1282  * Log details of all in-progress transactions. This should be the last
1283  * record we write, because standby will open up when it sees this.
1284  */
1285  running = GetRunningTransactionData();
1286 
1287  /*
1288  * GetRunningTransactionData() acquired ProcArrayLock, we must release it.
1289  * For Hot Standby this can be done before inserting the WAL record
1290  * because ProcArrayApplyRecoveryInfo() rechecks the commit status using
1291  * the clog. For logical decoding, though, the lock can't be released
1292  * early because the clog might be "in the future" from the POV of the
1293  * historic snapshot. This would allow for situations where we're waiting
1294  * for the end of a transaction listed in the xl_running_xacts record
1295  * which, according to the WAL, has committed before the xl_running_xacts
1296  * record. Fortunately this routine isn't executed frequently, and it's
1297  * only a shared lock.
1298  */
1300  LWLockRelease(ProcArrayLock);
1301 
1302  recptr = LogCurrentRunningXacts(running);
1303 
1304  /* Release lock if we kept it longer ... */
1306  LWLockRelease(ProcArrayLock);
1307 
1308  /* GetRunningTransactionData() acquired XidGenLock, we must release it */
1309  LWLockRelease(XidGenLock);
1310 
1311  return recptr;
1312 }
xl_standby_lock * GetRunningTransactionLocks(int *nlocks)
Definition: lock.c:3962
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
RunningTransactions GetRunningTransactionData(void)
Definition: procarray.c:2752
static XLogRecPtr LogCurrentRunningXacts(RunningTransactions CurrRunningXacts)
Definition: standby.c:1324
int wal_level
Definition: xlog.c:134
@ WAL_LEVEL_LOGICAL
Definition: xlog.h:71
#define XLogStandbyInfoActive()
Definition: xlog.h:118
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(), ReplicationSlotReserveWal(), and SnapBuildWaitSnapshot().

◆ ResolveRecoveryConflictWithBufferPin()

void ResolveRecoveryConflictWithBufferPin ( void  )

Definition at line 779 of file standby.c.

780 {
781  TimestampTz ltime;
782 
784 
785  ltime = GetStandbyLimitTime();
786 
787  if (GetCurrentTimestamp() >= ltime && ltime != 0)
788  {
789  /*
790  * We're already behind, so clear a path as quickly as possible.
791  */
793  }
794  else
795  {
796  /*
797  * Wake up at ltime, and check for deadlocks as well if we will be
798  * waiting longer than deadlock_timeout
799  */
800  EnableTimeoutParams timeouts[2];
801  int cnt = 0;
802 
803  if (ltime != 0)
804  {
805  timeouts[cnt].id = STANDBY_TIMEOUT;
806  timeouts[cnt].type = TMPARAM_AT;
807  timeouts[cnt].fin_time = ltime;
808  cnt++;
809  }
810 
812  timeouts[cnt].id = STANDBY_DEADLOCK_TIMEOUT;
813  timeouts[cnt].type = TMPARAM_AFTER;
814  timeouts[cnt].delay_ms = DeadlockTimeout;
815  cnt++;
816 
817  enable_timeouts(timeouts, cnt);
818  }
819 
820  /*
821  * Wait to be signaled by UnpinBuffer() or for the wait to be interrupted
822  * by one of the timeouts established above.
823  *
824  * We assume that only UnpinBuffer() and the timeout requests established
825  * above can wake us up here. WakeupRecovery() called by walreceiver or
826  * SIGHUP signal handler, etc cannot do that because it uses the different
827  * latch from that ProcWaitForSignal() waits on.
828  */
830 
834  {
835  /*
836  * Send out a request for hot-standby backends to check themselves for
837  * deadlocks.
838  *
839  * XXX The subsequent ResolveRecoveryConflictWithBufferPin() will wait
840  * to be signaled by UnpinBuffer() again and send a request for
841  * deadlocks check if deadlock_timeout happens. This causes the
842  * request to continue to be sent every deadlock_timeout until the
843  * buffer is unpinned or ltime is reached. This would increase the
844  * workload in the startup process and backends. In practice it may
845  * not be so harmful because the period that the buffer is kept pinned
846  * is basically no so long. But we should fix this?
847  */
849  }
850 
851  /*
852  * Clear any timeout requests established above. We assume here that the
853  * Startup process doesn't have any other timeouts than what this function
854  * uses. If that stops being true, we could cancel the timeouts
855  * individually, but that'd be slower.
856  */
857  disable_all_timeouts(false);
860 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1582
int64 TimestampTz
Definition: timestamp.h:39
@ PROCSIG_RECOVERY_CONFLICT_BUFFERPIN
Definition: procsignal.h:45
@ PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK
Definition: procsignal.h:46
int DeadlockTimeout
Definition: proc.c:58
void ProcWaitForSignal(uint32 wait_event_info)
Definition: proc.c:1797
static volatile sig_atomic_t got_standby_deadlock_timeout
Definition: standby.c:70
static TimestampTz GetStandbyLimitTime(void)
Definition: standby.c:201
static volatile sig_atomic_t got_standby_delay_timeout
Definition: standby.c:71
static void SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
Definition: standby.c:863
TimeoutType type
Definition: timeout.h:60
TimestampTz fin_time
Definition: timeout.h:62
TimeoutId id
Definition: timeout.h:59
void disable_all_timeouts(bool keep_indicators)
Definition: timeout.c:755
void enable_timeouts(const EnableTimeoutParams *timeouts, int count)
Definition: timeout.c:634
@ STANDBY_DEADLOCK_TIMEOUT
Definition: timeout.h:30
@ STANDBY_TIMEOUT
Definition: timeout.h:31
@ TMPARAM_AT
Definition: timeout.h:53
@ TMPARAM_AFTER
Definition: timeout.h:52
#define PG_WAIT_BUFFER_PIN
Definition: wait_event.h:20
#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, PG_WAIT_BUFFER_PIN, 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 555 of file standby.c.

556 {
557  /*
558  * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that
559  * only waits for transactions and completely idle sessions would block
560  * us. This is rare enough that we do this as simply as possible: no wait,
561  * just force them off immediately.
562  *
563  * No locking is required here because we already acquired
564  * AccessExclusiveLock. Anybody trying to connect while we do this will
565  * block during InitPostgres() and then disconnect when they see the
566  * database has been removed.
567  */
568  while (CountDBBackends(dbid) > 0)
569  {
571 
572  /*
573  * Wait awhile for them to die so that we avoid flooding an
574  * unresponsive backend when system is heavily loaded.
575  */
576  pg_usleep(10000);
577  }
578 }
void CancelDBBackends(Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3649
int CountDBBackends(Oid databaseid)
Definition: procarray.c:3588
@ PROCSIG_RECOVERY_CONFLICT_DATABASE
Definition: procsignal.h:41
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 609 of file standby.c.

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

Definition at line 468 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);
493  true);
494 }
VirtualTransactionId * GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
Definition: procarray.c:3406
@ PROCSIG_RECOVERY_CONFLICT_SNAPSHOT
Definition: procsignal.h:44
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
@ WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT
Definition: wait_event.h:123

References Assert(), RelFileLocator::dbOid, GetConflictingVirtualXIDs(), PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, ResolveRecoveryConflictWithVirtualXIDs(), TransactionIdIsNormal, TransactionIdIsValid, and WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT.

Referenced by btree_xlog_delete(), gistRedoDeleteRecord(), hash_xlog_vacuum_one_page(), heap_xlog_freeze_page(), heap_xlog_prune(), heap_xlog_visible(), ResolveRecoveryConflictWithSnapshotFullXid(), and spgRedoVacuumRedirect().

◆ ResolveRecoveryConflictWithSnapshotFullXid()

void ResolveRecoveryConflictWithSnapshotFullXid ( FullTransactionId  snapshotConflictHorizon,
RelFileLocator  locator 
)

Definition at line 501 of file standby.c.

503 {
504  /*
505  * ResolveRecoveryConflictWithSnapshot operates on 32-bit TransactionIds,
506  * so truncate the logged FullTransactionId. If the logged value is very
507  * old, so that XID wrap-around already happened on it, there can't be any
508  * snapshots that still see it.
509  */
511  uint64 diff;
512 
513  diff = U64FromFullTransactionId(nextXid) -
514  U64FromFullTransactionId(snapshotConflictHorizon);
515  if (diff < MaxTransactionId / 2)
516  {
517  TransactionId truncated;
518 
519  truncated = XidFromFullTransactionId(snapshotConflictHorizon);
520  ResolveRecoveryConflictWithSnapshot(truncated, locator);
521  }
522 }
void ResolveRecoveryConflictWithSnapshot(TransactionId snapshotConflictHorizon, 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:261

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

Referenced by btree_xlog_reuse_page(), and gistRedoPageReuse().

◆ ResolveRecoveryConflictWithTablespace()

void ResolveRecoveryConflictWithTablespace ( Oid  tsid)

Definition at line 525 of file standby.c.

526 {
527  VirtualTransactionId *temp_file_users;
528 
529  /*
530  * Standby users may be currently using this tablespace for their
531  * temporary files. We only care about current users because
532  * temp_tablespace parameter will just ignore tablespaces that no longer
533  * exist.
534  *
535  * Ask everybody to cancel their queries immediately so we can ensure no
536  * temp files remain and we can remove the tablespace. Nuke the entire
537  * site from orbit, it's the only way to be sure.
538  *
539  * XXX: We could work out the pids of active backends using this
540  * tablespace by examining the temp filenames in the directory. We would
541  * then convert the pids into VirtualXIDs before attempting to cancel
542  * them.
543  *
544  * We don't wait for commit because drop tablespace is non-transactional.
545  */
547  InvalidOid);
551  true);
552 }
#define InvalidOid
Definition: postgres_ext.h:36
@ PROCSIG_RECOVERY_CONFLICT_TABLESPACE
Definition: procsignal.h:42
#define InvalidTransactionId
Definition: transam.h:31
@ WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE
Definition: wait_event.h:124

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

Referenced by tblspc_redo().

◆ ShutdownRecoveryTransactionEnvironment()

void ShutdownRecoveryTransactionEnvironment ( void  )

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. */
181  RecoveryLockHash = NULL;
182  RecoveryLockXidHash = NULL;
183 
184  /* Cleanup our VirtualTransaction */
186 }
void hash_destroy(HTAB *hashp)
Definition: dynahash.c:863
void VirtualXactLockTableCleanup(void)
Definition: lock.c:4434
void ExpireAllKnownAssignedTransactionIds(void)
Definition: procarray.c:4550
void StandbyReleaseAllLocks(void)
Definition: standby.c:1093

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

973 {
974  RecoveryLockXidEntry *xidentry;
975  RecoveryLockEntry *lockentry;
977  LOCKTAG locktag;
978  bool found;
979 
980  /* Already processed? */
981  if (!TransactionIdIsValid(xid) ||
982  TransactionIdDidCommit(xid) ||
984  return;
985 
987  "adding recovery lock: db %u rel %u", dbOid, relOid);
988 
989  /* dbOid is InvalidOid when we are locking a shared relation. */
990  Assert(OidIsValid(relOid));
991 
992  /* Create a hash entry for this xid, if we don't have one already. */
993  xidentry = hash_search(RecoveryLockXidHash, &xid, HASH_ENTER, &found);
994  if (!found)
995  {
996  Assert(xidentry->xid == xid); /* dynahash should have set this */
997  xidentry->head = NULL;
998  }
999 
1000  /* Create a hash entry for this lock, unless we have one already. */
1001  key.xid = xid;
1002  key.dbOid = dbOid;
1003  key.relOid = relOid;
1004  lockentry = hash_search(RecoveryLockHash, &key, HASH_ENTER, &found);
1005  if (!found)
1006  {
1007  /* It's new, so link it into the XID's list ... */
1008  lockentry->next = xidentry->head;
1009  xidentry->head = lockentry;
1010 
1011  /* ... and acquire the lock locally. */
1012  SET_LOCKTAG_RELATION(locktag, dbOid, relOid);
1013 
1014  (void) LockAcquire(&locktag, AccessExclusiveLock, true, false);
1015  }
1016 }
#define OidIsValid(objectId)
Definition: c.h:759
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
int trace_recovery(int trace_level)
Definition: elog.c:3749
#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:747
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
Definition: lock.h:181
Definition: lock.h:165
struct RecoveryLockEntry * next
Definition: standby.c:57
TransactionId xid
Definition: standby.c:62
struct RecoveryLockEntry * head
Definition: standby.c:63
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, trace_recovery(), TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsValid, and RecoveryLockXidEntry::xid.

Referenced by lock_twophase_standby_recover(), and standby_redo().

◆ StandbyDeadLockHandler()

void StandbyDeadLockHandler ( void  )

Definition at line 922 of file standby.c.

923 {
925 }

References got_standby_deadlock_timeout.

Referenced by StartupProcessMain().

◆ StandbyLockTimeoutHandler()

void StandbyLockTimeoutHandler ( void  )

Definition at line 940 of file standby.c.

941 {
943 }

References got_standby_lock_timeout.

Referenced by StartupProcessMain().

◆ StandbyReleaseAllLocks()

void StandbyReleaseAllLocks ( void  )

Definition at line 1093 of file standby.c.

1094 {
1096  RecoveryLockXidEntry *entry;
1097 
1098  elog(trace_recovery(DEBUG2), "release all standby locks");
1099 
1101  while ((entry = hash_seq_search(&status)))
1102  {
1105  }
1106 }
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
#define DEBUG2
Definition: elog.h:29
@ HASH_REMOVE
Definition: hsearch.h:115
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
static void StandbyReleaseXidEntryLocks(RecoveryLockXidEntry *xidentry)
Definition: standby.c:1022

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

Referenced by ShutdownRecoveryTransactionEnvironment(), and StandbyReleaseLocks().

◆ StandbyReleaseLockTree()

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

Definition at line 1079 of file standby.c.

1080 {
1081  int i;
1082 
1083  StandbyReleaseLocks(xid);
1084 
1085  for (i = 0; i < nsubxids; i++)
1086  StandbyReleaseLocks(subxids[i]);
1087 }
int i
Definition: isn.c:73
static void StandbyReleaseLocks(TransactionId xid)
Definition: standby.c:1055

References i, and StandbyReleaseLocks().

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

◆ StandbyReleaseOldLocks()

void StandbyReleaseOldLocks ( TransactionId  oldxid)

Definition at line 1114 of file standby.c.

1115 {
1117  RecoveryLockXidEntry *entry;
1118 
1120  while ((entry = hash_seq_search(&status)))
1121  {
1122  Assert(TransactionIdIsValid(entry->xid));
1123 
1124  /* Skip if prepared transaction. */
1125  if (StandbyTransactionIdIsPrepared(entry->xid))
1126  continue;
1127 
1128  /* Skip if >= oldxid. */
1129  if (!TransactionIdPrecedes(entry->xid, oldxid))
1130  continue;
1131 
1132  /* Remove all locks and hash table entry. */
1135  }
1136 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1452

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

Referenced by ProcArrayApplyRecoveryInfo().

◆ StandbyTimeoutHandler()

void StandbyTimeoutHandler ( void  )

Definition at line 931 of file standby.c.

932 {
934 }

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

◆ vacuum_defer_cleanup_age

PGDLLIMPORT int vacuum_defer_cleanup_age
extern

Definition at line 40 of file standby.c.

Referenced by ComputeXidHorizons(), and GetSnapshotData().