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

Generated by: LCOV version 1.14