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

Generated by: LCOV version 1.14