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

Generated by: LCOV version 1.13