LCOV - code coverage report
Current view: top level - src/backend/storage/lmgr - lmgr.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18beta1 Lines: 283 397 71.3 %
Date: 2025-06-27 21:17:17 Functions: 42 48 87.5 %
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-2025, 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             :     ItemPointer 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     5730888 : RelationInitLockInfo(Relation relation)
      71             : {
      72             :     Assert(RelationIsValid(relation));
      73             :     Assert(OidIsValid(RelationGetRelid(relation)));
      74             : 
      75     5730888 :     relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
      76             : 
      77     5730888 :     if (relation->rd_rel->relisshared)
      78      859514 :         relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
      79             :     else
      80     4871374 :         relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
      81     5730888 : }
      82             : 
      83             : /*
      84             :  * SetLocktagRelationOid
      85             :  *      Set up a locktag for a relation, given only relation OID
      86             :  */
      87             : static inline void
      88    40633856 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
      89             : {
      90             :     Oid         dbid;
      91             : 
      92    40633856 :     if (IsSharedRelation(relid))
      93     1829970 :         dbid = InvalidOid;
      94             :     else
      95    38803886 :         dbid = MyDatabaseId;
      96             : 
      97    40633856 :     SET_LOCKTAG_RELATION(*tag, dbid, relid);
      98    40633856 : }
      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    40218534 : LockRelationOid(Oid relid, LOCKMODE lockmode)
     108             : {
     109             :     LOCKTAG     tag;
     110             :     LOCALLOCK  *locallock;
     111             :     LockAcquireResult res;
     112             : 
     113    40218534 :     SetLocktagRelationOid(&tag, relid);
     114             : 
     115    40218534 :     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    40218508 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     135             :     {
     136    36241422 :         AcceptInvalidationMessages();
     137    36241282 :         MarkLockClear(locallock);
     138             :     }
     139    40218368 : }
     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        3204 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
     152             : {
     153             :     LOCKTAG     tag;
     154             :     LOCALLOCK  *locallock;
     155             :     LockAcquireResult res;
     156             : 
     157        3204 :     SetLocktagRelationOid(&tag, relid);
     158             : 
     159        3204 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
     160             :                               false);
     161             : 
     162        3204 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     163          36 :         return false;
     164             : 
     165             :     /*
     166             :      * Now that we have the lock, check for invalidation messages; see notes
     167             :      * in LockRelationOid.
     168             :      */
     169        3168 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     170             :     {
     171        3060 :         AcceptInvalidationMessages();
     172        3060 :         MarkLockClear(locallock);
     173             :     }
     174             : 
     175        3168 :     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      220094 : LockRelationId(LockRelId *relid, LOCKMODE lockmode)
     186             : {
     187             :     LOCKTAG     tag;
     188             :     LOCALLOCK  *locallock;
     189             :     LockAcquireResult res;
     190             : 
     191      220094 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     192             : 
     193      220094 :     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      220094 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     201             :     {
     202      220094 :         AcceptInvalidationMessages();
     203      220094 :         MarkLockClear(locallock);
     204             :     }
     205      220094 : }
     206             : 
     207             : /*
     208             :  *      UnlockRelationId
     209             :  *
     210             :  * Unlock, given a LockRelId.  This is preferred over UnlockRelationOid
     211             :  * for speed reasons.
     212             :  */
     213             : void
     214    36172208 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
     215             : {
     216             :     LOCKTAG     tag;
     217             : 
     218    36172208 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     219             : 
     220    36172208 :     LockRelease(&tag, lockmode, false);
     221    36172208 : }
     222             : 
     223             : /*
     224             :  *      UnlockRelationOid
     225             :  *
     226             :  * Unlock, given only a relation Oid.  Use UnlockRelationId if you can.
     227             :  */
     228             : void
     229      412118 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
     230             : {
     231             :     LOCKTAG     tag;
     232             : 
     233      412118 :     SetLocktagRelationOid(&tag, relid);
     234             : 
     235      412118 :     LockRelease(&tag, lockmode, false);
     236      412118 : }
     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       48598 : LockRelation(Relation relation, LOCKMODE lockmode)
     247             : {
     248             :     LOCKTAG     tag;
     249             :     LOCALLOCK  *locallock;
     250             :     LockAcquireResult res;
     251             : 
     252       48598 :     SET_LOCKTAG_RELATION(tag,
     253             :                          relation->rd_lockInfo.lockRelId.dbId,
     254             :                          relation->rd_lockInfo.lockRelId.relId);
     255             : 
     256       48598 :     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       48598 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     264             :     {
     265       48598 :         AcceptInvalidationMessages();
     266       48598 :         MarkLockClear(locallock);
     267             :     }
     268       48598 : }
     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         700 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
     279             : {
     280             :     LOCKTAG     tag;
     281             :     LOCALLOCK  *locallock;
     282             :     LockAcquireResult res;
     283             : 
     284         700 :     SET_LOCKTAG_RELATION(tag,
     285             :                          relation->rd_lockInfo.lockRelId.dbId,
     286             :                          relation->rd_lockInfo.lockRelId.relId);
     287             : 
     288         700 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
     289             :                               false);
     290             : 
     291         700 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     292         404 :         return false;
     293             : 
     294             :     /*
     295             :      * Now that we have the lock, check for invalidation messages; see notes
     296             :      * in LockRelationOid.
     297             :      */
     298         296 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     299             :     {
     300         296 :         AcceptInvalidationMessages();
     301         296 :         MarkLockClear(locallock);
     302             :     }
     303             : 
     304         296 :     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         296 : UnlockRelation(Relation relation, LOCKMODE lockmode)
     315             : {
     316             :     LOCKTAG     tag;
     317             : 
     318         296 :     SET_LOCKTAG_RELATION(tag,
     319             :                          relation->rd_lockInfo.lockRelId.dbId,
     320             :                          relation->rd_lockInfo.lockRelId.relId);
     321             : 
     322         296 :     LockRelease(&tag, lockmode, false);
     323         296 : }
     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      220088 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     392             : {
     393             :     LOCKTAG     tag;
     394             : 
     395      220088 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     396             : 
     397      220088 :     (void) LockAcquire(&tag, lockmode, true, false);
     398      220088 : }
     399             : 
     400             : /*
     401             :  *      UnlockRelationIdForSession
     402             :  */
     403             : void
     404      220044 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     405             : {
     406             :     LOCKTAG     tag;
     407             : 
     408      220044 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     409             : 
     410      220044 :     LockRelease(&tag, lockmode, true);
     411      220044 : }
     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      321660 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
     425             : {
     426             :     LOCKTAG     tag;
     427             : 
     428      321660 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     429             :                                 relation->rd_lockInfo.lockRelId.dbId,
     430             :                                 relation->rd_lockInfo.lockRelId.relId);
     431             : 
     432      321660 :     (void) LockAcquire(&tag, lockmode, false, false);
     433      321660 : }
     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      135976 : RelationExtensionLockWaiterCount(Relation relation)
     460             : {
     461             :     LOCKTAG     tag;
     462             : 
     463      135976 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     464             :                                 relation->rd_lockInfo.lockRelId.dbId,
     465             :                                 relation->rd_lockInfo.lockRelId.relId);
     466             : 
     467      135976 :     return LockWaiterCount(&tag);
     468             : }
     469             : 
     470             : /*
     471             :  *      UnlockRelationForExtension
     472             :  */
     473             : void
     474      321660 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
     475             : {
     476             :     LOCKTAG     tag;
     477             : 
     478      321660 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     479             :                                 relation->rd_lockInfo.lockRelId.dbId,
     480             :                                 relation->rd_lockInfo.lockRelId.relId);
     481             : 
     482      321660 :     LockRelease(&tag, lockmode, false);
     483      321660 : }
     484             : 
     485             : /*
     486             :  *      LockDatabaseFrozenIds
     487             :  *
     488             :  * This allows one backend per database to execute vac_update_datfrozenxid().
     489             :  */
     490             : void
     491        5156 : LockDatabaseFrozenIds(LOCKMODE lockmode)
     492             : {
     493             :     LOCKTAG     tag;
     494             : 
     495        5156 :     SET_LOCKTAG_DATABASE_FROZEN_IDS(tag, MyDatabaseId);
     496             : 
     497        5156 :     (void) LockAcquire(&tag, lockmode, false, false);
     498        5156 : }
     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         132 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     508             : {
     509             :     LOCKTAG     tag;
     510             : 
     511         132 :     SET_LOCKTAG_PAGE(tag,
     512             :                      relation->rd_lockInfo.lockRelId.dbId,
     513             :                      relation->rd_lockInfo.lockRelId.relId,
     514             :                      blkno);
     515             : 
     516         132 :     (void) LockAcquire(&tag, lockmode, false, false);
     517         132 : }
     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         132 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     543             : {
     544             :     LOCKTAG     tag;
     545             : 
     546         132 :     SET_LOCKTAG_PAGE(tag,
     547             :                      relation->rd_lockInfo.lockRelId.dbId,
     548             :                      relation->rd_lockInfo.lockRelId.relId,
     549             :                      blkno);
     550             : 
     551         132 :     LockRelease(&tag, lockmode, false);
     552         132 : }
     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      412190 : LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     563             : {
     564             :     LOCKTAG     tag;
     565             : 
     566      412190 :     SET_LOCKTAG_TUPLE(tag,
     567             :                       relation->rd_lockInfo.lockRelId.dbId,
     568             :                       relation->rd_lockInfo.lockRelId.relId,
     569             :                       ItemPointerGetBlockNumber(tid),
     570             :                       ItemPointerGetOffsetNumber(tid));
     571             : 
     572      412190 :     (void) LockAcquire(&tag, lockmode, false, false);
     573      412190 : }
     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          82 : ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode,
     583             :                      bool logLockFailure)
     584             : {
     585             :     LOCKTAG     tag;
     586             : 
     587          82 :     SET_LOCKTAG_TUPLE(tag,
     588             :                       relation->rd_lockInfo.lockRelId.dbId,
     589             :                       relation->rd_lockInfo.lockRelId.relId,
     590             :                       ItemPointerGetBlockNumber(tid),
     591             :                       ItemPointerGetOffsetNumber(tid));
     592             : 
     593          82 :     return (LockAcquireExtended(&tag, lockmode, false, true, true, NULL,
     594          82 :                                 logLockFailure) != LOCKACQUIRE_NOT_AVAIL);
     595             : }
     596             : 
     597             : /*
     598             :  *      UnlockTuple
     599             :  */
     600             : void
     601      460362 : UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     602             : {
     603             :     LOCKTAG     tag;
     604             : 
     605      460362 :     SET_LOCKTAG_TUPLE(tag,
     606             :                       relation->rd_lockInfo.lockRelId.dbId,
     607             :                       relation->rd_lockInfo.lockRelId.relId,
     608             :                       ItemPointerGetBlockNumber(tid),
     609             :                       ItemPointerGetOffsetNumber(tid));
     610             : 
     611      460362 :     LockRelease(&tag, lockmode, false);
     612      460362 : }
     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      271434 : XactLockTableInsert(TransactionId xid)
     623             : {
     624             :     LOCKTAG     tag;
     625             : 
     626      271434 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     627             : 
     628      271434 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     629      271434 : }
     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        7338 : XactLockTableDelete(TransactionId xid)
     640             : {
     641             :     LOCKTAG     tag;
     642             : 
     643        7338 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     644             : 
     645        7338 :     LockRelease(&tag, ExclusiveLock, false);
     646        7338 : }
     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         720 : XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
     664             :                   XLTW_Oper oper)
     665             : {
     666             :     LOCKTAG     tag;
     667             :     XactLockTableWaitInfo info;
     668             :     ErrorContextCallback callback;
     669         720 :     bool        first = true;
     670             : 
     671             :     /*
     672             :      * If an operation is specified, set up our verbose error context
     673             :      * callback.
     674             :      */
     675         720 :     if (oper != XLTW_None)
     676             :     {
     677             :         Assert(RelationIsValid(rel));
     678             :         Assert(ItemPointerIsValid(ctid));
     679             : 
     680         678 :         info.rel = rel;
     681         678 :         info.ctid = ctid;
     682         678 :         info.oper = oper;
     683             : 
     684         678 :         callback.callback = XactLockTableWaitErrorCb;
     685         678 :         callback.arg = &info;
     686         678 :         callback.previous = error_context_stack;
     687         678 :         error_context_stack = &callback;
     688             :     }
     689             : 
     690             :     for (;;)
     691             :     {
     692           4 :         Assert(TransactionIdIsValid(xid));
     693             :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     694             : 
     695         724 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     696             : 
     697         724 :         (void) LockAcquire(&tag, ShareLock, false, false);
     698             : 
     699         710 :         LockRelease(&tag, ShareLock, false);
     700             : 
     701         710 :         if (!TransactionIdIsInProgress(xid))
     702         706 :             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           4 :         if (!first)
     720             :         {
     721           0 :             CHECK_FOR_INTERRUPTS();
     722           0 :             pg_usleep(1000L);
     723             :         }
     724           4 :         first = false;
     725           4 :         xid = SubTransGetTopmostTransaction(xid);
     726             :     }
     727             : 
     728         706 :     if (oper != XLTW_None)
     729         668 :         error_context_stack = callback.previous;
     730         706 : }
     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          90 : ConditionalXactLockTableWait(TransactionId xid, bool logLockFailure)
     740             : {
     741             :     LOCKTAG     tag;
     742          90 :     bool        first = true;
     743             : 
     744             :     for (;;)
     745             :     {
     746           0 :         Assert(TransactionIdIsValid(xid));
     747             :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     748             : 
     749          90 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     750             : 
     751          90 :         if (LockAcquireExtended(&tag, ShareLock, false, true, true, NULL,
     752             :                                 logLockFailure)
     753             :             == LOCKACQUIRE_NOT_AVAIL)
     754          90 :             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        4128 : SpeculativeInsertionLockAcquire(TransactionId xid)
     787             : {
     788             :     LOCKTAG     tag;
     789             : 
     790        4128 :     speculativeInsertionToken++;
     791             : 
     792             :     /*
     793             :      * Check for wrap-around. Zero means no token is held, so don't use that.
     794             :      */
     795        4128 :     if (speculativeInsertionToken == 0)
     796           0 :         speculativeInsertionToken = 1;
     797             : 
     798        4128 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     799             : 
     800        4128 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     801             : 
     802        4128 :     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        4122 : SpeculativeInsertionLockRelease(TransactionId xid)
     813             : {
     814             :     LOCKTAG     tag;
     815             : 
     816        4122 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     817             : 
     818        4122 :     LockRelease(&tag, ExclusiveLock, false);
     819        4122 : }
     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           2 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
     829             : {
     830             :     LOCKTAG     tag;
     831             : 
     832           2 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
     833             : 
     834             :     Assert(TransactionIdIsValid(xid));
     835             :     Assert(token != 0);
     836             : 
     837           2 :     (void) LockAcquire(&tag, ShareLock, false, false);
     838           2 :     LockRelease(&tag, ShareLock, false);
     839           2 : }
     840             : 
     841             : /*
     842             :  * XactLockTableWaitErrorCb
     843             :  *      Error context callback for transaction lock waits.
     844             :  */
     845             : static void
     846           8 : XactLockTableWaitErrorCb(void *arg)
     847             : {
     848           8 :     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          16 :     if (info->oper != XLTW_None &&
     855          16 :         ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
     856             :     {
     857             :         const char *cxt;
     858             : 
     859           8 :         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           8 :             case XLTW_Delete:
     865           8 :                 cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
     866           8 :                 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           0 :             case XLTW_InsertIndex:
     874           0 :                 cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
     875           0 :                 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          16 :         errcontext(cxt,
     891           8 :                    ItemPointerGetBlockNumber(info->ctid),
     892           8 :                    ItemPointerGetOffsetNumber(info->ctid),
     893           8 :                    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        2388 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
     912             : {
     913        2388 :     List       *holders = NIL;
     914             :     ListCell   *lc;
     915        2388 :     int         total = 0;
     916        2388 :     int         done = 0;
     917             : 
     918             :     /* Done if no locks to wait for */
     919        2388 :     if (locktags == NIL)
     920           0 :         return;
     921             : 
     922             :     /* Collect the transactions we need to wait on */
     923        5128 :     foreach(lc, locktags)
     924             :     {
     925        2740 :         LOCKTAG    *locktag = lfirst(lc);
     926             :         int         count;
     927             : 
     928        2740 :         holders = lappend(holders,
     929        2740 :                           GetLockConflicts(locktag, lockmode,
     930             :                                            progress ? &count : NULL));
     931        2740 :         if (progress)
     932        2600 :             total += count;
     933             :     }
     934             : 
     935        2388 :     if (progress)
     936        2248 :         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        5078 :     foreach(lc, holders)
     945             :     {
     946        2740 :         VirtualTransactionId *lockholders = lfirst(lc);
     947             : 
     948        3126 :         while (VirtualTransactionIdIsValid(*lockholders))
     949             :         {
     950             :             /* If requested, publish who we're going to wait for. */
     951         436 :             if (progress)
     952             :             {
     953         326 :                 PGPROC     *holder = ProcNumberGetProc(lockholders->procNumber);
     954             : 
     955         326 :                 if (holder)
     956         324 :                     pgstat_progress_update_param(PROGRESS_WAITFOR_CURRENT_PID,
     957         324 :                                                  holder->pid);
     958             :             }
     959         436 :             VirtualXactLock(*lockholders, true);
     960         386 :             lockholders++;
     961             : 
     962         386 :             if (progress)
     963         326 :                 pgstat_progress_update_param(PROGRESS_WAITFOR_DONE, ++done);
     964             :         }
     965             :     }
     966        2338 :     if (progress)
     967             :     {
     968        2248 :         const int   index[] = {
     969             :             PROGRESS_WAITFOR_TOTAL,
     970             :             PROGRESS_WAITFOR_DONE,
     971             :             PROGRESS_WAITFOR_CURRENT_PID
     972             :         };
     973        2248 :         const int64 values[] = {
     974             :             0, 0, 0
     975             :         };
     976             : 
     977        2248 :         pgstat_progress_update_multi_param(3, index, values);
     978             :     }
     979             : 
     980        2338 :     list_free_deep(holders);
     981             : }
     982             : 
     983             : /*
     984             :  * WaitForLockers
     985             :  *
     986             :  * Same as WaitForLockersMultiple, for a single lock tag.
     987             :  */
     988             : void
     989         570 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
     990             : {
     991             :     List       *l;
     992             : 
     993         570 :     l = list_make1(&heaplocktag);
     994         570 :     WaitForLockersMultiple(l, lockmode, progress);
     995         570 :     list_free(l);
     996         570 : }
     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      324344 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1009             :                    LOCKMODE lockmode)
    1010             : {
    1011             :     LOCKTAG     tag;
    1012             : 
    1013      324344 :     SET_LOCKTAG_OBJECT(tag,
    1014             :                        MyDatabaseId,
    1015             :                        classid,
    1016             :                        objid,
    1017             :                        objsubid);
    1018             : 
    1019      324344 :     (void) LockAcquire(&tag, lockmode, false, false);
    1020             : 
    1021             :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1022      324344 :     AcceptInvalidationMessages();
    1023      324344 : }
    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        1628 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1069             :                      LOCKMODE lockmode)
    1070             : {
    1071             :     LOCKTAG     tag;
    1072             : 
    1073        1628 :     SET_LOCKTAG_OBJECT(tag,
    1074             :                        MyDatabaseId,
    1075             :                        classid,
    1076             :                        objid,
    1077             :                        objsubid);
    1078             : 
    1079        1628 :     LockRelease(&tag, lockmode, false);
    1080        1628 : }
    1081             : 
    1082             : /*
    1083             :  *      LockSharedObject
    1084             :  *
    1085             :  * Obtain a lock on a shared-across-databases object.
    1086             :  */
    1087             : void
    1088       52912 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1089             :                  LOCKMODE lockmode)
    1090             : {
    1091             :     LOCKTAG     tag;
    1092             : 
    1093       52912 :     SET_LOCKTAG_OBJECT(tag,
    1094             :                        InvalidOid,
    1095             :                        classid,
    1096             :                        objid,
    1097             :                        objsubid);
    1098             : 
    1099       52912 :     (void) LockAcquire(&tag, lockmode, false, false);
    1100             : 
    1101             :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1102       52910 :     AcceptInvalidationMessages();
    1103       52910 : }
    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           6 : ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1113             :                             LOCKMODE lockmode)
    1114             : {
    1115             :     LOCKTAG     tag;
    1116             :     LOCALLOCK  *locallock;
    1117             :     LockAcquireResult res;
    1118             : 
    1119           6 :     SET_LOCKTAG_OBJECT(tag,
    1120             :                        InvalidOid,
    1121             :                        classid,
    1122             :                        objid,
    1123             :                        objsubid);
    1124             : 
    1125           6 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock,
    1126             :                               false);
    1127             : 
    1128           6 :     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           6 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
    1136             :     {
    1137           6 :         AcceptInvalidationMessages();
    1138           6 :         MarkLockClear(locallock);
    1139             :     }
    1140             : 
    1141           6 :     return true;
    1142             : }
    1143             : 
    1144             : /*
    1145             :  *      UnlockSharedObject
    1146             :  */
    1147             : void
    1148        1658 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1149             :                    LOCKMODE lockmode)
    1150             : {
    1151             :     LOCKTAG     tag;
    1152             : 
    1153        1658 :     SET_LOCKTAG_OBJECT(tag,
    1154             :                        InvalidOid,
    1155             :                        classid,
    1156             :                        objid,
    1157             :                        objsubid);
    1158             : 
    1159        1658 :     LockRelease(&tag, lockmode, false);
    1160        1658 : }
    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          42 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1170             :                            LOCKMODE lockmode)
    1171             : {
    1172             :     LOCKTAG     tag;
    1173             : 
    1174          42 :     SET_LOCKTAG_OBJECT(tag,
    1175             :                        InvalidOid,
    1176             :                        classid,
    1177             :                        objid,
    1178             :                        objsubid);
    1179             : 
    1180          42 :     (void) LockAcquire(&tag, lockmode, true, false);
    1181          42 : }
    1182             : 
    1183             : /*
    1184             :  *      UnlockSharedObjectForSession
    1185             :  */
    1186             : void
    1187          42 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1188             :                              LOCKMODE lockmode)
    1189             : {
    1190             :     LOCKTAG     tag;
    1191             : 
    1192          42 :     SET_LOCKTAG_OBJECT(tag,
    1193             :                        InvalidOid,
    1194             :                        classid,
    1195             :                        objid,
    1196             :                        objsubid);
    1197             : 
    1198          42 :     LockRelease(&tag, lockmode, true);
    1199          42 : }
    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         656 : LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1210             :                                LOCKMODE lockmode)
    1211             : {
    1212             :     LOCKTAG     tag;
    1213             : 
    1214         656 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1215             :                                   MyDatabaseId,
    1216             :                                   suboid,
    1217             :                                   xid,
    1218             :                                   objid);
    1219             : 
    1220         656 :     (void) LockAcquire(&tag, lockmode, true, false);
    1221         650 : }
    1222             : 
    1223             : /*
    1224             :  *      UnlockApplyTransactionForSession
    1225             :  */
    1226             : void
    1227         640 : UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1228             :                                  LOCKMODE lockmode)
    1229             : {
    1230             :     LOCKTAG     tag;
    1231             : 
    1232         640 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1233             :                                   MyDatabaseId,
    1234             :                                   suboid,
    1235             :                                   xid,
    1236             :                                   objid);
    1237             : 
    1238         640 :     LockRelease(&tag, lockmode, true);
    1239         640 : }
    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          80 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
    1250             : {
    1251          80 :     switch ((LockTagType) tag->locktag_type)
    1252             :     {
    1253          40 :         case LOCKTAG_RELATION:
    1254          40 :             appendStringInfo(buf,
    1255          40 :                              _("relation %u of database %u"),
    1256          40 :                              tag->locktag_field2,
    1257          40 :                              tag->locktag_field1);
    1258          40 :             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           6 :         case LOCKTAG_TRANSACTION:
    1286           6 :             appendStringInfo(buf,
    1287           6 :                              _("transaction %u"),
    1288           6 :                              tag->locktag_field1);
    1289           6 :             break;
    1290          16 :         case LOCKTAG_VIRTUALTRANSACTION:
    1291          16 :             appendStringInfo(buf,
    1292          16 :                              _("virtual transaction %d/%u"),
    1293          16 :                              tag->locktag_field1,
    1294          16 :                              tag->locktag_field2);
    1295          16 :             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           0 :         case LOCKTAG_OBJECT:
    1303           0 :             appendStringInfo(buf,
    1304           0 :                              _("object %u of class %u of database %u"),
    1305           0 :                              tag->locktag_field3,
    1306           0 :                              tag->locktag_field2,
    1307           0 :                              tag->locktag_field1);
    1308           0 :             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          12 :         case LOCKTAG_ADVISORY:
    1318          12 :             appendStringInfo(buf,
    1319          12 :                              _("advisory lock [%u,%u,%u,%u]"),
    1320          12 :                              tag->locktag_field1,
    1321          12 :                              tag->locktag_field2,
    1322          12 :                              tag->locktag_field3,
    1323          12 :                              tag->locktag_field4);
    1324          12 :             break;
    1325           6 :         case LOCKTAG_APPLY_TRANSACTION:
    1326           6 :             appendStringInfo(buf,
    1327           6 :                              _("remote transaction %u of subscription %u of database %u"),
    1328           6 :                              tag->locktag_field3,
    1329           6 :                              tag->locktag_field2,
    1330           6 :                              tag->locktag_field1);
    1331           6 :             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          80 : }
    1339             : 
    1340             : /*
    1341             :  * GetLockNameFromTagType
    1342             :  *
    1343             :  *  Given locktag type, return the corresponding lock name.
    1344             :  */
    1345             : const char *
    1346          14 : GetLockNameFromTagType(uint16 locktag_type)
    1347             : {
    1348          14 :     if (locktag_type > LOCKTAG_LAST_TYPE)
    1349           0 :         return "???";
    1350          14 :     return LockTagTypeNames[locktag_type];
    1351             : }

Generated by: LCOV version 1.16