#include "postgres.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
#include "storage/lmgr.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/sinvaladt.h"
#include "storage/standby.h"
#include "utils/ps_status.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
Go to the source code of this file.
void CheckRecoveryConflictDeadlock | ( | void | ) |
Definition at line 483 of file standby.c.
References Assert, ereport, errcode(), errdetail(), errmsg(), ERROR, HoldingBufferPinThatDelaysRecovery(), and InRecovery.
Referenced by ProcSleep().
{ Assert(!InRecovery); /* do not call in Startup process */ if (!HoldingBufferPinThatDelaysRecovery()) return; /* * Error message should match ProcessInterrupts() but we avoid calling * that because we aren't handling an interrupt at this point. Note that * we only cancel the current transaction here, so if we are in a * subtransaction and the pin is held by a parent, then the Startup * process will continue to wait even though we have avoided deadlock. */ ereport(ERROR, (errcode(ERRCODE_T_R_DEADLOCK_DETECTED), errmsg("canceling statement due to conflict with recovery"), errdetail("User transaction caused buffer deadlock with recovery."))); }
static TimestampTz GetStandbyLimitTime | ( | void | ) | [static] |
Definition at line 126 of file standby.c.
References GetXLogReceiptTime(), max_standby_archive_delay, max_standby_streaming_delay, and TimestampTzPlusMilliseconds.
Referenced by ResolveRecoveryConflictWithBufferPin(), and WaitExceedsMaxStandbyDelay().
{ TimestampTz rtime; bool fromStream; /* * The cutoff time is the last WAL data receipt time plus the appropriate * delay variable. Delay of -1 means wait forever. */ GetXLogReceiptTime(&rtime, &fromStream); if (fromStream) { if (max_standby_streaming_delay < 0) return 0; /* wait forever */ return TimestampTzPlusMilliseconds(rtime, max_standby_streaming_delay); } else { if (max_standby_archive_delay < 0) return 0; /* wait forever */ return TimestampTzPlusMilliseconds(rtime, max_standby_archive_delay); } }
void InitRecoveryTransactionEnvironment | ( | void | ) |
Definition at line 62 of file standby.c.
References VirtualTransactionId::backendId, GetNextLocalTransactionId(), VirtualTransactionId::localTransactionId, MyBackendId, SharedInvalBackendInit(), standbyState, and VirtualXactLockTableInsert().
Referenced by StartupXLOG().
{ VirtualTransactionId vxid; /* * Initialize shared invalidation management for Startup process, being * careful to register ourselves as a sendOnly process so we don't need to * read messages, nor will we get signalled when the queue starts filling * up. */ SharedInvalBackendInit(true); /* * Lock a virtual transaction id for Startup process. * * We need to do GetNextLocalTransactionId() because * SharedInvalBackendInit() leaves localTransactionid invalid and the lock * manager doesn't like that at all. * * Note that we don't need to run XactLockTableInsert() because nobody * needs to wait on xids. That sounds a little strange, but table locks * are held by vxids and row level locks are held by xids. All queries * hold AccessShareLocks so never block while we write or lock new rows. */ vxid.backendId = MyBackendId; vxid.localTransactionId = GetNextLocalTransactionId(); VirtualXactLockTableInsert(vxid); standbyState = STANDBY_INITIALIZED; }
Definition at line 978 of file standby.c.
References xl_standby_lock::dbOid, GetTopTransactionId(), LogAccessExclusiveLocks(), xl_standby_lock::relOid, and xl_standby_lock::xid.
Referenced by LockAcquireExtended().
{ xl_standby_lock xlrec; xlrec.xid = GetTopTransactionId(); /* * Decode the locktag back to the original values, to avoid sending lots * of empty bytes with every message. See lock.h to check how a locktag * is defined for LOCKTAG_RELATION */ xlrec.dbOid = dbOid; xlrec.relOid = relOid; LogAccessExclusiveLocks(1, &xlrec); }
void LogAccessExclusiveLockPrepare | ( | void | ) |
Definition at line 999 of file standby.c.
References GetTopTransactionId().
Referenced by LockAcquireExtended().
{ /* * Ensure that a TransactionId has been assigned to this transaction, for * two reasons, both related to lock release on the standby. First, we * must assign an xid so that RecordTransactionCommit() and * RecordTransactionAbort() do not optimise away the transaction * completion record which recovery relies upon to release locks. It's a * hack, but for a corner case not worth adding code for into the main * commit path. Second, we must assign an xid before the lock is recorded * in shared memory, otherwise a concurrently executing * GetRunningTransactionLocks() might see a lock associated with an * InvalidTransactionId which we later assert cannot happen. */ (void) GetTopTransactionId(); }
static void LogAccessExclusiveLocks | ( | int | nlocks, | |
xl_standby_lock * | locks | |||
) | [static] |
Definition at line 954 of file standby.c.
References XLogRecData::buffer, XLogRecData::data, XLogRecData::len, XLogRecData::next, xl_standby_locks::nlocks, offsetof, XLOG_STANDBY_LOCK, and XLogInsert().
Referenced by LogAccessExclusiveLock(), and LogStandbySnapshot().
{ XLogRecData rdata[2]; xl_standby_locks xlrec; xlrec.nlocks = nlocks; rdata[0].data = (char *) &xlrec; rdata[0].len = offsetof(xl_standby_locks, locks); rdata[0].buffer = InvalidBuffer; rdata[0].next = &rdata[1]; rdata[1].data = (char *) locks; rdata[1].len = nlocks * sizeof(xl_standby_lock); rdata[1].buffer = InvalidBuffer; rdata[1].next = NULL; (void) XLogInsert(RM_STANDBY_ID, XLOG_STANDBY_LOCK, rdata); }
static void LogCurrentRunningXacts | ( | RunningTransactions | CurrRunningXacts | ) | [static] |
Definition at line 898 of file standby.c.
References XLogRecData::buffer, XLogRecData::data, DEBUG2, elog, RunningTransactionsData::latestCompletedXid, xl_running_xacts::latestCompletedXid, XLogRecData::len, XLogRecData::next, RunningTransactionsData::nextXid, xl_running_xacts::nextXid, RunningTransactionsData::oldestRunningXid, xl_running_xacts::oldestRunningXid, RunningTransactionsData::subxcnt, xl_running_xacts::subxcnt, RunningTransactionsData::subxid_overflow, xl_running_xacts::subxid_overflow, trace_recovery(), RunningTransactionsData::xcnt, xl_running_xacts::xcnt, RunningTransactionsData::xids, XLOG_RUNNING_XACTS, and XLogInsert().
Referenced by LogStandbySnapshot().
{ xl_running_xacts xlrec; XLogRecData rdata[2]; int lastrdata = 0; XLogRecPtr recptr; xlrec.xcnt = CurrRunningXacts->xcnt; xlrec.subxcnt = CurrRunningXacts->subxcnt; xlrec.subxid_overflow = CurrRunningXacts->subxid_overflow; xlrec.nextXid = CurrRunningXacts->nextXid; xlrec.oldestRunningXid = CurrRunningXacts->oldestRunningXid; xlrec.latestCompletedXid = CurrRunningXacts->latestCompletedXid; /* Header */ rdata[0].data = (char *) (&xlrec); rdata[0].len = MinSizeOfXactRunningXacts; rdata[0].buffer = InvalidBuffer; /* array of TransactionIds */ if (xlrec.xcnt > 0) { rdata[0].next = &(rdata[1]); rdata[1].data = (char *) CurrRunningXacts->xids; rdata[1].len = (xlrec.xcnt + xlrec.subxcnt) * sizeof(TransactionId); rdata[1].buffer = InvalidBuffer; lastrdata = 1; } rdata[lastrdata].next = NULL; recptr = XLogInsert(RM_STANDBY_ID, XLOG_RUNNING_XACTS, rdata); if (CurrRunningXacts->subxid_overflow) elog(trace_recovery(DEBUG2), "snapshot of %u running transactions overflowed (lsn %X/%X oldest xid %u latest complete %u next xid %u)", CurrRunningXacts->xcnt, (uint32) (recptr >> 32), (uint32) recptr, CurrRunningXacts->oldestRunningXid, CurrRunningXacts->latestCompletedXid, CurrRunningXacts->nextXid); else elog(trace_recovery(DEBUG2), "snapshot of %u+%u running transaction ids (lsn %X/%X oldest xid %u latest complete %u next xid %u)", CurrRunningXacts->xcnt, CurrRunningXacts->subxcnt, (uint32) (recptr >> 32), (uint32) recptr, CurrRunningXacts->oldestRunningXid, CurrRunningXacts->latestCompletedXid, CurrRunningXacts->nextXid); }
void LogStandbySnapshot | ( | void | ) |
Definition at line 858 of file standby.c.
References Assert, GetRunningTransactionData(), GetRunningTransactionLocks(), LogAccessExclusiveLocks(), LogCurrentRunningXacts(), LWLockRelease(), XidGenLock, and XLogStandbyInfoActive.
Referenced by CreateCheckPoint().
{ RunningTransactions running; xl_standby_lock *locks; int nlocks; Assert(XLogStandbyInfoActive()); /* * Get details of any AccessExclusiveLocks being held at the moment. * * XXX GetRunningTransactionLocks() currently holds a lock on all * partitions though it is possible to further optimise the locking. By * reference counting locks and storing the value on the ProcArray entry * for each backend we can easily tell if any locks need recording without * trying to acquire the partition locks and scanning the lock table. */ locks = GetRunningTransactionLocks(&nlocks); if (nlocks > 0) LogAccessExclusiveLocks(nlocks, locks); /* * Log details of all in-progress transactions. This should be the last * record we write, because standby will open up when it sees this. */ running = GetRunningTransactionData(); LogCurrentRunningXacts(running); /* GetRunningTransactionData() acquired XidGenLock, we must release it */ LWLockRelease(XidGenLock); }
void ResolveRecoveryConflictWithBufferPin | ( | void | ) |
Definition at line 402 of file standby.c.
References Assert, DeadlockTimeout, EnableTimeoutParams::delay_ms, disable_all_timeouts(), enable_timeout_after(), enable_timeouts(), EnableTimeoutParams::fin_time, GetCurrentTimestamp(), GetStandbyLimitTime(), EnableTimeoutParams::id, InHotStandby, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, ProcWaitForSignal(), SendRecoveryConflictWithBufferPin(), STANDBY_DEADLOCK_TIMEOUT, and EnableTimeoutParams::type.
Referenced by LockBufferForCleanup().
{ TimestampTz ltime; Assert(InHotStandby); ltime = GetStandbyLimitTime(); if (ltime == 0) { /* * We're willing to wait forever for conflicts, so set timeout for * deadlock check only */ enable_timeout_after(STANDBY_DEADLOCK_TIMEOUT, DeadlockTimeout); } else if (GetCurrentTimestamp() >= ltime) { /* * We're already behind, so clear a path as quickly as possible. */ SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); } else { /* * Wake up at ltime, and check for deadlocks as well if we will be * waiting longer than deadlock_timeout */ EnableTimeoutParams timeouts[2]; timeouts[0].id = STANDBY_TIMEOUT; timeouts[0].type = TMPARAM_AT; timeouts[0].fin_time = ltime; timeouts[1].id = STANDBY_DEADLOCK_TIMEOUT; timeouts[1].type = TMPARAM_AFTER; timeouts[1].delay_ms = DeadlockTimeout; enable_timeouts(timeouts, 2); } /* Wait to be signaled by UnpinBuffer() */ ProcWaitForSignal(); /* * Clear any timeout requests established above. We assume here that * the Startup process doesn't have any other timeouts than what this * function uses. If that stops being true, we could cancel the * timeouts individually, but that'd be slower. */ disable_all_timeouts(false); }
void ResolveRecoveryConflictWithDatabase | ( | Oid | dbid | ) |
Definition at line 314 of file standby.c.
References CancelDBBackends(), CountDBBackends(), pg_usleep(), and PROCSIG_RECOVERY_CONFLICT_DATABASE.
Referenced by dbase_redo().
{ /* * We don't do ResolveRecoveryConflictWithVirtualXIDs() here since that * only waits for transactions and completely idle sessions would block * us. This is rare enough that we do this as simply as possible: no wait, * just force them off immediately. * * No locking is required here because we already acquired * AccessExclusiveLock. Anybody trying to connect while we do this will * block during InitPostgres() and then disconnect when they see the * database has been removed. */ while (CountDBBackends(dbid) > 0) { CancelDBBackends(dbid, PROCSIG_RECOVERY_CONFLICT_DATABASE, true); /* * Wait awhile for them to die so that we avoid flooding an * unresponsive backend when system is heavily loaded. */ pg_usleep(10000); } }
Definition at line 340 of file standby.c.
References AccessExclusiveLock, GetConflictingVirtualXIDs(), GetLockConflicts(), InvalidOid, InvalidTransactionId, LOCKACQUIRE_NOT_AVAIL, LockAcquireExtended(), PROCSIG_RECOVERY_CONFLICT_LOCK, ResolveRecoveryConflictWithVirtualXIDs(), and SET_LOCKTAG_RELATION.
Referenced by StandbyAcquireAccessExclusiveLock().
{ VirtualTransactionId *backends; bool lock_acquired = false; int num_attempts = 0; LOCKTAG locktag; SET_LOCKTAG_RELATION(locktag, dbOid, relOid); /* * If blowing away everybody with conflicting locks doesn't work, after * the first two attempts then we just start blowing everybody away until * it does work. We do this because its likely that we either have too * many locks and we just can't get one at all, or that there are many * people crowding for the same table. Recovery must win; the end * justifies the means. */ while (!lock_acquired) { if (++num_attempts < 3) backends = GetLockConflicts(&locktag, AccessExclusiveLock); else backends = GetConflictingVirtualXIDs(InvalidTransactionId, InvalidOid); ResolveRecoveryConflictWithVirtualXIDs(backends, PROCSIG_RECOVERY_CONFLICT_LOCK); if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false) != LOCKACQUIRE_NOT_AVAIL) lock_acquired = true; } }
void ResolveRecoveryConflictWithSnapshot | ( | TransactionId | latestRemovedXid, | |
RelFileNode | node | |||
) |
Definition at line 264 of file standby.c.
References RelFileNode::dbNode, GetConflictingVirtualXIDs(), PROCSIG_RECOVERY_CONFLICT_SNAPSHOT, ResolveRecoveryConflictWithVirtualXIDs(), and TransactionIdIsValid.
Referenced by btree_xlog_delete(), btree_xlog_reuse_page(), heap_xlog_clean(), heap_xlog_cleanup_info(), heap_xlog_freeze(), heap_xlog_visible(), and spgRedoVacuumRedirect().
{ VirtualTransactionId *backends; /* * If we get passed InvalidTransactionId then we are a little surprised, * but it is theoretically possible in normal running. It also happens * when replaying already applied WAL records after a standby crash or * restart. If latestRemovedXid is invalid then there is no conflict. That * rule applies across all record types that suffer from this conflict. */ if (!TransactionIdIsValid(latestRemovedXid)) return; backends = GetConflictingVirtualXIDs(latestRemovedXid, node.dbNode); ResolveRecoveryConflictWithVirtualXIDs(backends, PROCSIG_RECOVERY_CONFLICT_SNAPSHOT); }
void ResolveRecoveryConflictWithTablespace | ( | Oid | tsid | ) |
Definition at line 286 of file standby.c.
References GetConflictingVirtualXIDs(), InvalidOid, InvalidTransactionId, PROCSIG_RECOVERY_CONFLICT_TABLESPACE, and ResolveRecoveryConflictWithVirtualXIDs().
Referenced by tblspc_redo().
{ VirtualTransactionId *temp_file_users; /* * Standby users may be currently using this tablespace for their * temporary files. We only care about current users because * temp_tablespace parameter will just ignore tablespaces that no longer * exist. * * Ask everybody to cancel their queries immediately so we can ensure no * temp files remain and we can remove the tablespace. Nuke the entire * site from orbit, it's the only way to be sure. * * XXX: We could work out the pids of active backends using this * tablespace by examining the temp filenames in the directory. We would * then convert the pids into VirtualXIDs before attempting to cancel * them. * * We don't wait for commit because drop tablespace is non-transactional. */ temp_file_users = GetConflictingVirtualXIDs(InvalidTransactionId, InvalidOid); ResolveRecoveryConflictWithVirtualXIDs(temp_file_users, PROCSIG_RECOVERY_CONFLICT_TABLESPACE); }
static void ResolveRecoveryConflictWithVirtualXIDs | ( | VirtualTransactionId * | waitlist, | |
ProcSignalReason | reason | |||
) | [static] |
Definition at line 191 of file standby.c.
References Assert, CancelVirtualTransaction(), get_ps_display(), GetCurrentTimestamp(), NULL, palloc(), pfree(), pg_usleep(), set_ps_display(), standbyWait_us, TimestampDifferenceExceeds(), update_process_title, VirtualTransactionIdIsValid, VirtualXactLock(), and WaitExceedsMaxStandbyDelay().
Referenced by ResolveRecoveryConflictWithLock(), ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().
{ TimestampTz waitStart; char *new_status; /* Fast exit, to avoid a kernel call if there's no work to be done. */ if (!VirtualTransactionIdIsValid(*waitlist)) return; waitStart = GetCurrentTimestamp(); new_status = NULL; /* we haven't changed the ps display */ while (VirtualTransactionIdIsValid(*waitlist)) { /* reset standbyWait_us for each xact we wait for */ standbyWait_us = STANDBY_INITIAL_WAIT_US; /* wait until the virtual xid is gone */ while (!VirtualXactLock(*waitlist, false)) { /* * Report via ps if we have been waiting for more than 500 msec * (should that be configurable?) */ if (update_process_title && new_status == NULL && TimestampDifferenceExceeds(waitStart, GetCurrentTimestamp(), 500)) { const char *old_status; int len; old_status = get_ps_display(&len); new_status = (char *) palloc(len + 8 + 1); memcpy(new_status, old_status, len); strcpy(new_status + len, " waiting"); set_ps_display(new_status, false); new_status[len] = '\0'; /* truncate off " waiting" */ } /* Is it time to kill it? */ if (WaitExceedsMaxStandbyDelay()) { pid_t pid; /* * Now find out who to throw out of the balloon. */ Assert(VirtualTransactionIdIsValid(*waitlist)); pid = CancelVirtualTransaction(*waitlist, reason); /* * Wait a little bit for it to die so that we avoid flooding * an unresponsive backend when system is heavily loaded. */ if (pid != 0) pg_usleep(5000L); } } /* The virtual transaction is gone now, wait for the next one */ waitlist++; } /* Reset ps display if we changed it */ if (new_status) { set_ps_display(new_status, false); pfree(new_status); } }
static void SendRecoveryConflictWithBufferPin | ( | ProcSignalReason | reason | ) | [static] |
Definition at line 455 of file standby.c.
References Assert, CancelDBBackends(), InvalidOid, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, and PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK.
Referenced by ResolveRecoveryConflictWithBufferPin(), StandbyDeadLockHandler(), and StandbyTimeoutHandler().
{ Assert(reason == PROCSIG_RECOVERY_CONFLICT_BUFFERPIN || reason == PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK); /* * We send signal to all backends to ask them if they are holding the * buffer pin which is delaying the Startup process. We must not set the * conflict flag yet, since most backends will be innocent. Let the * SIGUSR1 handling in each backend decide their own fate. */ CancelDBBackends(InvalidOid, reason, false); }
void ShutdownRecoveryTransactionEnvironment | ( | void | ) |
Definition at line 101 of file standby.c.
References ExpireAllKnownAssignedTransactionIds(), StandbyReleaseAllLocks(), and VirtualXactLockTableCleanup().
Referenced by StartupXLOG().
{ /* Mark all tracked in-progress transactions as finished. */ ExpireAllKnownAssignedTransactionIds(); /* Release all locks the tracked transactions were holding */ StandbyReleaseAllLocks(); /* Cleanup our VirtualTransaction */ VirtualXactLockTableCleanup(); }
void standby_redo | ( | XLogRecPtr | lsn, | |
XLogRecord * | record | |||
) |
Definition at line 761 of file standby.c.
References Assert, xl_standby_lock::dbOid, elog, i, xl_running_xacts::latestCompletedXid, RunningTransactionsData::latestCompletedXid, xl_standby_locks::locks, xl_running_xacts::nextXid, RunningTransactionsData::nextXid, xl_standby_locks::nlocks, xl_running_xacts::oldestRunningXid, RunningTransactionsData::oldestRunningXid, PANIC, ProcArrayApplyRecoveryInfo(), xl_standby_lock::relOid, STANDBY_DISABLED, StandbyAcquireAccessExclusiveLock(), standbyState, xl_running_xacts::subxcnt, RunningTransactionsData::subxcnt, xl_running_xacts::subxid_overflow, RunningTransactionsData::subxid_overflow, xl_running_xacts::xcnt, RunningTransactionsData::xcnt, xl_standby_lock::xid, xl_running_xacts::xids, RunningTransactionsData::xids, XLogRecord::xl_info, XLOG_RUNNING_XACTS, XLOG_STANDBY_LOCK, XLogRecGetData, and XLR_BKP_BLOCK_MASK.
{ uint8 info = record->xl_info & ~XLR_INFO_MASK; /* Backup blocks are not used in standby records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); /* Do nothing if we're not in hot standby mode */ if (standbyState == STANDBY_DISABLED) return; if (info == XLOG_STANDBY_LOCK) { xl_standby_locks *xlrec = (xl_standby_locks *) XLogRecGetData(record); int i; for (i = 0; i < xlrec->nlocks; i++) StandbyAcquireAccessExclusiveLock(xlrec->locks[i].xid, xlrec->locks[i].dbOid, xlrec->locks[i].relOid); } else if (info == XLOG_RUNNING_XACTS) { xl_running_xacts *xlrec = (xl_running_xacts *) XLogRecGetData(record); RunningTransactionsData running; running.xcnt = xlrec->xcnt; running.subxcnt = xlrec->subxcnt; running.subxid_overflow = xlrec->subxid_overflow; running.nextXid = xlrec->nextXid; running.latestCompletedXid = xlrec->latestCompletedXid; running.oldestRunningXid = xlrec->oldestRunningXid; running.xids = xlrec->xids; ProcArrayApplyRecoveryInfo(&running); } else elog(PANIC, "standby_redo: unknown op code %u", info); }
void StandbyAcquireAccessExclusiveLock | ( | TransactionId | xid, | |
Oid | dbOid, | |||
Oid | relOid | |||
) |
Definition at line 566 of file standby.c.
References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, lappend(), LOCKACQUIRE_NOT_AVAIL, LockAcquireExtended(), OidIsValid, palloc(), xl_standby_lock::relOid, ResolveRecoveryConflictWithLock(), SET_LOCKTAG_RELATION, trace_recovery(), TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdIsValid, and xl_standby_lock::xid.
Referenced by lock_twophase_standby_recover(), and standby_redo().
{ xl_standby_lock *newlock; LOCKTAG locktag; /* Already processed? */ if (!TransactionIdIsValid(xid) || TransactionIdDidCommit(xid) || TransactionIdDidAbort(xid)) return; elog(trace_recovery(DEBUG4), "adding recovery lock: db %u rel %u", dbOid, relOid); /* dbOid is InvalidOid when we are locking a shared relation. */ Assert(OidIsValid(relOid)); newlock = palloc(sizeof(xl_standby_lock)); newlock->xid = xid; newlock->dbOid = dbOid; newlock->relOid = relOid; RecoveryLockList = lappend(RecoveryLockList, newlock); /* * Attempt to acquire the lock as requested, if not resolve conflict */ SET_LOCKTAG_RELATION(locktag, newlock->dbOid, newlock->relOid); if (LockAcquireExtended(&locktag, AccessExclusiveLock, true, true, false) == LOCKACQUIRE_NOT_AVAIL) ResolveRecoveryConflictWithLock(newlock->dbOid, newlock->relOid); }
void StandbyDeadLockHandler | ( | void | ) |
Definition at line 515 of file standby.c.
References PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK, and SendRecoveryConflictWithBufferPin().
Referenced by StartupProcessMain().
void StandbyReleaseAllLocks | ( | void | ) |
Definition at line 659 of file standby.c.
References AccessExclusiveLock, xl_standby_lock::dbOid, DEBUG2, DEBUG4, elog, lfirst, list_delete_cell(), list_head(), lnext, LockRelease(), LOG, pfree(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, trace_recovery(), and xl_standby_lock::xid.
Referenced by ShutdownRecoveryTransactionEnvironment().
{ ListCell *cell, *prev, *next; LOCKTAG locktag; elog(trace_recovery(DEBUG2), "release all standby locks"); prev = NULL; for (cell = list_head(RecoveryLockList); cell; cell = next) { xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell); next = lnext(cell); elog(trace_recovery(DEBUG4), "releasing recovery lock: xid %u db %u rel %u", lock->xid, lock->dbOid, lock->relOid); SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid); if (!LockRelease(&locktag, AccessExclusiveLock, true)) elog(LOG, "RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u", lock->xid, lock->dbOid, lock->relOid); RecoveryLockList = list_delete_cell(RecoveryLockList, cell, prev); pfree(lock); } }
static void StandbyReleaseLocks | ( | TransactionId | xid | ) | [static] |
Definition at line 600 of file standby.c.
References AccessExclusiveLock, xl_standby_lock::dbOid, DEBUG4, elog, lfirst, list_delete_cell(), list_head(), lnext, LockRelease(), LOG, pfree(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, trace_recovery(), TransactionIdIsValid, and xl_standby_lock::xid.
Referenced by StandbyReleaseLockTree().
{ ListCell *cell, *prev, *next; /* * Release all matching locks and remove them from list */ prev = NULL; for (cell = list_head(RecoveryLockList); cell; cell = next) { xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell); next = lnext(cell); if (!TransactionIdIsValid(xid) || lock->xid == xid) { LOCKTAG locktag; elog(trace_recovery(DEBUG4), "releasing recovery lock: xid %u db %u rel %u", lock->xid, lock->dbOid, lock->relOid); SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid); if (!LockRelease(&locktag, AccessExclusiveLock, true)) elog(LOG, "RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u", lock->xid, lock->dbOid, lock->relOid); RecoveryLockList = list_delete_cell(RecoveryLockList, cell, prev); pfree(lock); } else prev = cell; } }
void StandbyReleaseLockTree | ( | TransactionId | xid, | |
int | nsubxids, | |||
TransactionId * | subxids | |||
) |
Definition at line 645 of file standby.c.
References i, and StandbyReleaseLocks().
Referenced by RecoverPreparedTransactions(), xact_redo_abort(), and xact_redo_commit_internal().
{ int i; StandbyReleaseLocks(xid); for (i = 0; i < nsubxids; i++) StandbyReleaseLocks(subxids[i]); }
void StandbyReleaseOldLocks | ( | int | nxids, | |
TransactionId * | xids | |||
) |
Definition at line 694 of file standby.c.
References AccessExclusiveLock, Assert, xl_standby_lock::dbOid, DEBUG4, elog, i, lfirst, list_delete_cell(), list_head(), lnext, LockRelease(), LOG, pfree(), xl_standby_lock::relOid, SET_LOCKTAG_RELATION, StandbyTransactionIdIsPrepared(), trace_recovery(), TransactionIdIsValid, and xl_standby_lock::xid.
Referenced by ProcArrayApplyRecoveryInfo().
{ ListCell *cell, *prev, *next; LOCKTAG locktag; prev = NULL; for (cell = list_head(RecoveryLockList); cell; cell = next) { xl_standby_lock *lock = (xl_standby_lock *) lfirst(cell); bool remove = false; next = lnext(cell); Assert(TransactionIdIsValid(lock->xid)); if (StandbyTransactionIdIsPrepared(lock->xid)) remove = false; else { int i; bool found = false; for (i = 0; i < nxids; i++) { if (lock->xid == xids[i]) { found = true; break; } } /* * If its not a running transaction, remove it. */ if (!found) remove = true; } if (remove) { elog(trace_recovery(DEBUG4), "releasing recovery lock: xid %u db %u rel %u", lock->xid, lock->dbOid, lock->relOid); SET_LOCKTAG_RELATION(locktag, lock->dbOid, lock->relOid); if (!LockRelease(&locktag, AccessExclusiveLock, true)) elog(LOG, "RecoveryLockList contains entry for lock no longer recorded by lock manager: xid %u database %u relation %u", lock->xid, lock->dbOid, lock->relOid); RecoveryLockList = list_delete_cell(RecoveryLockList, cell, prev); pfree(lock); } else prev = cell; } }
void StandbyTimeoutHandler | ( | void | ) |
Definition at line 526 of file standby.c.
References disable_timeout(), PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, SendRecoveryConflictWithBufferPin(), and STANDBY_DEADLOCK_TIMEOUT.
Referenced by StartupProcessMain().
{ /* forget any pending STANDBY_DEADLOCK_TIMEOUT request */ disable_timeout(STANDBY_DEADLOCK_TIMEOUT, false); SendRecoveryConflictWithBufferPin(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN); }
static bool WaitExceedsMaxStandbyDelay | ( | void | ) | [static] |
Definition at line 159 of file standby.c.
References GetCurrentTimestamp(), GetStandbyLimitTime(), pg_usleep(), and standbyWait_us.
Referenced by ResolveRecoveryConflictWithVirtualXIDs().
{ TimestampTz ltime; /* Are we past the limit time? */ ltime = GetStandbyLimitTime(); if (ltime && GetCurrentTimestamp() >= ltime) return true; /* * Sleep a bit (this is essential to avoid busy-waiting). */ pg_usleep(standbyWait_us); /* * Progressively increase the sleep times, but not to more than 1s, since * pg_usleep isn't interruptable on some platforms. */ standbyWait_us *= 2; if (standbyWait_us > 1000000) standbyWait_us = 1000000; return false; }
int max_standby_archive_delay = 30 * 1000 |
Definition at line 36 of file standby.c.
Referenced by GetStandbyLimitTime().
int max_standby_streaming_delay = 30 * 1000 |
Definition at line 37 of file standby.c.
Referenced by GetStandbyLimitTime().
List* RecoveryLockList [static] |
int standbyWait_us = STANDBY_INITIAL_WAIT_US [static] |
Definition at line 151 of file standby.c.
Referenced by ResolveRecoveryConflictWithVirtualXIDs(), and WaitExceedsMaxStandbyDelay().
Definition at line 35 of file standby.c.
Referenced by GetOldestXmin(), and GetSnapshotData().