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

Generated by: LCOV version 1.13