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