LCOV - differential code coverage report
Current view: top level - src/backend/storage/lmgr - lmgr.c (source / functions) Coverage Total Hit LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 76.1 % 389 296 13 20 60 10 12 16 258 23 24 1
Current Date: 2023-04-08 15:15:32 Functions: 93.3 % 45 42 3 2 3 37 4
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  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 CBC     2145763 : RelationInitLockInfo(Relation relation)
      73                 : {
      74         2145763 :     Assert(RelationIsValid(relation));
      75         2145763 :     Assert(OidIsValid(RelationGetRelid(relation)));
      76                 : 
      77         2145763 :     relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
      78                 : 
      79         2145763 :     if (relation->rd_rel->relisshared)
      80          302740 :         relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
      81                 :     else
      82         1843023 :         relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
      83         2145763 : }
      84                 : 
      85                 : /*
      86                 :  * SetLocktagRelationOid
      87                 :  *      Set up a locktag for a relation, given only relation OID
      88                 :  */
      89                 : static inline void
      90        27650722 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
      91                 : {
      92                 :     Oid         dbid;
      93                 : 
      94        27650722 :     if (IsSharedRelation(relid))
      95         1336632 :         dbid = InvalidOid;
      96                 :     else
      97        26314090 :         dbid = MyDatabaseId;
      98                 : 
      99        27650722 :     SET_LOCKTAG_RELATION(*tag, dbid, relid);
     100        27650722 : }
     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        27518084 : LockRelationOid(Oid relid, LOCKMODE lockmode)
     110                 : {
     111                 :     LOCKTAG     tag;
     112                 :     LOCALLOCK  *locallock;
     113                 :     LockAcquireResult res;
     114                 : 
     115        27518084 :     SetLocktagRelationOid(&tag, relid);
     116                 : 
     117        27518084 :     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        27518074 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     136                 :     {
     137        25184815 :         AcceptInvalidationMessages();
     138        25184815 :         MarkLockClear(locallock);
     139                 :     }
     140        27518074 : }
     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             790 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
     153                 : {
     154                 :     LOCKTAG     tag;
     155                 :     LOCALLOCK  *locallock;
     156                 :     LockAcquireResult res;
     157                 : 
     158             790 :     SetLocktagRelationOid(&tag, relid);
     159                 : 
     160             790 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
     161                 : 
     162             790 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     163              18 :         return false;
     164                 : 
     165                 :     /*
     166                 :      * Now that we have the lock, check for invalidation messages; see notes
     167                 :      * in LockRelationOid.
     168                 :      */
     169             772 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     170                 :     {
     171             760 :         AcceptInvalidationMessages();
     172             760 :         MarkLockClear(locallock);
     173                 :     }
     174                 : 
     175             772 :     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           81906 : LockRelationId(LockRelId *relid, LOCKMODE lockmode)
     186                 : {
     187                 :     LOCKTAG     tag;
     188                 :     LOCALLOCK  *locallock;
     189                 :     LockAcquireResult res;
     190                 : 
     191           81906 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     192                 : 
     193           81906 :     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           81906 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     200                 :     {
     201           81906 :         AcceptInvalidationMessages();
     202           81906 :         MarkLockClear(locallock);
     203                 :     }
     204           81906 : }
     205                 : 
     206                 : /*
     207                 :  *      UnlockRelationId
     208                 :  *
     209                 :  * Unlock, given a LockRelId.  This is preferred over UnlockRelationOid
     210                 :  * for speed reasons.
     211                 :  */
     212                 : void
     213        24980568 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
     214                 : {
     215                 :     LOCKTAG     tag;
     216                 : 
     217        24980568 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     218                 : 
     219        24980568 :     LockRelease(&tag, lockmode, false);
     220        24980568 : }
     221                 : 
     222                 : /*
     223                 :  *      UnlockRelationOid
     224                 :  *
     225                 :  * Unlock, given only a relation Oid.  Use UnlockRelationId if you can.
     226                 :  */
     227                 : void
     228          131848 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
     229                 : {
     230                 :     LOCKTAG     tag;
     231                 : 
     232          131848 :     SetLocktagRelationOid(&tag, relid);
     233                 : 
     234          131848 :     LockRelease(&tag, lockmode, false);
     235          131848 : }
     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           63466 : LockRelation(Relation relation, LOCKMODE lockmode)
     246                 : {
     247                 :     LOCKTAG     tag;
     248                 :     LOCALLOCK  *locallock;
     249                 :     LockAcquireResult res;
     250                 : 
     251           63466 :     SET_LOCKTAG_RELATION(tag,
     252                 :                          relation->rd_lockInfo.lockRelId.dbId,
     253                 :                          relation->rd_lockInfo.lockRelId.relId);
     254                 : 
     255           63466 :     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           63466 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     262                 :     {
     263           63466 :         AcceptInvalidationMessages();
     264           63466 :         MarkLockClear(locallock);
     265                 :     }
     266           63466 : }
     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             295 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
     277                 : {
     278                 :     LOCKTAG     tag;
     279                 :     LOCALLOCK  *locallock;
     280                 :     LockAcquireResult res;
     281                 : 
     282             295 :     SET_LOCKTAG_RELATION(tag,
     283                 :                          relation->rd_lockInfo.lockRelId.dbId,
     284                 :                          relation->rd_lockInfo.lockRelId.relId);
     285                 : 
     286             295 :     res = LockAcquireExtended(&tag, lockmode, false, true, true, &locallock);
     287                 : 
     288             295 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     289             202 :         return false;
     290                 : 
     291                 :     /*
     292                 :      * Now that we have the lock, check for invalidation messages; see notes
     293                 :      * in LockRelationOid.
     294                 :      */
     295              93 :     if (res != LOCKACQUIRE_ALREADY_CLEAR)
     296                 :     {
     297              93 :         AcceptInvalidationMessages();
     298              93 :         MarkLockClear(locallock);
     299                 :     }
     300                 : 
     301              93 :     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              93 : UnlockRelation(Relation relation, LOCKMODE lockmode)
     312                 : {
     313                 :     LOCKTAG     tag;
     314                 : 
     315              93 :     SET_LOCKTAG_RELATION(tag,
     316                 :                          relation->rd_lockInfo.lockRelId.dbId,
     317                 :                          relation->rd_lockInfo.lockRelId.relId);
     318                 : 
     319              93 :     LockRelease(&tag, lockmode, false);
     320              93 : }
     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         2029197 : CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger)
     332                 : {
     333                 :     LOCKTAG     tag;
     334                 : 
     335         2029197 :     SET_LOCKTAG_RELATION(tag,
     336                 :                          relation->rd_lockInfo.lockRelId.dbId,
     337                 :                          relation->rd_lockInfo.lockRelId.relId);
     338                 : 
     339         2029197 :     if (LockHeldByMe(&tag, lockmode))
     340         1188362 :         return true;
     341                 : 
     342          840835 :     if (orstronger)
     343                 :     {
     344                 :         LOCKMODE    slockmode;
     345                 : 
     346          840835 :         for (slockmode = lockmode + 1;
     347         3400329 :              slockmode <= MaxLockMode;
     348         2559494 :              slockmode++)
     349                 :         {
     350         3400329 :             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          840835 :                 return true;
     360                 :             }
     361                 :         }
     362                 :     }
     363                 : 
     364 UBC           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 CBC       38019 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     399                 : {
     400                 :     LOCKTAG     tag;
     401                 : 
     402           38019 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     403                 : 
     404           38019 :     (void) LockAcquire(&tag, lockmode, true, false);
     405           38019 : }
     406                 : 
     407                 : /*
     408                 :  *      UnlockRelationIdForSession
     409                 :  */
     410                 : void
     411           38001 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     412                 : {
     413                 :     LOCKTAG     tag;
     414                 : 
     415           38001 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     416                 : 
     417           38001 :     LockRelease(&tag, lockmode, true);
     418           38001 : }
     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          325659 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
     432                 : {
     433                 :     LOCKTAG     tag;
     434                 : 
     435          325659 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     436                 :                                 relation->rd_lockInfo.lockRelId.dbId,
     437                 :                                 relation->rd_lockInfo.lockRelId.relId);
     438                 : 
     439          325659 :     (void) LockAcquire(&tag, lockmode, false, false);
     440          325659 : }
     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 UBC           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 CBC      114052 : RelationExtensionLockWaiterCount(Relation relation)
     467                 : {
     468                 :     LOCKTAG     tag;
     469                 : 
     470          114052 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     471                 :                                 relation->rd_lockInfo.lockRelId.dbId,
     472                 :                                 relation->rd_lockInfo.lockRelId.relId);
     473                 : 
     474          114052 :     return LockWaiterCount(&tag);
     475                 : }
     476                 : 
     477                 : /*
     478                 :  *      UnlockRelationForExtension
     479                 :  */
     480                 : void
     481          325659 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
     482                 : {
     483                 :     LOCKTAG     tag;
     484                 : 
     485          325659 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     486                 :                                 relation->rd_lockInfo.lockRelId.dbId,
     487                 :                                 relation->rd_lockInfo.lockRelId.relId);
     488                 : 
     489          325659 :     LockRelease(&tag, lockmode, false);
     490          325659 : }
     491                 : 
     492                 : /*
     493                 :  *      LockDatabaseFrozenIds
     494                 :  *
     495                 :  * This allows one backend per database to execute vac_update_datfrozenxid().
     496                 :  */
     497                 : void
     498            1250 : LockDatabaseFrozenIds(LOCKMODE lockmode)
     499                 : {
     500                 :     LOCKTAG     tag;
     501                 : 
     502            1250 :     SET_LOCKTAG_DATABASE_FROZEN_IDS(tag, MyDatabaseId);
     503                 : 
     504            1250 :     (void) LockAcquire(&tag, lockmode, false, false);
     505            1250 : }
     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              40 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     515                 : {
     516                 :     LOCKTAG     tag;
     517                 : 
     518              40 :     SET_LOCKTAG_PAGE(tag,
     519                 :                      relation->rd_lockInfo.lockRelId.dbId,
     520                 :                      relation->rd_lockInfo.lockRelId.relId,
     521                 :                      blkno);
     522                 : 
     523              40 :     (void) LockAcquire(&tag, lockmode, false, false);
     524              40 : }
     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 UBC           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 CBC          40 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     550                 : {
     551                 :     LOCKTAG     tag;
     552                 : 
     553              40 :     SET_LOCKTAG_PAGE(tag,
     554                 :                      relation->rd_lockInfo.lockRelId.dbId,
     555                 :                      relation->rd_lockInfo.lockRelId.relId,
     556                 :                      blkno);
     557                 : 
     558              40 :     LockRelease(&tag, lockmode, false);
     559              40 : }
     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             196 : LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     570                 : {
     571                 :     LOCKTAG     tag;
     572                 : 
     573             196 :     SET_LOCKTAG_TUPLE(tag,
     574                 :                       relation->rd_lockInfo.lockRelId.dbId,
     575                 :                       relation->rd_lockInfo.lockRelId.relId,
     576                 :                       ItemPointerGetBlockNumber(tid),
     577                 :                       ItemPointerGetOffsetNumber(tid));
     578                 : 
     579             196 :     (void) LockAcquire(&tag, lockmode, false, false);
     580             196 : }
     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              41 : ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     590                 : {
     591                 :     LOCKTAG     tag;
     592                 : 
     593              41 :     SET_LOCKTAG_TUPLE(tag,
     594                 :                       relation->rd_lockInfo.lockRelId.dbId,
     595                 :                       relation->rd_lockInfo.lockRelId.relId,
     596                 :                       ItemPointerGetBlockNumber(tid),
     597                 :                       ItemPointerGetOffsetNumber(tid));
     598                 : 
     599              41 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     600                 : }
     601                 : 
     602                 : /*
     603                 :  *      UnlockTuple
     604                 :  */
     605                 : void
     606             225 : UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     607                 : {
     608                 :     LOCKTAG     tag;
     609                 : 
     610             225 :     SET_LOCKTAG_TUPLE(tag,
     611                 :                       relation->rd_lockInfo.lockRelId.dbId,
     612                 :                       relation->rd_lockInfo.lockRelId.relId,
     613                 :                       ItemPointerGetBlockNumber(tid),
     614                 :                       ItemPointerGetOffsetNumber(tid));
     615                 : 
     616             225 :     LockRelease(&tag, lockmode, false);
     617             225 : }
     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          301485 : XactLockTableInsert(TransactionId xid)
     628                 : {
     629                 :     LOCKTAG     tag;
     630                 : 
     631          301485 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     632                 : 
     633          301485 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     634          301485 : }
     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            2810 : XactLockTableDelete(TransactionId xid)
     645                 : {
     646                 :     LOCKTAG     tag;
     647                 : 
     648            2810 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     649                 : 
     650            2810 :     LockRelease(&tag, ExclusiveLock, false);
     651            2810 : }
     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             333 : XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
     669                 :                   XLTW_Oper oper)
     670                 : {
     671                 :     LOCKTAG     tag;
     672                 :     XactLockTableWaitInfo info;
     673                 :     ErrorContextCallback callback;
     674             333 :     bool        first = true;
     675                 : 
     676                 :     /*
     677                 :      * If an operation is specified, set up our verbose error context
     678                 :      * callback.
     679                 :      */
     680             333 :     if (oper != XLTW_None)
     681                 :     {
     682             312 :         Assert(RelationIsValid(rel));
     683             312 :         Assert(ItemPointerIsValid(ctid));
     684                 : 
     685             312 :         info.rel = rel;
     686             312 :         info.ctid = ctid;
     687             312 :         info.oper = oper;
     688                 : 
     689             312 :         callback.callback = XactLockTableWaitErrorCb;
     690             312 :         callback.arg = &info;
     691             312 :         callback.previous = error_context_stack;
     692             312 :         error_context_stack = &callback;
     693                 :     }
     694                 : 
     695                 :     for (;;)
     696                 :     {
     697             335 :         Assert(TransactionIdIsValid(xid));
     698             335 :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     699                 : 
     700             335 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     701                 : 
     702             335 :         (void) LockAcquire(&tag, ShareLock, false, false);
     703                 : 
     704             327 :         LockRelease(&tag, ShareLock, false);
     705                 : 
     706             327 :         if (!TransactionIdIsInProgress(xid))
     707             325 :             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               2 :         if (!first)
     725 UBC           0 :             pg_usleep(1000L);
     726 CBC           2 :         first = false;
     727               2 :         xid = SubTransGetTopmostTransaction(xid);
     728                 :     }
     729                 : 
     730             325 :     if (oper != XLTW_None)
     731             306 :         error_context_stack = callback.previous;
     732             325 : }
     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              45 : ConditionalXactLockTableWait(TransactionId xid)
     742                 : {
     743                 :     LOCKTAG     tag;
     744              45 :     bool        first = true;
     745                 : 
     746                 :     for (;;)
     747                 :     {
     748              45 :         Assert(TransactionIdIsValid(xid));
     749              45 :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     750                 : 
     751              45 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     752                 : 
     753              45 :         if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
     754              45 :             return false;
     755                 : 
     756 UBC           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 CBC        2013 : SpeculativeInsertionLockAcquire(TransactionId xid)
     784                 : {
     785                 :     LOCKTAG     tag;
     786                 : 
     787            2013 :     speculativeInsertionToken++;
     788                 : 
     789                 :     /*
     790                 :      * Check for wrap-around. Zero means no token is held, so don't use that.
     791                 :      */
     792            2013 :     if (speculativeInsertionToken == 0)
     793 UBC           0 :         speculativeInsertionToken = 1;
     794                 : 
     795 CBC        2013 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     796                 : 
     797            2013 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     798                 : 
     799            2013 :     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            2010 : SpeculativeInsertionLockRelease(TransactionId xid)
     810                 : {
     811                 :     LOCKTAG     tag;
     812                 : 
     813            2010 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     814                 : 
     815            2010 :     LockRelease(&tag, ExclusiveLock, false);
     816            2010 : }
     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               1 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
     826                 : {
     827                 :     LOCKTAG     tag;
     828                 : 
     829               1 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
     830                 : 
     831               1 :     Assert(TransactionIdIsValid(xid));
     832               1 :     Assert(token != 0);
     833                 : 
     834               1 :     (void) LockAcquire(&tag, ShareLock, false, false);
     835               1 :     LockRelease(&tag, ShareLock, false);
     836               1 : }
     837                 : 
     838                 : /*
     839                 :  * XactLockTableWaitErrorCb
     840                 :  *      Error context callback for transaction lock waits.
     841                 :  */
     842                 : static void
     843               5 : XactLockTableWaitErrorCb(void *arg)
     844                 : {
     845               5 :     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              10 :     if (info->oper != XLTW_None &&
     852              10 :         ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
     853                 :     {
     854                 :         const char *cxt;
     855                 : 
     856               5 :         switch (info->oper)
     857                 :         {
     858 UBC           0 :             case XLTW_Update:
     859               0 :                 cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
     860               0 :                 break;
     861 CBC           4 :             case XLTW_Delete:
     862               4 :                 cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
     863               4 :                 break;
     864 UBC           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 CBC           1 :             case XLTW_InsertIndex:
     871               1 :                 cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
     872               1 :                 break;
     873 UBC           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 CBC          10 :         errcontext(cxt,
     888               5 :                    ItemPointerGetBlockNumber(info->ctid),
     889               5 :                    ItemPointerGetOffsetNumber(info->ctid),
     890               5 :                    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             989 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode, bool progress)
     909                 : {
     910             989 :     List       *holders = NIL;
     911                 :     ListCell   *lc;
     912             989 :     int         total = 0;
     913             989 :     int         done = 0;
     914                 : 
     915                 :     /* Done if no locks to wait for */
     916 GNC         989 :     if (locktags == NIL)
     917 UBC           0 :         return;
     918                 : 
     919                 :     /* Collect the transactions we need to wait on */
     920 CBC        2142 :     foreach(lc, locktags)
     921                 :     {
     922            1153 :         LOCKTAG    *locktag = lfirst(lc);
     923                 :         int         count;
     924                 : 
     925            1153 :         holders = lappend(holders,
     926            1153 :                           GetLockConflicts(locktag, lockmode,
     927                 :                                            progress ? &count : NULL));
     928            1153 :         if (progress)
     929            1083 :             total += count;
     930                 :     }
     931                 : 
     932             989 :     if (progress)
     933             919 :         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            2117 :     foreach(lc, holders)
     942                 :     {
     943            1153 :         VirtualTransactionId *lockholders = lfirst(lc);
     944                 : 
     945            1371 :         while (VirtualTransactionIdIsValid(*lockholders))
     946                 :         {
     947                 :             /* If requested, publish who we're going to wait for. */
     948             243 :             if (progress)
     949                 :             {
     950             188 :                 PGPROC     *holder = BackendIdGetProc(lockholders->backendId);
     951                 : 
     952             188 :                 if (holder)
     953             187 :                     pgstat_progress_update_param(PROGRESS_WAITFOR_CURRENT_PID,
     954             187 :                                                  holder->pid);
     955                 :             }
     956             243 :             VirtualXactLock(*lockholders, true);
     957             218 :             lockholders++;
     958                 : 
     959             218 :             if (progress)
     960             188 :                 pgstat_progress_update_param(PROGRESS_WAITFOR_DONE, ++done);
     961                 :         }
     962                 :     }
     963             964 :     if (progress)
     964                 :     {
     965             919 :         const int   index[] = {
     966                 :             PROGRESS_WAITFOR_TOTAL,
     967                 :             PROGRESS_WAITFOR_DONE,
     968                 :             PROGRESS_WAITFOR_CURRENT_PID
     969                 :         };
     970             919 :         const int64 values[] = {
     971                 :             0, 0, 0
     972                 :         };
     973                 : 
     974             919 :         pgstat_progress_update_multi_param(3, index, values);
     975                 :     }
     976                 : 
     977             964 :     list_free_deep(holders);
     978                 : }
     979                 : 
     980                 : /*
     981                 :  * WaitForLockers
     982                 :  *
     983                 :  * Same as WaitForLockersMultiple, for a single lock tag.
     984                 :  */
     985                 : void
     986             240 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode, bool progress)
     987                 : {
     988                 :     List       *l;
     989                 : 
     990             240 :     l = list_make1(&heaplocktag);
     991             240 :     WaitForLockersMultiple(l, lockmode, progress);
     992             240 :     list_free(l);
     993             240 : }
     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          215524 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1006                 :                    LOCKMODE lockmode)
    1007                 : {
    1008                 :     LOCKTAG     tag;
    1009                 : 
    1010          215524 :     SET_LOCKTAG_OBJECT(tag,
    1011                 :                        MyDatabaseId,
    1012                 :                        classid,
    1013                 :                        objid,
    1014                 :                        objsubid);
    1015                 : 
    1016          215524 :     (void) LockAcquire(&tag, lockmode, false, false);
    1017                 : 
    1018                 :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1019          215524 :     AcceptInvalidationMessages();
    1020          215524 : }
    1021                 : 
    1022                 : /*
    1023                 :  *      UnlockDatabaseObject
    1024                 :  */
    1025                 : void
    1026             673 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
    1027                 :                      LOCKMODE lockmode)
    1028                 : {
    1029                 :     LOCKTAG     tag;
    1030                 : 
    1031             673 :     SET_LOCKTAG_OBJECT(tag,
    1032                 :                        MyDatabaseId,
    1033                 :                        classid,
    1034                 :                        objid,
    1035                 :                        objsubid);
    1036                 : 
    1037             673 :     LockRelease(&tag, lockmode, false);
    1038             673 : }
    1039                 : 
    1040                 : /*
    1041                 :  *      LockSharedObject
    1042                 :  *
    1043                 :  * Obtain a lock on a shared-across-databases object.
    1044                 :  */
    1045                 : void
    1046           20434 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1047                 :                  LOCKMODE lockmode)
    1048                 : {
    1049                 :     LOCKTAG     tag;
    1050                 : 
    1051           20434 :     SET_LOCKTAG_OBJECT(tag,
    1052                 :                        InvalidOid,
    1053                 :                        classid,
    1054                 :                        objid,
    1055                 :                        objsubid);
    1056                 : 
    1057           20434 :     (void) LockAcquire(&tag, lockmode, false, false);
    1058                 : 
    1059                 :     /* Make sure syscaches are up-to-date with any changes we waited for */
    1060           20434 :     AcceptInvalidationMessages();
    1061           20434 : }
    1062                 : 
    1063                 : /*
    1064                 :  *      UnlockSharedObject
    1065                 :  */
    1066                 : void
    1067             661 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
    1068                 :                    LOCKMODE lockmode)
    1069                 : {
    1070                 :     LOCKTAG     tag;
    1071                 : 
    1072             661 :     SET_LOCKTAG_OBJECT(tag,
    1073                 :                        InvalidOid,
    1074                 :                        classid,
    1075                 :                        objid,
    1076                 :                        objsubid);
    1077                 : 
    1078             661 :     LockRelease(&tag, lockmode, false);
    1079             661 : }
    1080                 : 
    1081                 : /*
    1082                 :  *      LockSharedObjectForSession
    1083                 :  *
    1084                 :  * Obtain a session-level lock on a shared-across-databases object.
    1085                 :  * See LockRelationIdForSession for notes about session-level locks.
    1086                 :  */
    1087                 : void
    1088              14 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1089                 :                            LOCKMODE lockmode)
    1090                 : {
    1091                 :     LOCKTAG     tag;
    1092                 : 
    1093              14 :     SET_LOCKTAG_OBJECT(tag,
    1094                 :                        InvalidOid,
    1095                 :                        classid,
    1096                 :                        objid,
    1097                 :                        objsubid);
    1098                 : 
    1099              14 :     (void) LockAcquire(&tag, lockmode, true, false);
    1100              14 : }
    1101                 : 
    1102                 : /*
    1103                 :  *      UnlockSharedObjectForSession
    1104                 :  */
    1105                 : void
    1106              14 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
    1107                 :                              LOCKMODE lockmode)
    1108                 : {
    1109                 :     LOCKTAG     tag;
    1110                 : 
    1111              14 :     SET_LOCKTAG_OBJECT(tag,
    1112                 :                        InvalidOid,
    1113                 :                        classid,
    1114                 :                        objid,
    1115                 :                        objsubid);
    1116                 : 
    1117              14 :     LockRelease(&tag, lockmode, true);
    1118              14 : }
    1119                 : 
    1120                 : /*
    1121                 :  *      LockApplyTransactionForSession
    1122                 :  *
    1123                 :  * Obtain a session-level lock on a transaction being applied on a logical
    1124                 :  * replication subscriber. See LockRelationIdForSession for notes about
    1125                 :  * session-level locks.
    1126                 :  */
    1127                 : void
    1128 GNC         327 : LockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1129                 :                                LOCKMODE lockmode)
    1130                 : {
    1131                 :     LOCKTAG     tag;
    1132                 : 
    1133             327 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1134                 :                                   MyDatabaseId,
    1135                 :                                   suboid,
    1136                 :                                   xid,
    1137                 :                                   objid);
    1138                 : 
    1139             327 :     (void) LockAcquire(&tag, lockmode, true, false);
    1140             324 : }
    1141                 : 
    1142                 : /*
    1143                 :  *      UnlockApplyTransactionForSession
    1144                 :  */
    1145                 : void
    1146             319 : UnlockApplyTransactionForSession(Oid suboid, TransactionId xid, uint16 objid,
    1147                 :                                  LOCKMODE lockmode)
    1148                 : {
    1149                 :     LOCKTAG     tag;
    1150                 : 
    1151             319 :     SET_LOCKTAG_APPLY_TRANSACTION(tag,
    1152                 :                                   MyDatabaseId,
    1153                 :                                   suboid,
    1154                 :                                   xid,
    1155                 :                                   objid);
    1156                 : 
    1157             319 :     LockRelease(&tag, lockmode, true);
    1158             319 : }
    1159                 : 
    1160                 : /*
    1161                 :  * Append a description of a lockable object to buf.
    1162                 :  *
    1163                 :  * Ideally we would print names for the numeric values, but that requires
    1164                 :  * getting locks on system tables, which might cause problems since this is
    1165                 :  * typically used to report deadlock situations.
    1166                 :  */
    1167 ECB             : void
    1168 GIC          40 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
    1169                 : {
    1170              40 :     switch ((LockTagType) tag->locktag_type)
    1171                 :     {
    1172 CBC          14 :         case LOCKTAG_RELATION:
    1173 GIC          14 :             appendStringInfo(buf,
    1174              14 :                              _("relation %u of database %u"),
    1175              14 :                              tag->locktag_field2,
    1176              14 :                              tag->locktag_field1);
    1177              14 :             break;
    1178 LBC           0 :         case LOCKTAG_RELATION_EXTEND:
    1179               0 :             appendStringInfo(buf,
    1180 UIC           0 :                              _("extension of relation %u of database %u"),
    1181               0 :                              tag->locktag_field2,
    1182               0 :                              tag->locktag_field1);
    1183               0 :             break;
    1184               0 :         case LOCKTAG_DATABASE_FROZEN_IDS:
    1185 LBC           0 :             appendStringInfo(buf,
    1186 UIC           0 :                              _("pg_database.datfrozenxid of database %u"),
    1187               0 :                              tag->locktag_field1);
    1188               0 :             break;
    1189               0 :         case LOCKTAG_PAGE:
    1190 LBC           0 :             appendStringInfo(buf,
    1191 UIC           0 :                              _("page %u of relation %u of database %u"),
    1192               0 :                              tag->locktag_field3,
    1193               0 :                              tag->locktag_field2,
    1194               0 :                              tag->locktag_field1);
    1195               0 :             break;
    1196 LBC           0 :         case LOCKTAG_TUPLE:
    1197               0 :             appendStringInfo(buf,
    1198 UIC           0 :                              _("tuple (%u,%u) of relation %u of database %u"),
    1199               0 :                              tag->locktag_field3,
    1200               0 :                              tag->locktag_field4,
    1201               0 :                              tag->locktag_field2,
    1202               0 :                              tag->locktag_field1);
    1203               0 :             break;
    1204 GIC           2 :         case LOCKTAG_TRANSACTION:
    1205               2 :             appendStringInfo(buf,
    1206               2 :                              _("transaction %u"),
    1207 CBC           2 :                              tag->locktag_field1);
    1208 GIC           2 :             break;
    1209 CBC          15 :         case LOCKTAG_VIRTUALTRANSACTION:
    1210 GIC          15 :             appendStringInfo(buf,
    1211 CBC          15 :                              _("virtual transaction %d/%u"),
    1212              15 :                              tag->locktag_field1,
    1213              15 :                              tag->locktag_field2);
    1214              15 :             break;
    1215 LBC           0 :         case LOCKTAG_SPECULATIVE_TOKEN:
    1216               0 :             appendStringInfo(buf,
    1217 UBC           0 :                              _("speculative token %u of transaction %u"),
    1218               0 :                              tag->locktag_field2,
    1219               0 :                              tag->locktag_field1);
    1220               0 :             break;
    1221               0 :         case LOCKTAG_OBJECT:
    1222               0 :             appendStringInfo(buf,
    1223               0 :                              _("object %u of class %u of database %u"),
    1224               0 :                              tag->locktag_field3,
    1225               0 :                              tag->locktag_field2,
    1226               0 :                              tag->locktag_field1);
    1227               0 :             break;
    1228               0 :         case LOCKTAG_USERLOCK:
    1229 EUB             :             /* reserved for old contrib code, now on pgfoundry */
    1230 UBC           0 :             appendStringInfo(buf,
    1231               0 :                              _("user lock [%u,%u,%u]"),
    1232               0 :                              tag->locktag_field1,
    1233               0 :                              tag->locktag_field2,
    1234               0 :                              tag->locktag_field3);
    1235               0 :             break;
    1236 GBC           6 :         case LOCKTAG_ADVISORY:
    1237               6 :             appendStringInfo(buf,
    1238               6 :                              _("advisory lock [%u,%u,%u,%u]"),
    1239               6 :                              tag->locktag_field1,
    1240               6 :                              tag->locktag_field2,
    1241               6 :                              tag->locktag_field3,
    1242               6 :                              tag->locktag_field4);
    1243 CBC           6 :             break;
    1244 GNC           3 :         case LOCKTAG_APPLY_TRANSACTION:
    1245               3 :             appendStringInfo(buf,
    1246               3 :                              _("remote transaction %u of subscription %u of database %u"),
    1247               3 :                              tag->locktag_field3,
    1248               3 :                              tag->locktag_field2,
    1249               3 :                              tag->locktag_field1);
    1250               3 :             break;
    1251 LBC           0 :         default:
    1252               0 :             appendStringInfo(buf,
    1253               0 :                              _("unrecognized locktag type %d"),
    1254               0 :                              (int) tag->locktag_type);
    1255               0 :             break;
    1256 ECB             :     }
    1257 CBC          40 : }
    1258 ECB             : 
    1259                 : /*
    1260                 :  * GetLockNameFromTagType
    1261 EUB             :  *
    1262                 :  *  Given locktag type, return the corresponding lock name.
    1263                 :  */
    1264                 : const char *
    1265 GBC           7 : GetLockNameFromTagType(uint16 locktag_type)
    1266 EUB             : {
    1267 GBC           7 :     if (locktag_type > LOCKTAG_LAST_TYPE)
    1268 UBC           0 :         return "???";
    1269 GBC           7 :     return LockTagTypeNames[locktag_type];
    1270 EUB             : }
        

Generated by: LCOV version v1.16-55-g56c0a2a