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

Generated by: LCOV version 1.13