LCOV - code coverage report
Current view: top level - src/backend/storage/lmgr - lmgr.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 60.7 % 481 292
Test Date: 2026-01-26 10:56:24 Functions: 77.1 % 48 37
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 35.6 % 132 47

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

Generated by: LCOV version 2.3.2-1