LCOV - code coverage report
Current view: top level - src/backend/storage/lmgr - lmgr.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 163 264 61.7 %
Date: 2017-09-29 13:40:31 Functions: 30 40 75.0 %
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-2017, 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 "miscadmin.h"
      23             : #include "storage/lmgr.h"
      24             : #include "storage/procarray.h"
      25             : #include "utils/inval.h"
      26             : 
      27             : 
      28             : /*
      29             :  * Per-backend counter for generating speculative insertion tokens.
      30             :  *
      31             :  * This may wrap around, but that's OK as it's only used for the short
      32             :  * duration between inserting a tuple and checking that there are no (unique)
      33             :  * constraint violations.  It's theoretically possible that a backend sees a
      34             :  * tuple that was speculatively inserted by another backend, but before it has
      35             :  * started waiting on the token, the other backend completes its insertion,
      36             :  * and then performs 2^32 unrelated insertions.  And after all that, the
      37             :  * first backend finally calls SpeculativeInsertionLockAcquire(), with the
      38             :  * intention of waiting for the first insertion to complete, but ends up
      39             :  * waiting for the latest unrelated insertion instead.  Even then, nothing
      40             :  * particularly bad happens: in the worst case they deadlock, causing one of
      41             :  * the transactions to abort.
      42             :  */
      43             : static uint32 speculativeInsertionToken = 0;
      44             : 
      45             : 
      46             : /*
      47             :  * Struct to hold context info for transaction lock waits.
      48             :  *
      49             :  * 'oper' is the operation that needs to wait for the other transaction; 'rel'
      50             :  * and 'ctid' specify the address of the tuple being waited for.
      51             :  */
      52             : typedef struct XactLockTableWaitInfo
      53             : {
      54             :     XLTW_Oper   oper;
      55             :     Relation    rel;
      56             :     ItemPointer ctid;
      57             : } XactLockTableWaitInfo;
      58             : 
      59             : static void XactLockTableWaitErrorCb(void *arg);
      60             : 
      61             : /*
      62             :  * RelationInitLockInfo
      63             :  *      Initializes the lock information in a relation descriptor.
      64             :  *
      65             :  *      relcache.c must call this during creation of any reldesc.
      66             :  */
      67             : void
      68       70901 : RelationInitLockInfo(Relation relation)
      69             : {
      70       70901 :     Assert(RelationIsValid(relation));
      71       70901 :     Assert(OidIsValid(RelationGetRelid(relation)));
      72             : 
      73       70901 :     relation->rd_lockInfo.lockRelId.relId = RelationGetRelid(relation);
      74             : 
      75       70901 :     if (relation->rd_rel->relisshared)
      76        7945 :         relation->rd_lockInfo.lockRelId.dbId = InvalidOid;
      77             :     else
      78       62956 :         relation->rd_lockInfo.lockRelId.dbId = MyDatabaseId;
      79       70901 : }
      80             : 
      81             : /*
      82             :  * SetLocktagRelationOid
      83             :  *      Set up a locktag for a relation, given only relation OID
      84             :  */
      85             : static inline void
      86      940254 : SetLocktagRelationOid(LOCKTAG *tag, Oid relid)
      87             : {
      88             :     Oid         dbid;
      89             : 
      90      940254 :     if (IsSharedRelation(relid))
      91       41988 :         dbid = InvalidOid;
      92             :     else
      93      898266 :         dbid = MyDatabaseId;
      94             : 
      95      940254 :     SET_LOCKTAG_RELATION(*tag, dbid, relid);
      96      940254 : }
      97             : 
      98             : /*
      99             :  *      LockRelationOid
     100             :  *
     101             :  * Lock a relation given only its OID.  This should generally be used
     102             :  * before attempting to open the relation's relcache entry.
     103             :  */
     104             : void
     105      939368 : LockRelationOid(Oid relid, LOCKMODE lockmode)
     106             : {
     107             :     LOCKTAG     tag;
     108             :     LockAcquireResult res;
     109             : 
     110      939368 :     SetLocktagRelationOid(&tag, relid);
     111             : 
     112      939368 :     res = LockAcquire(&tag, lockmode, false, false);
     113             : 
     114             :     /*
     115             :      * Now that we have the lock, check for invalidation messages, so that we
     116             :      * will update or flush any stale relcache entry before we try to use it.
     117             :      * RangeVarGetRelid() specifically relies on us for this.  We can skip
     118             :      * this in the not-uncommon case that we already had the same type of lock
     119             :      * being requested, since then no one else could have modified the
     120             :      * relcache entry in an undesirable way.  (In the case where our own xact
     121             :      * modifies the rel, the relcache update happens via
     122             :      * CommandCounterIncrement, not here.)
     123             :      */
     124      939368 :     if (res != LOCKACQUIRE_ALREADY_HELD)
     125      844276 :         AcceptInvalidationMessages();
     126      939368 : }
     127             : 
     128             : /*
     129             :  *      ConditionalLockRelationOid
     130             :  *
     131             :  * As above, but only lock if we can get the lock without blocking.
     132             :  * Returns TRUE iff the lock was acquired.
     133             :  *
     134             :  * NOTE: we do not currently need conditional versions of all the
     135             :  * LockXXX routines in this file, but they could easily be added if needed.
     136             :  */
     137             : bool
     138          61 : ConditionalLockRelationOid(Oid relid, LOCKMODE lockmode)
     139             : {
     140             :     LOCKTAG     tag;
     141             :     LockAcquireResult res;
     142             : 
     143          61 :     SetLocktagRelationOid(&tag, relid);
     144             : 
     145          61 :     res = LockAcquire(&tag, lockmode, false, true);
     146             : 
     147          61 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     148           2 :         return false;
     149             : 
     150             :     /*
     151             :      * Now that we have the lock, check for invalidation messages; see notes
     152             :      * in LockRelationOid.
     153             :      */
     154          59 :     if (res != LOCKACQUIRE_ALREADY_HELD)
     155          59 :         AcceptInvalidationMessages();
     156             : 
     157          59 :     return true;
     158             : }
     159             : 
     160             : /*
     161             :  *      UnlockRelationId
     162             :  *
     163             :  * Unlock, given a LockRelId.  This is preferred over UnlockRelationOid
     164             :  * for speed reasons.
     165             :  */
     166             : void
     167      828830 : UnlockRelationId(LockRelId *relid, LOCKMODE lockmode)
     168             : {
     169             :     LOCKTAG     tag;
     170             : 
     171      828830 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     172             : 
     173      828830 :     LockRelease(&tag, lockmode, false);
     174      828830 : }
     175             : 
     176             : /*
     177             :  *      UnlockRelationOid
     178             :  *
     179             :  * Unlock, given only a relation Oid.  Use UnlockRelationId if you can.
     180             :  */
     181             : void
     182         825 : UnlockRelationOid(Oid relid, LOCKMODE lockmode)
     183             : {
     184             :     LOCKTAG     tag;
     185             : 
     186         825 :     SetLocktagRelationOid(&tag, relid);
     187             : 
     188         825 :     LockRelease(&tag, lockmode, false);
     189         825 : }
     190             : 
     191             : /*
     192             :  *      LockRelation
     193             :  *
     194             :  * This is a convenience routine for acquiring an additional lock on an
     195             :  * already-open relation.  Never try to do "relation_open(foo, NoLock)"
     196             :  * and then lock with this.
     197             :  */
     198             : void
     199        1365 : LockRelation(Relation relation, LOCKMODE lockmode)
     200             : {
     201             :     LOCKTAG     tag;
     202             :     LockAcquireResult res;
     203             : 
     204        1365 :     SET_LOCKTAG_RELATION(tag,
     205             :                          relation->rd_lockInfo.lockRelId.dbId,
     206             :                          relation->rd_lockInfo.lockRelId.relId);
     207             : 
     208        1365 :     res = LockAcquire(&tag, lockmode, false, false);
     209             : 
     210             :     /*
     211             :      * Now that we have the lock, check for invalidation messages; see notes
     212             :      * in LockRelationOid.
     213             :      */
     214        1365 :     if (res != LOCKACQUIRE_ALREADY_HELD)
     215        1365 :         AcceptInvalidationMessages();
     216        1365 : }
     217             : 
     218             : /*
     219             :  *      ConditionalLockRelation
     220             :  *
     221             :  * This is a convenience routine for acquiring an additional lock on an
     222             :  * already-open relation.  Never try to do "relation_open(foo, NoLock)"
     223             :  * and then lock with this.
     224             :  */
     225             : bool
     226          12 : ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
     227             : {
     228             :     LOCKTAG     tag;
     229             :     LockAcquireResult res;
     230             : 
     231          12 :     SET_LOCKTAG_RELATION(tag,
     232             :                          relation->rd_lockInfo.lockRelId.dbId,
     233             :                          relation->rd_lockInfo.lockRelId.relId);
     234             : 
     235          12 :     res = LockAcquire(&tag, lockmode, false, true);
     236             : 
     237          12 :     if (res == LOCKACQUIRE_NOT_AVAIL)
     238           0 :         return false;
     239             : 
     240             :     /*
     241             :      * Now that we have the lock, check for invalidation messages; see notes
     242             :      * in LockRelationOid.
     243             :      */
     244          12 :     if (res != LOCKACQUIRE_ALREADY_HELD)
     245          12 :         AcceptInvalidationMessages();
     246             : 
     247          12 :     return true;
     248             : }
     249             : 
     250             : /*
     251             :  *      UnlockRelation
     252             :  *
     253             :  * This is a convenience routine for unlocking a relation without also
     254             :  * closing it.
     255             :  */
     256             : void
     257          12 : UnlockRelation(Relation relation, LOCKMODE lockmode)
     258             : {
     259             :     LOCKTAG     tag;
     260             : 
     261          12 :     SET_LOCKTAG_RELATION(tag,
     262             :                          relation->rd_lockInfo.lockRelId.dbId,
     263             :                          relation->rd_lockInfo.lockRelId.relId);
     264             : 
     265          12 :     LockRelease(&tag, lockmode, false);
     266          12 : }
     267             : 
     268             : /*
     269             :  *      LockHasWaitersRelation
     270             :  *
     271             :  * This is a function to check whether someone else is waiting for a
     272             :  * lock which we are currently holding.
     273             :  */
     274             : bool
     275           0 : LockHasWaitersRelation(Relation relation, LOCKMODE lockmode)
     276             : {
     277             :     LOCKTAG     tag;
     278             : 
     279           0 :     SET_LOCKTAG_RELATION(tag,
     280             :                          relation->rd_lockInfo.lockRelId.dbId,
     281             :                          relation->rd_lockInfo.lockRelId.relId);
     282             : 
     283           0 :     return LockHasWaiters(&tag, lockmode, false);
     284             : }
     285             : 
     286             : /*
     287             :  *      LockRelationIdForSession
     288             :  *
     289             :  * This routine grabs a session-level lock on the target relation.  The
     290             :  * session lock persists across transaction boundaries.  It will be removed
     291             :  * when UnlockRelationIdForSession() is called, or if an ereport(ERROR) occurs,
     292             :  * or if the backend exits.
     293             :  *
     294             :  * Note that one should also grab a transaction-level lock on the rel
     295             :  * in any transaction that actually uses the rel, to ensure that the
     296             :  * relcache entry is up to date.
     297             :  */
     298             : void
     299         414 : LockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     300             : {
     301             :     LOCKTAG     tag;
     302             : 
     303         414 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     304             : 
     305         414 :     (void) LockAcquire(&tag, lockmode, true, false);
     306         414 : }
     307             : 
     308             : /*
     309             :  *      UnlockRelationIdForSession
     310             :  */
     311             : void
     312         411 : UnlockRelationIdForSession(LockRelId *relid, LOCKMODE lockmode)
     313             : {
     314             :     LOCKTAG     tag;
     315             : 
     316         411 :     SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
     317             : 
     318         411 :     LockRelease(&tag, lockmode, true);
     319         411 : }
     320             : 
     321             : /*
     322             :  *      LockRelationForExtension
     323             :  *
     324             :  * This lock tag is used to interlock addition of pages to relations.
     325             :  * We need such locking because bufmgr/smgr definition of P_NEW is not
     326             :  * race-condition-proof.
     327             :  *
     328             :  * We assume the caller is already holding some type of regular lock on
     329             :  * the relation, so no AcceptInvalidationMessages call is needed here.
     330             :  */
     331             : void
     332        2952 : LockRelationForExtension(Relation relation, LOCKMODE lockmode)
     333             : {
     334             :     LOCKTAG     tag;
     335             : 
     336        2952 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     337             :                                 relation->rd_lockInfo.lockRelId.dbId,
     338             :                                 relation->rd_lockInfo.lockRelId.relId);
     339             : 
     340        2952 :     (void) LockAcquire(&tag, lockmode, false, false);
     341        2952 : }
     342             : 
     343             : /*
     344             :  *      ConditionalLockRelationForExtension
     345             :  *
     346             :  * As above, but only lock if we can get the lock without blocking.
     347             :  * Returns TRUE iff the lock was acquired.
     348             :  */
     349             : bool
     350        6395 : ConditionalLockRelationForExtension(Relation relation, LOCKMODE lockmode)
     351             : {
     352             :     LOCKTAG     tag;
     353             : 
     354        6395 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     355             :                                 relation->rd_lockInfo.lockRelId.dbId,
     356             :                                 relation->rd_lockInfo.lockRelId.relId);
     357             : 
     358        6395 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     359             : }
     360             : 
     361             : /*
     362             :  *      RelationExtensionLockWaiterCount
     363             :  *
     364             :  * Count the number of processes waiting for the given relation extension lock.
     365             :  */
     366             : int
     367           6 : RelationExtensionLockWaiterCount(Relation relation)
     368             : {
     369             :     LOCKTAG     tag;
     370             : 
     371           6 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     372             :                                 relation->rd_lockInfo.lockRelId.dbId,
     373             :                                 relation->rd_lockInfo.lockRelId.relId);
     374             : 
     375           6 :     return LockWaiterCount(&tag);
     376             : }
     377             : 
     378             : /*
     379             :  *      UnlockRelationForExtension
     380             :  */
     381             : void
     382        9334 : UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
     383             : {
     384             :     LOCKTAG     tag;
     385             : 
     386        9334 :     SET_LOCKTAG_RELATION_EXTEND(tag,
     387             :                                 relation->rd_lockInfo.lockRelId.dbId,
     388             :                                 relation->rd_lockInfo.lockRelId.relId);
     389             : 
     390        9334 :     LockRelease(&tag, lockmode, false);
     391        9334 : }
     392             : 
     393             : /*
     394             :  *      LockPage
     395             :  *
     396             :  * Obtain a page-level lock.  This is currently used by some index access
     397             :  * methods to lock individual index pages.
     398             :  */
     399             : void
     400           0 : LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     401             : {
     402             :     LOCKTAG     tag;
     403             : 
     404           0 :     SET_LOCKTAG_PAGE(tag,
     405             :                      relation->rd_lockInfo.lockRelId.dbId,
     406             :                      relation->rd_lockInfo.lockRelId.relId,
     407             :                      blkno);
     408             : 
     409           0 :     (void) LockAcquire(&tag, lockmode, false, false);
     410           0 : }
     411             : 
     412             : /*
     413             :  *      ConditionalLockPage
     414             :  *
     415             :  * As above, but only lock if we can get the lock without blocking.
     416             :  * Returns TRUE iff the lock was acquired.
     417             :  */
     418             : bool
     419           7 : ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     420             : {
     421             :     LOCKTAG     tag;
     422             : 
     423           7 :     SET_LOCKTAG_PAGE(tag,
     424             :                      relation->rd_lockInfo.lockRelId.dbId,
     425             :                      relation->rd_lockInfo.lockRelId.relId,
     426             :                      blkno);
     427             : 
     428           7 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     429             : }
     430             : 
     431             : /*
     432             :  *      UnlockPage
     433             :  */
     434             : void
     435           7 : UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
     436             : {
     437             :     LOCKTAG     tag;
     438             : 
     439           7 :     SET_LOCKTAG_PAGE(tag,
     440             :                      relation->rd_lockInfo.lockRelId.dbId,
     441             :                      relation->rd_lockInfo.lockRelId.relId,
     442             :                      blkno);
     443             : 
     444           7 :     LockRelease(&tag, lockmode, false);
     445           7 : }
     446             : 
     447             : /*
     448             :  *      LockTuple
     449             :  *
     450             :  * Obtain a tuple-level lock.  This is used in a less-than-intuitive fashion
     451             :  * because we can't afford to keep a separate lock in shared memory for every
     452             :  * tuple.  See heap_lock_tuple before using this!
     453             :  */
     454             : void
     455           1 : LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     456             : {
     457             :     LOCKTAG     tag;
     458             : 
     459           1 :     SET_LOCKTAG_TUPLE(tag,
     460             :                       relation->rd_lockInfo.lockRelId.dbId,
     461             :                       relation->rd_lockInfo.lockRelId.relId,
     462             :                       ItemPointerGetBlockNumber(tid),
     463             :                       ItemPointerGetOffsetNumber(tid));
     464             : 
     465           1 :     (void) LockAcquire(&tag, lockmode, false, false);
     466           1 : }
     467             : 
     468             : /*
     469             :  *      ConditionalLockTuple
     470             :  *
     471             :  * As above, but only lock if we can get the lock without blocking.
     472             :  * Returns TRUE iff the lock was acquired.
     473             :  */
     474             : bool
     475           0 : ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     476             : {
     477             :     LOCKTAG     tag;
     478             : 
     479           0 :     SET_LOCKTAG_TUPLE(tag,
     480             :                       relation->rd_lockInfo.lockRelId.dbId,
     481             :                       relation->rd_lockInfo.lockRelId.relId,
     482             :                       ItemPointerGetBlockNumber(tid),
     483             :                       ItemPointerGetOffsetNumber(tid));
     484             : 
     485           0 :     return (LockAcquire(&tag, lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
     486             : }
     487             : 
     488             : /*
     489             :  *      UnlockTuple
     490             :  */
     491             : void
     492           1 : UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
     493             : {
     494             :     LOCKTAG     tag;
     495             : 
     496           1 :     SET_LOCKTAG_TUPLE(tag,
     497             :                       relation->rd_lockInfo.lockRelId.dbId,
     498             :                       relation->rd_lockInfo.lockRelId.relId,
     499             :                       ItemPointerGetBlockNumber(tid),
     500             :                       ItemPointerGetOffsetNumber(tid));
     501             : 
     502           1 :     LockRelease(&tag, lockmode, false);
     503           1 : }
     504             : 
     505             : /*
     506             :  *      XactLockTableInsert
     507             :  *
     508             :  * Insert a lock showing that the given transaction ID is running ---
     509             :  * this is done when an XID is acquired by a transaction or subtransaction.
     510             :  * The lock can then be used to wait for the transaction to finish.
     511             :  */
     512             : void
     513       10626 : XactLockTableInsert(TransactionId xid)
     514             : {
     515             :     LOCKTAG     tag;
     516             : 
     517       10626 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     518             : 
     519       10626 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     520       10626 : }
     521             : 
     522             : /*
     523             :  *      XactLockTableDelete
     524             :  *
     525             :  * Delete the lock showing that the given transaction ID is running.
     526             :  * (This is never used for main transaction IDs; those locks are only
     527             :  * released implicitly at transaction end.  But we do use it for subtrans IDs.)
     528             :  */
     529             : void
     530          24 : XactLockTableDelete(TransactionId xid)
     531             : {
     532             :     LOCKTAG     tag;
     533             : 
     534          24 :     SET_LOCKTAG_TRANSACTION(tag, xid);
     535             : 
     536          24 :     LockRelease(&tag, ExclusiveLock, false);
     537          24 : }
     538             : 
     539             : /*
     540             :  *      XactLockTableWait
     541             :  *
     542             :  * Wait for the specified transaction to commit or abort.  If an operation
     543             :  * is specified, an error context callback is set up.  If 'oper' is passed as
     544             :  * None, no error context callback is set up.
     545             :  *
     546             :  * Note that this does the right thing for subtransactions: if we wait on a
     547             :  * subtransaction, we will exit as soon as it aborts or its top parent commits.
     548             :  * It takes some extra work to ensure this, because to save on shared memory
     549             :  * the XID lock of a subtransaction is released when it ends, whether
     550             :  * successfully or unsuccessfully.  So we have to check if it's "still running"
     551             :  * and if so wait for its parent.
     552             :  */
     553             : void
     554           1 : XactLockTableWait(TransactionId xid, Relation rel, ItemPointer ctid,
     555             :                   XLTW_Oper oper)
     556             : {
     557             :     LOCKTAG     tag;
     558             :     XactLockTableWaitInfo info;
     559             :     ErrorContextCallback callback;
     560             : 
     561             :     /*
     562             :      * If an operation is specified, set up our verbose error context
     563             :      * callback.
     564             :      */
     565           1 :     if (oper != XLTW_None)
     566             :     {
     567           1 :         Assert(RelationIsValid(rel));
     568           1 :         Assert(ItemPointerIsValid(ctid));
     569             : 
     570           1 :         info.rel = rel;
     571           1 :         info.ctid = ctid;
     572           1 :         info.oper = oper;
     573             : 
     574           1 :         callback.callback = XactLockTableWaitErrorCb;
     575           1 :         callback.arg = &info;
     576           1 :         callback.previous = error_context_stack;
     577           1 :         error_context_stack = &callback;
     578             :     }
     579             : 
     580             :     for (;;)
     581             :     {
     582           1 :         Assert(TransactionIdIsValid(xid));
     583           1 :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     584             : 
     585           1 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     586             : 
     587           1 :         (void) LockAcquire(&tag, ShareLock, false, false);
     588             : 
     589           1 :         LockRelease(&tag, ShareLock, false);
     590             : 
     591           1 :         if (!TransactionIdIsInProgress(xid))
     592           1 :             break;
     593           0 :         xid = SubTransGetParent(xid);
     594           0 :     }
     595             : 
     596           1 :     if (oper != XLTW_None)
     597           1 :         error_context_stack = callback.previous;
     598           1 : }
     599             : 
     600             : /*
     601             :  *      ConditionalXactLockTableWait
     602             :  *
     603             :  * As above, but only lock if we can get the lock without blocking.
     604             :  * Returns TRUE if the lock was acquired.
     605             :  */
     606             : bool
     607           0 : ConditionalXactLockTableWait(TransactionId xid)
     608             : {
     609             :     LOCKTAG     tag;
     610             : 
     611             :     for (;;)
     612             :     {
     613           0 :         Assert(TransactionIdIsValid(xid));
     614           0 :         Assert(!TransactionIdEquals(xid, GetTopTransactionIdIfAny()));
     615             : 
     616           0 :         SET_LOCKTAG_TRANSACTION(tag, xid);
     617             : 
     618           0 :         if (LockAcquire(&tag, ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
     619           0 :             return false;
     620             : 
     621           0 :         LockRelease(&tag, ShareLock, false);
     622             : 
     623           0 :         if (!TransactionIdIsInProgress(xid))
     624           0 :             break;
     625           0 :         xid = SubTransGetParent(xid);
     626           0 :     }
     627             : 
     628           0 :     return true;
     629             : }
     630             : 
     631             : /*
     632             :  *      SpeculativeInsertionLockAcquire
     633             :  *
     634             :  * Insert a lock showing that the given transaction ID is inserting a tuple,
     635             :  * but hasn't yet decided whether it's going to keep it.  The lock can then be
     636             :  * used to wait for the decision to go ahead with the insertion, or aborting
     637             :  * it.
     638             :  *
     639             :  * The token is used to distinguish multiple insertions by the same
     640             :  * transaction.  It is returned to caller.
     641             :  */
     642             : uint32
     643          55 : SpeculativeInsertionLockAcquire(TransactionId xid)
     644             : {
     645             :     LOCKTAG     tag;
     646             : 
     647          55 :     speculativeInsertionToken++;
     648             : 
     649             :     /*
     650             :      * Check for wrap-around. Zero means no token is held, so don't use that.
     651             :      */
     652          55 :     if (speculativeInsertionToken == 0)
     653           0 :         speculativeInsertionToken = 1;
     654             : 
     655          55 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     656             : 
     657          55 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     658             : 
     659          55 :     return speculativeInsertionToken;
     660             : }
     661             : 
     662             : /*
     663             :  *      SpeculativeInsertionLockRelease
     664             :  *
     665             :  * Delete the lock showing that the given transaction is speculatively
     666             :  * inserting a tuple.
     667             :  */
     668             : void
     669          54 : SpeculativeInsertionLockRelease(TransactionId xid)
     670             : {
     671             :     LOCKTAG     tag;
     672             : 
     673          54 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, speculativeInsertionToken);
     674             : 
     675          54 :     LockRelease(&tag, ExclusiveLock, false);
     676          54 : }
     677             : 
     678             : /*
     679             :  *      SpeculativeInsertionWait
     680             :  *
     681             :  * Wait for the specified transaction to finish or abort the insertion of a
     682             :  * tuple.
     683             :  */
     684             : void
     685           0 : SpeculativeInsertionWait(TransactionId xid, uint32 token)
     686             : {
     687             :     LOCKTAG     tag;
     688             : 
     689           0 :     SET_LOCKTAG_SPECULATIVE_INSERTION(tag, xid, token);
     690             : 
     691           0 :     Assert(TransactionIdIsValid(xid));
     692           0 :     Assert(token != 0);
     693             : 
     694           0 :     (void) LockAcquire(&tag, ShareLock, false, false);
     695           0 :     LockRelease(&tag, ShareLock, false);
     696           0 : }
     697             : 
     698             : /*
     699             :  * XactLockTableWaitErrorContextCb
     700             :  *      Error context callback for transaction lock waits.
     701             :  */
     702             : static void
     703           0 : XactLockTableWaitErrorCb(void *arg)
     704             : {
     705           0 :     XactLockTableWaitInfo *info = (XactLockTableWaitInfo *) arg;
     706             : 
     707             :     /*
     708             :      * We would like to print schema name too, but that would require a
     709             :      * syscache lookup.
     710             :      */
     711           0 :     if (info->oper != XLTW_None &&
     712           0 :         ItemPointerIsValid(info->ctid) && RelationIsValid(info->rel))
     713             :     {
     714             :         const char *cxt;
     715             : 
     716           0 :         switch (info->oper)
     717             :         {
     718             :             case XLTW_Update:
     719           0 :                 cxt = gettext_noop("while updating tuple (%u,%u) in relation \"%s\"");
     720           0 :                 break;
     721             :             case XLTW_Delete:
     722           0 :                 cxt = gettext_noop("while deleting tuple (%u,%u) in relation \"%s\"");
     723           0 :                 break;
     724             :             case XLTW_Lock:
     725           0 :                 cxt = gettext_noop("while locking tuple (%u,%u) in relation \"%s\"");
     726           0 :                 break;
     727             :             case XLTW_LockUpdated:
     728           0 :                 cxt = gettext_noop("while locking updated version (%u,%u) of tuple in relation \"%s\"");
     729           0 :                 break;
     730             :             case XLTW_InsertIndex:
     731           0 :                 cxt = gettext_noop("while inserting index tuple (%u,%u) in relation \"%s\"");
     732           0 :                 break;
     733             :             case XLTW_InsertIndexUnique:
     734           0 :                 cxt = gettext_noop("while checking uniqueness of tuple (%u,%u) in relation \"%s\"");
     735           0 :                 break;
     736             :             case XLTW_FetchUpdated:
     737           0 :                 cxt = gettext_noop("while rechecking updated tuple (%u,%u) in relation \"%s\"");
     738           0 :                 break;
     739             :             case XLTW_RecheckExclusionConstr:
     740           0 :                 cxt = gettext_noop("while checking exclusion constraint on tuple (%u,%u) in relation \"%s\"");
     741           0 :                 break;
     742             : 
     743             :             default:
     744           0 :                 return;
     745             :         }
     746             : 
     747           0 :         errcontext(cxt,
     748           0 :                    ItemPointerGetBlockNumber(info->ctid),
     749           0 :                    ItemPointerGetOffsetNumber(info->ctid),
     750           0 :                    RelationGetRelationName(info->rel));
     751             :     }
     752             : }
     753             : 
     754             : /*
     755             :  * WaitForLockersMultiple
     756             :  *      Wait until no transaction holds locks that conflict with the given
     757             :  *      locktags at the given lockmode.
     758             :  *
     759             :  * To do this, obtain the current list of lockers, and wait on their VXIDs
     760             :  * until they are finished.
     761             :  *
     762             :  * Note we don't try to acquire the locks on the given locktags, only the VXIDs
     763             :  * of its lock holders; if somebody grabs a conflicting lock on the objects
     764             :  * after we obtained our initial list of lockers, we will not wait for them.
     765             :  */
     766             : void
     767          23 : WaitForLockersMultiple(List *locktags, LOCKMODE lockmode)
     768             : {
     769          23 :     List       *holders = NIL;
     770             :     ListCell   *lc;
     771             : 
     772             :     /* Done if no locks to wait for */
     773          23 :     if (list_length(locktags) == 0)
     774          23 :         return;
     775             : 
     776             :     /* Collect the transactions we need to wait on */
     777          46 :     foreach(lc, locktags)
     778             :     {
     779          23 :         LOCKTAG    *locktag = lfirst(lc);
     780             : 
     781          23 :         holders = lappend(holders, GetLockConflicts(locktag, lockmode));
     782             :     }
     783             : 
     784             :     /*
     785             :      * Note: GetLockConflicts() never reports our own xid, hence we need not
     786             :      * check for that.  Also, prepared xacts are not reported, which is fine
     787             :      * since they certainly aren't going to do anything anymore.
     788             :      */
     789             : 
     790             :     /* Finally wait for each such transaction to complete */
     791          46 :     foreach(lc, holders)
     792             :     {
     793          23 :         VirtualTransactionId *lockholders = lfirst(lc);
     794             : 
     795          46 :         while (VirtualTransactionIdIsValid(*lockholders))
     796             :         {
     797           0 :             VirtualXactLock(*lockholders, true);
     798           0 :             lockholders++;
     799             :         }
     800             :     }
     801             : 
     802          23 :     list_free_deep(holders);
     803             : }
     804             : 
     805             : /*
     806             :  * WaitForLockers
     807             :  *
     808             :  * Same as WaitForLockersMultiple, for a single lock tag.
     809             :  */
     810             : void
     811          23 : WaitForLockers(LOCKTAG heaplocktag, LOCKMODE lockmode)
     812             : {
     813             :     List       *l;
     814             : 
     815          23 :     l = list_make1(&heaplocktag);
     816          23 :     WaitForLockersMultiple(l, lockmode);
     817          23 :     list_free(l);
     818          23 : }
     819             : 
     820             : 
     821             : /*
     822             :  *      LockDatabaseObject
     823             :  *
     824             :  * Obtain a lock on a general object of the current database.  Don't use
     825             :  * this for shared objects (such as tablespaces).  It's unwise to apply it
     826             :  * to relations, also, since a lock taken this way will NOT conflict with
     827             :  * locks taken via LockRelation and friends.
     828             :  */
     829             : void
     830       12673 : LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
     831             :                    LOCKMODE lockmode)
     832             : {
     833             :     LOCKTAG     tag;
     834             : 
     835       12673 :     SET_LOCKTAG_OBJECT(tag,
     836             :                        MyDatabaseId,
     837             :                        classid,
     838             :                        objid,
     839             :                        objsubid);
     840             : 
     841       12673 :     (void) LockAcquire(&tag, lockmode, false, false);
     842             : 
     843             :     /* Make sure syscaches are up-to-date with any changes we waited for */
     844       12673 :     AcceptInvalidationMessages();
     845       12673 : }
     846             : 
     847             : /*
     848             :  *      UnlockDatabaseObject
     849             :  */
     850             : void
     851         115 : UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
     852             :                      LOCKMODE lockmode)
     853             : {
     854             :     LOCKTAG     tag;
     855             : 
     856         115 :     SET_LOCKTAG_OBJECT(tag,
     857             :                        MyDatabaseId,
     858             :                        classid,
     859             :                        objid,
     860             :                        objsubid);
     861             : 
     862         115 :     LockRelease(&tag, lockmode, false);
     863         115 : }
     864             : 
     865             : /*
     866             :  *      LockSharedObject
     867             :  *
     868             :  * Obtain a lock on a shared-across-databases object.
     869             :  */
     870             : void
     871        1072 : LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
     872             :                  LOCKMODE lockmode)
     873             : {
     874             :     LOCKTAG     tag;
     875             : 
     876        1072 :     SET_LOCKTAG_OBJECT(tag,
     877             :                        InvalidOid,
     878             :                        classid,
     879             :                        objid,
     880             :                        objsubid);
     881             : 
     882        1072 :     (void) LockAcquire(&tag, lockmode, false, false);
     883             : 
     884             :     /* Make sure syscaches are up-to-date with any changes we waited for */
     885        1072 :     AcceptInvalidationMessages();
     886        1072 : }
     887             : 
     888             : /*
     889             :  *      UnlockSharedObject
     890             :  */
     891             : void
     892           6 : UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
     893             :                    LOCKMODE lockmode)
     894             : {
     895             :     LOCKTAG     tag;
     896             : 
     897           6 :     SET_LOCKTAG_OBJECT(tag,
     898             :                        InvalidOid,
     899             :                        classid,
     900             :                        objid,
     901             :                        objsubid);
     902             : 
     903           6 :     LockRelease(&tag, lockmode, false);
     904           6 : }
     905             : 
     906             : /*
     907             :  *      LockSharedObjectForSession
     908             :  *
     909             :  * Obtain a session-level lock on a shared-across-databases object.
     910             :  * See LockRelationIdForSession for notes about session-level locks.
     911             :  */
     912             : void
     913           0 : LockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
     914             :                            LOCKMODE lockmode)
     915             : {
     916             :     LOCKTAG     tag;
     917             : 
     918           0 :     SET_LOCKTAG_OBJECT(tag,
     919             :                        InvalidOid,
     920             :                        classid,
     921             :                        objid,
     922             :                        objsubid);
     923             : 
     924           0 :     (void) LockAcquire(&tag, lockmode, true, false);
     925           0 : }
     926             : 
     927             : /*
     928             :  *      UnlockSharedObjectForSession
     929             :  */
     930             : void
     931           0 : UnlockSharedObjectForSession(Oid classid, Oid objid, uint16 objsubid,
     932             :                              LOCKMODE lockmode)
     933             : {
     934             :     LOCKTAG     tag;
     935             : 
     936           0 :     SET_LOCKTAG_OBJECT(tag,
     937             :                        InvalidOid,
     938             :                        classid,
     939             :                        objid,
     940             :                        objsubid);
     941             : 
     942           0 :     LockRelease(&tag, lockmode, true);
     943           0 : }
     944             : 
     945             : 
     946             : /*
     947             :  * Append a description of a lockable object to buf.
     948             :  *
     949             :  * Ideally we would print names for the numeric values, but that requires
     950             :  * getting locks on system tables, which might cause problems since this is
     951             :  * typically used to report deadlock situations.
     952             :  */
     953             : void
     954           0 : DescribeLockTag(StringInfo buf, const LOCKTAG *tag)
     955             : {
     956           0 :     switch ((LockTagType) tag->locktag_type)
     957             :     {
     958             :         case LOCKTAG_RELATION:
     959           0 :             appendStringInfo(buf,
     960             :                              _("relation %u of database %u"),
     961             :                              tag->locktag_field2,
     962             :                              tag->locktag_field1);
     963           0 :             break;
     964             :         case LOCKTAG_RELATION_EXTEND:
     965           0 :             appendStringInfo(buf,
     966             :                              _("extension of relation %u of database %u"),
     967             :                              tag->locktag_field2,
     968             :                              tag->locktag_field1);
     969           0 :             break;
     970             :         case LOCKTAG_PAGE:
     971           0 :             appendStringInfo(buf,
     972             :                              _("page %u of relation %u of database %u"),
     973             :                              tag->locktag_field3,
     974             :                              tag->locktag_field2,
     975             :                              tag->locktag_field1);
     976           0 :             break;
     977             :         case LOCKTAG_TUPLE:
     978           0 :             appendStringInfo(buf,
     979             :                              _("tuple (%u,%u) of relation %u of database %u"),
     980             :                              tag->locktag_field3,
     981           0 :                              tag->locktag_field4,
     982             :                              tag->locktag_field2,
     983             :                              tag->locktag_field1);
     984           0 :             break;
     985             :         case LOCKTAG_TRANSACTION:
     986           0 :             appendStringInfo(buf,
     987             :                              _("transaction %u"),
     988             :                              tag->locktag_field1);
     989           0 :             break;
     990             :         case LOCKTAG_VIRTUALTRANSACTION:
     991           0 :             appendStringInfo(buf,
     992             :                              _("virtual transaction %d/%u"),
     993             :                              tag->locktag_field1,
     994             :                              tag->locktag_field2);
     995           0 :             break;
     996             :         case LOCKTAG_SPECULATIVE_TOKEN:
     997           0 :             appendStringInfo(buf,
     998             :                              _("speculative token %u of transaction %u"),
     999             :                              tag->locktag_field2,
    1000             :                              tag->locktag_field1);
    1001           0 :             break;
    1002             :         case LOCKTAG_OBJECT:
    1003           0 :             appendStringInfo(buf,
    1004             :                              _("object %u of class %u of database %u"),
    1005             :                              tag->locktag_field3,
    1006             :                              tag->locktag_field2,
    1007             :                              tag->locktag_field1);
    1008           0 :             break;
    1009             :         case LOCKTAG_USERLOCK:
    1010             :             /* reserved for old contrib code, now on pgfoundry */
    1011           0 :             appendStringInfo(buf,
    1012             :                              _("user lock [%u,%u,%u]"),
    1013             :                              tag->locktag_field1,
    1014             :                              tag->locktag_field2,
    1015             :                              tag->locktag_field3);
    1016           0 :             break;
    1017             :         case LOCKTAG_ADVISORY:
    1018           0 :             appendStringInfo(buf,
    1019             :                              _("advisory lock [%u,%u,%u,%u]"),
    1020             :                              tag->locktag_field1,
    1021             :                              tag->locktag_field2,
    1022             :                              tag->locktag_field3,
    1023           0 :                              tag->locktag_field4);
    1024           0 :             break;
    1025             :         default:
    1026           0 :             appendStringInfo(buf,
    1027             :                              _("unrecognized locktag type %d"),
    1028           0 :                              (int) tag->locktag_type);
    1029           0 :             break;
    1030             :     }
    1031           0 : }
    1032             : 
    1033             : /*
    1034             :  * GetLockNameFromTagType
    1035             :  *
    1036             :  *  Given locktag type, return the corresponding lock name.
    1037             :  */
    1038             : const char *
    1039           0 : GetLockNameFromTagType(uint16 locktag_type)
    1040             : {
    1041           0 :     if (locktag_type > LOCKTAG_LAST_TYPE)
    1042           0 :         return "???";
    1043           0 :     return LockTagTypeNames[locktag_type];
    1044             : }

Generated by: LCOV version 1.11