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 % 367 296
Test Date: 2026-03-12 06:14:44 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         7533 : 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         7533 :     snprintf(vxidstr, sizeof(vxidstr), "%d/%u", procNumber, lxid);
      84              : 
      85         7533 :     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         6749 : pg_lock_status(PG_FUNCTION_ARGS)
      94              : {
      95              :     FuncCallContext *funcctx;
      96              :     PG_Lock_Status *mystatus;
      97              :     LockData   *lockData;
      98              :     PredicateLockData *predLockData;
      99              : 
     100         6749 :     if (SRF_IS_FIRSTCALL())
     101              :     {
     102              :         TupleDesc   tupdesc;
     103              :         MemoryContext oldcontext;
     104              : 
     105              :         /* create a function context for cross-call persistence */
     106          225 :         funcctx = SRF_FIRSTCALL_INIT();
     107              : 
     108              :         /*
     109              :          * switch to memory context appropriate for multiple function calls
     110              :          */
     111          225 :         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          225 :         tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
     116          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
     117              :                            TEXTOID, -1, 0);
     118          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
     119              :                            OIDOID, -1, 0);
     120          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
     121              :                            OIDOID, -1, 0);
     122          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
     123              :                            INT4OID, -1, 0);
     124          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
     125              :                            INT2OID, -1, 0);
     126          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
     127              :                            TEXTOID, -1, 0);
     128          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
     129              :                            XIDOID, -1, 0);
     130          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
     131              :                            OIDOID, -1, 0);
     132          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
     133              :                            OIDOID, -1, 0);
     134          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
     135              :                            INT2OID, -1, 0);
     136          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
     137              :                            TEXTOID, -1, 0);
     138          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
     139              :                            INT4OID, -1, 0);
     140          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
     141              :                            TEXTOID, -1, 0);
     142          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
     143              :                            BOOLOID, -1, 0);
     144          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
     145              :                            BOOLOID, -1, 0);
     146          225 :         TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
     147              :                            TIMESTAMPTZOID, -1, 0);
     148              : 
     149          225 :         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          225 :         mystatus = palloc_object(PG_Lock_Status);
     156          225 :         funcctx->user_fctx = mystatus;
     157              : 
     158          225 :         mystatus->lockData = GetLockStatusData();
     159          225 :         mystatus->currIdx = 0;
     160          225 :         mystatus->predLockData = GetPredicateLockStatusData();
     161          225 :         mystatus->predLockIdx = 0;
     162              : 
     163          225 :         MemoryContextSwitchTo(oldcontext);
     164              :     }
     165              : 
     166         6749 :     funcctx = SRF_PERCALL_SETUP();
     167         6749 :     mystatus = (PG_Lock_Status *) funcctx->user_fctx;
     168         6749 :     lockData = mystatus->lockData;
     169              : 
     170        12994 :     while (mystatus->currIdx < lockData->nelements)
     171              :     {
     172              :         bool        granted;
     173        12766 :         LOCKMODE    mode = 0;
     174              :         const char *locktypename;
     175              :         char        tnbuf[32];
     176        12766 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     177        12766 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     178              :         HeapTuple   tuple;
     179              :         Datum       result;
     180              :         LockInstanceData *instance;
     181              : 
     182        12766 :         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        12766 :         granted = false;
     190        12766 :         if (instance->holdMask)
     191              :         {
     192        30291 :             for (mode = 0; mode < MAX_LOCKMODES; mode++)
     193              :             {
     194        30291 :                 if (instance->holdMask & LOCKBIT_ON(mode))
     195              :                 {
     196         6512 :                     granted = true;
     197         6512 :                     instance->holdMask &= LOCKBIT_OFF(mode);
     198         6512 :                     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        12766 :         if (!granted)
     208              :         {
     209         6254 :             if (instance->waitLockMode != NoLock)
     210              :             {
     211              :                 /* Yes, so report it with proper mode */
     212            9 :                 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            9 :                 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         6245 :                 mystatus->currIdx++;
     227         6245 :                 continue;
     228              :             }
     229              :         }
     230              : 
     231              :         /*
     232              :          * Form tuple with appropriate data.
     233              :          */
     234              : 
     235         6521 :         if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
     236         6521 :             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         6521 :         values[0] = CStringGetTextDatum(locktypename);
     244              : 
     245         6521 :         switch ((LockTagType) instance->locktag.locktag_type)
     246              :         {
     247         4579 :             case LOCKTAG_RELATION:
     248              :             case LOCKTAG_RELATION_EXTEND:
     249         4579 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     250         4579 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     251         4579 :                 nulls[3] = true;
     252         4579 :                 nulls[4] = true;
     253         4579 :                 nulls[5] = true;
     254         4579 :                 nulls[6] = true;
     255         4579 :                 nulls[7] = true;
     256         4579 :                 nulls[8] = true;
     257         4579 :                 nulls[9] = true;
     258         4579 :                 break;
     259            1 :             case LOCKTAG_DATABASE_FROZEN_IDS:
     260            1 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     261            1 :                 nulls[2] = true;
     262            1 :                 nulls[3] = true;
     263            1 :                 nulls[4] = true;
     264            1 :                 nulls[5] = true;
     265            1 :                 nulls[6] = true;
     266            1 :                 nulls[7] = true;
     267            1 :                 nulls[8] = true;
     268            1 :                 nulls[9] = true;
     269            1 :                 break;
     270            0 :             case LOCKTAG_PAGE:
     271            0 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     272            0 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     273            0 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     274            0 :                 nulls[4] = true;
     275            0 :                 nulls[5] = true;
     276            0 :                 nulls[6] = true;
     277            0 :                 nulls[7] = true;
     278            0 :                 nulls[8] = true;
     279            0 :                 nulls[9] = true;
     280            0 :                 break;
     281            1 :             case LOCKTAG_TUPLE:
     282            1 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     283            1 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     284            1 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     285            1 :                 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
     286            1 :                 nulls[5] = true;
     287            1 :                 nulls[6] = true;
     288            1 :                 nulls[7] = true;
     289            1 :                 nulls[8] = true;
     290            1 :                 nulls[9] = true;
     291            1 :                 break;
     292          491 :             case LOCKTAG_TRANSACTION:
     293          491 :                 values[6] =
     294          491 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     295          491 :                 nulls[1] = true;
     296          491 :                 nulls[2] = true;
     297          491 :                 nulls[3] = true;
     298          491 :                 nulls[4] = true;
     299          491 :                 nulls[5] = true;
     300          491 :                 nulls[7] = true;
     301          491 :                 nulls[8] = true;
     302          491 :                 nulls[9] = true;
     303          491 :                 break;
     304         1009 :             case LOCKTAG_VIRTUALTRANSACTION:
     305         1009 :                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
     306              :                                          instance->locktag.locktag_field2);
     307         1009 :                 nulls[1] = true;
     308         1009 :                 nulls[2] = true;
     309         1009 :                 nulls[3] = true;
     310         1009 :                 nulls[4] = true;
     311         1009 :                 nulls[6] = true;
     312         1009 :                 nulls[7] = true;
     313         1009 :                 nulls[8] = true;
     314         1009 :                 nulls[9] = true;
     315         1009 :                 break;
     316            2 :             case LOCKTAG_SPECULATIVE_TOKEN:
     317            2 :                 values[6] =
     318            2 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     319            2 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     320            2 :                 nulls[1] = true;
     321            2 :                 nulls[2] = true;
     322            2 :                 nulls[3] = true;
     323            2 :                 nulls[4] = true;
     324            2 :                 nulls[5] = true;
     325            2 :                 nulls[7] = true;
     326            2 :                 nulls[9] = true;
     327            2 :                 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] = UInt16GetDatum(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          438 :             case LOCKTAG_OBJECT:
     340              :             case LOCKTAG_USERLOCK:
     341              :             case LOCKTAG_ADVISORY:
     342              :             default:            /* treat unknown locktags like OBJECT */
     343          438 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     344          438 :                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     345          438 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     346          438 :                 values[9] = UInt16GetDatum(instance->locktag.locktag_field4);
     347          438 :                 nulls[2] = true;
     348          438 :                 nulls[3] = true;
     349          438 :                 nulls[4] = true;
     350          438 :                 nulls[5] = true;
     351          438 :                 nulls[6] = true;
     352          438 :                 break;
     353              :         }
     354              : 
     355         6521 :         values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
     356         6521 :         if (instance->pid != 0)
     357         6499 :             values[11] = Int32GetDatum(instance->pid);
     358              :         else
     359           22 :             nulls[11] = true;
     360         6521 :         values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
     361         6521 :         values[13] = BoolGetDatum(granted);
     362         6521 :         values[14] = BoolGetDatum(instance->fastpath);
     363         6521 :         if (!granted && instance->waitStart != 0)
     364            9 :             values[15] = TimestampTzGetDatum(instance->waitStart);
     365              :         else
     366         6512 :             nulls[15] = true;
     367              : 
     368         6521 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     369         6521 :         result = HeapTupleGetDatum(tuple);
     370         6521 :         SRF_RETURN_NEXT(funcctx, result);
     371              :     }
     372              : 
     373              :     /*
     374              :      * Have returned all regular locks. Now start on the SIREAD predicate
     375              :      * locks.
     376              :      */
     377          228 :     predLockData = mystatus->predLockData;
     378          228 :     if (mystatus->predLockIdx < predLockData->nelements)
     379              :     {
     380              :         PredicateLockTargetType lockType;
     381              : 
     382            3 :         PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
     383            3 :         SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
     384            3 :         Datum       values[NUM_LOCK_STATUS_COLUMNS] = {0};
     385            3 :         bool        nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
     386              :         HeapTuple   tuple;
     387              :         Datum       result;
     388              : 
     389            3 :         mystatus->predLockIdx++;
     390              : 
     391              :         /*
     392              :          * Form tuple with appropriate data.
     393              :          */
     394              : 
     395              :         /* lock type */
     396            3 :         lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
     397              : 
     398            3 :         values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
     399              : 
     400              :         /* lock target */
     401            3 :         values[1] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_DB(*predTag));
     402            3 :         values[2] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_RELATION(*predTag));
     403            3 :         if (lockType == PREDLOCKTAG_TUPLE)
     404            3 :             values[4] = UInt16GetDatum(GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag));
     405              :         else
     406            0 :             nulls[4] = true;
     407            3 :         if ((lockType == PREDLOCKTAG_TUPLE) ||
     408              :             (lockType == PREDLOCKTAG_PAGE))
     409            3 :             values[3] = UInt32GetDatum(GET_PREDICATELOCKTARGETTAG_PAGE(*predTag));
     410              :         else
     411            0 :             nulls[3] = true;
     412              : 
     413              :         /* these fields are targets for other types of locks */
     414            3 :         nulls[5] = true;        /* virtualxid */
     415            3 :         nulls[6] = true;        /* transactionid */
     416            3 :         nulls[7] = true;        /* classid */
     417            3 :         nulls[8] = true;        /* objid */
     418            3 :         nulls[9] = true;        /* objsubid */
     419              : 
     420              :         /* lock holder */
     421            3 :         values[10] = VXIDGetDatum(xact->vxid.procNumber,
     422              :                                   xact->vxid.localTransactionId);
     423            3 :         if (xact->pid != 0)
     424            3 :             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            3 :         values[12] = CStringGetTextDatum("SIReadLock");
     433            3 :         values[13] = BoolGetDatum(true);
     434            3 :         values[14] = BoolGetDatum(false);
     435            3 :         nulls[15] = true;
     436              : 
     437            3 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     438            3 :         result = HeapTupleGetDatum(tuple);
     439            3 :         SRF_RETURN_NEXT(funcctx, result);
     440              :     }
     441              : 
     442          225 :     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         1723 : pg_blocking_pids(PG_FUNCTION_ARGS)
     467              : {
     468         1723 :     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         1723 :     lockData = GetBlockerStatusData(blocked_pid);
     477              : 
     478              :     /* We can't need more output entries than there are reported PROCLOCKs */
     479         1723 :     arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
     480         1723 :     narrayelems = 0;
     481              : 
     482              :     /* For each blocked proc in the lock group ... */
     483         2931 :     for (i = 0; i < lockData->nprocs; i++)
     484              :     {
     485         1208 :         BlockedProcData *bproc = &lockData->procs[i];
     486         1208 :         LockInstanceData *instances = &lockData->locks[bproc->first_lock];
     487         1208 :         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         1208 :         blocked_instance = NULL;
     497         3671 :         for (j = 0; j < bproc->num_locks; j++)
     498              :         {
     499         2463 :             LockInstanceData *instance = &(instances[j]);
     500              : 
     501         2463 :             if (instance->pid == bproc->pid)
     502              :             {
     503              :                 Assert(blocked_instance == NULL);
     504         1208 :                 blocked_instance = instance;
     505              :             }
     506              :         }
     507              :         Assert(blocked_instance != NULL);
     508              : 
     509         1208 :         lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
     510         1208 :         conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
     511              : 
     512              :         /* Now scan the PROCLOCK data for conflicting procs */
     513         3671 :         for (j = 0; j < bproc->num_locks; j++)
     514              :         {
     515         2463 :             LockInstanceData *instance = &(instances[j]);
     516              : 
     517              :             /* A proc never blocks itself, so ignore that entry */
     518         2463 :             if (instance == blocked_instance)
     519         1208 :                 continue;
     520              :             /* Members of same lock group never block each other, either */
     521         1255 :             if (instance->leaderPid == blocked_instance->leaderPid)
     522            2 :                 continue;
     523              : 
     524         1253 :             if (conflictMask & instance->holdMask)
     525              :             {
     526              :                 /* hard block: blocked by lock already held by this entry */
     527              :             }
     528           45 :             else if (instance->waitLockMode != NoLock &&
     529           40 :                      (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
     530            9 :             {
     531              :                 /* conflict in lock requests; who's in front in wait queue? */
     532           20 :                 bool        ahead = false;
     533              :                 int         k;
     534              : 
     535           20 :                 for (k = 0; k < bproc->num_waiters; k++)
     536              :                 {
     537            9 :                     if (preceding_waiters[k] == instance->pid)
     538              :                     {
     539              :                         /* soft block: this entry is ahead of blocked proc */
     540            9 :                         ahead = true;
     541            9 :                         break;
     542              :                     }
     543              :                 }
     544           20 :                 if (!ahead)
     545           11 :                     continue;   /* not blocked by this entry */
     546              :             }
     547              :             else
     548              :             {
     549              :                 /* not blocked by this entry */
     550           25 :                 continue;
     551              :             }
     552              : 
     553              :             /* blocked by this entry, so emit a record */
     554         1217 :             arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
     555              :         }
     556              :     }
     557              : 
     558              :     /* Assert we didn't overrun arrayelems[] */
     559              :     Assert(narrayelems <= lockData->nlocks);
     560              : 
     561         1723 :     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          211 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
     627              : {
     628          211 :     int64       key = PG_GETARG_INT64(0);
     629              :     LOCKTAG     tag;
     630              : 
     631          211 :     SET_LOCKTAG_INT64(tag, key);
     632              : 
     633          211 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     634              : 
     635          210 :     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          248 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     644              : {
     645          248 :     int64       key = PG_GETARG_INT64(0);
     646              :     LOCKTAG     tag;
     647              : 
     648          248 :     SET_LOCKTAG_INT64(tag, key);
     649              : 
     650          248 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     651              : 
     652          248 :     PG_RETURN_VOID();
     653              : }
     654              : 
     655              : /*
     656              :  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
     657              :  */
     658              : Datum
     659           28 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     660              : {
     661           28 :     int64       key = PG_GETARG_INT64(0);
     662              :     LOCKTAG     tag;
     663              : 
     664           28 :     SET_LOCKTAG_INT64(tag, key);
     665              : 
     666           28 :     (void) LockAcquire(&tag, ShareLock, true, false);
     667              : 
     668           28 :     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        20020 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     677              : {
     678        20020 :     int64       key = PG_GETARG_INT64(0);
     679              :     LOCKTAG     tag;
     680              : 
     681        20020 :     SET_LOCKTAG_INT64(tag, key);
     682              : 
     683        20020 :     (void) LockAcquire(&tag, ShareLock, false, false);
     684              : 
     685        20020 :     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          504 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
     695              : {
     696          504 :     int64       key = PG_GETARG_INT64(0);
     697              :     LOCKTAG     tag;
     698              :     LockAcquireResult res;
     699              : 
     700          504 :     SET_LOCKTAG_INT64(tag, key);
     701              : 
     702          504 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     703              : 
     704          504 :     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          161 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
     773              : {
     774          161 :     int64       key = PG_GETARG_INT64(0);
     775              :     LOCKTAG     tag;
     776              :     bool        res;
     777              : 
     778          161 :     SET_LOCKTAG_INT64(tag, key);
     779              : 
     780          161 :     res = LockRelease(&tag, ExclusiveLock, true);
     781              : 
     782          161 :     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           15 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
     792              : {
     793           15 :     int64       key = PG_GETARG_INT64(0);
     794              :     LOCKTAG     tag;
     795              :     bool        res;
     796              : 
     797           15 :     SET_LOCKTAG_INT64(tag, key);
     798              : 
     799           15 :     res = LockRelease(&tag, ShareLock, true);
     800              : 
     801           15 :     PG_RETURN_BOOL(res);
     802              : }
     803              : 
     804              : /*
     805              :  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
     806              :  */
     807              : Datum
     808           49 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
     809              : {
     810           49 :     int32       key1 = PG_GETARG_INT32(0);
     811           49 :     int32       key2 = PG_GETARG_INT32(1);
     812              :     LOCKTAG     tag;
     813              : 
     814           49 :     SET_LOCKTAG_INT32(tag, key1, key2);
     815              : 
     816           49 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     817              : 
     818           49 :     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           50 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     827              : {
     828           50 :     int32       key1 = PG_GETARG_INT32(0);
     829           50 :     int32       key2 = PG_GETARG_INT32(1);
     830              :     LOCKTAG     tag;
     831              : 
     832           50 :     SET_LOCKTAG_INT32(tag, key1, key2);
     833              : 
     834           50 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     835              : 
     836           50 :     PG_RETURN_VOID();
     837              : }
     838              : 
     839              : /*
     840              :  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
     841              :  */
     842              : Datum
     843           18 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     844              : {
     845           18 :     int32       key1 = PG_GETARG_INT32(0);
     846           18 :     int32       key2 = PG_GETARG_INT32(1);
     847              :     LOCKTAG     tag;
     848              : 
     849           18 :     SET_LOCKTAG_INT32(tag, key1, key2);
     850              : 
     851           18 :     (void) LockAcquire(&tag, ShareLock, true, false);
     852              : 
     853           18 :     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           15 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     862              : {
     863           15 :     int32       key1 = PG_GETARG_INT32(0);
     864           15 :     int32       key2 = PG_GETARG_INT32(1);
     865              :     LOCKTAG     tag;
     866              : 
     867           15 :     SET_LOCKTAG_INT32(tag, key1, key2);
     868              : 
     869           15 :     (void) LockAcquire(&tag, ShareLock, false, false);
     870              : 
     871           15 :     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           33 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     902              : {
     903           33 :     int32       key1 = PG_GETARG_INT32(0);
     904           33 :     int32       key2 = PG_GETARG_INT32(1);
     905              :     LOCKTAG     tag;
     906              :     LockAcquireResult res;
     907              : 
     908           33 :     SET_LOCKTAG_INT32(tag, key1, key2);
     909              : 
     910           33 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     911              : 
     912           33 :     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           47 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
     963              : {
     964           47 :     int32       key1 = PG_GETARG_INT32(0);
     965           47 :     int32       key2 = PG_GETARG_INT32(1);
     966              :     LOCKTAG     tag;
     967              :     bool        res;
     968              : 
     969           47 :     SET_LOCKTAG_INT32(tag, key1, key2);
     970              : 
     971           47 :     res = LockRelease(&tag, ExclusiveLock, true);
     972              : 
     973           47 :     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           15 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
     983              : {
     984           15 :     int32       key1 = PG_GETARG_INT32(0);
     985           15 :     int32       key2 = PG_GETARG_INT32(1);
     986              :     LOCKTAG     tag;
     987              :     bool        res;
     988              : 
     989           15 :     SET_LOCKTAG_INT32(tag, key1, key2);
     990              : 
     991           15 :     res = LockRelease(&tag, ShareLock, true);
     992              : 
     993           15 :     PG_RETURN_BOOL(res);
     994              : }
     995              : 
     996              : /*
     997              :  * pg_advisory_unlock_all() - release all advisory locks
     998              :  */
     999              : Datum
    1000          119 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
    1001              : {
    1002          119 :     LockReleaseSession(USER_LOCKMETHOD);
    1003              : 
    1004          119 :     PG_RETURN_VOID();
    1005              : }
        

Generated by: LCOV version 2.0-1