1 /*-------------------------------------------------------------------------
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2019, PostgreSQL Global Development Group
9 * src/backend/utils/adt/lockfuncs.c
11 *-------------------------------------------------------------------------
15 #include "access/htup_details.h"
16 #include "access/xact.h"
17 #include "catalog/pg_type.h"
19 #include "miscadmin.h"
20 #include "storage/predicate_internals.h"
21 #include "utils/array.h"
22 #include "utils/builtins.h"
25 /* This must match enum LockTagType! */
26 const char *const LockTagTypeNames[] = {
39 /* This must match enum PredicateLockTargetType (predicate_internals.h) */
40 static const char *const PredicateLockTagTypeNames[] = {
46 /* Working status for pg_lock_status */
49 LockData *lockData; /* state data from lmgr */
50 int currIdx; /* current PROCLOCK index */
51 PredicateLockData *predLockData; /* state data for pred locks */
52 int predLockIdx; /* current index for pred lock */
55 /* Number of columns in pg_locks output */
56 #define NUM_LOCK_STATUS_COLUMNS 15
59 * VXIDGetDatum - Construct a text representation of a VXID
61 * This is currently only used in pg_lock_status, so we put it here.
64 VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
67 * The representation is "<bid>/<lxid>", decimal and unsigned decimal
68 * respectively. Note that elog.c also knows how to format a vxid.
72 snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
74 return CStringGetTextDatum(vxidstr);
79 * pg_lock_status - produce a view with one row per held or awaited lock mode
82 pg_lock_status(PG_FUNCTION_ARGS)
84 FuncCallContext *funcctx;
85 PG_Lock_Status *mystatus;
87 PredicateLockData *predLockData;
89 if (SRF_IS_FIRSTCALL())
92 MemoryContext oldcontext;
94 /* create a function context for cross-call persistence */
95 funcctx = SRF_FIRSTCALL_INIT();
98 * switch to memory context appropriate for multiple function calls
100 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
102 /* build tupdesc for result tuples */
103 /* this had better match function's declaration in pg_proc.h */
104 tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS);
105 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
107 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
109 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
111 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
113 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
115 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
117 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
119 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
121 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
123 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
125 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
127 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
129 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
131 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
133 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
136 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
139 * Collect all the locking information that we will format and send
140 * out as a result set.
142 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
143 funcctx->user_fctx = (void *) mystatus;
145 mystatus->lockData = GetLockStatusData();
146 mystatus->currIdx = 0;
147 mystatus->predLockData = GetPredicateLockStatusData();
148 mystatus->predLockIdx = 0;
150 MemoryContextSwitchTo(oldcontext);
153 funcctx = SRF_PERCALL_SETUP();
154 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
155 lockData = mystatus->lockData;
157 while (mystatus->currIdx < lockData->nelements)
161 const char *locktypename;
163 Datum values[NUM_LOCK_STATUS_COLUMNS];
164 bool nulls[NUM_LOCK_STATUS_COLUMNS];
167 LockInstanceData *instance;
169 instance = &(lockData->locks[mystatus->currIdx]);
172 * Look to see if there are any held lock modes in this PROCLOCK. If
173 * so, report, and destructively modify lockData so we don't report
177 if (instance->holdMask)
179 for (mode = 0; mode < MAX_LOCKMODES; mode++)
181 if (instance->holdMask & LOCKBIT_ON(mode))
184 instance->holdMask &= LOCKBIT_OFF(mode);
191 * If no (more) held modes to report, see if PROC is waiting for a
196 if (instance->waitLockMode != NoLock)
198 /* Yes, so report it with proper mode */
199 mode = instance->waitLockMode;
202 * We are now done with this PROCLOCK, so advance pointer to
203 * continue with next one on next call.
210 * Okay, we've displayed all the locks associated with this
211 * PROCLOCK, proceed to the next one.
219 * Form tuple with appropriate data.
221 MemSet(values, 0, sizeof(values));
222 MemSet(nulls, false, sizeof(nulls));
224 if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
225 locktypename = LockTagTypeNames[instance->locktag.locktag_type];
228 snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
229 (int) instance->locktag.locktag_type);
230 locktypename = tnbuf;
232 values[0] = CStringGetTextDatum(locktypename);
234 switch ((LockTagType) instance->locktag.locktag_type)
236 case LOCKTAG_RELATION:
237 case LOCKTAG_RELATION_EXTEND:
238 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
239 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
249 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
250 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
251 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
260 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
261 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
262 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
263 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
270 case LOCKTAG_TRANSACTION:
272 TransactionIdGetDatum(instance->locktag.locktag_field1);
282 case LOCKTAG_VIRTUALTRANSACTION:
283 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
284 instance->locktag.locktag_field2);
295 case LOCKTAG_USERLOCK:
296 case LOCKTAG_ADVISORY:
297 default: /* treat unknown locktags like OBJECT */
298 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
299 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
300 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
301 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
310 values[10] = VXIDGetDatum(instance->backend, instance->lxid);
311 if (instance->pid != 0)
312 values[11] = Int32GetDatum(instance->pid);
315 values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
316 values[13] = BoolGetDatum(granted);
317 values[14] = BoolGetDatum(instance->fastpath);
319 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
320 result = HeapTupleGetDatum(tuple);
321 SRF_RETURN_NEXT(funcctx, result);
325 * Have returned all regular locks. Now start on the SIREAD predicate
328 predLockData = mystatus->predLockData;
329 if (mystatus->predLockIdx < predLockData->nelements)
331 PredicateLockTargetType lockType;
333 PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
334 SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
335 Datum values[NUM_LOCK_STATUS_COLUMNS];
336 bool nulls[NUM_LOCK_STATUS_COLUMNS];
340 mystatus->predLockIdx++;
343 * Form tuple with appropriate data.
345 MemSet(values, 0, sizeof(values));
346 MemSet(nulls, false, sizeof(nulls));
349 lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
351 values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
354 values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
355 values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
356 if (lockType == PREDLOCKTAG_TUPLE)
357 values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
360 if ((lockType == PREDLOCKTAG_TUPLE) ||
361 (lockType == PREDLOCKTAG_PAGE))
362 values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
366 /* these fields are targets for other types of locks */
367 nulls[5] = true; /* virtualxid */
368 nulls[6] = true; /* transactionid */
369 nulls[7] = true; /* classid */
370 nulls[8] = true; /* objid */
371 nulls[9] = true; /* objsubid */
374 values[10] = VXIDGetDatum(xact->vxid.backendId,
375 xact->vxid.localTransactionId);
377 values[11] = Int32GetDatum(xact->pid);
382 * Lock mode. Currently all predicate locks are SIReadLocks, which are
383 * always held (never waiting) and have no fast path
385 values[12] = CStringGetTextDatum("SIReadLock");
386 values[13] = BoolGetDatum(true);
387 values[14] = BoolGetDatum(false);
389 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
390 result = HeapTupleGetDatum(tuple);
391 SRF_RETURN_NEXT(funcctx, result);
394 SRF_RETURN_DONE(funcctx);
399 * pg_blocking_pids - produce an array of the PIDs blocking given PID
401 * The reported PIDs are those that hold a lock conflicting with blocked_pid's
402 * current request (hard block), or are requesting such a lock and are ahead
403 * of blocked_pid in the lock's wait queue (soft block).
405 * In parallel-query cases, we report all PIDs blocking any member of the
406 * given PID's lock group, and the reported PIDs are those of the blocking
407 * PIDs' lock group leaders. This allows callers to compare the result to
408 * lists of clients' pg_backend_pid() results even during a parallel query.
410 * Parallel query makes it possible for there to be duplicate PIDs in the
411 * result (either because multiple waiters are blocked by same PID, or
412 * because multiple blockers have same group leader PID). We do not bother
413 * to eliminate such duplicates from the result.
415 * We need not consider predicate locks here, since those don't block anything.
418 pg_blocking_pids(PG_FUNCTION_ARGS)
420 int blocked_pid = PG_GETARG_INT32(0);
423 BlockedProcsData *lockData; /* state data from lmgr */
427 /* Collect a snapshot of lock manager state */
428 lockData = GetBlockerStatusData(blocked_pid);
430 /* We can't need more output entries than there are reported PROCLOCKs */
431 arrayelems = (Datum *) palloc(lockData->nlocks * sizeof(Datum));
434 /* For each blocked proc in the lock group ... */
435 for (i = 0; i < lockData->nprocs; i++)
437 BlockedProcData *bproc = &lockData->procs[i];
438 LockInstanceData *instances = &lockData->locks[bproc->first_lock];
439 int *preceding_waiters = &lockData->waiter_pids[bproc->first_waiter];
440 LockInstanceData *blocked_instance;
441 LockMethod lockMethodTable;
445 * Locate the blocked proc's own entry in the LockInstanceData array.
446 * There should be exactly one matching entry.
448 blocked_instance = NULL;
449 for (j = 0; j < bproc->num_locks; j++)
451 LockInstanceData *instance = &(instances[j]);
453 if (instance->pid == bproc->pid)
455 Assert(blocked_instance == NULL);
456 blocked_instance = instance;
459 Assert(blocked_instance != NULL);
461 lockMethodTable = GetLockTagsMethodTable(&(blocked_instance->locktag));
462 conflictMask = lockMethodTable->conflictTab[blocked_instance->waitLockMode];
464 /* Now scan the PROCLOCK data for conflicting procs */
465 for (j = 0; j < bproc->num_locks; j++)
467 LockInstanceData *instance = &(instances[j]);
469 /* A proc never blocks itself, so ignore that entry */
470 if (instance == blocked_instance)
472 /* Members of same lock group never block each other, either */
473 if (instance->leaderPid == blocked_instance->leaderPid)
476 if (conflictMask & instance->holdMask)
478 /* hard block: blocked by lock already held by this entry */
480 else if (instance->waitLockMode != NoLock &&
481 (conflictMask & LOCKBIT_ON(instance->waitLockMode)))
483 /* conflict in lock requests; who's in front in wait queue? */
487 for (k = 0; k < bproc->num_waiters; k++)
489 if (preceding_waiters[k] == instance->pid)
491 /* soft block: this entry is ahead of blocked proc */
497 continue; /* not blocked by this entry */
501 /* not blocked by this entry */
505 /* blocked by this entry, so emit a record */
506 arrayelems[narrayelems++] = Int32GetDatum(instance->leaderPid);
510 /* Assert we didn't overrun arrayelems[] */
511 Assert(narrayelems <= lockData->nlocks);
513 /* Construct array, using hardwired knowledge about int4 type */
514 PG_RETURN_ARRAYTYPE_P(construct_array(arrayelems, narrayelems,
516 sizeof(int32), true, 'i'));
521 * pg_safe_snapshot_blocking_pids - produce an array of the PIDs blocking
522 * given PID from getting a safe snapshot
524 * XXX this does not consider parallel-query cases; not clear how big a
525 * problem that is in practice
528 pg_safe_snapshot_blocking_pids(PG_FUNCTION_ARGS)
530 int blocked_pid = PG_GETARG_INT32(0);
533 Datum *blocker_datums;
535 /* A buffer big enough for any possible blocker list without truncation */
536 blockers = (int *) palloc(MaxBackends * sizeof(int));
538 /* Collect a snapshot of processes waited for by GetSafeSnapshot */
540 GetSafeSnapshotBlockingPids(blocked_pid, blockers, MaxBackends);
542 /* Convert int array to Datum array */
543 if (num_blockers > 0)
547 blocker_datums = (Datum *) palloc(num_blockers * sizeof(Datum));
548 for (i = 0; i < num_blockers; ++i)
549 blocker_datums[i] = Int32GetDatum(blockers[i]);
552 blocker_datums = NULL;
554 /* Construct array, using hardwired knowledge about int4 type */
555 PG_RETURN_ARRAYTYPE_P(construct_array(blocker_datums, num_blockers,
557 sizeof(int32), true, 'i'));
562 * pg_isolation_test_session_is_blocked - support function for isolationtester
564 * Check if specified PID is blocked by any of the PIDs listed in the second
565 * argument. Currently, this looks for blocking caused by waiting for
566 * heavyweight locks or safe snapshots. We ignore blockage caused by PIDs
567 * not directly under the isolationtester's control, eg autovacuum.
569 * This is an undocumented function intended for use by the isolation tester,
570 * and may change in future releases as required for testing purposes.
573 pg_isolation_test_session_is_blocked(PG_FUNCTION_ARGS)
575 int blocked_pid = PG_GETARG_INT32(0);
576 ArrayType *interesting_pids_a = PG_GETARG_ARRAYTYPE_P(1);
577 ArrayType *blocking_pids_a;
578 int32 *interesting_pids;
579 int32 *blocking_pids;
580 int num_interesting_pids;
581 int num_blocking_pids;
586 /* Validate the passed-in array */
587 Assert(ARR_ELEMTYPE(interesting_pids_a) == INT4OID);
588 if (array_contains_nulls(interesting_pids_a))
589 elog(ERROR, "array must not contain nulls");
590 interesting_pids = (int32 *) ARR_DATA_PTR(interesting_pids_a);
591 num_interesting_pids = ArrayGetNItems(ARR_NDIM(interesting_pids_a),
592 ARR_DIMS(interesting_pids_a));
595 * Get the PIDs of all sessions blocking the given session's attempt to
596 * acquire heavyweight locks.
599 DatumGetArrayTypeP(DirectFunctionCall1(pg_blocking_pids, blocked_pid));
601 Assert(ARR_ELEMTYPE(blocking_pids_a) == INT4OID);
602 Assert(!array_contains_nulls(blocking_pids_a));
603 blocking_pids = (int32 *) ARR_DATA_PTR(blocking_pids_a);
604 num_blocking_pids = ArrayGetNItems(ARR_NDIM(blocking_pids_a),
605 ARR_DIMS(blocking_pids_a));
608 * Check if any of these are in the list of interesting PIDs, that being
609 * the sessions that the isolation tester is running. We don't use
610 * "arrayoverlaps" here, because it would lead to cache lookups and one of
611 * our goals is to run quickly under CLOBBER_CACHE_ALWAYS. We expect
612 * blocking_pids to be usually empty and otherwise a very small number in
613 * isolation tester cases, so make that the outer loop of a naive search
616 for (i = 0; i < num_blocking_pids; i++)
617 for (j = 0; j < num_interesting_pids; j++)
619 if (blocking_pids[i] == interesting_pids[j])
620 PG_RETURN_BOOL(true);
624 * Check if blocked_pid is waiting for a safe snapshot. We could in
625 * theory check the resulting array of blocker PIDs against the
626 * interesting PIDs whitelist, but since there is no danger of autovacuum
627 * blocking GetSafeSnapshot there seems to be no point in expending cycles
628 * on allocating a buffer and searching for overlap; so it's presently
629 * sufficient for the isolation tester's purposes to use a single element
630 * buffer and check if the number of safe snapshot blockers is non-zero.
632 if (GetSafeSnapshotBlockingPids(blocked_pid, &dummy, 1) > 0)
633 PG_RETURN_BOOL(true);
635 PG_RETURN_BOOL(false);
640 * Functions for manipulating advisory locks
642 * We make use of the locktag fields as follows:
644 * field1: MyDatabaseId ... ensures locks are local to each database
645 * field2: first of 2 int4 keys, or high-order half of an int8 key
646 * field3: second of 2 int4 keys, or low-order half of an int8 key
647 * field4: 1 if using an int8 key, 2 if using 2 int4 keys
649 #define SET_LOCKTAG_INT64(tag, key64) \
650 SET_LOCKTAG_ADVISORY(tag, \
652 (uint32) ((key64) >> 32), \
655 #define SET_LOCKTAG_INT32(tag, key1, key2) \
656 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
659 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
662 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
664 int64 key = PG_GETARG_INT64(0);
667 SET_LOCKTAG_INT64(tag, key);
669 (void) LockAcquire(&tag, ExclusiveLock, true, false);
675 * pg_advisory_xact_lock(int8) - acquire xact scoped
676 * exclusive lock on an int8 key
679 pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
681 int64 key = PG_GETARG_INT64(0);
684 SET_LOCKTAG_INT64(tag, key);
686 (void) LockAcquire(&tag, ExclusiveLock, false, false);
692 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
695 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
697 int64 key = PG_GETARG_INT64(0);
700 SET_LOCKTAG_INT64(tag, key);
702 (void) LockAcquire(&tag, ShareLock, true, false);
708 * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
709 * share lock on an int8 key
712 pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
714 int64 key = PG_GETARG_INT64(0);
717 SET_LOCKTAG_INT64(tag, key);
719 (void) LockAcquire(&tag, ShareLock, false, false);
725 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
727 * Returns true if successful, false if lock not available
730 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
732 int64 key = PG_GETARG_INT64(0);
734 LockAcquireResult res;
736 SET_LOCKTAG_INT64(tag, key);
738 res = LockAcquire(&tag, ExclusiveLock, true, true);
740 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
744 * pg_try_advisory_xact_lock(int8) - acquire xact scoped
745 * exclusive lock on an int8 key, no wait
747 * Returns true if successful, false if lock not available
750 pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
752 int64 key = PG_GETARG_INT64(0);
754 LockAcquireResult res;
756 SET_LOCKTAG_INT64(tag, key);
758 res = LockAcquire(&tag, ExclusiveLock, false, true);
760 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
764 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
766 * Returns true if successful, false if lock not available
769 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
771 int64 key = PG_GETARG_INT64(0);
773 LockAcquireResult res;
775 SET_LOCKTAG_INT64(tag, key);
777 res = LockAcquire(&tag, ShareLock, true, true);
779 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
783 * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
784 * share lock on an int8 key, no wait
786 * Returns true if successful, false if lock not available
789 pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
791 int64 key = PG_GETARG_INT64(0);
793 LockAcquireResult res;
795 SET_LOCKTAG_INT64(tag, key);
797 res = LockAcquire(&tag, ShareLock, false, true);
799 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
803 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
805 * Returns true if successful, false if lock was not held
808 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
810 int64 key = PG_GETARG_INT64(0);
814 SET_LOCKTAG_INT64(tag, key);
816 res = LockRelease(&tag, ExclusiveLock, true);
822 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
824 * Returns true if successful, false if lock was not held
827 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
829 int64 key = PG_GETARG_INT64(0);
833 SET_LOCKTAG_INT64(tag, key);
835 res = LockRelease(&tag, ShareLock, true);
841 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
844 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
846 int32 key1 = PG_GETARG_INT32(0);
847 int32 key2 = PG_GETARG_INT32(1);
850 SET_LOCKTAG_INT32(tag, key1, key2);
852 (void) LockAcquire(&tag, ExclusiveLock, true, false);
858 * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
859 * exclusive lock on 2 int4 keys
862 pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
864 int32 key1 = PG_GETARG_INT32(0);
865 int32 key2 = PG_GETARG_INT32(1);
868 SET_LOCKTAG_INT32(tag, key1, key2);
870 (void) LockAcquire(&tag, ExclusiveLock, false, false);
876 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
879 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
881 int32 key1 = PG_GETARG_INT32(0);
882 int32 key2 = PG_GETARG_INT32(1);
885 SET_LOCKTAG_INT32(tag, key1, key2);
887 (void) LockAcquire(&tag, ShareLock, true, false);
893 * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
894 * share lock on 2 int4 keys
897 pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
899 int32 key1 = PG_GETARG_INT32(0);
900 int32 key2 = PG_GETARG_INT32(1);
903 SET_LOCKTAG_INT32(tag, key1, key2);
905 (void) LockAcquire(&tag, ShareLock, false, false);
911 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
913 * Returns true if successful, false if lock not available
916 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
918 int32 key1 = PG_GETARG_INT32(0);
919 int32 key2 = PG_GETARG_INT32(1);
921 LockAcquireResult res;
923 SET_LOCKTAG_INT32(tag, key1, key2);
925 res = LockAcquire(&tag, ExclusiveLock, true, true);
927 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
931 * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
932 * exclusive lock on 2 int4 keys, no wait
934 * Returns true if successful, false if lock not available
937 pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
939 int32 key1 = PG_GETARG_INT32(0);
940 int32 key2 = PG_GETARG_INT32(1);
942 LockAcquireResult res;
944 SET_LOCKTAG_INT32(tag, key1, key2);
946 res = LockAcquire(&tag, ExclusiveLock, false, true);
948 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
952 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
954 * Returns true if successful, false if lock not available
957 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
959 int32 key1 = PG_GETARG_INT32(0);
960 int32 key2 = PG_GETARG_INT32(1);
962 LockAcquireResult res;
964 SET_LOCKTAG_INT32(tag, key1, key2);
966 res = LockAcquire(&tag, ShareLock, true, true);
968 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
972 * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
973 * share lock on 2 int4 keys, no wait
975 * Returns true if successful, false if lock not available
978 pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
980 int32 key1 = PG_GETARG_INT32(0);
981 int32 key2 = PG_GETARG_INT32(1);
983 LockAcquireResult res;
985 SET_LOCKTAG_INT32(tag, key1, key2);
987 res = LockAcquire(&tag, ShareLock, false, true);
989 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
993 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
995 * Returns true if successful, false if lock was not held
998 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
1000 int32 key1 = PG_GETARG_INT32(0);
1001 int32 key2 = PG_GETARG_INT32(1);
1005 SET_LOCKTAG_INT32(tag, key1, key2);
1007 res = LockRelease(&tag, ExclusiveLock, true);
1009 PG_RETURN_BOOL(res);
1013 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
1015 * Returns true if successful, false if lock was not held
1018 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
1020 int32 key1 = PG_GETARG_INT32(0);
1021 int32 key2 = PG_GETARG_INT32(1);
1025 SET_LOCKTAG_INT32(tag, key1, key2);
1027 res = LockRelease(&tag, ShareLock, true);
1029 PG_RETURN_BOOL(res);
1033 * pg_advisory_unlock_all() - release all advisory locks
1036 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
1038 LockReleaseSession(USER_LOCKMETHOD);