LCOV - code coverage report
Current view: top level - src/backend/utils/adt - lockfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 234 341 68.6 %
Date: 2019-09-19 02:07:14 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-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        6344 : 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        6344 :     snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
      73             : 
      74        6344 :     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        5790 : pg_lock_status(PG_FUNCTION_ARGS)
      83             : {
      84             :     FuncCallContext *funcctx;
      85             :     PG_Lock_Status *mystatus;
      86             :     LockData   *lockData;
      87             :     PredicateLockData *predLockData;
      88             : 
      89        5790 :     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        5790 :     funcctx = SRF_PERCALL_SETUP();
     154        5790 :     mystatus = (PG_Lock_Status *) funcctx->user_fctx;
     155        5790 :     lockData = mystatus->lockData;
     156             : 
     157       16938 :     while (mystatus->currIdx < lockData->nelements)
     158             :     {
     159             :         bool        granted;
     160       10914 :         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       10914 :         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       10914 :         granted = false;
     177       10914 :         if (instance->holdMask)
     178             :         {
     179       27264 :             for (mode = 0; mode < MAX_LOCKMODES; mode++)
     180             :             {
     181       27264 :                 if (instance->holdMask & LOCKBIT_ON(mode))
     182             :                 {
     183        5556 :                     granted = true;
     184        5556 :                     instance->holdMask &= LOCKBIT_OFF(mode);
     185        5556 :                     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       10914 :         if (!granted)
     195             :         {
     196        5358 :             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        5358 :                 mystatus->currIdx++;
     214        5358 :                 continue;
     215             :             }
     216             :         }
     217             : 
     218             :         /*
     219             :          * Form tuple with appropriate data.
     220             :          */
     221        5556 :         MemSet(values, 0, sizeof(values));
     222        5556 :         MemSet(nulls, false, sizeof(nulls));
     223             : 
     224        5556 :         if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
     225        5556 :             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        5556 :         values[0] = CStringGetTextDatum(locktypename);
     233             : 
     234        5556 :         switch ((LockTagType) instance->locktag.locktag_type)
     235             :         {
     236             :             case LOCKTAG_RELATION:
     237             :             case LOCKTAG_RELATION_EXTEND:
     238        3740 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     239        3740 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     240        3740 :                 nulls[3] = true;
     241        3740 :                 nulls[4] = true;
     242        3740 :                 nulls[5] = true;
     243        3740 :                 nulls[6] = true;
     244        3740 :                 nulls[7] = true;
     245        3740 :                 nulls[8] = true;
     246        3740 :                 nulls[9] = true;
     247        3740 :                 break;
     248             :             case LOCKTAG_PAGE:
     249           0 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     250           0 :                 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     251           0 :                 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
     252           0 :                 nulls[4] = true;
     253           0 :                 nulls[5] = true;
     254           0 :                 nulls[6] = true;
     255           0 :                 nulls[7] = true;
     256           0 :                 nulls[8] = true;
     257           0 :                 nulls[9] = true;
     258           0 :                 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         470 :                 values[6] =
     272         470 :                     TransactionIdGetDatum(instance->locktag.locktag_field1);
     273         470 :                 nulls[1] = true;
     274         470 :                 nulls[2] = true;
     275         470 :                 nulls[3] = true;
     276         470 :                 nulls[4] = true;
     277         470 :                 nulls[5] = true;
     278         470 :                 nulls[7] = true;
     279         470 :                 nulls[8] = true;
     280         470 :                 nulls[9] = true;
     281         470 :                 break;
     282             :             case LOCKTAG_VIRTUALTRANSACTION:
     283         788 :                 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
     284             :                                          instance->locktag.locktag_field2);
     285         788 :                 nulls[1] = true;
     286         788 :                 nulls[2] = true;
     287         788 :                 nulls[3] = true;
     288         788 :                 nulls[4] = true;
     289         788 :                 nulls[6] = true;
     290         788 :                 nulls[7] = true;
     291         788 :                 nulls[8] = true;
     292         788 :                 nulls[9] = true;
     293         788 :                 break;
     294             :             case LOCKTAG_OBJECT:
     295             :             case LOCKTAG_USERLOCK:
     296             :             case LOCKTAG_ADVISORY:
     297             :             default:            /* treat unknown locktags like OBJECT */
     298         558 :                 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
     299         558 :                 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
     300         558 :                 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
     301         558 :                 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
     302         558 :                 nulls[2] = true;
     303         558 :                 nulls[3] = true;
     304         558 :                 nulls[4] = true;
     305         558 :                 nulls[5] = true;
     306         558 :                 nulls[6] = true;
     307         558 :                 break;
     308             :         }
     309             : 
     310        5556 :         values[10] = VXIDGetDatum(instance->backend, instance->lxid);
     311        5556 :         if (instance->pid != 0)
     312        5556 :             values[11] = Int32GetDatum(instance->pid);
     313             :         else
     314           0 :             nulls[11] = true;
     315        5556 :         values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
     316        5556 :         values[13] = BoolGetDatum(granted);
     317        5556 :         values[14] = BoolGetDatum(instance->fastpath);
     318             : 
     319        5556 :         tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
     320        5556 :         result = HeapTupleGetDatum(tuple);
     321        5556 :         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       15248 : pg_blocking_pids(PG_FUNCTION_ARGS)
     419             : {
     420       15248 :     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       15248 :     lockData = GetBlockerStatusData(blocked_pid);
     429             : 
     430             :     /* We can't need more output entries than there are reported PROCLOCKs */
     431       15248 :     arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
     432       15248 :     narrayelems = 0;
     433             : 
     434             :     /* For each blocked proc in the lock group ... */
     435       16748 :     for (i = 0; i < lockData->nprocs; i++)
     436             :     {
     437        1500 :         BlockedProcData *bproc = &lockData->procs[i];
     438        1500 :         LockInstanceData *instances = &lockData->locks[bproc->first_lock];
     439        1500 :         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        1500 :         blocked_instance = NULL;
     449        4596 :         for (j = 0; j < bproc->num_locks; j++)
     450             :         {
     451        3096 :             LockInstanceData *instance = &(instances[j]);
     452             : 
     453        3096 :             if (instance->pid == bproc->pid)
     454             :             {
     455             :                 Assert(blocked_instance == NULL);
     456        1500 :                 blocked_instance = instance;
     457             :             }
     458             :         }
     459             :         Assert(blocked_instance != NULL);
     460             : 
     461        1500 :         lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
     462        1500 :         conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
     463             : 
     464             :         /* Now scan the PROCLOCK data for conflicting procs */
     465        4596 :         for (j = 0; j < bproc->num_locks; j++)
     466             :         {
     467        3096 :             LockInstanceData *instance = &(instances[j]);
     468             : 
     469             :             /* A proc never blocks itself, so ignore that entry */
     470        3096 :             if (instance == blocked_instance)
     471        1500 :                 continue;
     472             :             /* Members of same lock group never block each other, either */
     473        1596 :             if (instance->leaderPid == blocked_instance->leaderPid)
     474           0 :                 continue;
     475             : 
     476        1596 :             if (conflictMask & instance->holdMask)
     477             :             {
     478             :                 /* hard block: blocked by lock already held by this entry */
     479             :             }
     480         178 :             else if (instance->waitLockMode != NoLock &&
     481          84 :                      (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
     482          20 :             {
     483             :                 /* conflict in lock requests; who's in front in wait queue? */
     484          40 :                 bool        ahead = false;
     485             :                 int         k;
     486             : 
     487          44 :                 for (k = 0; k < bproc->num_waiters; k++)
     488             :                 {
     489          24 :                     if (preceding_waiters[k] == instance->pid)
     490             :                     {
     491             :                         /* soft block: this entry is ahead of blocked proc */
     492          20 :                         ahead = true;
     493          20 :                         break;
     494             :                     }
     495             :                 }
     496          40 :                 if (!ahead)
     497          20 :                     continue;   /* not blocked by this entry */
     498             :             }
     499             :             else
     500             :             {
     501             :                 /* not blocked by this entry */
     502          54 :                 continue;
     503             :             }
     504             : 
     505             :             /* blocked by this entry, so emit a record */
     506        1522 :             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       15248 :     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       15248 : pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
     574             : {
     575       15248 :     int         blocked_pid = PG_GETARG_INT32(0);
     576       15248 :     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       15248 :     if (array_contains_nulls(interesting_pids_a))
     589           0 :         elog(ERROR, "array must not contain nulls");
     590       15248 :     interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
     591       15248 :     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       15248 :     blocking_pids_a =
     599       15248 :         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       15248 :     blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
     604       15248 :     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       15248 :     for (i = 0; i < num_blocking_pids; i++)
     617        2442 :         for (j = 0; j < num_interesting_pids; j++)
     618             :         {
     619        2442 :             if (blocking_pids[i] == interesting_pids[j])
     620        1500 :                 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       13748 :     if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
     633           4 :         PG_RETURN_BOOL(true);
     634             : 
     635       13744 :     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             : /*
     659             :  * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
     660             :  */
     661             : Datum
     662         308 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
     663             : {
     664         308 :     int64       key = PG_GETARG_INT64(0);
     665             :     LOCKTAG     tag;
     666             : 
     667         308 :     SET_LOCKTAG_INT64(tag, key);
     668             : 
     669         308 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     670             : 
     671         308 :     PG_RETURN_VOID();
     672             : }
     673             : 
     674             : /*
     675             :  * pg_advisory_xact_lock(int8) - acquire xact scoped
     676             :  * exclusive lock on an int8 key
     677             :  */
     678             : Datum
     679          52 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     680             : {
     681          52 :     int64       key = PG_GETARG_INT64(0);
     682             :     LOCKTAG     tag;
     683             : 
     684          52 :     SET_LOCKTAG_INT64(tag, key);
     685             : 
     686          52 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     687             : 
     688          52 :     PG_RETURN_VOID();
     689             : }
     690             : 
     691             : /*
     692             :  * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
     693             :  */
     694             : Datum
     695          44 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     696             : {
     697          44 :     int64       key = PG_GETARG_INT64(0);
     698             :     LOCKTAG     tag;
     699             : 
     700          44 :     SET_LOCKTAG_INT64(tag, key);
     701             : 
     702          44 :     (void) LockAcquire(&tag, ShareLock, true, false);
     703             : 
     704          44 :     PG_RETURN_VOID();
     705             : }
     706             : 
     707             : /*
     708             :  * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
     709             :  * share lock on an int8 key
     710             :  */
     711             : Datum
     712       40034 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     713             : {
     714       40034 :     int64       key = PG_GETARG_INT64(0);
     715             :     LOCKTAG     tag;
     716             : 
     717       40034 :     SET_LOCKTAG_INT64(tag, key);
     718             : 
     719       40034 :     (void) LockAcquire(&tag, ShareLock, false, false);
     720             : 
     721       40034 :     PG_RETURN_VOID();
     722             : }
     723             : 
     724             : /*
     725             :  * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
     726             :  *
     727             :  * Returns true if successful, false if lock not available
     728             :  */
     729             : Datum
     730           0 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
     731             : {
     732           0 :     int64       key = PG_GETARG_INT64(0);
     733             :     LOCKTAG     tag;
     734             :     LockAcquireResult res;
     735             : 
     736           0 :     SET_LOCKTAG_INT64(tag, key);
     737             : 
     738           0 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     739             : 
     740           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     741             : }
     742             : 
     743             : /*
     744             :  * pg_try_advisory_xact_lock(int8) - acquire xact scoped
     745             :  * exclusive lock on an int8 key, no wait
     746             :  *
     747             :  * Returns true if successful, false if lock not available
     748             :  */
     749             : Datum
     750           0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
     751             : {
     752           0 :     int64       key = PG_GETARG_INT64(0);
     753             :     LOCKTAG     tag;
     754             :     LockAcquireResult res;
     755             : 
     756           0 :     SET_LOCKTAG_INT64(tag, key);
     757             : 
     758           0 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     759             : 
     760           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     761             : }
     762             : 
     763             : /*
     764             :  * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
     765             :  *
     766             :  * Returns true if successful, false if lock not available
     767             :  */
     768             : Datum
     769           0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
     770             : {
     771           0 :     int64       key = PG_GETARG_INT64(0);
     772             :     LOCKTAG     tag;
     773             :     LockAcquireResult res;
     774             : 
     775           0 :     SET_LOCKTAG_INT64(tag, key);
     776             : 
     777           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     778             : 
     779           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     780             : }
     781             : 
     782             : /*
     783             :  * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
     784             :  * share lock on an int8 key, no wait
     785             :  *
     786             :  * Returns true if successful, false if lock not available
     787             :  */
     788             : Datum
     789           0 : pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
     790             : {
     791           0 :     int64       key = PG_GETARG_INT64(0);
     792             :     LOCKTAG     tag;
     793             :     LockAcquireResult res;
     794             : 
     795           0 :     SET_LOCKTAG_INT64(tag, key);
     796             : 
     797           0 :     res = LockAcquire(&tag, ShareLock, false, true);
     798             : 
     799           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     800             : }
     801             : 
     802             : /*
     803             :  * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
     804             :  *
     805             :  * Returns true if successful, false if lock was not held
     806             : */
     807             : Datum
     808         150 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
     809             : {
     810         150 :     int64       key = PG_GETARG_INT64(0);
     811             :     LOCKTAG     tag;
     812             :     bool        res;
     813             : 
     814         150 :     SET_LOCKTAG_INT64(tag, key);
     815             : 
     816         150 :     res = LockRelease(&tag, ExclusiveLock, true);
     817             : 
     818         150 :     PG_RETURN_BOOL(res);
     819             : }
     820             : 
     821             : /*
     822             :  * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
     823             :  *
     824             :  * Returns true if successful, false if lock was not held
     825             :  */
     826             : Datum
     827          20 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
     828             : {
     829          20 :     int64       key = PG_GETARG_INT64(0);
     830             :     LOCKTAG     tag;
     831             :     bool        res;
     832             : 
     833          20 :     SET_LOCKTAG_INT64(tag, key);
     834             : 
     835          20 :     res = LockRelease(&tag, ShareLock, true);
     836             : 
     837          20 :     PG_RETURN_BOOL(res);
     838             : }
     839             : 
     840             : /*
     841             :  * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
     842             :  */
     843             : Datum
     844          60 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
     845             : {
     846          60 :     int32       key1 = PG_GETARG_INT32(0);
     847          60 :     int32       key2 = PG_GETARG_INT32(1);
     848             :     LOCKTAG     tag;
     849             : 
     850          60 :     SET_LOCKTAG_INT32(tag, key1, key2);
     851             : 
     852          60 :     (void) LockAcquire(&tag, ExclusiveLock, true, false);
     853             : 
     854          60 :     PG_RETURN_VOID();
     855             : }
     856             : 
     857             : /*
     858             :  * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
     859             :  * exclusive lock on 2 int4 keys
     860             :  */
     861             : Datum
     862          58 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     863             : {
     864          58 :     int32       key1 = PG_GETARG_INT32(0);
     865          58 :     int32       key2 = PG_GETARG_INT32(1);
     866             :     LOCKTAG     tag;
     867             : 
     868          58 :     SET_LOCKTAG_INT32(tag, key1, key2);
     869             : 
     870          58 :     (void) LockAcquire(&tag, ExclusiveLock, false, false);
     871             : 
     872          58 :     PG_RETURN_VOID();
     873             : }
     874             : 
     875             : /*
     876             :  * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
     877             :  */
     878             : Datum
     879          24 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     880             : {
     881          24 :     int32       key1 = PG_GETARG_INT32(0);
     882          24 :     int32       key2 = PG_GETARG_INT32(1);
     883             :     LOCKTAG     tag;
     884             : 
     885          24 :     SET_LOCKTAG_INT32(tag, key1, key2);
     886             : 
     887          24 :     (void) LockAcquire(&tag, ShareLock, true, false);
     888             : 
     889          24 :     PG_RETURN_VOID();
     890             : }
     891             : 
     892             : /*
     893             :  * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     894             :  * share lock on 2 int4 keys
     895             :  */
     896             : Datum
     897          20 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
     898             : {
     899          20 :     int32       key1 = PG_GETARG_INT32(0);
     900          20 :     int32       key2 = PG_GETARG_INT32(1);
     901             :     LOCKTAG     tag;
     902             : 
     903          20 :     SET_LOCKTAG_INT32(tag, key1, key2);
     904             : 
     905          20 :     (void) LockAcquire(&tag, ShareLock, false, false);
     906             : 
     907          20 :     PG_RETURN_VOID();
     908             : }
     909             : 
     910             : /*
     911             :  * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
     912             :  *
     913             :  * Returns true if successful, false if lock not available
     914             :  */
     915             : Datum
     916           0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
     917             : {
     918           0 :     int32       key1 = PG_GETARG_INT32(0);
     919           0 :     int32       key2 = PG_GETARG_INT32(1);
     920             :     LOCKTAG     tag;
     921             :     LockAcquireResult res;
     922             : 
     923           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     924             : 
     925           0 :     res = LockAcquire(&tag, ExclusiveLock, true, true);
     926             : 
     927           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     928             : }
     929             : 
     930             : /*
     931             :  * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
     932             :  * exclusive lock on 2 int4 keys, no wait
     933             :  *
     934             :  * Returns true if successful, false if lock not available
     935             :  */
     936             : Datum
     937          38 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
     938             : {
     939          38 :     int32       key1 = PG_GETARG_INT32(0);
     940          38 :     int32       key2 = PG_GETARG_INT32(1);
     941             :     LOCKTAG     tag;
     942             :     LockAcquireResult res;
     943             : 
     944          38 :     SET_LOCKTAG_INT32(tag, key1, key2);
     945             : 
     946          38 :     res = LockAcquire(&tag, ExclusiveLock, false, true);
     947             : 
     948          38 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     949             : }
     950             : 
     951             : /*
     952             :  * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
     953             :  *
     954             :  * Returns true if successful, false if lock not available
     955             :  */
     956             : Datum
     957           0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
     958             : {
     959           0 :     int32       key1 = PG_GETARG_INT32(0);
     960           0 :     int32       key2 = PG_GETARG_INT32(1);
     961             :     LOCKTAG     tag;
     962             :     LockAcquireResult res;
     963             : 
     964           0 :     SET_LOCKTAG_INT32(tag, key1, key2);
     965             : 
     966           0 :     res = LockAcquire(&tag, ShareLock, true, true);
     967             : 
     968           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     969             : }
     970             : 
     971             : /*
     972             :  * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
     973             :  * 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_xact_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, false, true);
     988             : 
     989           0 :     PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
     990             : }
     991             : 
     992             : /*
     993             :  * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
     994             :  *
     995             :  * Returns true if successful, false if lock was not held
     996             : */
     997             : Datum
     998          56 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
     999             : {
    1000          56 :     int32       key1 = PG_GETARG_INT32(0);
    1001          56 :     int32       key2 = PG_GETARG_INT32(1);
    1002             :     LOCKTAG     tag;
    1003             :     bool        res;
    1004             : 
    1005          56 :     SET_LOCKTAG_INT32(tag, key1, key2);
    1006             : 
    1007          56 :     res = LockRelease(&tag, ExclusiveLock, true);
    1008             : 
    1009          56 :     PG_RETURN_BOOL(res);
    1010             : }
    1011             : 
    1012             : /*
    1013             :  * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
    1014             :  *
    1015             :  * Returns true if successful, false if lock was not held
    1016             :  */
    1017             : Datum
    1018          20 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
    1019             : {
    1020          20 :     int32       key1 = PG_GETARG_INT32(0);
    1021          20 :     int32       key2 = PG_GETARG_INT32(1);
    1022             :     LOCKTAG     tag;
    1023             :     bool        res;
    1024             : 
    1025          20 :     SET_LOCKTAG_INT32(tag, key1, key2);
    1026             : 
    1027          20 :     res = LockRelease(&tag, ShareLock, true);
    1028             : 
    1029          20 :     PG_RETURN_BOOL(res);
    1030             : }
    1031             : 
    1032             : /*
    1033             :  * pg_advisory_unlock_all() - release all advisory locks
    1034             :  */
    1035             : Datum
    1036         210 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
    1037             : {
    1038         210 :     LockReleaseSession(USER_LOCKMETHOD);
    1039             : 
    1040         210 :     PG_RETURN_VOID();
    1041             : }

Generated by: LCOV version 1.13