1 /*-------------------------------------------------------------------------
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2012, PostgreSQL Global Development Group
9 * src/backend/utils/adt/lockfuncs.c
11 *-------------------------------------------------------------------------
15 #include "catalog/pg_type.h"
17 #include "miscadmin.h"
18 #include "storage/predicate_internals.h"
19 #include "utils/builtins.h"
22 /* This must match enum LockTagType! */
23 static const char *const LockTagTypeNames[] = {
35 /* This must match enum PredicateLockTargetType (predicate_internals.h) */
36 static const char *const PredicateLockTagTypeNames[] = {
42 /* Working status for pg_lock_status */
45 LockData *lockData; /* state data from lmgr */
46 int currIdx; /* current PROCLOCK index */
47 PredicateLockData *predLockData; /* state data for pred locks */
48 int predLockIdx; /* current index for pred lock */
51 /* Number of columns in pg_locks output */
52 #define NUM_LOCK_STATUS_COLUMNS 15
55 * VXIDGetDatum - Construct a text representation of a VXID
57 * This is currently only used in pg_lock_status, so we put it here.
60 VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
63 * The representation is "<bid>/<lxid>", decimal and unsigned decimal
64 * respectively. Note that elog.c also knows how to format a vxid.
68 snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
70 return CStringGetTextDatum(vxidstr);
75 * pg_lock_status - produce a view with one row per held or awaited lock mode
78 pg_lock_status(PG_FUNCTION_ARGS)
80 FuncCallContext *funcctx;
81 PG_Lock_Status *mystatus;
83 PredicateLockData *predLockData;
85 if (SRF_IS_FIRSTCALL())
88 MemoryContext oldcontext;
90 /* create a function context for cross-call persistence */
91 funcctx = SRF_FIRSTCALL_INIT();
94 * switch to memory context appropriate for multiple function calls
96 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
98 /* build tupdesc for result tuples */
99 /* this had better match pg_locks view in system_views.sql */
100 tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS, false);
101 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
103 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
105 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
107 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
109 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
111 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
113 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
115 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
117 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
119 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
121 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
123 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
125 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
127 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
129 TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
132 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
135 * Collect all the locking information that we will format and send
136 * out as a result set.
138 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
139 funcctx->user_fctx = (void *) mystatus;
141 mystatus->lockData = GetLockStatusData();
142 mystatus->currIdx = 0;
143 mystatus->predLockData = GetPredicateLockStatusData();
144 mystatus->predLockIdx = 0;
146 MemoryContextSwitchTo(oldcontext);
149 funcctx = SRF_PERCALL_SETUP();
150 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
151 lockData = mystatus->lockData;
153 while (mystatus->currIdx < lockData->nelements)
157 const char *locktypename;
159 Datum values[NUM_LOCK_STATUS_COLUMNS];
160 bool nulls[NUM_LOCK_STATUS_COLUMNS];
163 LockInstanceData *instance;
165 instance = &(lockData->locks[mystatus->currIdx]);
168 * Look to see if there are any held lock modes in this PROCLOCK. If
169 * so, report, and destructively modify lockData so we don't report
173 if (instance->holdMask)
175 for (mode = 0; mode < MAX_LOCKMODES; mode++)
177 if (instance->holdMask & LOCKBIT_ON(mode))
180 instance->holdMask &= LOCKBIT_OFF(mode);
187 * If no (more) held modes to report, see if PROC is waiting for a
192 if (instance->waitLockMode != NoLock)
194 /* Yes, so report it with proper mode */
195 mode = instance->waitLockMode;
198 * We are now done with this PROCLOCK, so advance pointer to
199 * continue with next one on next call.
206 * Okay, we've displayed all the locks associated with this
207 * PROCLOCK, proceed to the next one.
215 * Form tuple with appropriate data.
217 MemSet(values, 0, sizeof(values));
218 MemSet(nulls, false, sizeof(nulls));
220 if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
221 locktypename = LockTagTypeNames[instance->locktag.locktag_type];
224 snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
225 (int) instance->locktag.locktag_type);
226 locktypename = tnbuf;
228 values[0] = CStringGetTextDatum(locktypename);
230 switch ((LockTagType) instance->locktag.locktag_type)
232 case LOCKTAG_RELATION:
233 case LOCKTAG_RELATION_EXTEND:
234 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
235 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
245 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
246 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
247 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
256 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
257 values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
258 values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
259 values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
266 case LOCKTAG_TRANSACTION:
268 TransactionIdGetDatum(instance->locktag.locktag_field1);
278 case LOCKTAG_VIRTUALTRANSACTION:
279 values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
280 instance->locktag.locktag_field2);
291 case LOCKTAG_USERLOCK:
292 case LOCKTAG_ADVISORY:
293 default: /* treat unknown locktags like OBJECT */
294 values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
295 values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
296 values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
297 values[9] = Int16GetDatum(instance->locktag.locktag_field4);
306 values[10] = VXIDGetDatum(instance->backend, instance->lxid);
307 if (instance->pid != 0)
308 values[11] = Int32GetDatum(instance->pid);
311 values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
312 values[13] = BoolGetDatum(granted);
313 values[14] = BoolGetDatum(instance->fastpath);
315 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
316 result = HeapTupleGetDatum(tuple);
317 SRF_RETURN_NEXT(funcctx, result);
321 * Have returned all regular locks. Now start on the SIREAD predicate
324 predLockData = mystatus->predLockData;
325 if (mystatus->predLockIdx < predLockData->nelements)
327 PredicateLockTargetType lockType;
329 PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
330 SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
331 Datum values[NUM_LOCK_STATUS_COLUMNS];
332 bool nulls[NUM_LOCK_STATUS_COLUMNS];
336 mystatus->predLockIdx++;
339 * Form tuple with appropriate data.
341 MemSet(values, 0, sizeof(values));
342 MemSet(nulls, false, sizeof(nulls));
345 lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
347 values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
350 values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
351 values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
352 if (lockType == PREDLOCKTAG_TUPLE)
353 values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
356 if ((lockType == PREDLOCKTAG_TUPLE) ||
357 (lockType == PREDLOCKTAG_PAGE))
358 values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
362 /* these fields are targets for other types of locks */
363 nulls[5] = true; /* virtualxid */
364 nulls[6] = true; /* transactionid */
365 nulls[7] = true; /* classid */
366 nulls[8] = true; /* objid */
367 nulls[9] = true; /* objsubid */
370 values[10] = VXIDGetDatum(xact->vxid.backendId,
371 xact->vxid.localTransactionId);
373 values[11] = Int32GetDatum(xact->pid);
378 * Lock mode. Currently all predicate locks are SIReadLocks, which are
379 * always held (never waiting) and have no fast path
381 values[12] = CStringGetTextDatum("SIReadLock");
382 values[13] = BoolGetDatum(true);
383 values[14] = BoolGetDatum(false);
385 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
386 result = HeapTupleGetDatum(tuple);
387 SRF_RETURN_NEXT(funcctx, result);
390 SRF_RETURN_DONE(funcctx);
395 * Functions for manipulating advisory locks
397 * We make use of the locktag fields as follows:
399 * field1: MyDatabaseId ... ensures locks are local to each database
400 * field2: first of 2 int4 keys, or high-order half of an int8 key
401 * field3: second of 2 int4 keys, or low-order half of an int8 key
402 * field4: 1 if using an int8 key, 2 if using 2 int4 keys
404 #define SET_LOCKTAG_INT64(tag, key64) \
405 SET_LOCKTAG_ADVISORY(tag, \
407 (uint32) ((key64) >> 32), \
410 #define SET_LOCKTAG_INT32(tag, key1, key2) \
411 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
414 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
417 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
419 int64 key = PG_GETARG_INT64(0);
422 SET_LOCKTAG_INT64(tag, key);
424 (void) LockAcquire(&tag, ExclusiveLock, true, false);
430 * pg_advisory_xact_lock(int8) - acquire xact scoped
431 * exclusive lock on an int8 key
434 pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
436 int64 key = PG_GETARG_INT64(0);
439 SET_LOCKTAG_INT64(tag, key);
441 (void) LockAcquire(&tag, ExclusiveLock, false, false);
447 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
450 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
452 int64 key = PG_GETARG_INT64(0);
455 SET_LOCKTAG_INT64(tag, key);
457 (void) LockAcquire(&tag, ShareLock, true, false);
463 * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
464 * share lock on an int8 key
467 pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
469 int64 key = PG_GETARG_INT64(0);
472 SET_LOCKTAG_INT64(tag, key);
474 (void) LockAcquire(&tag, ShareLock, false, false);
480 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
482 * Returns true if successful, false if lock not available
485 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
487 int64 key = PG_GETARG_INT64(0);
489 LockAcquireResult res;
491 SET_LOCKTAG_INT64(tag, key);
493 res = LockAcquire(&tag, ExclusiveLock, true, true);
495 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
499 * pg_try_advisory_xact_lock(int8) - acquire xact scoped
500 * exclusive lock on an int8 key, no wait
502 * Returns true if successful, false if lock not available
505 pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
507 int64 key = PG_GETARG_INT64(0);
509 LockAcquireResult res;
511 SET_LOCKTAG_INT64(tag, key);
513 res = LockAcquire(&tag, ExclusiveLock, false, true);
515 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
519 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
521 * Returns true if successful, false if lock not available
524 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
526 int64 key = PG_GETARG_INT64(0);
528 LockAcquireResult res;
530 SET_LOCKTAG_INT64(tag, key);
532 res = LockAcquire(&tag, ShareLock, true, true);
534 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
538 * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
539 * share lock on an int8 key, no wait
541 * Returns true if successful, false if lock not available
544 pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
546 int64 key = PG_GETARG_INT64(0);
548 LockAcquireResult res;
550 SET_LOCKTAG_INT64(tag, key);
552 res = LockAcquire(&tag, ShareLock, false, true);
554 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
558 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
560 * Returns true if successful, false if lock was not held
563 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
565 int64 key = PG_GETARG_INT64(0);
569 SET_LOCKTAG_INT64(tag, key);
571 res = LockRelease(&tag, ExclusiveLock, true);
577 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
579 * Returns true if successful, false if lock was not held
582 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
584 int64 key = PG_GETARG_INT64(0);
588 SET_LOCKTAG_INT64(tag, key);
590 res = LockRelease(&tag, ShareLock, true);
596 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
599 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
601 int32 key1 = PG_GETARG_INT32(0);
602 int32 key2 = PG_GETARG_INT32(1);
605 SET_LOCKTAG_INT32(tag, key1, key2);
607 (void) LockAcquire(&tag, ExclusiveLock, true, false);
613 * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
614 * exclusive lock on 2 int4 keys
617 pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
619 int32 key1 = PG_GETARG_INT32(0);
620 int32 key2 = PG_GETARG_INT32(1);
623 SET_LOCKTAG_INT32(tag, key1, key2);
625 (void) LockAcquire(&tag, ExclusiveLock, false, false);
631 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
634 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
636 int32 key1 = PG_GETARG_INT32(0);
637 int32 key2 = PG_GETARG_INT32(1);
640 SET_LOCKTAG_INT32(tag, key1, key2);
642 (void) LockAcquire(&tag, ShareLock, true, false);
648 * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
649 * share lock on 2 int4 keys
652 pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
654 int32 key1 = PG_GETARG_INT32(0);
655 int32 key2 = PG_GETARG_INT32(1);
658 SET_LOCKTAG_INT32(tag, key1, key2);
660 (void) LockAcquire(&tag, ShareLock, false, false);
666 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
668 * Returns true if successful, false if lock not available
671 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
673 int32 key1 = PG_GETARG_INT32(0);
674 int32 key2 = PG_GETARG_INT32(1);
676 LockAcquireResult res;
678 SET_LOCKTAG_INT32(tag, key1, key2);
680 res = LockAcquire(&tag, ExclusiveLock, true, true);
682 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
686 * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
687 * exclusive lock on 2 int4 keys, no wait
689 * Returns true if successful, false if lock not available
692 pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
694 int32 key1 = PG_GETARG_INT32(0);
695 int32 key2 = PG_GETARG_INT32(1);
697 LockAcquireResult res;
699 SET_LOCKTAG_INT32(tag, key1, key2);
701 res = LockAcquire(&tag, ExclusiveLock, false, true);
703 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
707 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
709 * Returns true if successful, false if lock not available
712 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
714 int32 key1 = PG_GETARG_INT32(0);
715 int32 key2 = PG_GETARG_INT32(1);
717 LockAcquireResult res;
719 SET_LOCKTAG_INT32(tag, key1, key2);
721 res = LockAcquire(&tag, ShareLock, true, true);
723 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
727 * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
728 * share lock on 2 int4 keys, no wait
730 * Returns true if successful, false if lock not available
733 pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
735 int32 key1 = PG_GETARG_INT32(0);
736 int32 key2 = PG_GETARG_INT32(1);
738 LockAcquireResult res;
740 SET_LOCKTAG_INT32(tag, key1, key2);
742 res = LockAcquire(&tag, ShareLock, false, true);
744 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
748 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
750 * Returns true if successful, false if lock was not held
753 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
755 int32 key1 = PG_GETARG_INT32(0);
756 int32 key2 = PG_GETARG_INT32(1);
760 SET_LOCKTAG_INT32(tag, key1, key2);
762 res = LockRelease(&tag, ExclusiveLock, true);
768 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
770 * Returns true if successful, false if lock was not held
773 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
775 int32 key1 = PG_GETARG_INT32(0);
776 int32 key2 = PG_GETARG_INT32(1);
780 SET_LOCKTAG_INT32(tag, key1, key2);
782 res = LockRelease(&tag, ShareLock, true);
788 * pg_advisory_unlock_all() - release all advisory locks
791 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
793 LockReleaseSession(USER_LOCKMETHOD);