LCOV - code coverage report
Current view: top level - src/backend/storage/lmgr - lmgr.c (source / functions) Hit Total Coverage
Test: PostgreSQL 17devel Lines: 271 361 75.1 %
Date: 2023-12-05 08:11:01 Functions: 42 46 91.3 %
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-2023, 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/transam.h"
      20             : #include "access/xact.h"
      21             : #include "catalog/catalog.h"
      22             : #include "commands/progress.h"
      23             : #include "miscadmin.h"
      24             : #include "pgstat.h"
      25             : #include "storage/lmgr.h"
      26             : #include "storage/proc.h"
      27             : #include "storage/procarray.h"
      28             : #include "storage/sinvaladt.h"
      29             : #include "utils/inval.h"
      30             : 
      31             : 
      32             : /*
      33             :  * Per-backend counter for generating speculative insertion tokens.
      34             :  *
      35             :  * This may wrap around, but that's OK as it's only used for the short
      36             :  * duration between inserting a tuple and checking that there are no (unique)
      37             :  * constraint violations.  It's theoretically possible that a backend sees a
      38             :  * tuple that was speculatively inserted by another backend, but before it has
      39             :  * started waiting on the token, the other backend completes its insertion,
      40             :  * and then performs 2^32 unrelated insertions.  And after all that, the
      41             :  * first backend finally calls SpeculativeInsertionLockAcquire(), with the
      42             :  * intention of waiting for the first insertion to complete, but ends up
      43             :  * waiting for the latest unrelated insertion instead.  Even then, nothing
      44             :  * particularly bad happens: in the worst case they deadlock, causing one of
      45             :  * the transactions to abort.
      46             :  */
      47             : static uint32 speculativeInsertionToken = 0;
      48             : 
      49             : 
      50             : /*
      51             :  * Struct to hold context info for transaction lock waits.
      52             :  *
      53             :  * 'oper' is the operation that needs to wait for the other transaction; 'rel'
      54             :  * and 'ctid' specify the address of the tuple being waited for.
      55             :  */
      56             : typedef struct XactLockTableWaitInfo
      57             : {
      58             :     XLTW_Oper   oper;
      59             :     Relation    rel;
      60             :     ItemPointer ctid;
      61             : } XactLockTableWaitInfo;
      62             : 
      63             : static void XactLockTableWaitErrorCb(void *arg);
      64             : 
      65             : /*
      66             :  * RelationInitLockInfo
      67             :  *      Initializes the lock information in a relation descriptor.
      68             :  *
      69             :  *      relcache.c must call this during creation of any reldesc.
      70             :  */
      71             : void
      72     3781554 : RelationInitLockInfo(Relation relation)
      73             : {
      74             :     Assert(RelationIsValid(relation));
      75             :     Assert(OidIsValid(RelationGetRelid(relation)));
      76             : 
      77     3781554 :     relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
      78             : 
      79     3781554 :     if (relation->rd_rel->relisshared)
      80      571610 :         relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
      81             :     else
      82     3209944 :         relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
      83     3781554 : }
      84             : 
      85             : /*
      86             :  * SetLocktagRelationOid
      87             :  *      Set up a locktag for a relation, given only relation OID
      88             :  */
      89             : static inline void
      90    26279152 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
      91             : {
      92             :     Oid         dbid;
      93             : 
      94    26279152 :     if (IsSharedRelation(relid))
      95     1230946 :         dbid = InvalidOid;
      96             :     else
      97    25048206 :         dbid = MyDatabaseId;
      98             : 
      99    26279152 :     SET_LOCKTAG_RELATION(*tag, dbid, relid);
     100    26279152 : }
     101             : 
     102             : /*
     103             :  *      LockRelationOid
     104             :  *
     105             :  * Lock a relation given only its OID.  This should generally be used
     106             :  * before attempting to open the relation's relcache entry.
     107             :  */
     108             : void
     109    26070108 : LockRelationOid(Oid relid, LOCKMODE lockmode)
     110             : {
     111             :     LOCKTAG     tag;
     112             :     LOCALLOCK  *locallock;
     113             :     LockAcquireResult res;
     114             : 
     115    26070108 :     SetLocktagRelationOid(&tag, relid);
     116             : 
     117    26070108 :     res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock);
     118             : 
     119             :     /*
     120             :      * Now that we have the lock, check for invalidation messages, so that we
     121             :      * will update or flush any stale relcache entry before we try to use it.
     122             :      * RangeVarGetRelid() specifically relies on us for this.  We can skip
     123             :      * this in the not-uncommon case that we already had the same type of lock
     124             :      * being requested, since then no one else could have modified the
     125             :      * relcache entry in an undesirable way.  (In the case where our own xact
     126             :      * modifies the rel, the relcache update happens via
     127             :      * CommandCounterIncrement, not here.)
     128             :      *
     129             :      * However, in corner cases where code acts on tables (usually catalogs)
     130             :      * recursively, we might get here while still processing invalidation
     131             :      * messages in some outer execution of this function or a sibling.  The
     132             :      * "cleared" status of the lock tells us whether we really are done
     133             :      * absorbing relevant inval messages.
     134             :      */
     135    26070086 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     136             :     {
     137    23339106 :         AcceptInvalidationMessages();
     138    23339106 :         MarkLockClear(locallock);
     139             :     }
     140    26070086 : }
     141             : 
     142             : /*
     143             :  *      ConditionalLockRelationOid
     144             :  *
     145             :  * As above, but only lock if we can get the lock without blocking.
     146             :  * Returns true iff the lock was acquired.
     147             :  *
     148             :  * NOTE: we do not currently need conditional versions of all the
     149             :  * LockXXX routines in this file, but they could easily be added if needed.
     150             :  */
     151             : bool
     152        1588 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
     153             : {
     154             :     LOCKTAG     tag;
     155             :     LOCALLOCK  *locallock;
     156             :     LockAcquireResult res;
     157             : 
     158        1588 :     SetLocktagRelationOid(&tag, relid);
     159             : 
     160        1588 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
     161             : 
     162        1588 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     163          44 :         return false;
     164             : 
     165             :     /*
     166             :      * Now that we have the lock, check for invalidation messages; see notes
     167             :      * in LockRelationOid.
     168             :      */
     169        1544 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     170             :     {
     171        1526 :         AcceptInvalidationMessages();
     172        1526 :         MarkLockClear(locallock);
     173             :     }
     174             : 
     175        1544 :     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      179832 : LockRelationId(LockRelId *relid, LOCKMODE lockmode)
     186             : {
     187             :     LOCKTAG     tag;
     188             :     LOCALLOCK  *locallock;
     189             :     LockAcquireResult res;
     190             : 
     191      179832 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     192             : 
     193      179832 :     res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock);
     194             : 
     195             :     /*
     196             :      * Now that we have the lock, check for invalidation messages; see notes
     197             :      * in LockRelationOid.
     198             :      */
     199      179832 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     200             :     {
     201      179832 :         AcceptInvalidationMessages();
     202      179832 :         MarkLockClear(locallock);
     203             :     }
     204      179832 : }
     205             : 
     206             : /*
     207             :  *      UnlockRelationId
     208             :  *
     209             :  * Unlock, given a LockRelId.  This is preferred over UnlockRelationOid
     210             :  * for speed reasons.
     211             :  */
     212             : void
     213    23433652 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
     214             : {
     215             :     LOCKTAG     tag;
     216             : 
     217    23433652 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     218             : 
     219    23433652 :     LockRelease(&tag, lockmode, false);
     220    23433652 : }
     221             : 
     222             : /*
     223             :  *      UnlockRelationOid
     224             :  *
     225             :  * Unlock, given only a relation Oid.  Use UnlockRelationId if you can.
     226             :  */
     227             : void
     228      207456 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
     229             : {
     230             :     LOCKTAG     tag;
     231             : 
     232      207456 :     SetLocktagRelationOid(&tag, relid);
     233             : 
     234      207456 :     LockRelease(&tag, lockmode, false);
     235      207456 : }
     236             : 
     237             : /*
     238             :  *      LockRelation
     239             :  *
     240             :  * This is a convenience routine for acquiring an additional lock on an
     241             :  * already-open relation.  Never try to do "relation_open(foo, NoLock)"
     242             :  * and then lock with this.
     243             :  */
     244             : void
     245       37900 : LockRelation(Relation relation, LOCKMODE lockmode)
     246             : {
     247             :     LOCKTAG     tag;
     248             :     LOCALLOCK  *locallock;
     249             :     LockAcquireResult res;
     250             : 
     251       37900 :     SET_LOCKTAG_RELATION(tag,
     252             :                          relation->rd_lockInfo.lockRelId.dbId,
     253             :                          relation->rd_lockInfo.lockRelId.relId);
     254             : 
     255       37900 :     res = LockAcquireExtended(&tag, lockmode, false, false, true, &locallock);
     256             : 
     257             :     /*
     258             :      * Now that we have the lock, check for invalidation messages; see notes
     259             :      * in LockRelationOid.
     260             :      */
     261       37900 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     262             :     {
     263       37900 :         AcceptInvalidationMessages();
     264       37900 :         MarkLockClear(locallock);
     265             :     }
     266       37900 : }
     267             : 
     268             : /*
     269             :  *      ConditionalLockRelation
     270             :  *
     271             :  * This is a convenience routine for acquiring an additional lock on an
     272             :  * already-open relation.  Never try to do "relation_open(foo, NoLock)"
     273             :  * and then lock with this.
     274             :  */
     275             : bool
     276         710 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
     277             : {
     278             :     LOCKTAG     tag;
     279             :     LOCALLOCK  *locallock;
     280             :     LockAcquireResult res;
     281             : 
     282         710 :     SET_LOCKTAG_RELATION(tag,
     283             :                          relation->rd_lockInfo.lockRelId.dbId,
     284             :                          relation->rd_lockInfo.lockRelId.relId);
     285             : 
     286         710 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
     287             : 
     288         710 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     289         404 :         return false;
     290             : 
     291             :     /*
     292             :      * Now that we have the lock, check for invalidation messages; see notes
     293             :      * in LockRelationOid.
     294             :      */
     295         306 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     296             :     {
     297         306 :         AcceptInvalidationMessages();
     298         306 :         MarkLockClear(locallock);
     299             :     }
     300             : 
     301         306 :     return true;
     302             : }
     303             : 
     304             : /*
     305             :  *      UnlockRelation
     306             :  *
     307             :  * This is a convenience routine for unlocking a relation without also
     308             :  * closing it.
     309             :  */
     310             : void
     311         306 : UnlockRelation(Relation relation, LOCKMODE lockmode)
     312             : {
     313             :     LOCKTAG     tag;
     314             : 
     315         306 :     SET_LOCKTAG_RELATION(tag,
     316             :                          relation->rd_lockInfo.lockRelId.dbId,
     317             :                          relation->rd_lockInfo.lockRelId.relId);
     318             : 
     319         306 :     LockRelease(&tag, lockmode, false);
     320         306 : }
     321             : 
     322             : /*
     323             :  *      CheckRelationLockedByMe
     324             :  *
     325             :  * Returns true if current transaction holds a lock on 'relation' of mode
     326             :  * 'lockmode'.  If 'orstronger' is true, a stronger lockmode is also OK.
     327             :  * ("Stronger" is defined as "numerically higher", which is a bit
     328             :  * semantically dubious but is OK for the purposes we use this for.)
     329             :  */
     330             : bool
     331           0 : CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
     332             : {
     333             :     LOCKTAG     tag;
     334             : 
     335           0 :     SET_LOCKTAG_RELATION(tag,
     336             :                          relation->rd_lockInfo.lockRelId.dbId,
     337             :                          relation->rd_lockInfo.lockRelId.relId);
     338             : 
     339           0 :     if (LockHeldByMe(&tag, lockmode))
     340           0 :         return true;
     341             : 
     342           0 :     if (orstronger)
     343             :     {
     344             :         LOCKMODE    slockmode;
     345             : 
     346           0 :         for (slockmode = lockmode + 1;
     347             :              slockmode <= MaxLockMode;
     348           0 :              slockmode++)
     349             :         {
     350           0 :             if (LockHeldByMe(&tag, slockmode))
     351             :             {
     352             : #ifdef NOT_USED
     353             :                 /* Sometimes this might be useful for debugging purposes */
     354             :                 elog(WARNING, "lock mode %s substituted for %s on relation %s",
     355             :                      GetLockmodeName(tag.locktag_lockmethodid, slockmode),
     356             :                      GetLockmodeName(tag.locktag_lockmethodid, lockmode),
     357             :                      RelationGetRelationName(relation));
     358             : #endif
     359           0 :                 return true;
     360             :             }
     361             :         }
     362             :     }
     363             : 
     364           0 :     return false;
     365             : }
     366             : 
     367             : /*
     368             :  *      LockHasWaitersRelation
     369             :  *
     370             :  * This is a function to check whether someone else is waiting for a
     371             :  * lock which we are currently holding.
     372             :  */
     373             : bool
     374           0 : LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
     375             : {
     376             :     LOCKTAG     tag;
     377             : 
     378           0 :     SET_LOCKTAG_RELATION(tag,
     379             :                          relation->rd_lockInfo.lockRelId.dbId,
     380             :                          relation->rd_lockInfo.lockRelId.relId);
     381             : 
     382           0 :     return LockHasWaiters(&tag, lockmode, false);
     383             : }
     384             : 
     385             : /*
     386             :  *      LockRelationIdForSession
     387             :  *
     388             :  * This routine grabs a session-level lock on the target relation.  The
     389             :  * session lock persists across transaction boundaries.  It will be removed
     390             :  * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
     391             :  * or if the backend exits.
     392             :  *
     393             :  * Note that one should also grab a transaction-level lock on the rel
     394             :  * in any transaction that actually uses the rel, to ensure that the
     395             :  * relcache entry is up to date.
     396             :  */
     397             : void
     398       18010 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     399             : {
     400             :     LOCKTAG     tag;
     401             : 
     402       18010 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     403             : 
     404       18010 :     (void) LockAcquire(&tag, lockmode, true, false);
     405       18010 : }
     406             : 
     407             : /*
     408             :  *      UnlockRelationIdForSession
     409             :  */
     410             : void
     411       17968 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     412             : {
     413             :     LOCKTAG     tag;
     414             : 
     415       17968 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     416             : 
     417       17968 :     LockRelease(&tag, lockmode, true);
     418       17968 : }
     419             : 
     420             : /*
     421             :  *      LockRelationForExtension
     422             :  *
     423             :  * This lock tag is used to interlock addition of pages to relations.
     424             :  * We need such locking because bufmgr/smgr definition of P_NEW is not
     425             :  * race-condition-proof.
     426             :  *
     427             :  * We assume the caller is already holding some type of regular lock on
     428             :  * the relation, so no AcceptInvalidationMessages call is needed here.
     429             :  */
     430             : void
     431      259182 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
     432             : {
     433             :     LOCKTAG     tag;
     434             : 
     435      259182 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     436             :                                 relation->rd_lockInfo.lockRelId.dbId,
     437             :                                 relation->rd_lockInfo.lockRelId.relId);
     438             : 
     439      259182 :     (void) LockAcquire(&tag, lockmode, false, false);
     440      259182 : }
     441             : 
     442             : /*
     443             :  *      ConditionalLockRelationForExtension
     444             :  *
     445             :  * As above, but only lock if we can get the lock without blocking.
     446             :  * Returns true iff the lock was acquired.
     447             :  */
     448             : bool
     449           0 : ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
     450             : {
     451             :     LOCKTAG     tag;
     452             : 
     453           0 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     454             :                                 relation->rd_lockInfo.lockRelId.dbId,
     455             :                                 relation->rd_lockInfo.lockRelId.relId);
     456             : 
     457           0 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     458             : }
     459             : 
     460             : /*
     461             :  *      RelationExtensionLockWaiterCount
     462             :  *
     463             :  * Count the number of processes waiting for the given relation extension lock.
     464             :  */
     465             : int
     466      105892 : RelationExtensionLockWaiterCount(Relation relation)
     467             : {
     468             :     LOCKTAG     tag;
     469             : 
     470      105892 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     471             :                                 relation->rd_lockInfo.lockRelId.dbId,
     472             :                                 relation->rd_lockInfo.lockRelId.relId);
     473             : 
     474      105892 :     return LockWaiterCount(&tag);
     475             : }
     476             : 
     477             : /*
     478             :  *      UnlockRelationForExtension
     479             :  */
     480             : void
     481      259182 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
     482             : {
     483             :     LOCKTAG     tag;
     484             : 
     485      259182 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     486             :                                 relation->rd_lockInfo.lockRelId.dbId,
     487             :                                 relation->rd_lockInfo.lockRelId.relId);
     488             : 
     489      259182 :     LockRelease(&tag, lockmode, false);
     490      259182 : }
     491             : 
     492             : /*
     493             :  *      LockDatabaseFrozenIds
     494             :  *
     495             :  * This allows one backend per database to execute vac_update_datfrozenxid().
     496             :  */
     497             : void
     498        1406 : LockDatabaseFrozenIds(LOCKMODE lockmode)
     499             : {
     500             :     LOCKTAG     tag;
     501             : 
     502        1406 :     SET_LOCKTAG_DATABASE_FROZEN_IDS(tag, MyDatabaseId);
     503             : 
     504        1406 :     (void) LockAcquire(&tag, lockmode, false, false);
     505        1406 : }
     506             : 
     507             : /*
     508             :  *      LockPage
     509             :  *
     510             :  * Obtain a page-level lock.  This is currently used by some index access
     511             :  * methods to lock individual index pages.
     512             :  */
     513             : void
     514          82 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     515             : {
     516             :     LOCKTAG     tag;
     517             : 
     518          82 :     SET_LOCKTAG_PAGE(tag,
     519             :                      relation->rd_lockInfo.lockRelId.dbId,
     520             :                      relation->rd_lockInfo.lockRelId.relId,
     521             :                      blkno);
     522             : 
     523          82 :     (void) LockAcquire(&tag, lockmode, false, false);
     524          82 : }
     525             : 
     526             : /*
     527             :  *      ConditionalLockPage
     528             :  *
     529             :  * As above, but only lock if we can get the lock without blocking.
     530             :  * Returns true iff the lock was acquired.
     531             :  */
     532             : bool
     533           0 : ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     534             : {
     535             :     LOCKTAG     tag;
     536             : 
     537           0 :     SET_LOCKTAG_PAGE(tag,
     538             :                      relation->rd_lockInfo.lockRelId.dbId,
     539             :                      relation->rd_lockInfo.lockRelId.relId,
     540             :                      blkno);
     541             : 
     542           0 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     543             : }
     544             : 
     545             : /*
     546             :  *      UnlockPage
     547             :  */
     548             : void
     549          82 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     550             : {
     551             :     LOCKTAG     tag;
     552             : 
     553          82 :     SET_LOCKTAG_PAGE(tag,
     554             :                      relation->rd_lockInfo.lockRelId.dbId,
     555             :                      relation->rd_lockInfo.lockRelId.relId,
     556             :                      blkno);
     557             : 
     558          82 :     LockRelease(&tag, lockmode, false);
     559          82 : }
     560             : 
     561             : /*
     562             :  *      LockTuple
     563             :  *
     564             :  * Obtain a tuple-level lock.  This is used in a less-than-intuitive fashion
     565             :  * because we can't afford to keep a separate lock in shared memory for every
     566             :  * tuple.  See heap_lock_tuple before using this!
     567             :  */
     568             : void
     569         410 : LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     570             : {
     571             :     LOCKTAG     tag;
     572             : 
     573         410 :     SET_LOCKTAG_TUPLE(tag,
     574             :                       relation->rd_lockInfo.lockRelId.dbId,
     575             :                       relation->rd_lockInfo.lockRelId.relId,
     576             :                       ItemPointerGetBlockNumber(tid),
     577             :                       ItemPointerGetOffsetNumber(tid));
     578             : 
     579         410 :     (void) LockAcquire(&tag, lockmode, false, false);
     580         410 : }
     581             : 
     582             : /*
     583             :  *      ConditionalLockTuple
     584             :  *
     585             :  * As above, but only lock if we can get the lock without blocking.
     586             :  * Returns true iff the lock was acquired.
     587             :  */
     588             : bool
     589          82 : ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     590             : {
     591             :     LOCKTAG     tag;
     592             : 
     593          82 :     SET_LOCKTAG_TUPLE(tag,
     594             :                       relation->rd_lockInfo.lockRelId.dbId,
     595             :                       relation->rd_lockInfo.lockRelId.relId,
     596             :                       ItemPointerGetBlockNumber(tid),
     597             :                       ItemPointerGetOffsetNumber(tid));
     598             : 
     599          82 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     600             : }
     601             : 
     602             : /*
     603             :  *      UnlockTuple
     604             :  */
     605             : void
     606         468 : UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     607             : {
     608             :     LOCKTAG     tag;
     609             : 
     610         468 :     SET_LOCKTAG_TUPLE(tag,
     611             :                       relation->rd_lockInfo.lockRelId.dbId,
     612             :                       relation->rd_lockInfo.lockRelId.relId,
     613             :                       ItemPointerGetBlockNumber(tid),
     614             :                       ItemPointerGetOffsetNumber(tid));
     615             : 
     616         468 :     LockRelease(&tag, lockmode, false);
     617         468 : }
     618             : 
     619             : /*
     620             :  *      XactLockTableInsert
     621             :  *
     622             :  * Insert a lock showing that the given transaction ID is running ---
     623             :  * this is done when an XID is acquired by a transaction or subtransaction.
     624             :  * The lock can then be used to wait for the transaction to finish.
     625             :  */
     626             : void
     627      210796 : XactLockTableInsert(TransactionId xid)
     628             : {
     629             :     LOCKTAG     tag;
     630             : 
     631      210796 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     632             : 
     633      210796 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     634      210796 : }
     635             : 
     636             : /*
     637             :  *      XactLockTableDelete
     638             :  *
     639             :  * Delete the lock showing that the given transaction ID is running.
     640             :  * (This is never used for main transaction IDs; those locks are only
     641             :  * released implicitly at transaction end.  But we do use it for subtrans IDs.)
     642             :  */
     643             : void
     644        5612 : XactLockTableDelete(TransactionId xid)
     645             : {
     646             :     LOCKTAG     tag;
     647             : 
     648        5612 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     649             : 
     650        5612 :     LockRelease(&tag, ExclusiveLock, false);
     651        5612 : }
     652             : 
     653             : /*
     654             :  *      XactLockTableWait
     655             :  *
     656             :  * Wait for the specified transaction to commit or abort.  If an operation
     657             :  * is specified, an error context callback is set up.  If 'oper' is passed as
     658             :  * None, no error context callback is set up.
     659             :  *
     660             :  * Note that this does the right thing for subtransactions: if we wait on a
     661             :  * subtransaction, we will exit as soon as it aborts or its top parent commits.
     662             :  * It takes some extra work to ensure this, because to save on shared memory
     663             :  * the XID lock of a subtransaction is released when it ends, whether
     664             :  * successfully or unsuccessfully.  So we have to check if it's "still running"
     665             :  * and if so wait for its parent.
     666             :  */
     667             : void
     668         680 : XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
     669             :                   XLTW_Oper oper)
     670             : {
     671             :     LOCKTAG     tag;
     672             :     XactLockTableWaitInfo info;
     673             :     ErrorContextCallback callback;
     674         680 :     bool        first = true;
     675             : 
     676             :     /*
     677             :      * If an operation is specified, set up our verbose error context
     678             :      * callback.
     679             :      */
     680         680 :     if (oper != XLTW_None)
     681             :     {
     682             :         Assert(RelationIsValid(rel));
     683             :         Assert(ItemPointerIsValid(ctid));
     684             : 
     685         642 :         info.rel = rel;
     686         642 :         info.ctid = ctid;
     687         642 :         info.oper = oper;
     688             : 
     689         642 :         callback.callback = XactLockTableWaitErrorCb;
     690         642 :         callback.arg = &info;
     691         642 :         callback.previous = error_context_stack;
     692         642 :         error_context_stack = &callback;
     693             :     }
     694             : 
     695             :     for (;;)
     696             :     {
     697           8 :         Assert(TransactionIdIsValid(xid));
     698             :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     699             : 
     700         688 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     701             : 
     702         688 :         (void) LockAcquire(&tag, ShareLock, false, false);
     703             : 
     704         674 :         LockRelease(&tag, ShareLock, false);
     705             : 
     706         674 :         if (!TransactionIdIsInProgress(xid))
     707         666 :             break;
     708             : 
     709             :         /*
     710             :          * If the Xid belonged to a subtransaction, then the lock would have
     711             :          * gone away as soon as it was finished; for correct tuple visibility,
     712             :          * the right action is to wait on its parent transaction to go away.
     713             :          * But instead of going levels up one by one, we can just wait for the
     714             :          * topmost transaction to finish with the same end result, which also
     715             :          * incurs less locktable traffic.
     716             :          *
     717             :          * Some uses of this function don't involve tuple visibility -- such
     718             :          * as when building snapshots for logical decoding.  It is possible to
     719             :          * see a transaction in ProcArray before it registers itself in the
     720             :          * locktable.  The topmost transaction in that case is the same xid,
     721             :          * so we try again after a short sleep.  (Don't sleep the first time
     722             :          * through, to avoid slowing down the normal case.)
     723             :          */
     724           8 :         if (!first)
     725           0 :             pg_usleep(1000L);
     726           8 :         first = false;
     727           8 :         xid = SubTransGetTopmostTransaction(xid);
     728             :     }
     729             : 
     730         666 :     if (oper != XLTW_None)
     731         632 :         error_context_stack = callback.previous;
     732         666 : }
     733             : 
     734             : /*
     735             :  *      ConditionalXactLockTableWait
     736             :  *
     737             :  * As above, but only lock if we can get the lock without blocking.
     738             :  * Returns true if the lock was acquired.
     739             :  */
     740             : bool
     741          90 : ConditionalXactLockTableWait(TransactionId xid)
     742             : {
     743             :     LOCKTAG     tag;
     744          90 :     bool        first = true;
     745             : 
     746             :     for (;;)
     747             :     {
     748           0 :         Assert(TransactionIdIsValid(xid));
     749             :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     750             : 
     751          90 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     752             : 
     753          90 :         if (LockAcquire(&tag, ShareLock, false, true) == 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           0 :             pg_usleep(1000L);
     764           0 :         first = false;
     765           0 :         xid = SubTransGetTopmostTransaction(xid);
     766             :     }
     767             : 
     768           0 :     return true;
     769             : }
     770             : 
     771             : /*
     772             :  *      SpeculativeInsertionLockAcquire
     773             :  *
     774             :  * Insert a lock showing that the given transaction ID is inserting a tuple,
     775             :  * but hasn't yet decided whether it's going to keep it.  The lock can then be
     776             :  * used to wait for the decision to go ahead with the insertion, or aborting
     777             :  * it.
     778             :  *
     779             :  * The token is used to distinguish multiple insertions by the same
     780             :  * transaction.  It is returned to caller.
     781             :  */
     782             : uint32
     783        4026 : SpeculativeInsertionLockAcquire(TransactionId xid)
     784             : {
     785             :     LOCKTAG     tag;
     786             : 
     787        4026 :     speculativeInsertionToken++;
     788             : 
     789             :     /*
     790             :      * Check for wrap-around. Zero means no token is held, so don't use that.
     791             :      */
     792        4026 :     if (speculativeInsertionToken == 0)
     793           0 :         speculativeInsertionToken = 1;
     794             : 
     795        4026 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     796             : 
     797        4026 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     798             : 
     799        4026 :     return speculativeInsertionToken;
     800             : }
     801             : 
     802             : /*
     803             :  *      SpeculativeInsertionLockRelease
     804             :  *
     805             :  * Delete the lock showing that the given transaction is speculatively
     806             :  * inserting a tuple.
     807             :  */
     808             : void
     809        4020 : SpeculativeInsertionLockRelease(TransactionId xid)
     810             : {
     811             :     LOCKTAG     tag;
     812             : 
     813        4020 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     814             : 
     815        4020 :     LockRelease(&tag, ExclusiveLock, false);
     816        4020 : }
     817             : 
     818             : /*
     819             :  *      SpeculativeInsertionWait
     820             :  *
     821             :  * Wait for the specified transaction to finish or abort the insertion of a
     822             :  * tuple.
     823             :  */
     824             : void
     825           2 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
     826             : {
     827             :     LOCKTAG     tag;
     828             : 
     829           2 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
     830             : 
     831             :     Assert(TransactionIdIsValid(xid));
     832             :     Assert(token != 0);
     833             : 
     834           2 :     (void) LockAcquire(&tag, ShareLock, false, false);
     835           2 :     LockRelease(&tag, ShareLock, false);
     836           2 : }
     837             : 
     838             : /*
     839             :  * XactLockTableWaitErrorCb
     840             :  *      Error context callback for transaction lock waits.
     841             :  */
     842             : static void
     843           8 : XactLockTableWaitErrorCb(void *arg)
     844             : {
     845           8 :     XactLockTableWaitInfo *info = (XactLockTableWaitInfo *) arg;
     846             : 
     847             :     /*
     848             :      * We would like to print schema name too, but that would require a
     849             :      * syscache lookup.
     850             :      */
     851          16 :     if (info->oper != XLTW_None &&
     852          16 :         ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
     853             :     {
     854             :         const char *cxt;
     855             : 
     856           8 :         switch (info->oper)
     857             :         {
     858           0 :             case XLTW_Update:
     859           0 :                 cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
     860           0 :                 break;
     861           8 :             case XLTW_Delete:
     862           8 :                 cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
     863           8 :                 break;
     864           0 :             case XLTW_Lock:
     865           0 :                 cxt = gettext_noop("while locking tuple (%u,%u) in relation \"%s\"");
     866           0 :                 break;
     867           0 :             case XLTW_LockUpdated:
     868           0 :                 cxt = gettext_noop("while locking updated version (%u,%u) of tuple in relation \"%s\"");
     869           0 :                 break;
     870           0 :             case XLTW_InsertIndex:
     871           0 :                 cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
     872           0 :                 break;
     873           0 :             case XLTW_InsertIndexUnique:
     874           0 :                 cxt = gettext_noop("while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
     875           0 :                 break;
     876           0 :             case XLTW_FetchUpdated:
     877           0 :                 cxt = gettext_noop("while rechecking updated tuple (%u,%u) in relation \"%s\"");
     878           0 :                 break;
     879           0 :             case XLTW_RecheckExclusionConstr:
     880           0 :                 cxt = gettext_noop("while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
     881           0 :                 break;
     882             : 
     883           0 :             default:
     884           0 :                 return;
     885             :         }
     886             : 
     887          16 :         errcontext(cxt,
     888           8 :                    ItemPointerGetBlockNumber(info->ctid),
     889           8 :                    ItemPointerGetOffsetNumber(info->ctid),
     890           8 :                    RelationGetRelationName(info->rel));
     891             :     }
     892             : }
     893             : 
     894             : /*
     895             :  * WaitForLockersMultiple
     896             :  *      Wait until no transaction holds locks that conflict with the given
     897             :  *      locktags at the given lockmode.
     898             :  *
     899             :  * To do this, obtain the current list of lockers, and wait on their VXIDs
     900             :  * until they are finished.
     901             :  *
     902             :  * Note we don't try to acquire the locks on the given locktags, only the
     903             :  * VXIDs and XIDs of their lock holders; if somebody grabs a conflicting lock
     904             :  * on the objects after we obtained our initial list of lockers, we will not
     905             :  * wait for them.
     906             :  */
     907             : void
     908        2024 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
     909             : {
     910        2024 :     List       *holders = NIL;
     911             :     ListCell   *lc;
     912        2024 :     int         total = 0;
     913        2024 :     int         done = 0;
     914             : 
     915             :     /* Done if no locks to wait for */
     916        2024 :     if (locktags == NIL)
     917           0 :         return;
     918             : 
     919             :     /* Collect the transactions we need to wait on */
     920        4376 :     foreach(lc, locktags)
     921             :     {
     922        2352 :         LOCKTAG    *locktag = lfirst(lc);
     923             :         int         count;
     924             : 
     925        2352 :         holders = lappend(holders,
     926        2352 :                           GetLockConflicts(locktag, lockmode,
     927             :                                            progress ? &count : NULL));
     928        2352 :         if (progress)
     929        2212 :             total += count;
     930             :     }
     931             : 
     932        2024 :     if (progress)
     933        1884 :         pgstat_progress_update_param(PROGRESS_WAITFOR_TOTAL, total);
     934             : 
     935             :     /*
     936             :      * Note: GetLockConflicts() never reports our own xid, hence we need not
     937             :      * check for that.  Also, prepared xacts are reported and awaited.
     938             :      */
     939             : 
     940             :     /* Finally wait for each such transaction to complete */
     941        4326 :     foreach(lc, holders)
     942             :     {
     943        2352 :         VirtualTransactionId *lockholders = lfirst(lc);
     944             : 
     945        2740 :         while (VirtualTransactionIdIsValid(*lockholders))
     946             :         {
     947             :             /* If requested, publish who we're going to wait for. */
     948         438 :             if (progress)
     949             :             {
     950         328 :                 PGPROC     *holder = BackendIdGetProc(lockholders->backendId);
     951             : 
     952         328 :                 if (holder)
     953         326 :                     pgstat_progress_update_param(PROGRESS_WAITFOR_CURRENT_PID,
     954         326 :                                                  holder->pid);
     955             :             }
     956         438 :             VirtualXactLock(*lockholders, true);
     957         388 :             lockholders++;
     958             : 
     959         388 :             if (progress)
     960         328 :                 pgstat_progress_update_param(PROGRESS_WAITFOR_DONE, ++done);
     961             :         }
     962             :     }
     963        1974 :     if (progress)
     964             :     {
     965        1884 :         const int   index[] = {
     966             :             PROGRESS_WAITFOR_TOTAL,
     967             :             PROGRESS_WAITFOR_DONE,
     968             :             PROGRESS_WAITFOR_CURRENT_PID
     969             :         };
     970        1884 :         const int64 values[] = {
     971             :             0, 0, 0
     972             :         };
     973             : 
     974        1884 :         pgstat_progress_update_multi_param(3, index, values);
     975             :     }
     976             : 
     977        1974 :     list_free_deep(holders);
     978             : }
     979             : 
     980             : /*
     981             :  * WaitForLockers
     982             :  *
     983             :  * Same as WaitForLockersMultiple, for a single lock tag.
     984             :  */
     985             : void
     986         454 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
     987             : {
     988             :     List       *l;
     989             : 
     990         454 :     l = list_make1(&heaplocktag);
     991         454 :     WaitForLockersMultiple(l, lockmode, progress);
     992         454 :     list_free(l);
     993         454 : }
     994             : 
     995             : 
     996             : /*
     997             :  *      LockDatabaseObject
     998             :  *
     999             :  * Obtain a lock on a general object of the current database.  Don't use
    1000             :  * this for shared objects (such as tablespaces).  It's unwise to apply it
    1001             :  * to relations, also, since a lock taken this way will NOT conflict with
    1002             :  * locks taken via LockRelation and friends.
    1003             :  */
    1004             : void
    1005      245046 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1006             :                    LOCKMODE lockmode)
    1007             : {
    1008             :     LOCKTAG     tag;
    1009             : 
    1010      245046 :     SET_LOCKTAG_OBJECT(tag,
    1011             :                        MyDatabaseId,
    1012             :                        classid,
    1013             :                        objid,
    1014             :                        objsubid);
    1015             : 
    1016      245046 :     (void) LockAcquire(&tag, lockmode, false, false);
    1017             : 
    1018             :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1019      245046 :     AcceptInvalidationMessages();
    1020      245046 : }
    1021             : 
    1022             : /*
    1023             :  *      UnlockDatabaseObject
    1024             :  */
    1025             : void
    1026        1268 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1027             :                      LOCKMODE lockmode)
    1028             : {
    1029             :     LOCKTAG     tag;
    1030             : 
    1031        1268 :     SET_LOCKTAG_OBJECT(tag,
    1032             :                        MyDatabaseId,
    1033             :                        classid,
    1034             :                        objid,
    1035             :                        objsubid);
    1036             : 
    1037        1268 :     LockRelease(&tag, lockmode, false);
    1038        1268 : }
    1039             : 
    1040             : /*
    1041             :  *      LockSharedObject
    1042             :  *
    1043             :  * Obtain a lock on a shared-across-databases object.
    1044             :  */
    1045             : void
    1046       39390 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1047             :                  LOCKMODE lockmode)
    1048             : {
    1049             :     LOCKTAG     tag;
    1050             : 
    1051       39390 :     SET_LOCKTAG_OBJECT(tag,
    1052             :                        InvalidOid,
    1053             :                        classid,
    1054             :                        objid,
    1055             :                        objsubid);
    1056             : 
    1057       39390 :     (void) LockAcquire(&tag, lockmode, false, false);
    1058             : 
    1059             :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1060       39390 :     AcceptInvalidationMessages();
    1061       39390 : }
    1062             : 
    1063             : /*
    1064             :  *      ConditionalLockSharedObject
    1065             :  *
    1066             :  * As above, but only lock if we can get the lock without blocking.
    1067             :  * Returns true iff the lock was acquired.
    1068             :  */
    1069             : bool
    1070           8 : ConditionalLockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1071             :                             LOCKMODE lockmode)
    1072             : {
    1073             :     LOCKTAG     tag;
    1074             :     LOCALLOCK  *locallock;
    1075             :     LockAcquireResult res;
    1076             : 
    1077           8 :     SET_LOCKTAG_OBJECT(tag,
    1078             :                        InvalidOid,
    1079             :                        classid,
    1080             :                        objid,
    1081             :                        objsubid);
    1082             : 
    1083           8 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
    1084             : 
    1085           8 :     if (res == LOCKACQUIRE_NOT_AVAIL)
    1086           0 :         return false;
    1087             : 
    1088             :     /*
    1089             :      * Now that we have the lock, check for invalidation messages; see notes
    1090             :      * in LockRelationOid.
    1091             :      */
    1092           8 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
    1093             :     {
    1094           8 :         AcceptInvalidationMessages();
    1095           8 :         MarkLockClear(locallock);
    1096             :     }
    1097             : 
    1098           8 :     return true;
    1099             : }
    1100             : 
    1101             : /*
    1102             :  *      UnlockSharedObject
    1103             :  */
    1104             : void
    1105        1340 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1106             :                    LOCKMODE lockmode)
    1107             : {
    1108             :     LOCKTAG     tag;
    1109             : 
    1110        1340 :     SET_LOCKTAG_OBJECT(tag,
    1111             :                        InvalidOid,
    1112             :                        classid,
    1113             :                        objid,
    1114             :                        objsubid);
    1115             : 
    1116        1340 :     LockRelease(&tag, lockmode, false);
    1117        1340 : }
    1118             : 
    1119             : /*
    1120             :  *      LockSharedObjectForSession
    1121             :  *
    1122             :  * Obtain a session-level lock on a shared-across-databases object.
    1123             :  * See LockRelationIdForSession for notes about session-level locks.
    1124             :  */
    1125             : void
    1126          28 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1127             :                            LOCKMODE lockmode)
    1128             : {
    1129             :     LOCKTAG     tag;
    1130             : 
    1131          28 :     SET_LOCKTAG_OBJECT(tag,
    1132             :                        InvalidOid,
    1133             :                        classid,
    1134             :                        objid,
    1135             :                        objsubid);
    1136             : 
    1137          28 :     (void) LockAcquire(&tag, lockmode, true, false);
    1138          28 : }
    1139             : 
    1140             : /*
    1141             :  *      UnlockSharedObjectForSession
    1142             :  */
    1143             : void
    1144          28 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1145             :                              LOCKMODE lockmode)
    1146             : {
    1147             :     LOCKTAG     tag;
    1148             : 
    1149          28 :     SET_LOCKTAG_OBJECT(tag,
    1150             :                        InvalidOid,
    1151             :                        classid,
    1152             :                        objid,
    1153             :                        objsubid);
    1154             : 
    1155          28 :     LockRelease(&tag, lockmode, true);
    1156          28 : }
    1157             : 
    1158             : /*
    1159             :  *      LockApplyTransactionForSession
    1160             :  *
    1161             :  * Obtain a session-level lock on a transaction being applied on a logical
    1162             :  * replication subscriber. See LockRelationIdForSession for notes about
    1163             :  * session-level locks.
    1164             :  */
    1165             : void
    1166         654 : LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1167             :                                LOCKMODE lockmode)
    1168             : {
    1169             :     LOCKTAG     tag;
    1170             : 
    1171         654 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1172             :                                   MyDatabaseId,
    1173             :                                   suboid,
    1174             :                                   xid,
    1175             :                                   objid);
    1176             : 
    1177         654 :     (void) LockAcquire(&tag, lockmode, true, false);
    1178         648 : }
    1179             : 
    1180             : /*
    1181             :  *      UnlockApplyTransactionForSession
    1182             :  */
    1183             : void
    1184         638 : UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1185             :                                  LOCKMODE lockmode)
    1186             : {
    1187             :     LOCKTAG     tag;
    1188             : 
    1189         638 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1190             :                                   MyDatabaseId,
    1191             :                                   suboid,
    1192             :                                   xid,
    1193             :                                   objid);
    1194             : 
    1195         638 :     LockRelease(&tag, lockmode, true);
    1196         638 : }
    1197             : 
    1198             : /*
    1199             :  * Append a description of a lockable object to buf.
    1200             :  *
    1201             :  * Ideally we would print names for the numeric values, but that requires
    1202             :  * getting locks on system tables, which might cause problems since this is
    1203             :  * typically used to report deadlock situations.
    1204             :  */
    1205             : void
    1206          62 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
    1207             : {
    1208          62 :     switch ((LockTagType) tag->locktag_type)
    1209             :     {
    1210          28 :         case LOCKTAG_RELATION:
    1211          28 :             appendStringInfo(buf,
    1212          28 :                              _("relation %u of database %u"),
    1213             :                              tag->locktag_field2,
    1214             :                              tag->locktag_field1);
    1215          28 :             break;
    1216           0 :         case LOCKTAG_RELATION_EXTEND:
    1217           0 :             appendStringInfo(buf,
    1218           0 :                              _("extension of relation %u of database %u"),
    1219             :                              tag->locktag_field2,
    1220             :                              tag->locktag_field1);
    1221           0 :             break;
    1222           0 :         case LOCKTAG_DATABASE_FROZEN_IDS:
    1223           0 :             appendStringInfo(buf,
    1224           0 :                              _("pg_database.datfrozenxid of database %u"),
    1225             :                              tag->locktag_field1);
    1226           0 :             break;
    1227           0 :         case LOCKTAG_PAGE:
    1228           0 :             appendStringInfo(buf,
    1229           0 :                              _("page %u of relation %u of database %u"),
    1230             :                              tag->locktag_field3,
    1231             :                              tag->locktag_field2,
    1232             :                              tag->locktag_field1);
    1233           0 :             break;
    1234           0 :         case LOCKTAG_TUPLE:
    1235           0 :             appendStringInfo(buf,
    1236           0 :                              _("tuple (%u,%u) of relation %u of database %u"),
    1237             :                              tag->locktag_field3,
    1238           0 :                              tag->locktag_field4,
    1239             :                              tag->locktag_field2,
    1240             :                              tag->locktag_field1);
    1241           0 :             break;
    1242           4 :         case LOCKTAG_TRANSACTION:
    1243           4 :             appendStringInfo(buf,
    1244           4 :                              _("transaction %u"),
    1245             :                              tag->locktag_field1);
    1246           4 :             break;
    1247          12 :         case LOCKTAG_VIRTUALTRANSACTION:
    1248          12 :             appendStringInfo(buf,
    1249          12 :                              _("virtual transaction %d/%u"),
    1250             :                              tag->locktag_field1,
    1251             :                              tag->locktag_field2);
    1252          12 :             break;
    1253           0 :         case LOCKTAG_SPECULATIVE_TOKEN:
    1254           0 :             appendStringInfo(buf,
    1255           0 :                              _("speculative token %u of transaction %u"),
    1256             :                              tag->locktag_field2,
    1257             :                              tag->locktag_field1);
    1258           0 :             break;
    1259           0 :         case LOCKTAG_OBJECT:
    1260           0 :             appendStringInfo(buf,
    1261           0 :                              _("object %u of class %u of database %u"),
    1262             :                              tag->locktag_field3,
    1263             :                              tag->locktag_field2,
    1264             :                              tag->locktag_field1);
    1265           0 :             break;
    1266           0 :         case LOCKTAG_USERLOCK:
    1267             :             /* reserved for old contrib code, now on pgfoundry */
    1268           0 :             appendStringInfo(buf,
    1269           0 :                              _("user lock [%u,%u,%u]"),
    1270             :                              tag->locktag_field1,
    1271             :                              tag->locktag_field2,
    1272             :                              tag->locktag_field3);
    1273           0 :             break;
    1274          12 :         case LOCKTAG_ADVISORY:
    1275          12 :             appendStringInfo(buf,
    1276          12 :                              _("advisory lock [%u,%u,%u,%u]"),
    1277             :                              tag->locktag_field1,
    1278             :                              tag->locktag_field2,
    1279             :                              tag->locktag_field3,
    1280          12 :                              tag->locktag_field4);
    1281          12 :             break;
    1282           6 :         case LOCKTAG_APPLY_TRANSACTION:
    1283           6 :             appendStringInfo(buf,
    1284           6 :                              _("remote transaction %u of subscription %u of database %u"),
    1285             :                              tag->locktag_field3,
    1286             :                              tag->locktag_field2,
    1287             :                              tag->locktag_field1);
    1288           6 :             break;
    1289           0 :         default:
    1290           0 :             appendStringInfo(buf,
    1291           0 :                              _("unrecognized locktag type %d"),
    1292           0 :                              (int) tag->locktag_type);
    1293           0 :             break;
    1294             :     }
    1295          62 : }
    1296             : 
    1297             : /*
    1298             :  * GetLockNameFromTagType
    1299             :  *
    1300             :  *  Given locktag type, return the corresponding lock name.
    1301             :  */
    1302             : const char *
    1303          14 : GetLockNameFromTagType(uint16 locktag_type)
    1304             : {
    1305          14 :     if (locktag_type > LOCKTAG_LAST_TYPE)
    1306           0 :         return "???";
    1307          14 :     return LockTagTypeNames[locktag_type];
    1308             : }

Generated by: LCOV version 1.14