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

Generated by: LCOV version 2.0-1