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

Generated by: LCOV version 1.13