LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - lockfuncs.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 75.6 % 390 295 12 6 37 40 13 156 17 109 41 175 1 5
Current Date: 2023-04-08 15:15:32 Functions: 73.1 % 26 19 7 19 7 19
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

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

Generated by: LCOV version v1.16-55-g56c0a2a