1 /*-------------------------------------------------------------------------
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2008, PostgreSQL Global Development Group
9 * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.33 2008/03/25 22:42:44 tgl Exp $
11 *-------------------------------------------------------------------------
15 #include "access/heapam.h"
16 #include "catalog/pg_type.h"
18 #include "miscadmin.h"
19 #include "storage/proc.h"
20 #include "utils/builtins.h"
23 /* This must match enum LockTagType! */
24 static const char *const LockTagTypeNames[] = {
36 /* Working status for pg_lock_status */
39 LockData *lockData; /* state data from lmgr */
40 int currIdx; /* current PROCLOCK index */
45 * VXIDGetDatum - Construct a text representation of a VXID
47 * This is currently only used in pg_lock_status, so we put it here.
50 VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
53 * The representation is "<bid>/<lxid>", decimal and unsigned decimal
54 * respectively. Note that elog.c also knows how to format a vxid.
58 snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
60 return CStringGetTextDatum(vxidstr);
65 * pg_lock_status - produce a view with one row per held or awaited lock mode
68 pg_lock_status(PG_FUNCTION_ARGS)
70 FuncCallContext *funcctx;
71 PG_Lock_Status *mystatus;
74 if (SRF_IS_FIRSTCALL())
77 MemoryContext oldcontext;
79 /* create a function context for cross-call persistence */
80 funcctx = SRF_FIRSTCALL_INIT();
83 * switch to memory context appropriate for multiple function calls
85 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
87 /* build tupdesc for result tuples */
88 /* this had better match pg_locks view in system_views.sql */
89 tupdesc = CreateTemplateTupleDesc(14, false);
90 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
92 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
94 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
96 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
98 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
100 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
102 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
104 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
106 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
108 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
110 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
112 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
114 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
116 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
119 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
122 * Collect all the locking information that we will format and send
123 * out as a result set.
125 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
126 funcctx->user_fctx = (void *) mystatus;
128 mystatus->lockData = GetLockStatusData();
129 mystatus->currIdx = 0;
131 MemoryContextSwitchTo(oldcontext);
134 funcctx = SRF_PERCALL_SETUP();
135 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
136 lockData = mystatus->lockData;
138 while (mystatus->currIdx < lockData->nelements)
145 const char *locktypename;
152 proclock = &(lockData->proclocks[mystatus->currIdx]);
153 lock = &(lockData->locks[mystatus->currIdx]);
154 proc = &(lockData->procs[mystatus->currIdx]);
157 * Look to see if there are any held lock modes in this PROCLOCK. If
158 * so, report, and destructively modify lockData so we don't report
162 if (proclock->holdMask)
164 for (mode = 0; mode < MAX_LOCKMODES; mode++)
166 if (proclock->holdMask & LOCKBIT_ON(mode))
169 proclock->holdMask &= LOCKBIT_OFF(mode);
176 * If no (more) held modes to report, see if PROC is waiting for a
181 if (proc->waitLock == proclock->tag.myLock)
183 /* Yes, so report it with proper mode */
184 mode = proc->waitLockMode;
187 * We are now done with this PROCLOCK, so advance pointer to
188 * continue with next one on next call.
195 * Okay, we've displayed all the locks associated with this
196 * PROCLOCK, proceed to the next one.
204 * Form tuple with appropriate data.
206 MemSet(values, 0, sizeof(values));
207 MemSet(nulls, ' ', sizeof(nulls));
209 if (lock->tag.locktag_type <= LOCKTAG_LAST_TYPE)
210 locktypename = LockTagTypeNames[lock->tag.locktag_type];
213 snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
214 (int) lock->tag.locktag_type);
215 locktypename = tnbuf;
217 values[0] = CStringGetTextDatum(locktypename);
219 switch ((LockTagType) lock->tag.locktag_type)
221 case LOCKTAG_RELATION:
222 case LOCKTAG_RELATION_EXTEND:
223 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
224 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
234 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
235 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
236 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
245 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
246 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
247 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
248 values[4] = UInt16GetDatum(lock->tag.locktag_field4);
255 case LOCKTAG_TRANSACTION:
256 values[6] = TransactionIdGetDatum(lock->tag.locktag_field1);
266 case LOCKTAG_VIRTUALTRANSACTION:
267 values[5] = VXIDGetDatum(lock->tag.locktag_field1,
268 lock->tag.locktag_field2);
279 case LOCKTAG_USERLOCK:
280 case LOCKTAG_ADVISORY:
281 default: /* treat unknown locktags like OBJECT */
282 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
283 values[7] = ObjectIdGetDatum(lock->tag.locktag_field2);
284 values[8] = ObjectIdGetDatum(lock->tag.locktag_field3);
285 values[9] = Int16GetDatum(lock->tag.locktag_field4);
294 values[10] = VXIDGetDatum(proc->backendId, proc->lxid);
296 values[11] = Int32GetDatum(proc->pid);
299 values[12] = CStringGetTextDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock), mode));
300 values[13] = BoolGetDatum(granted);
302 tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
303 result = HeapTupleGetDatum(tuple);
304 SRF_RETURN_NEXT(funcctx, result);
307 SRF_RETURN_DONE(funcctx);
312 * Functions for manipulating advisory locks
314 * We make use of the locktag fields as follows:
316 * field1: MyDatabaseId ... ensures locks are local to each database
317 * field2: first of 2 int4 keys, or high-order half of an int8 key
318 * field3: second of 2 int4 keys, or low-order half of an int8 key
319 * field4: 1 if using an int8 key, 2 if using 2 int4 keys
321 #define SET_LOCKTAG_INT64(tag, key64) \
322 SET_LOCKTAG_ADVISORY(tag, \
324 (uint32) ((key64) >> 32), \
327 #define SET_LOCKTAG_INT32(tag, key1, key2) \
328 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
331 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
334 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
336 int64 key = PG_GETARG_INT64(0);
339 SET_LOCKTAG_INT64(tag, key);
341 (void) LockAcquire(&tag, ExclusiveLock, true, false);
347 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
350 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
352 int64 key = PG_GETARG_INT64(0);
355 SET_LOCKTAG_INT64(tag, key);
357 (void) LockAcquire(&tag, ShareLock, true, false);
363 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
365 * Returns true if successful, false if lock not available
368 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
370 int64 key = PG_GETARG_INT64(0);
372 LockAcquireResult res;
374 SET_LOCKTAG_INT64(tag, key);
376 res = LockAcquire(&tag, ExclusiveLock, true, true);
378 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
382 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
384 * Returns true if successful, false if lock not available
387 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
389 int64 key = PG_GETARG_INT64(0);
391 LockAcquireResult res;
393 SET_LOCKTAG_INT64(tag, key);
395 res = LockAcquire(&tag, ShareLock, true, true);
397 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
401 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
403 * Returns true if successful, false if lock was not held
406 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
408 int64 key = PG_GETARG_INT64(0);
412 SET_LOCKTAG_INT64(tag, key);
414 res = LockRelease(&tag, ExclusiveLock, true);
420 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
422 * Returns true if successful, false if lock was not held
425 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
427 int64 key = PG_GETARG_INT64(0);
431 SET_LOCKTAG_INT64(tag, key);
433 res = LockRelease(&tag, ShareLock, true);
439 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
442 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
444 int32 key1 = PG_GETARG_INT32(0);
445 int32 key2 = PG_GETARG_INT32(1);
448 SET_LOCKTAG_INT32(tag, key1, key2);
450 (void) LockAcquire(&tag, ExclusiveLock, true, false);
456 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
459 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
461 int32 key1 = PG_GETARG_INT32(0);
462 int32 key2 = PG_GETARG_INT32(1);
465 SET_LOCKTAG_INT32(tag, key1, key2);
467 (void) LockAcquire(&tag, ShareLock, true, false);
473 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
475 * Returns true if successful, false if lock not available
478 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
480 int32 key1 = PG_GETARG_INT32(0);
481 int32 key2 = PG_GETARG_INT32(1);
483 LockAcquireResult res;
485 SET_LOCKTAG_INT32(tag, key1, key2);
487 res = LockAcquire(&tag, ExclusiveLock, true, true);
489 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
493 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
495 * Returns true if successful, false if lock not available
498 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
500 int32 key1 = PG_GETARG_INT32(0);
501 int32 key2 = PG_GETARG_INT32(1);
503 LockAcquireResult res;
505 SET_LOCKTAG_INT32(tag, key1, key2);
507 res = LockAcquire(&tag, ShareLock, true, true);
509 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
513 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
515 * Returns true if successful, false if lock was not held
518 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
520 int32 key1 = PG_GETARG_INT32(0);
521 int32 key2 = PG_GETARG_INT32(1);
525 SET_LOCKTAG_INT32(tag, key1, key2);
527 res = LockRelease(&tag, ExclusiveLock, true);
533 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
535 * Returns true if successful, false if lock was not held
538 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
540 int32 key1 = PG_GETARG_INT32(0);
541 int32 key2 = PG_GETARG_INT32(1);
545 SET_LOCKTAG_INT32(tag, key1, key2);
547 res = LockRelease(&tag, ShareLock, true);
553 * pg_advisory_unlock_all() - release all advisory locks
556 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
558 LockReleaseAll(USER_LOCKMETHOD, true);