1/*-------------------------------------------------------------------------
4 * POSTGRES lock manager code
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/storage/lmgr/lmgr.c
13 *-------------------------------------------------------------------------
31 * Per-backend counter for generating speculative insertion tokens.
33 * This may wrap around, but that's OK as it's only used for the short
34 * duration between inserting a tuple and checking that there are no (unique)
35 * constraint violations. It's theoretically possible that a backend sees a
36 * tuple that was speculatively inserted by another backend, but before it has
37 * started waiting on the token, the other backend completes its insertion,
38 * and then performs 2^32 unrelated insertions. And after all that, the
39 * first backend finally calls SpeculativeInsertionLockAcquire(), with the
40 * intention of waiting for the first insertion to complete, but ends up
41 * waiting for the latest unrelated insertion instead. Even then, nothing
42 * particularly bad happens: in the worst case they deadlock, causing one of
43 * the transactions to abort.
49 * Struct to hold context info for transaction lock waits.
51 * 'oper' is the operation that needs to wait for the other transaction; 'rel'
52 * and 'ctid' specify the address of the tuple being waited for.
64 * RelationInitLockInfo
65 * Initializes the lock information in a relation descriptor.
67 * relcache.c must call this during creation of any reldesc.
77 if (relation->
rd_rel->relisshared)
84 * SetLocktagRelationOid
85 * Set up a locktag for a relation, given only relation OID
103 * Lock a relation given only its OID. This should generally be used
104 * before attempting to open the relation's relcache entry.
119 * Now that we have the lock, check for invalidation messages, so that we
120 * will update or flush any stale relcache entry before we try to use it.
121 * RangeVarGetRelid() specifically relies on us for this. We can skip
122 * this in the not-uncommon case that we already had the same type of lock
123 * being requested, since then no one else could have modified the
124 * relcache entry in an undesirable way. (In the case where our own xact
125 * modifies the rel, the relcache update happens via
126 * CommandCounterIncrement, not here.)
128 * However, in corner cases where code acts on tables (usually catalogs)
129 * recursively, we might get here while still processing invalidation
130 * messages in some outer execution of this function or a sibling. The
131 * "cleared" status of the lock tells us whether we really are done
132 * absorbing relevant inval messages.
142 * ConditionalLockRelationOid
144 * As above, but only lock if we can get the lock without blocking.
145 * Returns true iff the lock was acquired.
147 * NOTE: we do not currently need conditional versions of all the
148 * LockXXX routines in this file, but they could easily be added if needed.
166 * Now that we have the lock, check for invalidation messages; see notes
167 * in LockRelationOid.
181 * Lock, given a LockRelId. Same as LockRelationOid but take LockRelId as an
197 * Now that we have the lock, check for invalidation messages; see notes
198 * in LockRelationOid.
210 * Unlock, given a LockRelId. This is preferred over UnlockRelationOid
226 * Unlock, given only a relation Oid. Use UnlockRelationId if you can.
241 * This is a convenience routine for acquiring an additional lock on an
242 * already-open relation. Never try to do "relation_open(foo, NoLock)"
243 * and then lock with this.
260 * Now that we have the lock, check for invalidation messages; see notes
261 * in LockRelationOid.
271 * ConditionalLockRelation
273 * This is a convenience routine for acquiring an additional lock on an
274 * already-open relation. Never try to do "relation_open(foo, NoLock)"
275 * and then lock with this.
295 * Now that we have the lock, check for invalidation messages; see notes
296 * in LockRelationOid.
310 * This is a convenience routine for unlocking a relation without also
326 * CheckRelationLockedByMe
328 * Returns true if current transaction holds a lock on 'relation' of mode
329 * 'lockmode'. If 'orstronger' is true, a stronger lockmode is also OK.
330 * ("Stronger" is defined as "numerically higher", which is a bit
331 * semantically dubious but is OK for the purposes we use this for.)
346 * CheckRelationOidLockedByMe
348 * Like the above, but takes an OID as argument.
361 * LockHasWaitersRelation
363 * This is a function to check whether someone else is waiting for a
364 * lock which we are currently holding.
379 * LockRelationIdForSession
381 * This routine grabs a session-level lock on the target relation. The
382 * session lock persists across transaction boundaries. It will be removed
383 * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
384 * or if the backend exits.
386 * Note that one should also grab a transaction-level lock on the rel
387 * in any transaction that actually uses the rel, to ensure that the
388 * relcache entry is up to date.
401 * UnlockRelationIdForSession
414 * LockRelationForExtension
416 * This lock tag is used to interlock addition of pages to relations.
417 * We need such locking because bufmgr/smgr definition of P_NEW is not
418 * race-condition-proof.
420 * We assume the caller is already holding some type of regular lock on
421 * the relation, so no AcceptInvalidationMessages call is needed here.
436 * ConditionalLockRelationForExtension
438 * As above, but only lock if we can get the lock without blocking.
439 * Returns true iff the lock was acquired.
454 * RelationExtensionLockWaiterCount
456 * Count the number of processes waiting for the given relation extension lock.
471 * UnlockRelationForExtension
486 * LockDatabaseFrozenIds
488 * This allows one backend per database to execute vac_update_datfrozenxid().
503 * Obtain a page-level lock. This is currently used by some index access
504 * methods to lock individual index pages.
520 * ConditionalLockPage
522 * As above, but only lock if we can get the lock without blocking.
523 * Returns true iff the lock was acquired.
557 * Obtain a tuple-level lock. This is used in a less-than-intuitive fashion
558 * because we can't afford to keep a separate lock in shared memory for every
559 * tuple. See heap_lock_tuple before using this!
576 * ConditionalLockTuple
578 * As above, but only lock if we can get the lock without blocking.
579 * Returns true iff the lock was acquired.
615 * XactLockTableInsert
617 * Insert a lock showing that the given transaction ID is running ---
618 * this is done when an XID is acquired by a transaction or subtransaction.
619 * The lock can then be used to wait for the transaction to finish.
632 * XactLockTableDelete
634 * Delete the lock showing that the given transaction ID is running.
635 * (This is never used for main transaction IDs; those locks are only
636 * released implicitly at transaction end. But we do use it for subtrans IDs.)
651 * Wait for the specified transaction to commit or abort. If an operation
652 * is specified, an error context callback is set up. If 'oper' is passed as
653 * None, no error context callback is set up.
655 * Note that this does the right thing for subtransactions: if we wait on a
656 * subtransaction, we will exit as soon as it aborts or its top parent commits.
657 * It takes some extra work to ensure this, because to save on shared memory
658 * the XID lock of a subtransaction is released when it ends, whether
659 * successfully or unsuccessfully. So we have to check if it's "still running"
660 * and if so wait for its parent.
672 * If an operation is specified, set up our verbose error context
705 * If the Xid belonged to a subtransaction, then the lock would have
706 * gone away as soon as it was finished; for correct tuple visibility,
707 * the right action is to wait on its parent transaction to go away.
708 * But instead of going levels up one by one, we can just wait for the
709 * topmost transaction to finish with the same end result, which also
710 * incurs less locktable traffic.
712 * Some uses of this function don't involve tuple visibility -- such
713 * as when building snapshots for logical decoding. It is possible to
714 * see a transaction in ProcArray before it registers itself in the
715 * locktable. The topmost transaction in that case is the same xid,
716 * so we try again after a short sleep. (Don't sleep the first time
717 * through, to avoid slowing down the normal case.)
733 * ConditionalXactLockTableWait
735 * As above, but only lock if we can get the lock without blocking.
736 * Returns true if the lock was acquired.
761 /* See XactLockTableWait about this case */
775 * SpeculativeInsertionLockAcquire
777 * Insert a lock showing that the given transaction ID is inserting a tuple,
778 * but hasn't yet decided whether it's going to keep it. The lock can then be
779 * used to wait for the decision to go ahead with the insertion, or aborting
782 * The token is used to distinguish multiple insertions by the same
783 * transaction. It is returned to caller.
793 * Check for wrap-around. Zero means no token is held, so don't use that.
806 * SpeculativeInsertionLockRelease
808 * Delete the lock showing that the given transaction is speculatively
822 * SpeculativeInsertionWait
824 * Wait for the specified transaction to finish or abort the insertion of a
842 * XactLockTableWaitErrorCb
843 * Error context callback for transaction lock waits.
851 * We would like to print schema name too, but that would require a
862 cxt =
gettext_noop(
"while updating tuple (%u,%u) in relation \"%s\"");
865 cxt =
gettext_noop(
"while deleting tuple (%u,%u) in relation \"%s\"");
868 cxt =
gettext_noop(
"while locking tuple (%u,%u) in relation \"%s\"");
871 cxt =
gettext_noop(
"while locking updated version (%u,%u) of tuple in relation \"%s\"");
874 cxt =
gettext_noop(
"while inserting index tuple (%u,%u) in relation \"%s\"");
877 cxt =
gettext_noop(
"while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
880 cxt =
gettext_noop(
"while rechecking updated tuple (%u,%u) in relation \"%s\"");
883 cxt =
gettext_noop(
"while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
898 * WaitForLockersMultiple
899 * Wait until no transaction holds locks that conflict with the given
900 * locktags at the given lockmode.
902 * To do this, obtain the current list of lockers, and wait on their VXIDs
903 * until they are finished.
905 * Note we don't try to acquire the locks on the given locktags, only the
906 * VXIDs and XIDs of their lock holders; if somebody grabs a conflicting lock
907 * on the objects after we obtained our initial list of lockers, we will not
918 /* Done if no locks to wait for */
922 /* Collect the transactions we need to wait on */
923 foreach(lc, locktags)
939 * Note: GetLockConflicts() never reports our own xid, hence we need not
940 * check for that. Also, prepared xacts are reported and awaited.
943 /* Finally wait for each such transaction to complete */
950 /* If requested, publish who we're going to wait for. */
968 const int index[] = {
986 * Same as WaitForLockersMultiple, for a single lock tag.
1000 * LockDatabaseObject
1002 * Obtain a lock on a general object of the current database. Don't use
1003 * this for shared objects (such as tablespaces). It's unwise to apply it
1004 * to relations, also, since a lock taken this way will NOT conflict with
1005 * locks taken via LockRelation and friends.
1021 /* Make sure syscaches are up-to-date with any changes we waited for */
1026 * ConditionalLockDatabaseObject
1028 * As above, but only lock if we can get the lock without blocking.
1029 * Returns true iff the lock was acquired.
1052 * Now that we have the lock, check for invalidation messages; see notes
1053 * in LockRelationOid.
1065 * UnlockDatabaseObject
1085 * Obtain a lock on a shared-across-databases object.
1101 /* Make sure syscaches are up-to-date with any changes we waited for */
1106 * ConditionalLockSharedObject
1108 * As above, but only lock if we can get the lock without blocking.
1109 * Returns true iff the lock was acquired.
1132 * Now that we have the lock, check for invalidation messages; see notes
1133 * in LockRelationOid.
1145 * UnlockSharedObject
1163 * LockSharedObjectForSession
1165 * Obtain a session-level lock on a shared-across-databases object.
1166 * See LockRelationIdForSession for notes about session-level locks.
1184 * UnlockSharedObjectForSession
1202 * LockApplyTransactionForSession
1204 * Obtain a session-level lock on a transaction being applied on a logical
1205 * replication subscriber. See LockRelationIdForSession for notes about
1206 * session-level locks.
1224 * UnlockApplyTransactionForSession
1242 * Append a description of a lockable object to buf.
1244 * Ideally we would print names for the numeric values, but that requires
1245 * getting locks on system tables, which might cause problems since this is
1246 * typically used to report deadlock situations.
1255 _(
"relation %u of database %u"),
1261 _(
"extension of relation %u of database %u"),
1267 _(
"pg_database.datfrozenxid of database %u"),
1272 _(
"page %u of relation %u of database %u"),
1279 _(
"tuple (%u,%u) of relation %u of database %u"),
1287 _(
"transaction %u"),
1292 _(
"virtual transaction %d/%u"),
1298 _(
"speculative token %u of transaction %u"),
1304 _(
"object %u of class %u of database %u"),
1310 /* reserved for old contrib code, now on pgfoundry */
1312 _(
"user lock [%u,%u,%u]"),
1319 _(
"advisory lock [%u,%u,%u,%u]"),
1327 _(
"remote transaction %u of subscription %u of database %u"),
1334 _(
"unrecognized locktag type %d"),
1341 * GetLockNameFromTagType
1343 * Given locktag type, return the corresponding lock name.
void pgstat_progress_update_param(int index, int64 val)
void pgstat_progress_update_multi_param(int nparam, const int *index, const int64 *val)
static Datum values[MAXATTR]
#define OidIsValid(objectId)
bool IsSharedRelation(Oid relationId)
ErrorContextCallback * error_context_stack
Assert(PointerIsAligned(start, uint64))
void AcceptInvalidationMessages(void)
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
static bool ItemPointerIsValid(const ItemPointerData *pointer)
List * lappend(List *list, void *datum)
void list_free(List *list)
void list_free_deep(List *list)
bool ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
void UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
void LockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
bool ConditionalLockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode, bool logLockFailure)
void UnlockRelationOid(Oid relid, LOCKMODE lockmode)
void LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
void UnlockRelation(Relation relation, LOCKMODE lockmode)
void DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
void SpeculativeInsertionWait(TransactionId xid, uint32 token)
bool ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
void UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
void WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
void LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
void RelationInitLockInfo(Relation relation)
void LockRelationOid(Oid relid, LOCKMODE lockmode)
void LockRelation(Relation relation, LOCKMODE lockmode)
void UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
void WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
bool ConditionalXactLockTableWait(TransactionId xid, bool logLockFailure)
void XactLockTableDelete(TransactionId xid)
void XactLockTableInsert(TransactionId xid)
uint32 SpeculativeInsertionLockAcquire(TransactionId xid)
void LockRelationForExtension(Relation relation, LOCKMODE lockmode)
bool CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
void UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid, LOCKMODE lockmode)
void SpeculativeInsertionLockRelease(TransactionId xid)
static void XactLockTableWaitErrorCb(void *arg)
void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
bool ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
bool CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
static void SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
void UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
bool ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
static uint32 speculativeInsertionToken
void LockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
bool ConditionalLockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
void LockDatabaseFrozenIds(LOCKMODE lockmode)
struct XactLockTableWaitInfo XactLockTableWaitInfo
void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
const char * GetLockNameFromTagType(uint16 locktag_type)
void UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
void XactLockTableWait(TransactionId xid, Relation rel, const ItemPointerData *ctid, XLTW_Oper oper)
void LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid, LOCKMODE lockmode)
void LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
void LockRelationId(LockRelId *relid, LOCKMODE lockmode)
bool LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
void UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid, LOCKMODE lockmode)
int RelationExtensionLockWaiterCount(Relation relation)
@ XLTW_RecheckExclusionConstr
LockAcquireResult LockAcquire(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait)
bool LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode, bool orstronger)
int LockWaiterCount(const LOCKTAG *locktag)
bool LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
bool VirtualXactLock(VirtualTransactionId vxid, bool wait)
VirtualTransactionId * GetLockConflicts(const LOCKTAG *locktag, LOCKMODE lockmode, int *countp)
LockAcquireResult LockAcquireExtended(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock, bool dontWait, bool reportMemoryError, LOCALLOCK **locallockp, bool logLockFailure)
bool LockHasWaiters(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
void MarkLockClear(LOCALLOCK *locallock)
#define SET_LOCKTAG_DATABASE_FROZEN_IDS(locktag, dboid)
#define SET_LOCKTAG_RELATION_EXTEND(locktag, dboid, reloid)
@ LOCKTAG_RELATION_EXTEND
@ LOCKTAG_SPECULATIVE_TOKEN
@ LOCKTAG_APPLY_TRANSACTION
@ LOCKTAG_DATABASE_FROZEN_IDS
@ LOCKTAG_VIRTUALTRANSACTION
#define SET_LOCKTAG_APPLY_TRANSACTION(locktag, dboid, suboid, xid, objid)
#define VirtualTransactionIdIsValid(vxid)
#define SET_LOCKTAG_TRANSACTION(locktag, xid)
#define SET_LOCKTAG_RELATION(locktag, dboid, reloid)
#define SET_LOCKTAG_SPECULATIVE_INSERTION(locktag, xid, token)
#define LOCKTAG_LAST_TYPE
#define SET_LOCKTAG_PAGE(locktag, dboid, reloid, blocknum)
#define SET_LOCKTAG_TUPLE(locktag, dboid, reloid, blocknum, offnum)
#define SET_LOCKTAG_OBJECT(locktag, dboid, classoid, objoid, objsubid)
@ LOCKACQUIRE_ALREADY_CLEAR
const char *const LockTagTypeNames[]
#define CHECK_FOR_INTERRUPTS()
Operator oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId, bool noError, int location)
PGPROC * ProcNumberGetProc(ProcNumber procNumber)
bool TransactionIdIsInProgress(TransactionId xid)
#define PROGRESS_WAITFOR_DONE
#define PROGRESS_WAITFOR_TOTAL
#define PROGRESS_WAITFOR_CURRENT_PID
#define RelationGetRelid(relation)
#define RelationGetRelationName(relation)
#define RelationIsValid(relation)
void pg_usleep(long microsec)
void appendStringInfo(StringInfo str, const char *fmt,...)
const ItemPointerData * ctid
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
static void callback(struct sockaddr *addr, struct sockaddr *mask, void *unused)
#define TransactionIdEquals(id1, id2)
#define TransactionIdIsValid(xid)
TransactionId GetTopTransactionIdIfAny(void)