Age Owner 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
5695 tgl 75 GIC 9382 : VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
5695 tgl 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 :
5695 tgl 83 GIC 9382 : snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
5695 tgl 84 ECB :
5493 tgl 85 GIC 9382 : return CStringGetTextDatum(vxidstr);
5695 tgl 86 ECB : }
87 :
88 :
89 : /*
90 : * pg_lock_status - produce a view with one row per held or awaited lock mode
91 : */
92 : Datum
7530 bruce 93 GIC 8396 : pg_lock_status(PG_FUNCTION_ARGS)
7540 bruce 94 ECB : {
95 : FuncCallContext *funcctx;
96 : PG_Lock_Status *mystatus;
97 : LockData *lockData;
98 : PredicateLockData *predLockData;
99 :
7540 bruce 100 GIC 8396 : if (SRF_IS_FIRSTCALL())
7540 bruce 101 ECB : {
102 : TupleDesc tupdesc;
103 : MemoryContext oldcontext;
104 :
105 : /* create a function context for cross-call persistence */
7528 tgl 106 GIC 264 : funcctx = SRF_FIRSTCALL_INIT();
7528 tgl 107 ECB :
108 : /*
109 : * switch to memory context appropriate for multiple function calls
110 : */
7528 tgl 111 GIC 264 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
7528 tgl 112 ECB :
113 : /* build tupdesc for result tuples */
114 : /* this had better match function's declaration in pg_proc.h */
1601 andres 115 GIC 264 : tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
6536 tgl 116 CBC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
6536 tgl 117 ECB : TEXTOID, -1, 0);
7354 bruce 118 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
6947 tgl 119 ECB : OIDOID, -1, 0);
6536 tgl 120 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
6536 tgl 121 ECB : OIDOID, -1, 0);
6536 tgl 122 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
6536 tgl 123 ECB : INT4OID, -1, 0);
6536 tgl 124 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
6536 tgl 125 ECB : INT2OID, -1, 0);
5695 tgl 126 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
5695 tgl 127 ECB : TEXTOID, -1, 0);
5695 tgl 128 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
6947 tgl 129 ECB : XIDOID, -1, 0);
5695 tgl 130 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
6536 tgl 131 ECB : OIDOID, -1, 0);
5695 tgl 132 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
6536 tgl 133 ECB : OIDOID, -1, 0);
5695 tgl 134 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
6536 tgl 135 ECB : INT2OID, -1, 0);
5695 tgl 136 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
5695 tgl 137 ECB : TEXTOID, -1, 0);
5695 tgl 138 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
6947 tgl 139 ECB : INT4OID, -1, 0);
5695 tgl 140 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
6947 tgl 141 ECB : TEXTOID, -1, 0);
5695 tgl 142 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
6947 tgl 143 ECB : BOOLOID, -1, 0);
4334 rhaas 144 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
4334 rhaas 145 ECB : BOOLOID, -1, 0);
783 fujii 146 GIC 264 : TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
783 fujii 147 ECB : TIMESTAMPTZOID, -1, 0);
148 :
6947 tgl 149 GIC 264 : funcctx->tuple_desc = BlessTupleDesc(tupdesc);
7540 bruce 150 ECB :
151 : /*
152 : * Collect all the locking information that we will format and send
153 : * out as a result set.
154 : */
7526 tgl 155 GIC 264 : mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
7526 tgl 156 CBC 264 : funcctx->user_fctx = (void *) mystatus;
7540 bruce 157 ECB :
7526 tgl 158 GIC 264 : mystatus->lockData = GetLockStatusData();
7526 tgl 159 CBC 264 : mystatus->currIdx = 0;
4444 heikki.linnakangas 160 264 : mystatus->predLockData = GetPredicateLockStatusData();
161 264 : mystatus->predLockIdx = 0;
7540 bruce 162 ECB :
7528 tgl 163 GIC 264 : MemoryContextSwitchTo(oldcontext);
7540 bruce 164 ECB : }
165 :
7522 bruce 166 GIC 8396 : funcctx = SRF_PERCALL_SETUP();
7526 tgl 167 CBC 8396 : mystatus = (PG_Lock_Status *) funcctx->user_fctx;
168 8396 : lockData = mystatus->lockData;
7540 bruce 169 ECB :
7526 tgl 170 GIC 16248 : while (mystatus->currIdx < lockData->nelements)
7540 bruce 171 ECB : {
172 : bool granted;
6799 tgl 173 GIC 15981 : LOCKMODE mode = 0;
6536 tgl 174 ECB : const char *locktypename;
175 : char tnbuf[32];
267 peter 176 GNC 15981 : Datum values[NUM_LOCK_STATUS_COLUMNS] = {0};
177 15981 : bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
7522 bruce 178 ECB : HeapTuple tuple;
179 : Datum result;
180 : LockInstanceData *instance;
181 :
4334 rhaas 182 GIC 15981 : instance = &(lockData->locks[mystatus->currIdx]);
7540 bruce 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 : */
7526 tgl 189 GIC 15981 : granted = false;
4334 rhaas 190 CBC 15981 : if (instance->holdMask)
7540 bruce 191 ECB : {
6799 tgl 192 GIC 39209 : for (mode = 0; mode < MAX_LOCKMODES; mode++)
7526 tgl 193 ECB : {
4334 rhaas 194 GIC 39209 : if (instance->holdMask & LOCKBIT_ON(mode))
6799 tgl 195 ECB : {
6799 tgl 196 GIC 8121 : granted = true;
4334 rhaas 197 CBC 8121 : instance->holdMask &= LOCKBIT_OFF(mode);
6799 tgl 198 8121 : break;
6799 tgl 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 : */
7526 tgl 207 GIC 15981 : if (!granted)
7540 bruce 208 ECB : {
4334 rhaas 209 GIC 7860 : if (instance->waitLockMode != NoLock)
7526 tgl 210 ECB : {
211 : /* Yes, so report it with proper mode */
4334 rhaas 212 GIC 8 : mode = instance->waitLockMode;
7522 bruce 213 ECB :
214 : /*
215 : * We are now done with this PROCLOCK, so advance pointer to
216 : * continue with next one on next call.
217 : */
7526 tgl 218 GIC 8 : mystatus->currIdx++;
7526 tgl 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 : */
7526 tgl 226 GIC 7852 : mystatus->currIdx++;
7526 tgl 227 CBC 7852 : continue;
7526 tgl 228 ECB : }
229 : }
230 :
231 : /*
232 : * Form tuple with appropriate data.
233 : */
234 :
4334 rhaas 235 CBC 8129 : if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
4334 rhaas 236 GIC 8129 : locktypename = LockTagTypeNames[instance->locktag.locktag_type];
237 : else
6536 tgl 238 EUB : {
6536 tgl 239 UBC 0 : snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
4334 rhaas 240 0 : (int) instance->locktag.locktag_type);
6536 tgl 241 UIC 0 : locktypename = tnbuf;
6536 tgl 242 ECB : }
5493 tgl 243 GIC 8129 : values[0] = CStringGetTextDatum(locktypename);
6536 tgl 244 ECB :
4334 rhaas 245 GIC 8129 : switch ((LockTagType) instance->locktag.locktag_type)
7526 tgl 246 ECB : {
6554 tgl 247 GIC 5378 : case LOCKTAG_RELATION:
6554 tgl 248 ECB : case LOCKTAG_RELATION_EXTEND:
4334 rhaas 249 CBC 5378 : values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
250 5378 : values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
5271 tgl 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;
6536 tgl 258 GBC 5378 : break;
967 noah 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;
6554 tgl 270 0 : case LOCKTAG_PAGE:
4334 rhaas 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);
5271 tgl 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;
6536 280 0 : break;
6554 281 0 : case LOCKTAG_TUPLE:
4334 rhaas 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);
5271 tgl 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;
6554 tgl 291 LBC 0 : break;
6554 tgl 292 CBC 673 : case LOCKTAG_TRANSACTION:
4334 rhaas 293 673 : values[6] =
294 673 : TransactionIdGetDatum(instance->locktag.locktag_field1);
5271 tgl 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;
5695 303 673 : break;
304 1250 : case LOCKTAG_VIRTUALTRANSACTION:
4334 rhaas 305 GIC 1250 : values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
4334 rhaas 306 ECB : instance->locktag.locktag_field2);
5271 tgl 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;
6536 315 1250 : break;
89 akapila 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;
90 akapila 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;
6536 tgl 339 CBC 826 : case LOCKTAG_OBJECT:
6536 tgl 340 ECB : case LOCKTAG_USERLOCK:
6043 341 : case LOCKTAG_ADVISORY:
6536 342 : default: /* treat unknown locktags like OBJECT */
4334 rhaas 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);
5271 tgl 347 826 : nulls[2] = true;
348 826 : nulls[3] = true;
349 826 : nulls[4] = true;
5271 tgl 350 GBC 826 : nulls[5] = true;
351 826 : nulls[6] = true;
6554 352 826 : break;
7540 bruce 353 EUB : }
354 :
4334 rhaas 355 GBC 8129 : values[10] = VXIDGetDatum(instance->backend, instance->lxid);
356 8129 : if (instance->pid != 0)
357 8110 : values[11] = Int32GetDatum(instance->pid);
6504 tgl 358 EUB : else
5271 tgl 359 GBC 19 : nulls[11] = true;
4334 rhaas 360 8129 : values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
5695 tgl 361 CBC 8129 : values[13] = BoolGetDatum(granted);
4334 rhaas 362 GIC 8129 : values[14] = BoolGetDatum(instance->fastpath);
783 fujii 363 8129 : if (!granted && instance->waitStart != 0)
364 8 : values[15] = TimestampTzGetDatum(instance->waitStart);
783 fujii 365 ECB : else
783 fujii 366 CBC 8121 : nulls[15] = true;
7540 bruce 367 ECB :
5271 tgl 368 CBC 8129 : tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
6947 369 8129 : result = HeapTupleGetDatum(tuple);
7528 370 8129 : SRF_RETURN_NEXT(funcctx, result);
7540 bruce 371 ECB : }
372 :
4444 heikki.linnakangas 373 : /*
374 : * Have returned all regular locks. Now start on the SIREAD predicate
375 : * locks.
376 : */
4444 heikki.linnakangas 377 CBC 267 : predLockData = mystatus->predLockData;
378 267 : if (mystatus->predLockIdx < predLockData->nelements)
4444 heikki.linnakangas 379 ECB : {
380 : PredicateLockTargetType lockType;
381 :
4444 heikki.linnakangas 382 CBC 3 : PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
383 3 : SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
267 peter 384 GNC 3 : Datum values[NUM_LOCK_STATUS_COLUMNS] = {0};
385 3 : bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
4444 heikki.linnakangas 386 ECB : HeapTuple tuple;
387 : Datum result;
388 :
4444 heikki.linnakangas 389 GIC 3 : mystatus->predLockIdx++;
4444 heikki.linnakangas 390 ECB :
391 : /*
392 : * Form tuple with appropriate data.
393 : */
394 :
395 : /* lock type */
4444 heikki.linnakangas 396 GIC 3 : lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
4444 heikki.linnakangas 397 ECB :
4444 heikki.linnakangas 398 CBC 3 : values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
399 :
400 : /* lock target */
4444 heikki.linnakangas 401 GIC 3 : values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
4444 heikki.linnakangas 402 CBC 3 : values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
403 3 : if (lockType == PREDLOCKTAG_TUPLE)
404 3 : values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
4444 heikki.linnakangas 405 ECB : else
4444 heikki.linnakangas 406 UIC 0 : nulls[4] = true;
4444 heikki.linnakangas 407 GIC 3 : if ((lockType == PREDLOCKTAG_TUPLE) ||
408 : (lockType == PREDLOCKTAG_PAGE))
4444 heikki.linnakangas 409 CBC 3 : values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
410 : else
4444 heikki.linnakangas 411 UIC 0 : nulls[3] = true;
412 :
413 : /* these fields are targets for other types of locks */
4444 heikki.linnakangas 414 GIC 3 : nulls[5] = true; /* virtualxid */
415 3 : nulls[6] = true; /* transactionid */
4444 heikki.linnakangas 416 CBC 3 : nulls[7] = true; /* classid */
4444 heikki.linnakangas 417 GIC 3 : nulls[8] = true; /* objid */
4444 heikki.linnakangas 418 CBC 3 : nulls[9] = true; /* objsubid */
419 :
420 : /* lock holder */
421 3 : values[10] = VXIDGetDatum(xact->vxid.backendId,
4444 heikki.linnakangas 422 ECB : xact->vxid.localTransactionId);
4388 rhaas 423 CBC 3 : if (xact->pid != 0)
424 3 : values[11] = Int32GetDatum(xact->pid);
425 : else
4388 rhaas 426 UBC 0 : nulls[11] = true;
4444 heikki.linnakangas 427 ECB :
428 : /*
3955 bruce 429 : * Lock mode. Currently all predicate locks are SIReadLocks, which are
430 : * always held (never waiting) and have no fast path
4444 heikki.linnakangas 431 EUB : */
4444 heikki.linnakangas 432 GIC 3 : values[12] = CStringGetTextDatum("SIReadLock");
433 3 : values[13] = BoolGetDatum(true);
4334 rhaas 434 CBC 3 : values[14] = BoolGetDatum(false);
783 fujii 435 3 : nulls[15] = true;
4444 heikki.linnakangas 436 ECB :
4444 heikki.linnakangas 437 CBC 3 : tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
438 3 : result = HeapTupleGetDatum(tuple);
4444 heikki.linnakangas 439 GIC 3 : SRF_RETURN_NEXT(funcctx, result);
440 : }
4444 heikki.linnakangas 441 ECB :
7528 tgl 442 GIC 264 : SRF_RETURN_DONE(funcctx);
7540 bruce 443 ECB : }
6047 tgl 444 :
445 :
2603 tgl 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).
2603 tgl 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
2603 tgl 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];
2603 tgl 486 CBC 1089 : LockInstanceData *instances = &lockData->locks[bproc->first_lock];
2603 tgl 487 GIC 1089 : int *preceding_waiters = &lockData->waiter_pids[bproc->first_waiter];
2603 tgl 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 : */
2603 tgl 496 CBC 1089 : blocked_instance = NULL;
2603 tgl 497 GIC 3312 : for (j = 0; j < bproc->num_locks; j++)
498 : {
2603 tgl 499 CBC 2223 : LockInstanceData *instance = &(instances[j]);
2603 tgl 500 ECB :
2603 tgl 501 GIC 2223 : if (instance->pid == bproc->pid)
502 : {
2603 tgl 503 CBC 1089 : Assert(blocked_instance == NULL);
2603 tgl 504 GIC 1089 : blocked_instance = instance;
2603 tgl 505 ECB : }
506 : }
2603 tgl 507 CBC 1089 : Assert(blocked_instance != NULL);
508 :
2603 tgl 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]);
2603 tgl 516 ECB :
517 : /* A proc never blocks itself, so ignore that entry */
2603 tgl 518 GIC 2223 : if (instance == blocked_instance)
2603 tgl 519 CBC 1089 : continue;
520 : /* Members of same lock group never block each other, either */
521 1134 : if (instance->leaderPid == blocked_instance->leaderPid)
2603 tgl 522 UIC 0 : continue;
2603 tgl 523 ECB :
2603 tgl 524 CBC 1134 : if (conflictMask & instance->holdMask)
525 : {
526 : /* hard block: blocked by lock already held by this entry */
2603 tgl 527 ECB : }
2603 tgl 528 GIC 41 : else if (instance->waitLockMode != NoLock &&
2603 tgl 529 CBC 37 : (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
530 8 : {
531 : /* conflict in lock requests; who's in front in wait queue? */
2603 tgl 532 GIC 17 : bool ahead = false;
2603 tgl 533 ECB : int k;
534 :
2603 tgl 535 CBC 17 : for (k = 0; k < bproc->num_waiters; k++)
536 : {
2603 tgl 537 GIC 8 : if (preceding_waiters[k] == instance->pid)
2603 tgl 538 ECB : {
539 : /* soft block: this entry is ahead of blocked proc */
2603 tgl 540 GIC 8 : ahead = true;
2603 tgl 541 CBC 8 : break;
2603 tgl 542 EUB : }
543 : }
2603 tgl 544 CBC 17 : if (!ahead)
2603 tgl 545 GIC 9 : continue; /* not blocked by this entry */
546 : }
547 : else
2603 tgl 548 ECB : {
549 : /* not blocked by this entry */
2603 tgl 550 CBC 24 : continue;
551 : }
2603 tgl 552 ECB :
553 : /* blocked by this entry, so emit a record */
2603 tgl 554 GIC 1101 : arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
2603 tgl 555 ECB : }
556 : }
557 :
558 : /* Assert we didn't overrun arrayelems[] */
2603 tgl 559 GIC 3192 : Assert(narrayelems <= lockData->nlocks);
2603 tgl 560 ECB :
282 peter 561 GNC 3192 : PG_RETURN_ARRAYTYPE_P(construct_array_builtin(arrayelems, narrayelems, INT4OID));
2603 tgl 562 ECB : }
563 :
564 :
565 : /*
566 : * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
2190 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
2190 tgl 573 UIC 0 : pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
574 : {
575 0 : int blocked_pid = PG_GETARG_INT32(0);
2190 tgl 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 */
362 rhaas 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 */
2190 tgl 588 0 : if (num_blockers > 0)
589 : {
2190 tgl 590 EUB : int i;
591 :
2190 tgl 592 UBC 0 : blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
2190 tgl 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;
2190 tgl 598 EUB :
282 peter 599 UNC 0 : PG_RETURN_ARRAYTYPE_P(construct_array_builtin(blocker_datums, num_blockers, INT4OID));
600 : }
601 :
2190 tgl 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
2190 tgl 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 */
2190 tgl 629 CBC 3192 : Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
2190 tgl 630 GIC 3192 : if (array_contains_nulls(interesting_pids_a))
2190 tgl 631 LBC 0 : elog(ERROR, "array must not contain nulls");
2190 tgl 632 CBC 3192 : interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
2190 tgl 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 :
2190 tgl 643 CBC 3192 : Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
644 3192 : Assert(!array_contains_nulls(blocking_pids_a));
2190 tgl 645 GBC 3192 : blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
2190 tgl 646 CBC 3192 : num_blocking_pids = ArrayGetNItems(ARR_NDIM(blocking_pids_a),
2190 tgl 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
635 655 : * isolation tester cases, so make that the outer loop of a naive search
656 : * for a match.
2190 657 : */
2190 tgl 658 CBC 3192 : for (i = 0; i < num_blocking_pids; i++)
659 1659 : for (j = 0; j < num_interesting_pids; j++)
2190 tgl 660 ECB : {
2190 tgl 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
2190 tgl 672 ECB : * buffer and check if the number of safe snapshot blockers is non-zero.
673 : */
2190 tgl 674 GIC 2103 : if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
2190 tgl 675 CBC 2 : PG_RETURN_BOOL(true);
2190 tgl 676 ECB :
2190 tgl 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
6047 tgl 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
6047 tgl 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
4433 itagaki.takahiro 718 ECB : * exclusive lock on an int8 key
719 : */
720 : Datum
4433 itagaki.takahiro 721 GIC 30 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
722 : {
4433 itagaki.takahiro 723 CBC 30 : int64 key = PG_GETARG_INT64(0);
724 : LOCKTAG tag;
4433 itagaki.takahiro 725 ECB :
4433 itagaki.takahiro 726 GIC 30 : SET_LOCKTAG_INT64(tag, key);
4433 itagaki.takahiro 727 ECB :
4433 itagaki.takahiro 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
6047 tgl 735 ECB : */
736 : Datum
6047 tgl 737 CBC 28 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
738 : {
6047 tgl 739 GIC 28 : int64 key = PG_GETARG_INT64(0);
6047 tgl 740 ECB : LOCKTAG tag;
741 :
6047 tgl 742 CBC 28 : SET_LOCKTAG_INT64(tag, key);
743 :
744 28 : (void) LockAcquire(&tag, ShareLock, true, false);
745 :
6047 tgl 746 GIC 28 : PG_RETURN_VOID();
747 : }
748 :
749 : /*
750 : * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
4433 itagaki.takahiro 751 ECB : * share lock on an int8 key
752 : */
753 : Datum
4433 itagaki.takahiro 754 GIC 20021 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
755 : {
4433 itagaki.takahiro 756 CBC 20021 : int64 key = PG_GETARG_INT64(0);
757 : LOCKTAG tag;
4433 itagaki.takahiro 758 ECB :
4433 itagaki.takahiro 759 GIC 20021 : SET_LOCKTAG_INT64(tag, key);
4433 itagaki.takahiro 760 ECB :
4433 itagaki.takahiro 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
6047 tgl 768 ECB : *
769 : * Returns true if successful, false if lock not available
770 : */
771 : Datum
6047 tgl 772 GIC 408 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
6047 tgl 773 ECB : {
6047 tgl 774 GIC 408 : int64 key = PG_GETARG_INT64(0);
6047 tgl 775 ECB : LOCKTAG tag;
776 : LockAcquireResult res;
777 :
6047 tgl 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 : /*
4433 itagaki.takahiro 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
4433 itagaki.takahiro 792 LBC 0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
793 : {
794 0 : int64 key = PG_GETARG_INT64(0);
795 : LOCKTAG tag;
4433 itagaki.takahiro 796 ECB : LockAcquireResult res;
797 :
4433 itagaki.takahiro 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 : /*
6047 tgl 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
6047 tgl 811 UIC 0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
6047 tgl 812 EUB : {
6047 tgl 813 UIC 0 : int64 key = PG_GETARG_INT64(0);
6047 tgl 814 EUB : LOCKTAG tag;
815 : LockAcquireResult res;
816 :
6047 tgl 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 : /*
4433 itagaki.takahiro 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
4433 itagaki.takahiro 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;
4433 itagaki.takahiro 835 EUB : LockAcquireResult res;
836 :
4433 itagaki.takahiro 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 : /*
6031 bruce 845 EUB : * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
846 : *
6047 tgl 847 : * Returns true if successful, false if lock was not held
848 : */
849 : Datum
6047 tgl 850 GIC 147 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
6047 tgl 851 EUB : {
6047 tgl 852 GIC 147 : int64 key = PG_GETARG_INT64(0);
6047 tgl 853 EUB : LOCKTAG tag;
854 : bool res;
855 :
6047 tgl 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 : /*
6047 tgl 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
6047 tgl 869 GIC 15 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
6047 tgl 870 ECB : {
6047 tgl 871 GIC 15 : int64 key = PG_GETARG_INT64(0);
6047 tgl 872 ECB : LOCKTAG tag;
873 : bool res;
874 :
6047 tgl 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 : /*
6047 tgl 883 ECB : * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
884 : */
885 : Datum
6047 tgl 886 GIC 49 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
887 : {
888 49 : int32 key1 = PG_GETARG_INT32(0);
6047 tgl 889 CBC 49 : int32 key2 = PG_GETARG_INT32(1);
890 : LOCKTAG tag;
6047 tgl 891 ECB :
6047 tgl 892 GIC 49 : SET_LOCKTAG_INT32(tag, key1, key2);
6047 tgl 893 ECB :
6047 tgl 894 GIC 49 : (void) LockAcquire(&tag, ExclusiveLock, true, false);
895 :
896 49 : PG_RETURN_VOID();
897 : }
898 :
899 : /*
4433 itagaki.takahiro 900 ECB : * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
901 : * exclusive lock on 2 int4 keys
902 : */
903 : Datum
4433 itagaki.takahiro 904 GIC 50 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
905 : {
4433 itagaki.takahiro 906 CBC 50 : int32 key1 = PG_GETARG_INT32(0);
4433 itagaki.takahiro 907 GIC 50 : int32 key2 = PG_GETARG_INT32(1);
4433 itagaki.takahiro 908 ECB : LOCKTAG tag;
909 :
4433 itagaki.takahiro 910 CBC 50 : SET_LOCKTAG_INT32(tag, key1, key2);
911 :
4433 itagaki.takahiro 912 GIC 50 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
913 :
914 50 : PG_RETURN_VOID();
915 : }
916 :
917 : /*
6047 tgl 918 ECB : * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
919 : */
920 : Datum
6047 tgl 921 CBC 18 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
922 : {
6047 tgl 923 GIC 18 : int32 key1 = PG_GETARG_INT32(0);
6047 tgl 924 CBC 18 : int32 key2 = PG_GETARG_INT32(1);
925 : LOCKTAG tag;
6047 tgl 926 ECB :
6047 tgl 927 GIC 18 : SET_LOCKTAG_INT32(tag, key1, key2);
6047 tgl 928 ECB :
6047 tgl 929 GIC 18 : (void) LockAcquire(&tag, ShareLock, true, false);
930 :
931 18 : PG_RETURN_VOID();
932 : }
933 :
934 : /*
4433 itagaki.takahiro 935 ECB : * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
936 : * share lock on 2 int4 keys
937 : */
938 : Datum
4433 itagaki.takahiro 939 GIC 15 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
940 : {
4433 itagaki.takahiro 941 CBC 15 : int32 key1 = PG_GETARG_INT32(0);
4433 itagaki.takahiro 942 GIC 15 : int32 key2 = PG_GETARG_INT32(1);
4433 itagaki.takahiro 943 ECB : LOCKTAG tag;
944 :
4433 itagaki.takahiro 945 CBC 15 : SET_LOCKTAG_INT32(tag, key1, key2);
946 :
4433 itagaki.takahiro 947 GIC 15 : (void) LockAcquire(&tag, ShareLock, false, false);
948 :
949 15 : PG_RETURN_VOID();
950 : }
951 :
952 : /*
6047 tgl 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
6047 tgl 958 UIC 0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
6047 tgl 959 ECB : {
6047 tgl 960 UIC 0 : int32 key1 = PG_GETARG_INT32(0);
6047 tgl 961 LBC 0 : int32 key2 = PG_GETARG_INT32(1);
962 : LOCKTAG tag;
6047 tgl 963 ECB : LockAcquireResult res;
964 :
6047 tgl 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 :
4433 itagaki.takahiro 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
4433 itagaki.takahiro 979 GBC 33 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
980 : {
981 33 : int32 key1 = PG_GETARG_INT32(0);
4433 itagaki.takahiro 982 GIC 33 : int32 key2 = PG_GETARG_INT32(1);
4433 itagaki.takahiro 983 EUB : LOCKTAG tag;
984 : LockAcquireResult res;
985 :
4433 itagaki.takahiro 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 :
6047 tgl 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
6047 tgl 999 UIC 0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
6047 tgl 1000 ECB : {
6047 tgl 1001 UIC 0 : int32 key1 = PG_GETARG_INT32(0);
6047 tgl 1002 LBC 0 : int32 key2 = PG_GETARG_INT32(1);
1003 : LOCKTAG tag;
6047 tgl 1004 ECB : LockAcquireResult res;
1005 :
6047 tgl 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 :
4433 itagaki.takahiro 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
4433 itagaki.takahiro 1020 UBC 0 : pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
1021 : {
1022 0 : int32 key1 = PG_GETARG_INT32(0);
4433 itagaki.takahiro 1023 UIC 0 : int32 key2 = PG_GETARG_INT32(1);
4433 itagaki.takahiro 1024 EUB : LOCKTAG tag;
1025 : LockAcquireResult res;
1026 :
4433 itagaki.takahiro 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 :
6047 tgl 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
6047 tgl 1040 GIC 47 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
6047 tgl 1041 EUB : {
6047 tgl 1042 GIC 47 : int32 key1 = PG_GETARG_INT32(0);
6047 tgl 1043 GBC 47 : int32 key2 = PG_GETARG_INT32(1);
1044 : LOCKTAG tag;
6047 tgl 1045 EUB : bool res;
1046 :
6047 tgl 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 :
6047 tgl 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
6047 tgl 1060 GIC 15 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
6047 tgl 1061 ECB : {
6047 tgl 1062 GIC 15 : int32 key1 = PG_GETARG_INT32(0);
6047 tgl 1063 CBC 15 : int32 key2 = PG_GETARG_INT32(1);
1064 : LOCKTAG tag;
6047 tgl 1065 ECB : bool res;
1066 :
6047 tgl 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 :
6047 tgl 1074 ECB : /*
1075 : * pg_advisory_unlock_all() - release all advisory locks
1076 : */
1077 : Datum
6047 tgl 1078 GIC 119 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
1079 : {
4433 itagaki.takahiro 1080 119 : LockReleaseSession(USER_LOCKMETHOD);
6047 tgl 1081 ECB :
6047 tgl 1082 GIC 119 : PG_RETURN_VOID();
6047 tgl 1083 ECB : }
|