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