LCOV - code coverage report
Current view: top level - src/backend/storage/lmgr - lmgr.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 73.7 % 396 292
Test Date: 2026-02-17 17:20:33 Functions: 87.5 % 48 42
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * lmgr.c
       4              :  *    POSTGRES lock manager code
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/storage/lmgr/lmgr.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : 
      16              : #include "postgres.h"
      17              : 
      18              : #include "access/subtrans.h"
      19              : #include "access/xact.h"
      20              : #include "catalog/catalog.h"
      21              : #include "commands/progress.h"
      22              : #include "miscadmin.h"
      23              : #include "pgstat.h"
      24              : #include "storage/lmgr.h"
      25              : #include "storage/proc.h"
      26              : #include "storage/procarray.h"
      27              : #include "utils/inval.h"
      28              : 
      29              : 
      30              : /*
      31              :  * Per-backend counter for generating speculative insertion tokens.
      32              :  *
      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.
      44              :  */
      45              : static uint32 speculativeInsertionToken = 0;
      46              : 
      47              : 
      48              : /*
      49              :  * Struct to hold context info for transaction lock waits.
      50              :  *
      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.
      53              :  */
      54              : typedef struct XactLockTableWaitInfo
      55              : {
      56              :     XLTW_Oper   oper;
      57              :     Relation    rel;
      58              :     const ItemPointerData *ctid;
      59              : } XactLockTableWaitInfo;
      60              : 
      61              : static void XactLockTableWaitErrorCb(void *arg);
      62              : 
      63              : /*
      64              :  * RelationInitLockInfo
      65              :  *      Initializes the lock information in a relation descriptor.
      66              :  *
      67              :  *      relcache.c must call this during creation of any reldesc.
      68              :  */
      69              : void
      70      3083663 : RelationInitLockInfo(Relation relation)
      71              : {
      72              :     Assert(RelationIsValid(relation));
      73              :     Assert(OidIsValid(RelationGetRelid(relation)));
      74              : 
      75      3083663 :     relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
      76              : 
      77      3083663 :     if (relation->rd_rel->relisshared)
      78       465891 :         relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
      79              :     else
      80      2617772 :         relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
      81      3083663 : }
      82              : 
      83              : /*
      84              :  * SetLocktagRelationOid
      85              :  *      Set up a locktag for a relation, given only relation OID
      86              :  */
      87              : static inline void
      88     21263702 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
      89              : {
      90              :     Oid         dbid;
      91              : 
      92     21263702 :     if (IsSharedRelation(relid))
      93       974877 :         dbid = InvalidOid;
      94              :     else
      95     20288825 :         dbid = MyDatabaseId;
      96              : 
      97     21263702 :     SET_LOCKTAG_RELATION(*tag, dbid, relid);
      98     21263702 : }
      99              : 
     100              : /*
     101              :  *      LockRelationOid
     102              :  *
     103              :  * Lock a relation given only its OID.  This should generally be used
     104              :  * before attempting to open the relation's relcache entry.
     105              :  */
     106              : void
     107     21053949 : LockRelationOid(Oid relid, LOCKMODE lockmode)
     108              : {
     109              :     LOCKTAG     tag;
     110              :     LOCALLOCK  *locallock;
     111              :     LockAcquireResult res;
     112              : 
     113     21053949 :     SetLocktagRelationOid(&tag, relid);
     114              : 
     115     21053949 :     res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock,
     116              :                               false);
     117              : 
     118              :     /*
     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.)
     127              :      *
     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.
     133              :      */
     134     21053940 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     135              :     {
     136     19059472 :         AcceptInvalidationMessages();
     137     19059472 :         MarkLockClear(locallock);
     138              :     }
     139     21053940 : }
     140              : 
     141              : /*
     142              :  *      ConditionalLockRelationOid
     143              :  *
     144              :  * As above, but only lock if we can get the lock without blocking.
     145              :  * Returns true iff the lock was acquired.
     146              :  *
     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.
     149              :  */
     150              : bool
     151          928 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
     152              : {
     153              :     LOCKTAG     tag;
     154              :     LOCALLOCK  *locallock;
     155              :     LockAcquireResult res;
     156              : 
     157          928 :     SetLocktagRelationOid(&tag, relid);
     158              : 
     159          928 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
     160              :                               false);
     161              : 
     162          928 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     163           18 :         return false;
     164              : 
     165              :     /*
     166              :      * Now that we have the lock, check for invalidation messages; see notes
     167              :      * in LockRelationOid.
     168              :      */
     169          910 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     170              :     {
     171          903 :         AcceptInvalidationMessages();
     172          903 :         MarkLockClear(locallock);
     173              :     }
     174              : 
     175          910 :     return true;
     176              : }
     177              : 
     178              : /*
     179              :  *      LockRelationId
     180              :  *
     181              :  * Lock, given a LockRelId.  Same as LockRelationOid but take LockRelId as an
     182              :  * input.
     183              :  */
     184              : void
     185       113206 : LockRelationId(LockRelId *relid, LOCKMODE lockmode)
     186              : {
     187              :     LOCKTAG     tag;
     188              :     LOCALLOCK  *locallock;
     189              :     LockAcquireResult res;
     190              : 
     191       113206 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     192              : 
     193       113206 :     res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock,
     194              :                               false);
     195              : 
     196              :     /*
     197              :      * Now that we have the lock, check for invalidation messages; see notes
     198              :      * in LockRelationOid.
     199              :      */
     200       113206 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     201              :     {
     202       113206 :         AcceptInvalidationMessages();
     203       113206 :         MarkLockClear(locallock);
     204              :     }
     205       113206 : }
     206              : 
     207              : /*
     208              :  *      UnlockRelationId
     209              :  *
     210              :  * Unlock, given a LockRelId.  This is preferred over UnlockRelationOid
     211              :  * for speed reasons.
     212              :  */
     213              : void
     214     18968248 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
     215              : {
     216              :     LOCKTAG     tag;
     217              : 
     218     18968248 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     219              : 
     220     18968248 :     LockRelease(&tag, lockmode, false);
     221     18968248 : }
     222              : 
     223              : /*
     224              :  *      UnlockRelationOid
     225              :  *
     226              :  * Unlock, given only a relation Oid.  Use UnlockRelationId if you can.
     227              :  */
     228              : void
     229       208825 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
     230              : {
     231              :     LOCKTAG     tag;
     232              : 
     233       208825 :     SetLocktagRelationOid(&tag, relid);
     234              : 
     235       208825 :     LockRelease(&tag, lockmode, false);
     236       208825 : }
     237              : 
     238              : /*
     239              :  *      LockRelation
     240              :  *
     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.
     244              :  */
     245              : void
     246        24877 : LockRelation(Relation relation, LOCKMODE lockmode)
     247              : {
     248              :     LOCKTAG     tag;
     249              :     LOCALLOCK  *locallock;
     250              :     LockAcquireResult res;
     251              : 
     252        24877 :     SET_LOCKTAG_RELATION(tag,
     253              :                          relation->rd_lockInfo.lockRelId.dbId,
     254              :                          relation->rd_lockInfo.lockRelId.relId);
     255              : 
     256        24877 :     res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock,
     257              :                               false);
     258              : 
     259              :     /*
     260              :      * Now that we have the lock, check for invalidation messages; see notes
     261              :      * in LockRelationOid.
     262              :      */
     263        24877 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     264              :     {
     265        24877 :         AcceptInvalidationMessages();
     266        24877 :         MarkLockClear(locallock);
     267              :     }
     268        24877 : }
     269              : 
     270              : /*
     271              :  *      ConditionalLockRelation
     272              :  *
     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.
     276              :  */
     277              : bool
     278          354 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
     279              : {
     280              :     LOCKTAG     tag;
     281              :     LOCALLOCK  *locallock;
     282              :     LockAcquireResult res;
     283              : 
     284          354 :     SET_LOCKTAG_RELATION(tag,
     285              :                          relation->rd_lockInfo.lockRelId.dbId,
     286              :                          relation->rd_lockInfo.lockRelId.relId);
     287              : 
     288          354 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
     289              :                               false);
     290              : 
     291          354 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     292          204 :         return false;
     293              : 
     294              :     /*
     295              :      * Now that we have the lock, check for invalidation messages; see notes
     296              :      * in LockRelationOid.
     297              :      */
     298          150 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     299              :     {
     300          150 :         AcceptInvalidationMessages();
     301          150 :         MarkLockClear(locallock);
     302              :     }
     303              : 
     304          150 :     return true;
     305              : }
     306              : 
     307              : /*
     308              :  *      UnlockRelation
     309              :  *
     310              :  * This is a convenience routine for unlocking a relation without also
     311              :  * closing it.
     312              :  */
     313              : void
     314          150 : UnlockRelation(Relation relation, LOCKMODE lockmode)
     315              : {
     316              :     LOCKTAG     tag;
     317              : 
     318          150 :     SET_LOCKTAG_RELATION(tag,
     319              :                          relation->rd_lockInfo.lockRelId.dbId,
     320              :                          relation->rd_lockInfo.lockRelId.relId);
     321              : 
     322          150 :     LockRelease(&tag, lockmode, false);
     323          150 : }
     324              : 
     325              : /*
     326              :  *      CheckRelationLockedByMe
     327              :  *
     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.)
     332              :  */
     333              : bool
     334            0 : CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
     335              : {
     336              :     LOCKTAG     tag;
     337              : 
     338            0 :     SET_LOCKTAG_RELATION(tag,
     339              :                          relation->rd_lockInfo.lockRelId.dbId,
     340              :                          relation->rd_lockInfo.lockRelId.relId);
     341              : 
     342            0 :     return LockHeldByMe(&tag, lockmode, orstronger);
     343              : }
     344              : 
     345              : /*
     346              :  *      CheckRelationOidLockedByMe
     347              :  *
     348              :  * Like the above, but takes an OID as argument.
     349              :  */
     350              : bool
     351            0 : CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger)
     352              : {
     353              :     LOCKTAG     tag;
     354              : 
     355            0 :     SetLocktagRelationOid(&tag, relid);
     356              : 
     357            0 :     return LockHeldByMe(&tag, lockmode, orstronger);
     358              : }
     359              : 
     360              : /*
     361              :  *      LockHasWaitersRelation
     362              :  *
     363              :  * This is a function to check whether someone else is waiting for a
     364              :  * lock which we are currently holding.
     365              :  */
     366              : bool
     367            0 : LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
     368              : {
     369              :     LOCKTAG     tag;
     370              : 
     371            0 :     SET_LOCKTAG_RELATION(tag,
     372              :                          relation->rd_lockInfo.lockRelId.dbId,
     373              :                          relation->rd_lockInfo.lockRelId.relId);
     374              : 
     375            0 :     return LockHasWaiters(&tag, lockmode, false);
     376              : }
     377              : 
     378              : /*
     379              :  *      LockRelationIdForSession
     380              :  *
     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.
     385              :  *
     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.
     389              :  */
     390              : void
     391       117650 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     392              : {
     393              :     LOCKTAG     tag;
     394              : 
     395       117650 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     396              : 
     397       117650 :     (void) LockAcquire(&tag, lockmode, true, false);
     398       117650 : }
     399              : 
     400              : /*
     401              :  *      UnlockRelationIdForSession
     402              :  */
     403              : void
     404       117629 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     405              : {
     406              :     LOCKTAG     tag;
     407              : 
     408       117629 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     409              : 
     410       117629 :     LockRelease(&tag, lockmode, true);
     411       117629 : }
     412              : 
     413              : /*
     414              :  *      LockRelationForExtension
     415              :  *
     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.
     419              :  *
     420              :  * We assume the caller is already holding some type of regular lock on
     421              :  * the relation, so no AcceptInvalidationMessages call is needed here.
     422              :  */
     423              : void
     424       162260 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
     425              : {
     426              :     LOCKTAG     tag;
     427              : 
     428       162260 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     429              :                                 relation->rd_lockInfo.lockRelId.dbId,
     430              :                                 relation->rd_lockInfo.lockRelId.relId);
     431              : 
     432       162260 :     (void) LockAcquire(&tag, lockmode, false, false);
     433       162260 : }
     434              : 
     435              : /*
     436              :  *      ConditionalLockRelationForExtension
     437              :  *
     438              :  * As above, but only lock if we can get the lock without blocking.
     439              :  * Returns true iff the lock was acquired.
     440              :  */
     441              : bool
     442            0 : ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
     443              : {
     444              :     LOCKTAG     tag;
     445              : 
     446            0 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     447              :                                 relation->rd_lockInfo.lockRelId.dbId,
     448              :                                 relation->rd_lockInfo.lockRelId.relId);
     449              : 
     450            0 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     451              : }
     452              : 
     453              : /*
     454              :  *      RelationExtensionLockWaiterCount
     455              :  *
     456              :  * Count the number of processes waiting for the given relation extension lock.
     457              :  */
     458              : int
     459        68113 : RelationExtensionLockWaiterCount(Relation relation)
     460              : {
     461              :     LOCKTAG     tag;
     462              : 
     463        68113 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     464              :                                 relation->rd_lockInfo.lockRelId.dbId,
     465              :                                 relation->rd_lockInfo.lockRelId.relId);
     466              : 
     467        68113 :     return LockWaiterCount(&tag);
     468              : }
     469              : 
     470              : /*
     471              :  *      UnlockRelationForExtension
     472              :  */
     473              : void
     474       162260 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
     475              : {
     476              :     LOCKTAG     tag;
     477              : 
     478       162260 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     479              :                                 relation->rd_lockInfo.lockRelId.dbId,
     480              :                                 relation->rd_lockInfo.lockRelId.relId);
     481              : 
     482       162260 :     LockRelease(&tag, lockmode, false);
     483       162260 : }
     484              : 
     485              : /*
     486              :  *      LockDatabaseFrozenIds
     487              :  *
     488              :  * This allows one backend per database to execute vac_update_datfrozenxid().
     489              :  */
     490              : void
     491         2641 : LockDatabaseFrozenIds(LOCKMODE lockmode)
     492              : {
     493              :     LOCKTAG     tag;
     494              : 
     495         2641 :     SET_LOCKTAG_DATABASE_FROZEN_IDS(tag, MyDatabaseId);
     496              : 
     497         2641 :     (void) LockAcquire(&tag, lockmode, false, false);
     498         2641 : }
     499              : 
     500              : /*
     501              :  *      LockPage
     502              :  *
     503              :  * Obtain a page-level lock.  This is currently used by some index access
     504              :  * methods to lock individual index pages.
     505              :  */
     506              : void
     507           76 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     508              : {
     509              :     LOCKTAG     tag;
     510              : 
     511           76 :     SET_LOCKTAG_PAGE(tag,
     512              :                      relation->rd_lockInfo.lockRelId.dbId,
     513              :                      relation->rd_lockInfo.lockRelId.relId,
     514              :                      blkno);
     515              : 
     516           76 :     (void) LockAcquire(&tag, lockmode, false, false);
     517           76 : }
     518              : 
     519              : /*
     520              :  *      ConditionalLockPage
     521              :  *
     522              :  * As above, but only lock if we can get the lock without blocking.
     523              :  * Returns true iff the lock was acquired.
     524              :  */
     525              : bool
     526            0 : ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     527              : {
     528              :     LOCKTAG     tag;
     529              : 
     530            0 :     SET_LOCKTAG_PAGE(tag,
     531              :                      relation->rd_lockInfo.lockRelId.dbId,
     532              :                      relation->rd_lockInfo.lockRelId.relId,
     533              :                      blkno);
     534              : 
     535            0 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     536              : }
     537              : 
     538              : /*
     539              :  *      UnlockPage
     540              :  */
     541              : void
     542           76 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     543              : {
     544              :     LOCKTAG     tag;
     545              : 
     546           76 :     SET_LOCKTAG_PAGE(tag,
     547              :                      relation->rd_lockInfo.lockRelId.dbId,
     548              :                      relation->rd_lockInfo.lockRelId.relId,
     549              :                      blkno);
     550              : 
     551           76 :     LockRelease(&tag, lockmode, false);
     552           76 : }
     553              : 
     554              : /*
     555              :  *      LockTuple
     556              :  *
     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!
     560              :  */
     561              : void
     562       216844 : LockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
     563              : {
     564              :     LOCKTAG     tag;
     565              : 
     566       216844 :     SET_LOCKTAG_TUPLE(tag,
     567              :                       relation->rd_lockInfo.lockRelId.dbId,
     568              :                       relation->rd_lockInfo.lockRelId.relId,
     569              :                       ItemPointerGetBlockNumber(tid),
     570              :                       ItemPointerGetOffsetNumber(tid));
     571              : 
     572       216844 :     (void) LockAcquire(&tag, lockmode, false, false);
     573       216844 : }
     574              : 
     575              : /*
     576              :  *      ConditionalLockTuple
     577              :  *
     578              :  * As above, but only lock if we can get the lock without blocking.
     579              :  * Returns true iff the lock was acquired.
     580              :  */
     581              : bool
     582           41 : ConditionalLockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode,
     583              :                      bool logLockFailure)
     584              : {
     585              :     LOCKTAG     tag;
     586              : 
     587           41 :     SET_LOCKTAG_TUPLE(tag,
     588              :                       relation->rd_lockInfo.lockRelId.dbId,
     589              :                       relation->rd_lockInfo.lockRelId.relId,
     590              :                       ItemPointerGetBlockNumber(tid),
     591              :                       ItemPointerGetOffsetNumber(tid));
     592              : 
     593           41 :     return (LockAcquireExtended(&tag, lockmode, false, true, true, NULL,
     594           41 :                                 logLockFailure) != LOCKACQUIRE_NOT_AVAIL);
     595              : }
     596              : 
     597              : /*
     598              :  *      UnlockTuple
     599              :  */
     600              : void
     601       240961 : UnlockTuple(Relation relation, const ItemPointerData *tid, LOCKMODE lockmode)
     602              : {
     603              :     LOCKTAG     tag;
     604              : 
     605       240961 :     SET_LOCKTAG_TUPLE(tag,
     606              :                       relation->rd_lockInfo.lockRelId.dbId,
     607              :                       relation->rd_lockInfo.lockRelId.relId,
     608              :                       ItemPointerGetBlockNumber(tid),
     609              :                       ItemPointerGetOffsetNumber(tid));
     610              : 
     611       240961 :     LockRelease(&tag, lockmode, false);
     612       240961 : }
     613              : 
     614              : /*
     615              :  *      XactLockTableInsert
     616              :  *
     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.
     620              :  */
     621              : void
     622       143637 : XactLockTableInsert(TransactionId xid)
     623              : {
     624              :     LOCKTAG     tag;
     625              : 
     626       143637 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     627              : 
     628       143637 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     629       143637 : }
     630              : 
     631              : /*
     632              :  *      XactLockTableDelete
     633              :  *
     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.)
     637              :  */
     638              : void
     639         3691 : XactLockTableDelete(TransactionId xid)
     640              : {
     641              :     LOCKTAG     tag;
     642              : 
     643         3691 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     644              : 
     645         3691 :     LockRelease(&tag, ExclusiveLock, false);
     646         3691 : }
     647              : 
     648              : /*
     649              :  *      XactLockTableWait
     650              :  *
     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.
     654              :  *
     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.
     661              :  */
     662              : void
     663          483 : XactLockTableWait(TransactionId xid, Relation rel, const ItemPointerData *ctid,
     664              :                   XLTW_Oper oper)
     665              : {
     666              :     LOCKTAG     tag;
     667              :     XactLockTableWaitInfo info;
     668              :     ErrorContextCallback callback;
     669          483 :     bool        first = true;
     670              : 
     671              :     /*
     672              :      * If an operation is specified, set up our verbose error context
     673              :      * callback.
     674              :      */
     675          483 :     if (oper != XLTW_None)
     676              :     {
     677              :         Assert(RelationIsValid(rel));
     678              :         Assert(ItemPointerIsValid(ctid));
     679              : 
     680          463 :         info.rel = rel;
     681          463 :         info.ctid = ctid;
     682          463 :         info.oper = oper;
     683              : 
     684          463 :         callback.callback = XactLockTableWaitErrorCb;
     685          463 :         callback.arg = &info;
     686          463 :         callback.previous = error_context_stack;
     687          463 :         error_context_stack = &callback;
     688              :     }
     689              : 
     690              :     for (;;)
     691              :     {
     692            3 :         Assert(TransactionIdIsValid(xid));
     693              :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     694              : 
     695          486 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     696              : 
     697          486 :         (void) LockAcquire(&tag, ShareLock, false, false);
     698              : 
     699          479 :         LockRelease(&tag, ShareLock, false);
     700              : 
     701          479 :         if (!TransactionIdIsInProgress(xid))
     702          476 :             break;
     703              : 
     704              :         /*
     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.
     711              :          *
     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.)
     718              :          */
     719            3 :         if (!first)
     720              :         {
     721            0 :             CHECK_FOR_INTERRUPTS();
     722            0 :             pg_usleep(1000L);
     723              :         }
     724            3 :         first = false;
     725            3 :         xid = SubTransGetTopmostTransaction(xid);
     726              :     }
     727              : 
     728          476 :     if (oper != XLTW_None)
     729          458 :         error_context_stack = callback.previous;
     730          476 : }
     731              : 
     732              : /*
     733              :  *      ConditionalXactLockTableWait
     734              :  *
     735              :  * As above, but only lock if we can get the lock without blocking.
     736              :  * Returns true if the lock was acquired.
     737              :  */
     738              : bool
     739           45 : ConditionalXactLockTableWait(TransactionId xid, bool logLockFailure)
     740              : {
     741              :     LOCKTAG     tag;
     742           45 :     bool        first = true;
     743              : 
     744              :     for (;;)
     745              :     {
     746            0 :         Assert(TransactionIdIsValid(xid));
     747              :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     748              : 
     749           45 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     750              : 
     751           45 :         if (LockAcquireExtended(&tag, ShareLock, false, true, true, NULL,
     752              :                                 logLockFailure)
     753              :             == LOCKACQUIRE_NOT_AVAIL)
     754           45 :             return false;
     755              : 
     756            0 :         LockRelease(&tag, ShareLock, false);
     757              : 
     758            0 :         if (!TransactionIdIsInProgress(xid))
     759            0 :             break;
     760              : 
     761              :         /* See XactLockTableWait about this case */
     762            0 :         if (!first)
     763              :         {
     764            0 :             CHECK_FOR_INTERRUPTS();
     765            0 :             pg_usleep(1000L);
     766              :         }
     767            0 :         first = false;
     768            0 :         xid = SubTransGetTopmostTransaction(xid);
     769              :     }
     770              : 
     771            0 :     return true;
     772              : }
     773              : 
     774              : /*
     775              :  *      SpeculativeInsertionLockAcquire
     776              :  *
     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
     780              :  * it.
     781              :  *
     782              :  * The token is used to distinguish multiple insertions by the same
     783              :  * transaction.  It is returned to caller.
     784              :  */
     785              : uint32
     786         2133 : SpeculativeInsertionLockAcquire(TransactionId xid)
     787              : {
     788              :     LOCKTAG     tag;
     789              : 
     790         2133 :     speculativeInsertionToken++;
     791              : 
     792              :     /*
     793              :      * Check for wrap-around. Zero means no token is held, so don't use that.
     794              :      */
     795         2133 :     if (speculativeInsertionToken == 0)
     796            0 :         speculativeInsertionToken = 1;
     797              : 
     798         2133 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     799              : 
     800         2133 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     801              : 
     802         2133 :     return speculativeInsertionToken;
     803              : }
     804              : 
     805              : /*
     806              :  *      SpeculativeInsertionLockRelease
     807              :  *
     808              :  * Delete the lock showing that the given transaction is speculatively
     809              :  * inserting a tuple.
     810              :  */
     811              : void
     812         2130 : SpeculativeInsertionLockRelease(TransactionId xid)
     813              : {
     814              :     LOCKTAG     tag;
     815              : 
     816         2130 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     817              : 
     818         2130 :     LockRelease(&tag, ExclusiveLock, false);
     819         2130 : }
     820              : 
     821              : /*
     822              :  *      SpeculativeInsertionWait
     823              :  *
     824              :  * Wait for the specified transaction to finish or abort the insertion of a
     825              :  * tuple.
     826              :  */
     827              : void
     828            1 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
     829              : {
     830              :     LOCKTAG     tag;
     831              : 
     832            1 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
     833              : 
     834              :     Assert(TransactionIdIsValid(xid));
     835              :     Assert(token != 0);
     836              : 
     837            1 :     (void) LockAcquire(&tag, ShareLock, false, false);
     838            1 :     LockRelease(&tag, ShareLock, false);
     839            1 : }
     840              : 
     841              : /*
     842              :  * XactLockTableWaitErrorCb
     843              :  *      Error context callback for transaction lock waits.
     844              :  */
     845              : static void
     846          183 : XactLockTableWaitErrorCb(void *arg)
     847              : {
     848          183 :     XactLockTableWaitInfo *info = (XactLockTableWaitInfo *) arg;
     849              : 
     850              :     /*
     851              :      * We would like to print schema name too, but that would require a
     852              :      * syscache lookup.
     853              :      */
     854          366 :     if (info->oper != XLTW_None &&
     855          366 :         ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
     856              :     {
     857              :         const char *cxt;
     858              : 
     859          183 :         switch (info->oper)
     860              :         {
     861            0 :             case XLTW_Update:
     862            0 :                 cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
     863            0 :                 break;
     864            4 :             case XLTW_Delete:
     865            4 :                 cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
     866            4 :                 break;
     867            0 :             case XLTW_Lock:
     868            0 :                 cxt = gettext_noop("while locking tuple (%u,%u) in relation \"%s\"");
     869            0 :                 break;
     870            0 :             case XLTW_LockUpdated:
     871            0 :                 cxt = gettext_noop("while locking updated version (%u,%u) of tuple in relation \"%s\"");
     872            0 :                 break;
     873          179 :             case XLTW_InsertIndex:
     874          179 :                 cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
     875          179 :                 break;
     876            0 :             case XLTW_InsertIndexUnique:
     877            0 :                 cxt = gettext_noop("while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
     878            0 :                 break;
     879            0 :             case XLTW_FetchUpdated:
     880            0 :                 cxt = gettext_noop("while rechecking updated tuple (%u,%u) in relation \"%s\"");
     881            0 :                 break;
     882            0 :             case XLTW_RecheckExclusionConstr:
     883            0 :                 cxt = gettext_noop("while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
     884            0 :                 break;
     885              : 
     886            0 :             default:
     887            0 :                 return;
     888              :         }
     889              : 
     890          366 :         errcontext(cxt,
     891              :                    ItemPointerGetBlockNumber(info->ctid),
     892          183 :                    ItemPointerGetOffsetNumber(info->ctid),
     893          183 :                    RelationGetRelationName(info->rel));
     894              :     }
     895              : }
     896              : 
     897              : /*
     898              :  * WaitForLockersMultiple
     899              :  *      Wait until no transaction holds locks that conflict with the given
     900              :  *      locktags at the given lockmode.
     901              :  *
     902              :  * To do this, obtain the current list of lockers, and wait on their VXIDs
     903              :  * until they are finished.
     904              :  *
     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
     908              :  * wait for them.
     909              :  */
     910              : void
     911         1246 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
     912              : {
     913         1246 :     List       *holders = NIL;
     914              :     ListCell   *lc;
     915         1246 :     int         total = 0;
     916         1246 :     int         done = 0;
     917              : 
     918              :     /* Done if no locks to wait for */
     919         1246 :     if (locktags == NIL)
     920            0 :         return;
     921              : 
     922              :     /* Collect the transactions we need to wait on */
     923         2668 :     foreach(lc, locktags)
     924              :     {
     925         1422 :         LOCKTAG    *locktag = lfirst(lc);
     926              :         int         count;
     927              : 
     928         1422 :         holders = lappend(holders,
     929         1422 :                           GetLockConflicts(locktag, lockmode,
     930              :                                            progress ? &count : NULL));
     931         1422 :         if (progress)
     932         1352 :             total += count;
     933              :     }
     934              : 
     935         1246 :     if (progress)
     936         1176 :         pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, total);
     937              : 
     938              :     /*
     939              :      * Note: GetLockConflicts() never reports our own xid, hence we need not
     940              :      * check for that.  Also, prepared xacts are reported and awaited.
     941              :      */
     942              : 
     943              :     /* Finally wait for each such transaction to complete */
     944         2643 :     foreach(lc, holders)
     945              :     {
     946         1422 :         VirtualTransactionId *lockholders = lfirst(lc);
     947              : 
     948         1611 :         while (VirtualTransactionIdIsValid(*lockholders))
     949              :         {
     950              :             /* If requested, publish who we're going to wait for. */
     951          214 :             if (progress)
     952              :             {
     953          159 :                 PGPROC     *holder = ProcNumberGetProc(lockholders->procNumber);
     954              : 
     955          159 :                 if (holder)
     956          158 :                     pgstat_progress_update_param(PROGRESS_WAITFOR_CURRENT_PID,
     957          158 :                                                  holder->pid);
     958              :             }
     959          214 :             VirtualXactLock(*lockholders, true);
     960          189 :             lockholders++;
     961              : 
     962          189 :             if (progress)
     963          159 :                 pgstat_progress_update_param(PROGRESS_WAITFOR_DONE, ++done);
     964              :         }
     965              :     }
     966         1221 :     if (progress)
     967              :     {
     968         1176 :         const int   index[] = {
     969              :             PROGRESS_WAITFOR_TOTAL,
     970              :             PROGRESS_WAITFOR_DONE,
     971              :             PROGRESS_WAITFOR_CURRENT_PID
     972              :         };
     973         1176 :         const int64 values[] = {
     974              :             0, 0, 0
     975              :         };
     976              : 
     977         1176 :         pgstat_progress_update_multi_param(3, index, values);
     978              :     }
     979              : 
     980         1221 :     list_free_deep(holders);
     981              : }
     982              : 
     983              : /*
     984              :  * WaitForLockers
     985              :  *
     986              :  * Same as WaitForLockersMultiple, for a single lock tag.
     987              :  */
     988              : void
     989          305 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
     990              : {
     991              :     List       *l;
     992              : 
     993          305 :     l = list_make1(&heaplocktag);
     994          305 :     WaitForLockersMultiple(l, lockmode, progress);
     995          305 :     list_free(l);
     996          305 : }
     997              : 
     998              : 
     999              : /*
    1000              :  *      LockDatabaseObject
    1001              :  *
    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.
    1006              :  */
    1007              : void
    1008       175630 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1009              :                    LOCKMODE lockmode)
    1010              : {
    1011              :     LOCKTAG     tag;
    1012              : 
    1013       175630 :     SET_LOCKTAG_OBJECT(tag,
    1014              :                        MyDatabaseId,
    1015              :                        classid,
    1016              :                        objid,
    1017              :                        objsubid);
    1018              : 
    1019       175630 :     (void) LockAcquire(&tag, lockmode, false, false);
    1020              : 
    1021              :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1022       175630 :     AcceptInvalidationMessages();
    1023       175630 : }
    1024              : 
    1025              : /*
    1026              :  *      ConditionalLockDatabaseObject
    1027              :  *
    1028              :  * As above, but only lock if we can get the lock without blocking.
    1029              :  * Returns true iff the lock was acquired.
    1030              :  */
    1031              : bool
    1032            0 : ConditionalLockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1033              :                               LOCKMODE lockmode)
    1034              : {
    1035              :     LOCKTAG     tag;
    1036              :     LOCALLOCK  *locallock;
    1037              :     LockAcquireResult res;
    1038              : 
    1039            0 :     SET_LOCKTAG_OBJECT(tag,
    1040              :                        MyDatabaseId,
    1041              :                        classid,
    1042              :                        objid,
    1043              :                        objsubid);
    1044              : 
    1045            0 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
    1046              :                               false);
    1047              : 
    1048            0 :     if (res == LOCKACQUIRE_NOT_AVAIL)
    1049            0 :         return false;
    1050              : 
    1051              :     /*
    1052              :      * Now that we have the lock, check for invalidation messages; see notes
    1053              :      * in LockRelationOid.
    1054              :      */
    1055            0 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
    1056              :     {
    1057            0 :         AcceptInvalidationMessages();
    1058            0 :         MarkLockClear(locallock);
    1059              :     }
    1060              : 
    1061            0 :     return true;
    1062              : }
    1063              : 
    1064              : /*
    1065              :  *      UnlockDatabaseObject
    1066              :  */
    1067              : void
    1068          847 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1069              :                      LOCKMODE lockmode)
    1070              : {
    1071              :     LOCKTAG     tag;
    1072              : 
    1073          847 :     SET_LOCKTAG_OBJECT(tag,
    1074              :                        MyDatabaseId,
    1075              :                        classid,
    1076              :                        objid,
    1077              :                        objsubid);
    1078              : 
    1079          847 :     LockRelease(&tag, lockmode, false);
    1080          847 : }
    1081              : 
    1082              : /*
    1083              :  *      LockSharedObject
    1084              :  *
    1085              :  * Obtain a lock on a shared-across-databases object.
    1086              :  */
    1087              : void
    1088        28297 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1089              :                  LOCKMODE lockmode)
    1090              : {
    1091              :     LOCKTAG     tag;
    1092              : 
    1093        28297 :     SET_LOCKTAG_OBJECT(tag,
    1094              :                        InvalidOid,
    1095              :                        classid,
    1096              :                        objid,
    1097              :                        objsubid);
    1098              : 
    1099        28297 :     (void) LockAcquire(&tag, lockmode, false, false);
    1100              : 
    1101              :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1102        28296 :     AcceptInvalidationMessages();
    1103        28296 : }
    1104              : 
    1105              : /*
    1106              :  *      ConditionalLockSharedObject
    1107              :  *
    1108              :  * As above, but only lock if we can get the lock without blocking.
    1109              :  * Returns true iff the lock was acquired.
    1110              :  */
    1111              : bool
    1112            3 : ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1113              :                             LOCKMODE lockmode)
    1114              : {
    1115              :     LOCKTAG     tag;
    1116              :     LOCALLOCK  *locallock;
    1117              :     LockAcquireResult res;
    1118              : 
    1119            3 :     SET_LOCKTAG_OBJECT(tag,
    1120              :                        InvalidOid,
    1121              :                        classid,
    1122              :                        objid,
    1123              :                        objsubid);
    1124              : 
    1125            3 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
    1126              :                               false);
    1127              : 
    1128            3 :     if (res == LOCKACQUIRE_NOT_AVAIL)
    1129            0 :         return false;
    1130              : 
    1131              :     /*
    1132              :      * Now that we have the lock, check for invalidation messages; see notes
    1133              :      * in LockRelationOid.
    1134              :      */
    1135            3 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
    1136              :     {
    1137            3 :         AcceptInvalidationMessages();
    1138            3 :         MarkLockClear(locallock);
    1139              :     }
    1140              : 
    1141            3 :     return true;
    1142              : }
    1143              : 
    1144              : /*
    1145              :  *      UnlockSharedObject
    1146              :  */
    1147              : void
    1148          866 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1149              :                    LOCKMODE lockmode)
    1150              : {
    1151              :     LOCKTAG     tag;
    1152              : 
    1153          866 :     SET_LOCKTAG_OBJECT(tag,
    1154              :                        InvalidOid,
    1155              :                        classid,
    1156              :                        objid,
    1157              :                        objsubid);
    1158              : 
    1159          866 :     LockRelease(&tag, lockmode, false);
    1160          866 : }
    1161              : 
    1162              : /*
    1163              :  *      LockSharedObjectForSession
    1164              :  *
    1165              :  * Obtain a session-level lock on a shared-across-databases object.
    1166              :  * See LockRelationIdForSession for notes about session-level locks.
    1167              :  */
    1168              : void
    1169           26 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1170              :                            LOCKMODE lockmode)
    1171              : {
    1172              :     LOCKTAG     tag;
    1173              : 
    1174           26 :     SET_LOCKTAG_OBJECT(tag,
    1175              :                        InvalidOid,
    1176              :                        classid,
    1177              :                        objid,
    1178              :                        objsubid);
    1179              : 
    1180           26 :     (void) LockAcquire(&tag, lockmode, true, false);
    1181           26 : }
    1182              : 
    1183              : /*
    1184              :  *      UnlockSharedObjectForSession
    1185              :  */
    1186              : void
    1187           26 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1188              :                              LOCKMODE lockmode)
    1189              : {
    1190              :     LOCKTAG     tag;
    1191              : 
    1192           26 :     SET_LOCKTAG_OBJECT(tag,
    1193              :                        InvalidOid,
    1194              :                        classid,
    1195              :                        objid,
    1196              :                        objsubid);
    1197              : 
    1198           26 :     LockRelease(&tag, lockmode, true);
    1199           26 : }
    1200              : 
    1201              : /*
    1202              :  *      LockApplyTransactionForSession
    1203              :  *
    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.
    1207              :  */
    1208              : void
    1209          334 : LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1210              :                                LOCKMODE lockmode)
    1211              : {
    1212              :     LOCKTAG     tag;
    1213              : 
    1214          334 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1215              :                                   MyDatabaseId,
    1216              :                                   suboid,
    1217              :                                   xid,
    1218              :                                   objid);
    1219              : 
    1220          334 :     (void) LockAcquire(&tag, lockmode, true, false);
    1221          331 : }
    1222              : 
    1223              : /*
    1224              :  *      UnlockApplyTransactionForSession
    1225              :  */
    1226              : void
    1227          325 : UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1228              :                                  LOCKMODE lockmode)
    1229              : {
    1230              :     LOCKTAG     tag;
    1231              : 
    1232          325 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1233              :                                   MyDatabaseId,
    1234              :                                   suboid,
    1235              :                                   xid,
    1236              :                                   objid);
    1237              : 
    1238          325 :     LockRelease(&tag, lockmode, true);
    1239          325 : }
    1240              : 
    1241              : /*
    1242              :  * Append a description of a lockable object to buf.
    1243              :  *
    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.
    1247              :  */
    1248              : void
    1249          505 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
    1250              : {
    1251          505 :     switch ((LockTagType) tag->locktag_type)
    1252              :     {
    1253           39 :         case LOCKTAG_RELATION:
    1254           39 :             appendStringInfo(buf,
    1255           39 :                              _("relation %u of database %u"),
    1256           39 :                              tag->locktag_field2,
    1257           39 :                              tag->locktag_field1);
    1258           39 :             break;
    1259            0 :         case LOCKTAG_RELATION_EXTEND:
    1260            0 :             appendStringInfo(buf,
    1261            0 :                              _("extension of relation %u of database %u"),
    1262            0 :                              tag->locktag_field2,
    1263            0 :                              tag->locktag_field1);
    1264            0 :             break;
    1265            0 :         case LOCKTAG_DATABASE_FROZEN_IDS:
    1266            0 :             appendStringInfo(buf,
    1267            0 :                              _("pg_database.datfrozenxid of database %u"),
    1268            0 :                              tag->locktag_field1);
    1269            0 :             break;
    1270            0 :         case LOCKTAG_PAGE:
    1271            0 :             appendStringInfo(buf,
    1272            0 :                              _("page %u of relation %u of database %u"),
    1273            0 :                              tag->locktag_field3,
    1274            0 :                              tag->locktag_field2,
    1275            0 :                              tag->locktag_field1);
    1276            0 :             break;
    1277            0 :         case LOCKTAG_TUPLE:
    1278            0 :             appendStringInfo(buf,
    1279            0 :                              _("tuple (%u,%u) of relation %u of database %u"),
    1280            0 :                              tag->locktag_field3,
    1281            0 :                              tag->locktag_field4,
    1282            0 :                              tag->locktag_field2,
    1283            0 :                              tag->locktag_field1);
    1284            0 :             break;
    1285          367 :         case LOCKTAG_TRANSACTION:
    1286          367 :             appendStringInfo(buf,
    1287          367 :                              _("transaction %u"),
    1288          367 :                              tag->locktag_field1);
    1289          367 :             break;
    1290           59 :         case LOCKTAG_VIRTUALTRANSACTION:
    1291           59 :             appendStringInfo(buf,
    1292           59 :                              _("virtual transaction %d/%u"),
    1293           59 :                              tag->locktag_field1,
    1294           59 :                              tag->locktag_field2);
    1295           59 :             break;
    1296            0 :         case LOCKTAG_SPECULATIVE_TOKEN:
    1297            0 :             appendStringInfo(buf,
    1298            0 :                              _("speculative token %u of transaction %u"),
    1299            0 :                              tag->locktag_field2,
    1300            0 :                              tag->locktag_field1);
    1301            0 :             break;
    1302            1 :         case LOCKTAG_OBJECT:
    1303            1 :             appendStringInfo(buf,
    1304            1 :                              _("object %u of class %u of database %u"),
    1305            1 :                              tag->locktag_field3,
    1306            1 :                              tag->locktag_field2,
    1307            1 :                              tag->locktag_field1);
    1308            1 :             break;
    1309            0 :         case LOCKTAG_USERLOCK:
    1310              :             /* reserved for old contrib code, now on pgfoundry */
    1311            0 :             appendStringInfo(buf,
    1312            0 :                              _("user lock [%u,%u,%u]"),
    1313            0 :                              tag->locktag_field1,
    1314            0 :                              tag->locktag_field2,
    1315            0 :                              tag->locktag_field3);
    1316            0 :             break;
    1317           15 :         case LOCKTAG_ADVISORY:
    1318           15 :             appendStringInfo(buf,
    1319           15 :                              _("advisory lock [%u,%u,%u,%u]"),
    1320           15 :                              tag->locktag_field1,
    1321           15 :                              tag->locktag_field2,
    1322           15 :                              tag->locktag_field3,
    1323           15 :                              tag->locktag_field4);
    1324           15 :             break;
    1325           24 :         case LOCKTAG_APPLY_TRANSACTION:
    1326           24 :             appendStringInfo(buf,
    1327           24 :                              _("remote transaction %u of subscription %u of database %u"),
    1328           24 :                              tag->locktag_field3,
    1329           24 :                              tag->locktag_field2,
    1330           24 :                              tag->locktag_field1);
    1331           24 :             break;
    1332            0 :         default:
    1333            0 :             appendStringInfo(buf,
    1334            0 :                              _("unrecognized locktag type %d"),
    1335            0 :                              (int) tag->locktag_type);
    1336            0 :             break;
    1337              :     }
    1338          505 : }
    1339              : 
    1340              : /*
    1341              :  * GetLockNameFromTagType
    1342              :  *
    1343              :  *  Given locktag type, return the corresponding lock name.
    1344              :  */
    1345              : const char *
    1346           15 : GetLockNameFromTagType(uint16 locktag_type)
    1347              : {
    1348           15 :     if (locktag_type > LOCKTAG_LAST_TYPE)
    1349            0 :         return "???";
    1350           15 :     return LockTagTypeNames[locktag_type];
    1351              : }
        

Generated by: LCOV version 2.0-1