LCOV - code coverage report
Current view: top level - src/backend/utils/adt - lockfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 306 367 83.4 %
Date: 2024-11-21 08:14:44 Functions: 18 25 72.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * lockfuncs.c
       4             :  *      Functions for SQL access to various lock-manager capabilities.
       5             :  *
       6             :  * Copyright (c) 2002-2024, PostgreSQL Global Development Group
       7             :  *
       8             :  * IDENTIFICATION
       9             :  *      src/backend/utils/adt/lockfuncs.c
      10             :  *
      11             :  *-------------------------------------------------------------------------
      12             :  */
      13             : #include "postgres.h"
      14             : 
      15             : #include "access/htup_details.h"
      16             : #include "funcapi.h"
      17             : #include "miscadmin.h"
      18             : #include "storage/predicate_internals.h"
      19             : #include "utils/array.h"
      20             : #include "utils/builtins.h"
      21             : 
      22             : 
      23             : /*
      24             :  * This must match enum LockTagType!  Also, be sure to document any changes
      25             :  * in the docs for the pg_locks view and update the WaitEventLOCK section in
      26             :  * src/backend/utils/activity/wait_event_names.txt.
      27             :  */
      28             : const char *const LockTagTypeNames[] = {
      29             :     "relation",
      30             :     "extend",
      31             :     "frozenid",
      32             :     "page",
      33             :     "tuple",
      34             :     "transactionid",
      35             :     "virtualxid",
      36             :     "spectoken",
      37             :     "object",
      38             :     "userlock",
      39             :     "advisory",
      40             :     "applytransaction"
      41             : };
      42             : 
      43             : StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_LAST_TYPE + 1),
      44             :                  "array length mismatch");
      45             : 
      46             : /* This must match enum PredicateLockTargetType (predicate_internals.h) */
      47             : static const char *const PredicateLockTagTypeNames[] = {
      48             :     "relation",
      49             :     "page",
      50             :     "tuple"
      51             : };
      52             : 
      53             : StaticAssertDecl(lengthof(PredicateLockTagTypeNames) == (PREDLOCKTAG_TUPLE + 1),
      54             :                  "array length mismatch");
      55             : 
      56             : /* Working status for pg_lock_status */
      57             : typedef struct
      58             : {
      59             :     LockData   *lockData;       /* state data from lmgr */
      60             :     int         currIdx;        /* current PROCLOCK index */
      61             :     PredicateLockData *predLockData;    /* state data for pred locks */
      62             :     int         predLockIdx;    /* current index for pred lock */
      63             : } PG_Lock_Status;
      64             : 
      65             : /* Number of columns in pg_locks output */
      66             : #define NUM_LOCK_STATUS_COLUMNS     16
      67             : 
      68             : /*
      69             :  * VXIDGetDatum - Construct a text representation of a VXID
      70             :  *
      71             :  * This is currently only used in pg_lock_status, so we put it here.
      72             :  */
      73             : static Datum
      74       13856 : VXIDGetDatum(ProcNumber procNumber, LocalTransactionId lxid)
      75             : {
      76             :     /*
      77             :      * The representation is "<procNumber>/<lxid>", decimal and unsigned
      78             :      * decimal respectively.  Note that elog.c also knows how to format a
      79             :      * vxid.
      80             :      */
      81             :     char        vxidstr[32];
      82             : 
      83       13856 :     snprintf(vxidstr, sizeof(vxidstr), "%d/%u", procNumber, lxid);
      84             : 
      85       13856 :     return CStringGetTextDatum(vxidstr);
      86             : }
      87             : 
      88             : 
      89             : /*
      90             :  * pg_lock_status - produce a view with one row per held or awaited lock mode
      91             :  */
      92             : Datum
      93       12570 : pg_lock_status(PG_FUNCTION_ARGS)
      94             : {
      95             :     FuncCallContext *funcctx;
      96             :     PG_Lock_Status *mystatus;
      97             :     LockData   *lockData;
      98             :     PredicateLockData *predLockData;
      99             : 
     100       12570 :     if (SRF_IS_FIRSTCALL())
     101             :     {
     102             :         TupleDesc   tupdesc;
     103             :         MemoryContext oldcontext;
     104             : 
     105             :         /* create a function context for cross-call persistence */
     106         492 :         funcctx = SRF_FIRSTCALL_INIT();
     107             : 
     108             :         /*
     109             :          * switch to memory context appropriate for multiple function calls
     110             :          */
     111         492 :         oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
     112             : 
     113             :         /* build tupdesc for result tuples */
     114             :         /* this had better match function's declaration in pg_proc.h */
     115         492 :         tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
     116         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
     117             :                            TEXTOID, -1, 0);
     118         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
     119             :                            OIDOID, -1, 0);
     120         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
     121             :                            OIDOID, -1, 0);
     122         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
     123             :                            INT4OID, -1, 0);
     124         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
     125             :                            INT2OID, -1, 0);
     126         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
     127             :                            TEXTOID, -1, 0);
     128         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
     129             :                            XIDOID, -1, 0);
     130         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
     131             :                            OIDOID, -1, 0);
     132         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
     133             :                            OIDOID, -1, 0);
     134         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
     135             :                            INT2OID, -1, 0);
     136         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
     137             :                            TEXTOID, -1, 0);
     138         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
     139             :                            INT4OID, -1, 0);
     140         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
     141             :                            TEXTOID, -1, 0);
     142         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
     143             :                            BOOLOID, -1, 0);
     144         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
     145             :                            BOOLOID, -1, 0);
     146         492 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
     147             :                            TIMESTAMPTZOID, -1, 0);
     148             : 
     149         492 :         funcctx->tuple_desc = BlessTupleDesc(tupdesc);
     150             : 
     151             :         /*
     152             :          * Collect all the locking information that we will format and send
     153             :          * out as a result set.
     154             :          */
     155         492 :         mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
     156         492 :         funcctx->user_fctx = (void *) mystatus;
     157             : 
     158         492 :         mystatus->lockData = GetLockStatusData();
     159         492 :         mystatus->currIdx = 0;
     160         492 :         mystatus->predLockData = GetPredicateLockStatusData();
     161         492 :         mystatus->predLockIdx = 0;
     162             : 
     163         492 :         MemoryContextSwitchTo(oldcontext);
     164             :     }
     165             : 
     166       12570 :     funcctx = SRF_PERCALL_SETUP();
     167       12570 :     mystatus = (PG_Lock_Status *) funcctx->user_fctx;
     168       12570 :     lockData = mystatus->lockData;
     169             : 
     170       24036 :     while (mystatus->currIdx < lockData->nelements)
     171             :     {
     172             :         bool        granted;
     173       23538 :         LOCKMODE    mode = 0;
     174             :         const char *locktypename;
     175             :         char        tnbuf[32];
     176       23538 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     177       23538 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     178             :         HeapTuple   tuple;
     179             :         Datum       result;
     180             :         LockInstanceData *instance;
     181             : 
     182       23538 :         instance = &(lockData->locks[mystatus->currIdx]);
     183             : 
     184             :         /*
     185             :          * Look to see if there are any held lock modes in this PROCLOCK. If
     186             :          * so, report, and destructively modify lockData so we don't report
     187             :          * again.
     188             :          */
     189       23538 :         granted = false;
     190       23538 :         if (instance->holdMask)
     191             :         {
     192       62450 :             for (mode = 0; mode < MAX_LOCKMODES; mode++)
     193             :             {
     194       62450 :                 if (instance->holdMask & LOCKBIT_ON(mode))
     195             :                 {
     196       12054 :                     granted = true;
     197       12054 :                     instance->holdMask &= LOCKBIT_OFF(mode);
     198       12054 :                     break;
     199             :                 }
     200             :             }
     201             :         }
     202             : 
     203             :         /*
     204             :          * If no (more) held modes to report, see if PROC is waiting for a
     205             :          * lock on this lock.
     206             :          */
     207       23538 :         if (!granted)
     208             :         {
     209       11484 :             if (instance->waitLockMode != NoLock)
     210             :             {
     211             :                 /* Yes, so report it with proper mode */
     212          18 :                 mode = instance->waitLockMode;
     213             : 
     214             :                 /*
     215             :                  * We are now done with this PROCLOCK, so advance pointer to
     216             :                  * continue with next one on next call.
     217             :                  */
     218          18 :                 mystatus->currIdx++;
     219             :             }
     220             :             else
     221             :             {
     222             :                 /*
     223             :                  * Okay, we've displayed all the locks associated with this
     224             :                  * PROCLOCK, proceed to the next one.
     225             :                  */
     226       11466 :                 mystatus->currIdx++;
     227       11466 :                 continue;
     228             :             }
     229             :         }
     230             : 
     231             :         /*
     232             :          * Form tuple with appropriate data.
     233             :          */
     234             : 
     235       12072 :         if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
     236       12072 :             locktypename = LockTagTypeNames[instance->locktag.locktag_type];
     237             :         else
     238             :         {
     239           0 :             snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
     240           0 :                      (int) instance->locktag.locktag_type);
     241           0 :             locktypename = tnbuf;
     242             :         }
     243       12072 :         values[0] = CStringGetTextDatum(locktypename);
     244             : 
     245       12072 :         switch ((LockTagType) instance->locktag.locktag_type)
     246             :         {
     247        7848 :             case LOCKTAG_RELATION:
     248             :             case LOCKTAG_RELATION_EXTEND:
     249        7848 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     250        7848 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     251        7848 :                 nulls[3] = true;
     252        7848 :                 nulls[4] = true;
     253        7848 :                 nulls[5] = true;
     254        7848 :                 nulls[6] = true;
     255        7848 :                 nulls[7] = true;
     256        7848 :                 nulls[8] = true;
     257        7848 :                 nulls[9] = true;
     258        7848 :                 break;
     259           2 :             case LOCKTAG_DATABASE_FROZEN_IDS:
     260           2 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     261           2 :                 nulls[2] = true;
     262           2 :                 nulls[3] = true;
     263           2 :                 nulls[4] = true;
     264           2 :                 nulls[5] = true;
     265           2 :                 nulls[6] = true;
     266           2 :                 nulls[7] = true;
     267           2 :                 nulls[8] = true;
     268           2 :                 nulls[9] = true;
     269           2 :                 break;
     270          16 :             case LOCKTAG_PAGE:
     271          16 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     272          16 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     273          16 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     274          16 :                 nulls[4] = true;
     275          16 :                 nulls[5] = true;
     276          16 :                 nulls[6] = true;
     277          16 :                 nulls[7] = true;
     278          16 :                 nulls[8] = true;
     279          16 :                 nulls[9] = true;
     280          16 :                 break;
     281          30 :             case LOCKTAG_TUPLE:
     282          30 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     283          30 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     284          30 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     285          30 :                 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
     286          30 :                 nulls[5] = true;
     287          30 :                 nulls[6] = true;
     288          30 :                 nulls[7] = true;
     289          30 :                 nulls[8] = true;
     290          30 :                 nulls[9] = true;
     291          30 :                 break;
     292        1126 :             case LOCKTAG_TRANSACTION:
     293        1126 :                 values[6] =
     294        1126 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     295        1126 :                 nulls[1] = true;
     296        1126 :                 nulls[2] = true;
     297        1126 :                 nulls[3] = true;
     298        1126 :                 nulls[4] = true;
     299        1126 :                 nulls[5] = true;
     300        1126 :                 nulls[7] = true;
     301        1126 :                 nulls[8] = true;
     302        1126 :                 nulls[9] = true;
     303        1126 :                 break;
     304        1778 :             case LOCKTAG_VIRTUALTRANSACTION:
     305        1778 :                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
     306             :                                          instance->locktag.locktag_field2);
     307        1778 :                 nulls[1] = true;
     308        1778 :                 nulls[2] = true;
     309        1778 :                 nulls[3] = true;
     310        1778 :                 nulls[4] = true;
     311        1778 :                 nulls[6] = true;
     312        1778 :                 nulls[7] = true;
     313        1778 :                 nulls[8] = true;
     314        1778 :                 nulls[9] = true;
     315        1778 :                 break;
     316           4 :             case LOCKTAG_SPECULATIVE_TOKEN:
     317           4 :                 values[6] =
     318           4 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     319           4 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     320           4 :                 nulls[1] = true;
     321           4 :                 nulls[2] = true;
     322           4 :                 nulls[3] = true;
     323           4 :                 nulls[4] = true;
     324           4 :                 nulls[5] = true;
     325           4 :                 nulls[7] = true;
     326           4 :                 nulls[9] = true;
     327           4 :                 break;
     328           0 :             case LOCKTAG_APPLY_TRANSACTION:
     329           0 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     330           0 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     331           0 :                 values[6] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     332           0 :                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
     333           0 :                 nulls[2] = true;
     334           0 :                 nulls[3] = true;
     335           0 :                 nulls[4] = true;
     336           0 :                 nulls[5] = true;
     337           0 :                 nulls[7] = true;
     338           0 :                 break;
     339        1268 :             case LOCKTAG_OBJECT:
     340             :             case LOCKTAG_USERLOCK:
     341             :             case LOCKTAG_ADVISORY:
     342             :             default:            /* treat unknown locktags like OBJECT */
     343        1268 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     344        1268 :                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     345        1268 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     346        1268 :                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
     347        1268 :                 nulls[2] = true;
     348        1268 :                 nulls[3] = true;
     349        1268 :                 nulls[4] = true;
     350        1268 :                 nulls[5] = true;
     351        1268 :                 nulls[6] = true;
     352        1268 :                 break;
     353             :         }
     354             : 
     355       12072 :         values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
     356       12072 :         if (instance->pid != 0)
     357       12024 :             values[11] = Int32GetDatum(instance->pid);
     358             :         else
     359          48 :             nulls[11] = true;
     360       12072 :         values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
     361       12072 :         values[13] = BoolGetDatum(granted);
     362       12072 :         values[14] = BoolGetDatum(instance->fastpath);
     363       12072 :         if (!granted && instance->waitStart != 0)
     364          18 :             values[15] = TimestampTzGetDatum(instance->waitStart);
     365             :         else
     366       12054 :             nulls[15] = true;
     367             : 
     368       12072 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     369       12072 :         result = HeapTupleGetDatum(tuple);
     370       12072 :         SRF_RETURN_NEXT(funcctx, result);
     371             :     }
     372             : 
     373             :     /*
     374             :      * Have returned all regular locks. Now start on the SIREAD predicate
     375             :      * locks.
     376             :      */
     377         498 :     predLockData = mystatus->predLockData;
     378         498 :     if (mystatus->predLockIdx < predLockData->nelements)
     379             :     {
     380             :         PredicateLockTargetType lockType;
     381             : 
     382           6 :         PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
     383           6 :         SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
     384           6 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     385           6 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     386             :         HeapTuple   tuple;
     387             :         Datum       result;
     388             : 
     389           6 :         mystatus->predLockIdx++;
     390             : 
     391             :         /*
     392             :          * Form tuple with appropriate data.
     393             :          */
     394             : 
     395             :         /* lock type */
     396           6 :         lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
     397             : 
     398           6 :         values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
     399             : 
     400             :         /* lock target */
     401           6 :         values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
     402           6 :         values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
     403           6 :         if (lockType == PREDLOCKTAG_TUPLE)
     404           6 :             values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
     405             :         else
     406           0 :             nulls[4] = true;
     407           6 :         if ((lockType == PREDLOCKTAG_TUPLE) ||
     408             :             (lockType == PREDLOCKTAG_PAGE))
     409           6 :             values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
     410             :         else
     411           0 :             nulls[3] = true;
     412             : 
     413             :         /* these fields are targets for other types of locks */
     414           6 :         nulls[5] = true;        /* virtualxid */
     415           6 :         nulls[6] = true;        /* transactionid */
     416           6 :         nulls[7] = true;        /* classid */
     417           6 :         nulls[8] = true;        /* objid */
     418           6 :         nulls[9] = true;        /* objsubid */
     419             : 
     420             :         /* lock holder */
     421           6 :         values[10] = VXIDGetDatum(xact->vxid.procNumber,
     422             :                                   xact->vxid.localTransactionId);
     423           6 :         if (xact->pid != 0)
     424           6 :             values[11] = Int32GetDatum(xact->pid);
     425             :         else
     426           0 :             nulls[11] = true;
     427             : 
     428             :         /*
     429             :          * Lock mode. Currently all predicate locks are SIReadLocks, which are
     430             :          * always held (never waiting) and have no fast path
     431             :          */
     432           6 :         values[12] = CStringGetTextDatum("SIReadLock");
     433           6 :         values[13] = BoolGetDatum(true);
     434           6 :         values[14] = BoolGetDatum(false);
     435           6 :         nulls[15] = true;
     436             : 
     437           6 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     438           6 :         result = HeapTupleGetDatum(tuple);
     439           6 :         SRF_RETURN_NEXT(funcctx, result);
     440             :     }
     441             : 
     442         492 :     SRF_RETURN_DONE(funcctx);
     443             : }
     444             : 
     445             : 
     446             : /*
     447             :  * pg_blocking_pids - produce an array of the PIDs blocking given PID
     448             :  *
     449             :  * The reported PIDs are those that hold a lock conflicting with blocked_pid's
     450             :  * current request (hard block), or are requesting such a lock and are ahead
     451             :  * of blocked_pid in the lock's wait queue (soft block).
     452             :  *
     453             :  * In parallel-query cases, we report all PIDs blocking any member of the
     454             :  * given PID's lock group, and the reported PIDs are those of the blocking
     455             :  * PIDs' lock group leaders.  This allows callers to compare the result to
     456             :  * lists of clients' pg_backend_pid() results even during a parallel query.
     457             :  *
     458             :  * Parallel query makes it possible for there to be duplicate PIDs in the
     459             :  * result (either because multiple waiters are blocked by same PID, or
     460             :  * because multiple blockers have same group leader PID).  We do not bother
     461             :  * to eliminate such duplicates from the result.
     462             :  *
     463             :  * We need not consider predicate locks here, since those don't block anything.
     464             :  */
     465             : Datum
     466        3484 : pg_blocking_pids(PG_FUNCTION_ARGS)
     467             : {
     468        3484 :     int         blocked_pid = PG_GETARG_INT32(0);
     469             :     Datum      *arrayelems;
     470             :     int         narrayelems;
     471             :     BlockedProcsData *lockData; /* state data from lmgr */
     472             :     int         i,
     473             :                 j;
     474             : 
     475             :     /* Collect a snapshot of lock manager state */
     476        3484 :     lockData = GetBlockerStatusData(blocked_pid);
     477             : 
     478             :     /* We can't need more output entries than there are reported PROCLOCKs */
     479        3484 :     arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
     480        3484 :     narrayelems = 0;
     481             : 
     482             :     /* For each blocked proc in the lock group ... */
     483        5738 :     for (i = 0; i < lockData->nprocs; i++)
     484             :     {
     485        2254 :         BlockedProcData *bproc = &lockData->procs[i];
     486        2254 :         LockInstanceData *instances = &lockData->locks[bproc->first_lock];
     487        2254 :         int        *preceding_waiters = &lockData->waiter_pids[bproc->first_waiter];
     488             :         LockInstanceData *blocked_instance;
     489             :         LockMethod  lockMethodTable;
     490             :         int         conflictMask;
     491             : 
     492             :         /*
     493             :          * Locate the blocked proc's own entry in the LockInstanceData array.
     494             :          * There should be exactly one matching entry.
     495             :          */
     496        2254 :         blocked_instance = NULL;
     497        6850 :         for (j = 0; j < bproc->num_locks; j++)
     498             :         {
     499        4596 :             LockInstanceData *instance = &(instances[j]);
     500             : 
     501        4596 :             if (instance->pid == bproc->pid)
     502             :             {
     503             :                 Assert(blocked_instance == NULL);
     504        2254 :                 blocked_instance = instance;
     505             :             }
     506             :         }
     507             :         Assert(blocked_instance != NULL);
     508             : 
     509        2254 :         lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
     510        2254 :         conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
     511             : 
     512             :         /* Now scan the PROCLOCK data for conflicting procs */
     513        6850 :         for (j = 0; j < bproc->num_locks; j++)
     514             :         {
     515        4596 :             LockInstanceData *instance = &(instances[j]);
     516             : 
     517             :             /* A proc never blocks itself, so ignore that entry */
     518        4596 :             if (instance == blocked_instance)
     519        2254 :                 continue;
     520             :             /* Members of same lock group never block each other, either */
     521        2342 :             if (instance->leaderPid == blocked_instance->leaderPid)
     522           0 :                 continue;
     523             : 
     524        2342 :             if (conflictMask & instance->holdMask)
     525             :             {
     526             :                 /* hard block: blocked by lock already held by this entry */
     527             :             }
     528          80 :             else if (instance->waitLockMode != NoLock &&
     529          72 :                      (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
     530          16 :             {
     531             :                 /* conflict in lock requests; who's in front in wait queue? */
     532          32 :                 bool        ahead = false;
     533             :                 int         k;
     534             : 
     535          32 :                 for (k = 0; k < bproc->num_waiters; k++)
     536             :                 {
     537          16 :                     if (preceding_waiters[k] == instance->pid)
     538             :                     {
     539             :                         /* soft block: this entry is ahead of blocked proc */
     540          16 :                         ahead = true;
     541          16 :                         break;
     542             :                     }
     543             :                 }
     544          32 :                 if (!ahead)
     545          16 :                     continue;   /* not blocked by this entry */
     546             :             }
     547             :             else
     548             :             {
     549             :                 /* not blocked by this entry */
     550          48 :                 continue;
     551             :             }
     552             : 
     553             :             /* blocked by this entry, so emit a record */
     554        2278 :             arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
     555             :         }
     556             :     }
     557             : 
     558             :     /* Assert we didn't overrun arrayelems[] */
     559             :     Assert(narrayelems <= lockData->nlocks);
     560             : 
     561        3484 :     PG_RETURN_ARRAYTYPE_P(construct_array_builtin(arrayelems, narrayelems, INT4OID));
     562             : }
     563             : 
     564             : 
     565             : /*
     566             :  * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
     567             :  * given PID from getting a safe snapshot
     568             :  *
     569             :  * XXX this does not consider parallel-query cases; not clear how big a
     570             :  * problem that is in practice
     571             :  */
     572             : Datum
     573           0 : pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
     574             : {
     575           0 :     int         blocked_pid = PG_GETARG_INT32(0);
     576             :     int        *blockers;
     577             :     int         num_blockers;
     578             :     Datum      *blocker_datums;
     579             : 
     580             :     /* A buffer big enough for any possible blocker list without truncation */
     581           0 :     blockers = (int *) palloc(MaxBackends * sizeof(int));
     582             : 
     583             :     /* Collect a snapshot of processes waited for by GetSafeSnapshot */
     584             :     num_blockers =
     585           0 :         GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
     586             : 
     587             :     /* Convert int array to Datum array */
     588           0 :     if (num_blockers > 0)
     589             :     {
     590             :         int         i;
     591             : 
     592           0 :         blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
     593           0 :         for (i = 0; i < num_blockers; ++i)
     594           0 :             blocker_datums[i] = Int32GetDatum(blockers[i]);
     595             :     }
     596             :     else
     597           0 :         blocker_datums = NULL;
     598             : 
     599           0 :     PG_RETURN_ARRAYTYPE_P(construct_array_builtin(blocker_datums, num_blockers, INT4OID));
     600             : }
     601             : 
     602             : 
     603             : /*
     604             :  * Functions for manipulating advisory locks
     605             :  *
     606             :  * We make use of the locktag fields as follows:
     607             :  *
     608             :  *  field1: MyDatabaseId ... ensures locks are local to each database
     609             :  *  field2: first of 2 int4 keys, or high-order half of an int8 key
     610             :  *  field3: second of 2 int4 keys, or low-order half of an int8 key
     611             :  *  field4: 1 if using an int8 key, 2 if using 2 int4 keys
     612             :  */
     613             : #define SET_LOCKTAG_INT64(tag, key64) \
     614             :     SET_LOCKTAG_ADVISORY(tag, \
     615             :                          MyDatabaseId, \
     616             :                          (uint32) ((key64) >> 32), \
     617             :                          (uint32) (key64), \
     618             :                          1)
     619             : #define SET_LOCKTAG_INT32(tag, key1, key2) \
     620             :     SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
     621             : 
     622             : /*
     623             :  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
     624             :  */
     625             : Datum
     626         424 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
     627             : {
     628         424 :     int64       key = PG_GETARG_INT64(0);
     629             :     LOCKTAG     tag;
     630             : 
     631         424 :     SET_LOCKTAG_INT64(tag, key);
     632             : 
     633         424 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     634             : 
     635         422 :     PG_RETURN_VOID();
     636             : }
     637             : 
     638             : /*
     639             :  * pg_advisory_xact_lock(int8) - acquire xact scoped
     640             :  * exclusive lock on an int8 key
     641             :  */
     642             : Datum
     643         514 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     644             : {
     645         514 :     int64       key = PG_GETARG_INT64(0);
     646             :     LOCKTAG     tag;
     647             : 
     648         514 :     SET_LOCKTAG_INT64(tag, key);
     649             : 
     650         514 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     651             : 
     652         514 :     PG_RETURN_VOID();
     653             : }
     654             : 
     655             : /*
     656             :  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
     657             :  */
     658             : Datum
     659          56 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     660             : {
     661          56 :     int64       key = PG_GETARG_INT64(0);
     662             :     LOCKTAG     tag;
     663             : 
     664          56 :     SET_LOCKTAG_INT64(tag, key);
     665             : 
     666          56 :     (void) LockAcquire(&tag, ShareLock, true, false);
     667             : 
     668          56 :     PG_RETURN_VOID();
     669             : }
     670             : 
     671             : /*
     672             :  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
     673             :  * share lock on an int8 key
     674             :  */
     675             : Datum
     676       40042 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     677             : {
     678       40042 :     int64       key = PG_GETARG_INT64(0);
     679             :     LOCKTAG     tag;
     680             : 
     681       40042 :     SET_LOCKTAG_INT64(tag, key);
     682             : 
     683       40042 :     (void) LockAcquire(&tag, ShareLock, false, false);
     684             : 
     685       40042 :     PG_RETURN_VOID();
     686             : }
     687             : 
     688             : /*
     689             :  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
     690             :  *
     691             :  * Returns true if successful, false if lock not available
     692             :  */
     693             : Datum
     694         836 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
     695             : {
     696         836 :     int64       key = PG_GETARG_INT64(0);
     697             :     LOCKTAG     tag;
     698             :     LockAcquireResult res;
     699             : 
     700         836 :     SET_LOCKTAG_INT64(tag, key);
     701             : 
     702         836 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     703             : 
     704         836 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     705             : }
     706             : 
     707             : /*
     708             :  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
     709             :  * exclusive lock on an int8 key, no wait
     710             :  *
     711             :  * Returns true if successful, false if lock not available
     712             :  */
     713             : Datum
     714           0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     715             : {
     716           0 :     int64       key = PG_GETARG_INT64(0);
     717             :     LOCKTAG     tag;
     718             :     LockAcquireResult res;
     719             : 
     720           0 :     SET_LOCKTAG_INT64(tag, key);
     721             : 
     722           0 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     723             : 
     724           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     725             : }
     726             : 
     727             : /*
     728             :  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
     729             :  *
     730             :  * Returns true if successful, false if lock not available
     731             :  */
     732             : Datum
     733           0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     734             : {
     735           0 :     int64       key = PG_GETARG_INT64(0);
     736             :     LOCKTAG     tag;
     737             :     LockAcquireResult res;
     738             : 
     739           0 :     SET_LOCKTAG_INT64(tag, key);
     740             : 
     741           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     742             : 
     743           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     744             : }
     745             : 
     746             : /*
     747             :  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
     748             :  * share lock on an int8 key, no wait
     749             :  *
     750             :  * Returns true if successful, false if lock not available
     751             :  */
     752             : Datum
     753           0 : pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     754             : {
     755           0 :     int64       key = PG_GETARG_INT64(0);
     756             :     LOCKTAG     tag;
     757             :     LockAcquireResult res;
     758             : 
     759           0 :     SET_LOCKTAG_INT64(tag, key);
     760             : 
     761           0 :     res = LockAcquire(&tag, ShareLock, false, true);
     762             : 
     763           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     764             : }
     765             : 
     766             : /*
     767             :  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
     768             :  *
     769             :  * Returns true if successful, false if lock was not held
     770             : */
     771             : Datum
     772         276 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
     773             : {
     774         276 :     int64       key = PG_GETARG_INT64(0);
     775             :     LOCKTAG     tag;
     776             :     bool        res;
     777             : 
     778         276 :     SET_LOCKTAG_INT64(tag, key);
     779             : 
     780         276 :     res = LockRelease(&tag, ExclusiveLock, true);
     781             : 
     782         276 :     PG_RETURN_BOOL(res);
     783             : }
     784             : 
     785             : /*
     786             :  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
     787             :  *
     788             :  * Returns true if successful, false if lock was not held
     789             :  */
     790             : Datum
     791          30 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
     792             : {
     793          30 :     int64       key = PG_GETARG_INT64(0);
     794             :     LOCKTAG     tag;
     795             :     bool        res;
     796             : 
     797          30 :     SET_LOCKTAG_INT64(tag, key);
     798             : 
     799          30 :     res = LockRelease(&tag, ShareLock, true);
     800             : 
     801          30 :     PG_RETURN_BOOL(res);
     802             : }
     803             : 
     804             : /*
     805             :  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
     806             :  */
     807             : Datum
     808          98 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
     809             : {
     810          98 :     int32       key1 = PG_GETARG_INT32(0);
     811          98 :     int32       key2 = PG_GETARG_INT32(1);
     812             :     LOCKTAG     tag;
     813             : 
     814          98 :     SET_LOCKTAG_INT32(tag, key1, key2);
     815             : 
     816          98 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     817             : 
     818          98 :     PG_RETURN_VOID();
     819             : }
     820             : 
     821             : /*
     822             :  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
     823             :  * exclusive lock on 2 int4 keys
     824             :  */
     825             : Datum
     826         100 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     827             : {
     828         100 :     int32       key1 = PG_GETARG_INT32(0);
     829         100 :     int32       key2 = PG_GETARG_INT32(1);
     830             :     LOCKTAG     tag;
     831             : 
     832         100 :     SET_LOCKTAG_INT32(tag, key1, key2);
     833             : 
     834         100 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     835             : 
     836         100 :     PG_RETURN_VOID();
     837             : }
     838             : 
     839             : /*
     840             :  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
     841             :  */
     842             : Datum
     843          36 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     844             : {
     845          36 :     int32       key1 = PG_GETARG_INT32(0);
     846          36 :     int32       key2 = PG_GETARG_INT32(1);
     847             :     LOCKTAG     tag;
     848             : 
     849          36 :     SET_LOCKTAG_INT32(tag, key1, key2);
     850             : 
     851          36 :     (void) LockAcquire(&tag, ShareLock, true, false);
     852             : 
     853          36 :     PG_RETURN_VOID();
     854             : }
     855             : 
     856             : /*
     857             :  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     858             :  * share lock on 2 int4 keys
     859             :  */
     860             : Datum
     861          30 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     862             : {
     863          30 :     int32       key1 = PG_GETARG_INT32(0);
     864          30 :     int32       key2 = PG_GETARG_INT32(1);
     865             :     LOCKTAG     tag;
     866             : 
     867          30 :     SET_LOCKTAG_INT32(tag, key1, key2);
     868             : 
     869          30 :     (void) LockAcquire(&tag, ShareLock, false, false);
     870             : 
     871          30 :     PG_RETURN_VOID();
     872             : }
     873             : 
     874             : /*
     875             :  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
     876             :  *
     877             :  * Returns true if successful, false if lock not available
     878             :  */
     879             : Datum
     880           0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
     881             : {
     882           0 :     int32       key1 = PG_GETARG_INT32(0);
     883           0 :     int32       key2 = PG_GETARG_INT32(1);
     884             :     LOCKTAG     tag;
     885             :     LockAcquireResult res;
     886             : 
     887           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     888             : 
     889           0 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     890             : 
     891           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     892             : }
     893             : 
     894             : /*
     895             :  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
     896             :  * exclusive lock on 2 int4 keys, no wait
     897             :  *
     898             :  * Returns true if successful, false if lock not available
     899             :  */
     900             : Datum
     901          66 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     902             : {
     903          66 :     int32       key1 = PG_GETARG_INT32(0);
     904          66 :     int32       key2 = PG_GETARG_INT32(1);
     905             :     LOCKTAG     tag;
     906             :     LockAcquireResult res;
     907             : 
     908          66 :     SET_LOCKTAG_INT32(tag, key1, key2);
     909             : 
     910          66 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     911             : 
     912          66 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     913             : }
     914             : 
     915             : /*
     916             :  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
     917             :  *
     918             :  * Returns true if successful, false if lock not available
     919             :  */
     920             : Datum
     921           0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     922             : {
     923           0 :     int32       key1 = PG_GETARG_INT32(0);
     924           0 :     int32       key2 = PG_GETARG_INT32(1);
     925             :     LOCKTAG     tag;
     926             :     LockAcquireResult res;
     927             : 
     928           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     929             : 
     930           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     931             : 
     932           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     933             : }
     934             : 
     935             : /*
     936             :  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     937             :  * share lock on 2 int4 keys, no wait
     938             :  *
     939             :  * Returns true if successful, false if lock not available
     940             :  */
     941             : Datum
     942           0 : pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     943             : {
     944           0 :     int32       key1 = PG_GETARG_INT32(0);
     945           0 :     int32       key2 = PG_GETARG_INT32(1);
     946             :     LOCKTAG     tag;
     947             :     LockAcquireResult res;
     948             : 
     949           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     950             : 
     951           0 :     res = LockAcquire(&tag, ShareLock, false, true);
     952             : 
     953           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     954             : }
     955             : 
     956             : /*
     957             :  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
     958             :  *
     959             :  * Returns true if successful, false if lock was not held
     960             : */
     961             : Datum
     962          94 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
     963             : {
     964          94 :     int32       key1 = PG_GETARG_INT32(0);
     965          94 :     int32       key2 = PG_GETARG_INT32(1);
     966             :     LOCKTAG     tag;
     967             :     bool        res;
     968             : 
     969          94 :     SET_LOCKTAG_INT32(tag, key1, key2);
     970             : 
     971          94 :     res = LockRelease(&tag, ExclusiveLock, true);
     972             : 
     973          94 :     PG_RETURN_BOOL(res);
     974             : }
     975             : 
     976             : /*
     977             :  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
     978             :  *
     979             :  * Returns true if successful, false if lock was not held
     980             :  */
     981             : Datum
     982          30 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
     983             : {
     984          30 :     int32       key1 = PG_GETARG_INT32(0);
     985          30 :     int32       key2 = PG_GETARG_INT32(1);
     986             :     LOCKTAG     tag;
     987             :     bool        res;
     988             : 
     989          30 :     SET_LOCKTAG_INT32(tag, key1, key2);
     990             : 
     991          30 :     res = LockRelease(&tag, ShareLock, true);
     992             : 
     993          30 :     PG_RETURN_BOOL(res);
     994             : }
     995             : 
     996             : /*
     997             :  * pg_advisory_unlock_all() - release all advisory locks
     998             :  */
     999             : Datum
    1000         238 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
    1001             : {
    1002         238 :     LockReleaseSession(USER_LOCKMETHOD);
    1003             : 
    1004         238 :     PG_RETURN_VOID();
    1005             : }

Generated by: LCOV version 1.14