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