Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * lockfuncs.c
4 : * Functions for SQL access to various lock-manager capabilities.
5 : *
6 : * Copyright (c) 2002-2026, 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 "funcapi.h"
17 : #include "miscadmin.h"
18 : #include "storage/predicate_internals.h"
19 : #include "utils/array.h"
20 : #include "utils/builtins.h"
21 :
22 :
23 : /*
24 : * This must match enum LockTagType! Also, be sure to document any changes
25 : * in the docs for the pg_locks view and update the WaitEventLOCK section in
26 : * src/backend/utils/activity/wait_event_names.txt.
27 : */
28 : const char *const LockTagTypeNames[] = {
29 : "relation",
30 : "extend",
31 : "frozenid",
32 : "page",
33 : "tuple",
34 : "transactionid",
35 : "virtualxid",
36 : "spectoken",
37 : "object",
38 : "userlock",
39 : "advisory",
40 : "applytransaction"
41 : };
42 :
43 : StaticAssertDecl(lengthof(LockTagTypeNames) == (LOCKTAG_LAST_TYPE + 1),
44 : "array length mismatch");
45 :
46 : /* This must match enum PredicateLockTargetType (predicate_internals.h) */
47 : static const char *const PredicateLockTagTypeNames[] = {
48 : "relation",
49 : "page",
50 : "tuple"
51 : };
52 :
53 : StaticAssertDecl(lengthof(PredicateLockTagTypeNames) == (PREDLOCKTAG_TUPLE + 1),
54 : "array length mismatch");
55 :
56 : /* Working status for pg_lock_status */
57 : typedef struct
58 : {
59 : LockData *lockData; /* state data from lmgr */
60 : int currIdx; /* current PROCLOCK index */
61 : PredicateLockData *predLockData; /* state data for pred locks */
62 : int predLockIdx; /* current index for pred lock */
63 : } PG_Lock_Status;
64 :
65 : /* Number of columns in pg_locks output */
66 : #define NUM_LOCK_STATUS_COLUMNS 16
67 :
68 : /*
69 : * VXIDGetDatum - Construct a text representation of a VXID
70 : *
71 : * This is currently only used in pg_lock_status, so we put it here.
72 : */
73 : static Datum
74 12214 : VXIDGetDatum(ProcNumber procNumber, LocalTransactionId lxid)
75 : {
76 : /*
77 : * The representation is "<procNumber>/<lxid>", decimal and unsigned
78 : * decimal respectively. Note that elog.c also knows how to format a
79 : * vxid.
80 : */
81 : char vxidstr[32];
82 :
83 12214 : snprintf(vxidstr, sizeof(vxidstr), "%d/%u", procNumber, lxid);
84 :
85 12214 : return CStringGetTextDatum(vxidstr);
86 : }
87 :
88 :
89 : /*
90 : * pg_lock_status - produce a view with one row per held or awaited lock mode
91 : */
92 : Datum
93 11028 : pg_lock_status(PG_FUNCTION_ARGS)
94 : {
95 : FuncCallContext *funcctx;
96 : PG_Lock_Status *mystatus;
97 : LockData *lockData;
98 : PredicateLockData *predLockData;
99 :
100 11028 : if (SRF_IS_FIRSTCALL())
101 : {
102 : TupleDesc tupdesc;
103 : MemoryContext oldcontext;
104 :
105 : /* create a function context for cross-call persistence */
106 412 : funcctx = SRF_FIRSTCALL_INIT();
107 :
108 : /*
109 : * switch to memory context appropriate for multiple function calls
110 : */
111 412 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
112 :
113 : /* build tupdesc for result tuples */
114 : /* this had better match function's declaration in pg_proc.h */
115 412 : tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
116 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
117 : TEXTOID, -1, 0);
118 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
119 : OIDOID, -1, 0);
120 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
121 : OIDOID, -1, 0);
122 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
123 : INT4OID, -1, 0);
124 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
125 : INT2OID, -1, 0);
126 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
127 : TEXTOID, -1, 0);
128 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
129 : XIDOID, -1, 0);
130 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
131 : OIDOID, -1, 0);
132 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
133 : OIDOID, -1, 0);
134 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
135 : INT2OID, -1, 0);
136 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
137 : TEXTOID, -1, 0);
138 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
139 : INT4OID, -1, 0);
140 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
141 : TEXTOID, -1, 0);
142 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
143 : BOOLOID, -1, 0);
144 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
145 : BOOLOID, -1, 0);
146 412 : TupleDescInitEntry(tupdesc, (AttrNumber) 16, "waitstart",
147 : TIMESTAMPTZOID, -1, 0);
148 :
149 412 : TupleDescFinalize(tupdesc);
150 412 : 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 412 : mystatus = palloc_object(PG_Lock_Status);
157 412 : funcctx->user_fctx = mystatus;
158 :
159 412 : mystatus->lockData = GetLockStatusData();
160 412 : mystatus->currIdx = 0;
161 412 : mystatus->predLockData = GetPredicateLockStatusData();
162 412 : mystatus->predLockIdx = 0;
163 :
164 412 : MemoryContextSwitchTo(oldcontext);
165 : }
166 :
167 11028 : funcctx = SRF_PERCALL_SETUP();
168 11028 : mystatus = (PG_Lock_Status *) funcctx->user_fctx;
169 11028 : lockData = mystatus->lockData;
170 :
171 21153 : while (mystatus->currIdx < lockData->nelements)
172 : {
173 : bool granted;
174 20737 : LOCKMODE mode = 0;
175 : const char *locktypename;
176 : char tnbuf[32];
177 20737 : Datum values[NUM_LOCK_STATUS_COLUMNS] = {0};
178 20737 : bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
179 : HeapTuple tuple;
180 : Datum result;
181 : LockInstanceData *instance;
182 :
183 20737 : 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 20737 : granted = false;
191 20737 : if (instance->holdMask)
192 : {
193 51824 : for (mode = 0; mode < MAX_LOCKMODES; mode++)
194 : {
195 51824 : if (instance->holdMask & LOCKBIT_ON(mode))
196 : {
197 10602 : granted = true;
198 10602 : instance->holdMask &= LOCKBIT_OFF(mode);
199 10602 : 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 20737 : if (!granted)
209 : {
210 10135 : if (instance->waitLockMode != NoLock)
211 : {
212 : /* Yes, so report it with proper mode */
213 10 : 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 10 : 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 10125 : mystatus->currIdx++;
228 10125 : continue;
229 : }
230 : }
231 :
232 : /*
233 : * Form tuple with appropriate data.
234 : */
235 :
236 10612 : if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
237 10612 : 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 10612 : values[0] = CStringGetTextDatum(locktypename);
245 :
246 10612 : switch ((LockTagType) instance->locktag.locktag_type)
247 : {
248 7084 : case LOCKTAG_RELATION:
249 : case LOCKTAG_RELATION_EXTEND:
250 7084 : values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
251 7084 : values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
252 7084 : nulls[3] = true;
253 7084 : nulls[4] = true;
254 7084 : nulls[5] = true;
255 7084 : nulls[6] = true;
256 7084 : nulls[7] = true;
257 7084 : nulls[8] = true;
258 7084 : nulls[9] = true;
259 7084 : 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 3 : case LOCKTAG_PAGE:
272 3 : values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
273 3 : values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
274 3 : values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
275 3 : nulls[4] = true;
276 3 : nulls[5] = true;
277 3 : nulls[6] = true;
278 3 : nulls[7] = true;
279 3 : nulls[8] = true;
280 3 : nulls[9] = true;
281 3 : break;
282 2 : case LOCKTAG_TUPLE:
283 2 : values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
284 2 : values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
285 2 : values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
286 2 : values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
287 2 : nulls[5] = true;
288 2 : nulls[6] = true;
289 2 : nulls[7] = true;
290 2 : nulls[8] = true;
291 2 : nulls[9] = true;
292 2 : break;
293 942 : case LOCKTAG_TRANSACTION:
294 942 : values[6] =
295 942 : TransactionIdGetDatum(instance->locktag.locktag_field1);
296 942 : nulls[1] = true;
297 942 : nulls[2] = true;
298 942 : nulls[3] = true;
299 942 : nulls[4] = true;
300 942 : nulls[5] = true;
301 942 : nulls[7] = true;
302 942 : nulls[8] = true;
303 942 : nulls[9] = true;
304 942 : break;
305 1598 : case LOCKTAG_VIRTUALTRANSACTION:
306 1598 : values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
307 : instance->locktag.locktag_field2);
308 1598 : nulls[1] = true;
309 1598 : nulls[2] = true;
310 1598 : nulls[3] = true;
311 1598 : nulls[4] = true;
312 1598 : nulls[6] = true;
313 1598 : nulls[7] = true;
314 1598 : nulls[8] = true;
315 1598 : nulls[9] = true;
316 1598 : break;
317 2 : case LOCKTAG_SPECULATIVE_TOKEN:
318 2 : values[6] =
319 2 : TransactionIdGetDatum(instance->locktag.locktag_field1);
320 2 : values[8] = ObjectIdGetDatum(instance->locktag.locktag_field2);
321 2 : nulls[1] = true;
322 2 : nulls[2] = true;
323 2 : nulls[3] = true;
324 2 : nulls[4] = true;
325 2 : nulls[5] = true;
326 2 : nulls[7] = true;
327 2 : nulls[9] = true;
328 2 : 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] = UInt16GetDatum(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 981 : case LOCKTAG_OBJECT:
341 : case LOCKTAG_USERLOCK:
342 : case LOCKTAG_ADVISORY:
343 : default: /* treat unknown locktags like OBJECT */
344 981 : values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
345 981 : values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
346 981 : values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
347 981 : values[9] = UInt16GetDatum(instance->locktag.locktag_field4);
348 981 : nulls[2] = true;
349 981 : nulls[3] = true;
350 981 : nulls[4] = true;
351 981 : nulls[5] = true;
352 981 : nulls[6] = true;
353 981 : break;
354 : }
355 :
356 10612 : values[10] = VXIDGetDatum(instance->vxid.procNumber, instance->vxid.localTransactionId);
357 10612 : if (instance->pid != 0)
358 10579 : values[11] = Int32GetDatum(instance->pid);
359 : else
360 33 : nulls[11] = true;
361 10612 : values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
362 10612 : values[13] = BoolGetDatum(granted);
363 10612 : values[14] = BoolGetDatum(instance->fastpath);
364 10612 : if (!granted && instance->waitStart != 0)
365 10 : values[15] = TimestampTzGetDatum(instance->waitStart);
366 : else
367 10602 : nulls[15] = true;
368 :
369 10612 : tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
370 10612 : result = HeapTupleGetDatum(tuple);
371 10612 : SRF_RETURN_NEXT(funcctx, result);
372 : }
373 :
374 : /*
375 : * Have returned all regular locks. Now start on the SIREAD predicate
376 : * locks.
377 : */
378 416 : predLockData = mystatus->predLockData;
379 416 : if (mystatus->predLockIdx < predLockData->nelements)
380 : {
381 : PredicateLockTargetType lockType;
382 :
383 4 : PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
384 4 : SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
385 4 : Datum values[NUM_LOCK_STATUS_COLUMNS] = {0};
386 4 : bool nulls[NUM_LOCK_STATUS_COLUMNS] = {0};
387 : HeapTuple tuple;
388 : Datum result;
389 :
390 4 : mystatus->predLockIdx++;
391 :
392 : /*
393 : * Form tuple with appropriate data.
394 : */
395 :
396 : /* lock type */
397 4 : lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
398 :
399 4 : values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
400 :
401 : /* lock target */
402 4 : values[1] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_DB(*predTag));
403 4 : values[2] = ObjectIdGetDatum(GET_PREDICATELOCKTARGETTAG_RELATION(*predTag));
404 4 : if (lockType == PREDLOCKTAG_TUPLE)
405 4 : values[4] = UInt16GetDatum(GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag));
406 : else
407 0 : nulls[4] = true;
408 4 : if ((lockType == PREDLOCKTAG_TUPLE) ||
409 : (lockType == PREDLOCKTAG_PAGE))
410 4 : values[3] = UInt32GetDatum(GET_PREDICATELOCKTARGETTAG_PAGE(*predTag));
411 : else
412 0 : nulls[3] = true;
413 :
414 : /* these fields are targets for other types of locks */
415 4 : nulls[5] = true; /* virtualxid */
416 4 : nulls[6] = true; /* transactionid */
417 4 : nulls[7] = true; /* classid */
418 4 : nulls[8] = true; /* objid */
419 4 : nulls[9] = true; /* objsubid */
420 :
421 : /* lock holder */
422 4 : values[10] = VXIDGetDatum(xact->vxid.procNumber,
423 : xact->vxid.localTransactionId);
424 4 : if (xact->pid != 0)
425 4 : 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 4 : values[12] = CStringGetTextDatum("SIReadLock");
434 4 : values[13] = BoolGetDatum(true);
435 4 : values[14] = BoolGetDatum(false);
436 4 : nulls[15] = true;
437 :
438 4 : tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
439 4 : result = HeapTupleGetDatum(tuple);
440 4 : SRF_RETURN_NEXT(funcctx, result);
441 : }
442 :
443 412 : 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 1650 : pg_blocking_pids(PG_FUNCTION_ARGS)
468 : {
469 1650 : 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 1650 : lockData = GetBlockerStatusData(blocked_pid);
478 :
479 : /* We can't need more output entries than there are reported PROCLOCKs */
480 1650 : arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
481 1650 : narrayelems = 0;
482 :
483 : /* For each blocked proc in the lock group ... */
484 2910 : for (i = 0; i < lockData->nprocs; i++)
485 : {
486 1260 : BlockedProcData *bproc = &lockData->procs[i];
487 1260 : LockInstanceData *instances = &lockData->locks[bproc->first_lock];
488 1260 : 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 1260 : blocked_instance = NULL;
498 3827 : for (j = 0; j < bproc->num_locks; j++)
499 : {
500 2567 : LockInstanceData *instance = &(instances[j]);
501 :
502 2567 : if (instance->pid == bproc->pid)
503 : {
504 : Assert(blocked_instance == NULL);
505 1260 : blocked_instance = instance;
506 : }
507 : }
508 : Assert(blocked_instance != NULL);
509 :
510 1260 : lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
511 1260 : conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
512 :
513 : /* Now scan the PROCLOCK data for conflicting procs */
514 3827 : for (j = 0; j < bproc->num_locks; j++)
515 : {
516 2567 : LockInstanceData *instance = &(instances[j]);
517 :
518 : /* A proc never blocks itself, so ignore that entry */
519 2567 : if (instance == blocked_instance)
520 1260 : continue;
521 : /* Members of same lock group never block each other, either */
522 1307 : if (instance->leaderPid == blocked_instance->leaderPid)
523 2 : continue;
524 :
525 1305 : if (conflictMask & instance->holdMask)
526 : {
527 : /* hard block: blocked by lock already held by this entry */
528 : }
529 45 : else if (instance->waitLockMode != NoLock &&
530 40 : (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
531 9 : {
532 : /* conflict in lock requests; who's in front in wait queue? */
533 20 : bool ahead = false;
534 : int k;
535 :
536 20 : for (k = 0; k < bproc->num_waiters; k++)
537 : {
538 9 : if (preceding_waiters[k] == instance->pid)
539 : {
540 : /* soft block: this entry is ahead of blocked proc */
541 9 : ahead = true;
542 9 : break;
543 : }
544 : }
545 20 : if (!ahead)
546 11 : continue; /* not blocked by this entry */
547 : }
548 : else
549 : {
550 : /* not blocked by this entry */
551 25 : continue;
552 : }
553 :
554 : /* blocked by this entry, so emit a record */
555 1269 : arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
556 : }
557 : }
558 :
559 : /* Assert we didn't overrun arrayelems[] */
560 : Assert(narrayelems <= lockData->nlocks);
561 :
562 1650 : 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 : * Functions for manipulating advisory locks
606 : *
607 : * We make use of the locktag fields as follows:
608 : *
609 : * field1: MyDatabaseId ... ensures locks are local to each database
610 : * field2: first of 2 int4 keys, or high-order half of an int8 key
611 : * field3: second of 2 int4 keys, or low-order half of an int8 key
612 : * field4: 1 if using an int8 key, 2 if using 2 int4 keys
613 : */
614 : #define SET_LOCKTAG_INT64(tag, key64) \
615 : SET_LOCKTAG_ADVISORY(tag, \
616 : MyDatabaseId, \
617 : (uint32) ((key64) >> 32), \
618 : (uint32) (key64), \
619 : 1)
620 : #define SET_LOCKTAG_INT32(tag, key1, key2) \
621 : SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
622 :
623 : /*
624 : * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
625 : */
626 : Datum
627 219 : pg_advisory_lock_int8(PG_FUNCTION_ARGS)
628 : {
629 219 : int64 key = PG_GETARG_INT64(0);
630 : LOCKTAG tag;
631 :
632 219 : SET_LOCKTAG_INT64(tag, key);
633 :
634 219 : (void) LockAcquire(&tag, ExclusiveLock, true, false);
635 :
636 218 : PG_RETURN_VOID();
637 : }
638 :
639 : /*
640 : * pg_advisory_xact_lock(int8) - acquire xact scoped
641 : * exclusive lock on an int8 key
642 : */
643 : Datum
644 264 : pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
645 : {
646 264 : int64 key = PG_GETARG_INT64(0);
647 : LOCKTAG tag;
648 :
649 264 : SET_LOCKTAG_INT64(tag, key);
650 :
651 264 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
652 :
653 264 : PG_RETURN_VOID();
654 : }
655 :
656 : /*
657 : * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
658 : */
659 : Datum
660 34 : pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
661 : {
662 34 : int64 key = PG_GETARG_INT64(0);
663 : LOCKTAG tag;
664 :
665 34 : SET_LOCKTAG_INT64(tag, key);
666 :
667 34 : (void) LockAcquire(&tag, ShareLock, true, false);
668 :
669 34 : PG_RETURN_VOID();
670 : }
671 :
672 : /*
673 : * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
674 : * share lock on an int8 key
675 : */
676 : Datum
677 20025 : pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
678 : {
679 20025 : int64 key = PG_GETARG_INT64(0);
680 : LOCKTAG tag;
681 :
682 20025 : SET_LOCKTAG_INT64(tag, key);
683 :
684 20025 : (void) LockAcquire(&tag, ShareLock, false, false);
685 :
686 20025 : PG_RETURN_VOID();
687 : }
688 :
689 : /*
690 : * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
691 : *
692 : * Returns true if successful, false if lock not available
693 : */
694 : Datum
695 486 : pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
696 : {
697 486 : int64 key = PG_GETARG_INT64(0);
698 : LOCKTAG tag;
699 : LockAcquireResult res;
700 :
701 486 : SET_LOCKTAG_INT64(tag, key);
702 :
703 486 : res = LockAcquire(&tag, ExclusiveLock, true, true);
704 :
705 486 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
706 : }
707 :
708 : /*
709 : * pg_try_advisory_xact_lock(int8) - acquire xact scoped
710 : * exclusive lock on an int8 key, no wait
711 : *
712 : * Returns true if successful, false if lock not available
713 : */
714 : Datum
715 0 : pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
716 : {
717 0 : int64 key = PG_GETARG_INT64(0);
718 : LOCKTAG tag;
719 : LockAcquireResult res;
720 :
721 0 : SET_LOCKTAG_INT64(tag, key);
722 :
723 0 : res = LockAcquire(&tag, ExclusiveLock, false, true);
724 :
725 0 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
726 : }
727 :
728 : /*
729 : * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
730 : *
731 : * Returns true if successful, false if lock not available
732 : */
733 : Datum
734 0 : pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
735 : {
736 0 : int64 key = PG_GETARG_INT64(0);
737 : LOCKTAG tag;
738 : LockAcquireResult res;
739 :
740 0 : SET_LOCKTAG_INT64(tag, key);
741 :
742 0 : res = LockAcquire(&tag, ShareLock, true, true);
743 :
744 0 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
745 : }
746 :
747 : /*
748 : * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
749 : * share lock on an int8 key, no wait
750 : *
751 : * Returns true if successful, false if lock not available
752 : */
753 : Datum
754 0 : pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
755 : {
756 0 : int64 key = PG_GETARG_INT64(0);
757 : LOCKTAG tag;
758 : LockAcquireResult res;
759 :
760 0 : SET_LOCKTAG_INT64(tag, key);
761 :
762 0 : res = LockAcquire(&tag, ShareLock, false, true);
763 :
764 0 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
765 : }
766 :
767 : /*
768 : * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
769 : *
770 : * Returns true if successful, false if lock was not held
771 : */
772 : Datum
773 150 : pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
774 : {
775 150 : int64 key = PG_GETARG_INT64(0);
776 : LOCKTAG tag;
777 : bool res;
778 :
779 150 : SET_LOCKTAG_INT64(tag, key);
780 :
781 150 : res = LockRelease(&tag, ExclusiveLock, true);
782 :
783 150 : PG_RETURN_BOOL(res);
784 : }
785 :
786 : /*
787 : * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
788 : *
789 : * Returns true if successful, false if lock was not held
790 : */
791 : Datum
792 20 : pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
793 : {
794 20 : int64 key = PG_GETARG_INT64(0);
795 : LOCKTAG tag;
796 : bool res;
797 :
798 20 : SET_LOCKTAG_INT64(tag, key);
799 :
800 20 : res = LockRelease(&tag, ShareLock, true);
801 :
802 20 : PG_RETURN_BOOL(res);
803 : }
804 :
805 : /*
806 : * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
807 : */
808 : Datum
809 55 : pg_advisory_lock_int4(PG_FUNCTION_ARGS)
810 : {
811 55 : int32 key1 = PG_GETARG_INT32(0);
812 55 : int32 key2 = PG_GETARG_INT32(1);
813 : LOCKTAG tag;
814 :
815 55 : SET_LOCKTAG_INT32(tag, key1, key2);
816 :
817 55 : (void) LockAcquire(&tag, ExclusiveLock, true, false);
818 :
819 55 : PG_RETURN_VOID();
820 : }
821 :
822 : /*
823 : * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
824 : * exclusive lock on 2 int4 keys
825 : */
826 : Datum
827 55 : pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
828 : {
829 55 : int32 key1 = PG_GETARG_INT32(0);
830 55 : int32 key2 = PG_GETARG_INT32(1);
831 : LOCKTAG tag;
832 :
833 55 : SET_LOCKTAG_INT32(tag, key1, key2);
834 :
835 55 : (void) LockAcquire(&tag, ExclusiveLock, false, false);
836 :
837 55 : PG_RETURN_VOID();
838 : }
839 :
840 : /*
841 : * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
842 : */
843 : Datum
844 24 : pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
845 : {
846 24 : int32 key1 = PG_GETARG_INT32(0);
847 24 : int32 key2 = PG_GETARG_INT32(1);
848 : LOCKTAG tag;
849 :
850 24 : SET_LOCKTAG_INT32(tag, key1, key2);
851 :
852 24 : (void) LockAcquire(&tag, ShareLock, true, false);
853 :
854 24 : PG_RETURN_VOID();
855 : }
856 :
857 : /*
858 : * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
859 : * share lock on 2 int4 keys
860 : */
861 : Datum
862 20 : pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
863 : {
864 20 : int32 key1 = PG_GETARG_INT32(0);
865 20 : int32 key2 = PG_GETARG_INT32(1);
866 : LOCKTAG tag;
867 :
868 20 : SET_LOCKTAG_INT32(tag, key1, key2);
869 :
870 20 : (void) LockAcquire(&tag, ShareLock, false, false);
871 :
872 20 : PG_RETURN_VOID();
873 : }
874 :
875 : /*
876 : * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
877 : *
878 : * Returns true if successful, false if lock not available
879 : */
880 : Datum
881 0 : pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
882 : {
883 0 : int32 key1 = PG_GETARG_INT32(0);
884 0 : int32 key2 = PG_GETARG_INT32(1);
885 : LOCKTAG tag;
886 : LockAcquireResult res;
887 :
888 0 : SET_LOCKTAG_INT32(tag, key1, key2);
889 :
890 0 : res = LockAcquire(&tag, ExclusiveLock, true, true);
891 :
892 0 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
893 : }
894 :
895 : /*
896 : * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
897 : * exclusive lock on 2 int4 keys, no wait
898 : *
899 : * Returns true if successful, false if lock not available
900 : */
901 : Datum
902 33 : pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
903 : {
904 33 : int32 key1 = PG_GETARG_INT32(0);
905 33 : int32 key2 = PG_GETARG_INT32(1);
906 : LOCKTAG tag;
907 : LockAcquireResult res;
908 :
909 33 : SET_LOCKTAG_INT32(tag, key1, key2);
910 :
911 33 : res = LockAcquire(&tag, ExclusiveLock, false, true);
912 :
913 33 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
914 : }
915 :
916 : /*
917 : * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
918 : *
919 : * Returns true if successful, false if lock not available
920 : */
921 : Datum
922 0 : pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
923 : {
924 0 : int32 key1 = PG_GETARG_INT32(0);
925 0 : int32 key2 = PG_GETARG_INT32(1);
926 : LOCKTAG tag;
927 : LockAcquireResult res;
928 :
929 0 : SET_LOCKTAG_INT32(tag, key1, key2);
930 :
931 0 : res = LockAcquire(&tag, ShareLock, true, true);
932 :
933 0 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
934 : }
935 :
936 : /*
937 : * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
938 : * share lock on 2 int4 keys, no wait
939 : *
940 : * Returns true if successful, false if lock not available
941 : */
942 : Datum
943 0 : pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
944 : {
945 0 : int32 key1 = PG_GETARG_INT32(0);
946 0 : int32 key2 = PG_GETARG_INT32(1);
947 : LOCKTAG tag;
948 : LockAcquireResult res;
949 :
950 0 : SET_LOCKTAG_INT32(tag, key1, key2);
951 :
952 0 : res = LockAcquire(&tag, ShareLock, false, true);
953 :
954 0 : PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
955 : }
956 :
957 : /*
958 : * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
959 : *
960 : * Returns true if successful, false if lock was not held
961 : */
962 : Datum
963 52 : pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
964 : {
965 52 : int32 key1 = PG_GETARG_INT32(0);
966 52 : int32 key2 = PG_GETARG_INT32(1);
967 : LOCKTAG tag;
968 : bool res;
969 :
970 52 : SET_LOCKTAG_INT32(tag, key1, key2);
971 :
972 52 : res = LockRelease(&tag, ExclusiveLock, true);
973 :
974 52 : PG_RETURN_BOOL(res);
975 : }
976 :
977 : /*
978 : * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
979 : *
980 : * Returns true if successful, false if lock was not held
981 : */
982 : Datum
983 20 : pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
984 : {
985 20 : int32 key1 = PG_GETARG_INT32(0);
986 20 : int32 key2 = PG_GETARG_INT32(1);
987 : LOCKTAG tag;
988 : bool res;
989 :
990 20 : SET_LOCKTAG_INT32(tag, key1, key2);
991 :
992 20 : res = LockRelease(&tag, ShareLock, true);
993 :
994 20 : PG_RETURN_BOOL(res);
995 : }
996 :
997 : /*
998 : * pg_advisory_unlock_all() - release all advisory locks
999 : */
1000 : Datum
1001 122 : pg_advisory_unlock_all(PG_FUNCTION_ARGS)
1002 : {
1003 122 : LockReleaseSession(USER_LOCKMETHOD);
1004 :
1005 122 : PG_RETURN_VOID();
1006 : }
|