1 /*-------------------------------------------------------------------------
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2009, PostgreSQL Global Development Group
9 * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.36 2009/01/01 17:23:49 momjian Exp $
11 *-------------------------------------------------------------------------
15 #include "catalog/pg_type.h"
17 #include "miscadmin.h"
18 #include "storage/proc.h"
19 #include "utils/builtins.h"
22 /* This must match enum LockTagType! */
23 static const char *const LockTagTypeNames[] = {
35 /* Working status for pg_lock_status */
38 LockData *lockData; /* state data from lmgr */
39 int currIdx; /* current PROCLOCK index */
44 * VXIDGetDatum - Construct a text representation of a VXID
46 * This is currently only used in pg_lock_status, so we put it here.
49 VXIDGetDatum(BackendId bid, LocalTransactionId lxid)
52 * The representation is "<bid>/<lxid>", decimal and unsigned decimal
53 * respectively. Note that elog.c also knows how to format a vxid.
57 snprintf(vxidstr, sizeof(vxidstr), "%d/%u", bid, lxid);
59 return CStringGetTextDatum(vxidstr);
64 * pg_lock_status - produce a view with one row per held or awaited lock mode
67 pg_lock_status(PG_FUNCTION_ARGS)
69 FuncCallContext *funcctx;
70 PG_Lock_Status *mystatus;
73 if (SRF_IS_FIRSTCALL())
76 MemoryContext oldcontext;
78 /* create a function context for cross-call persistence */
79 funcctx = SRF_FIRSTCALL_INIT();
82 * switch to memory context appropriate for multiple function calls
84 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
86 /* build tupdesc for result tuples */
87 /* this had better match pg_locks view in system_views.sql */
88 tupdesc = CreateTemplateTupleDesc(14, false);
89 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
91 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
93 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
95 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
97 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
99 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "virtualxid",
101 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "transactionid",
103 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "classid",
105 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objid",
107 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "objsubid",
109 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "virtualtransaction",
111 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "pid",
113 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "mode",
115 TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
118 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
121 * Collect all the locking information that we will format and send
122 * out as a result set.
124 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
125 funcctx->user_fctx = (void *) mystatus;
127 mystatus->lockData = GetLockStatusData();
128 mystatus->currIdx = 0;
130 MemoryContextSwitchTo(oldcontext);
133 funcctx = SRF_PERCALL_SETUP();
134 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
135 lockData = mystatus->lockData;
137 while (mystatus->currIdx < lockData->nelements)
144 const char *locktypename;
151 proclock = &(lockData->proclocks[mystatus->currIdx]);
152 lock = &(lockData->locks[mystatus->currIdx]);
153 proc = &(lockData->procs[mystatus->currIdx]);
156 * Look to see if there are any held lock modes in this PROCLOCK. If
157 * so, report, and destructively modify lockData so we don't report
161 if (proclock->holdMask)
163 for (mode = 0; mode < MAX_LOCKMODES; mode++)
165 if (proclock->holdMask & LOCKBIT_ON(mode))
168 proclock->holdMask &= LOCKBIT_OFF(mode);
175 * If no (more) held modes to report, see if PROC is waiting for a
180 if (proc->waitLock == proclock->tag.myLock)
182 /* Yes, so report it with proper mode */
183 mode = proc->waitLockMode;
186 * We are now done with this PROCLOCK, so advance pointer to
187 * continue with next one on next call.
194 * Okay, we've displayed all the locks associated with this
195 * PROCLOCK, proceed to the next one.
203 * Form tuple with appropriate data.
205 MemSet(values, 0, sizeof(values));
206 MemSet(nulls, false, sizeof(nulls));
208 if (lock->tag.locktag_type <= LOCKTAG_LAST_TYPE)
209 locktypename = LockTagTypeNames[lock->tag.locktag_type];
212 snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
213 (int) lock->tag.locktag_type);
214 locktypename = tnbuf;
216 values[0] = CStringGetTextDatum(locktypename);
218 switch ((LockTagType) lock->tag.locktag_type)
220 case LOCKTAG_RELATION:
221 case LOCKTAG_RELATION_EXTEND:
222 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
223 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
233 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
234 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
235 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
244 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
245 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
246 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
247 values[4] = UInt16GetDatum(lock->tag.locktag_field4);
254 case LOCKTAG_TRANSACTION:
255 values[6] = TransactionIdGetDatum(lock->tag.locktag_field1);
265 case LOCKTAG_VIRTUALTRANSACTION:
266 values[5] = VXIDGetDatum(lock->tag.locktag_field1,
267 lock->tag.locktag_field2);
278 case LOCKTAG_USERLOCK:
279 case LOCKTAG_ADVISORY:
280 default: /* treat unknown locktags like OBJECT */
281 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
282 values[7] = ObjectIdGetDatum(lock->tag.locktag_field2);
283 values[8] = ObjectIdGetDatum(lock->tag.locktag_field3);
284 values[9] = Int16GetDatum(lock->tag.locktag_field4);
293 values[10] = VXIDGetDatum(proc->backendId, proc->lxid);
295 values[11] = Int32GetDatum(proc->pid);
298 values[12] = CStringGetTextDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock), mode));
299 values[13] = BoolGetDatum(granted);
301 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
302 result = HeapTupleGetDatum(tuple);
303 SRF_RETURN_NEXT(funcctx, result);
306 SRF_RETURN_DONE(funcctx);
311 * Functions for manipulating advisory locks
313 * We make use of the locktag fields as follows:
315 * field1: MyDatabaseId ... ensures locks are local to each database
316 * field2: first of 2 int4 keys, or high-order half of an int8 key
317 * field3: second of 2 int4 keys, or low-order half of an int8 key
318 * field4: 1 if using an int8 key, 2 if using 2 int4 keys
320 #define SET_LOCKTAG_INT64(tag, key64) \
321 SET_LOCKTAG_ADVISORY(tag, \
323 (uint32) ((key64) >> 32), \
326 #define SET_LOCKTAG_INT32(tag, key1, key2) \
327 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
330 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
333 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
335 int64 key = PG_GETARG_INT64(0);
338 SET_LOCKTAG_INT64(tag, key);
340 (void) LockAcquire(&tag, ExclusiveLock, true, false);
346 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
349 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
351 int64 key = PG_GETARG_INT64(0);
354 SET_LOCKTAG_INT64(tag, key);
356 (void) LockAcquire(&tag, ShareLock, true, false);
362 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
364 * Returns true if successful, false if lock not available
367 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
369 int64 key = PG_GETARG_INT64(0);
371 LockAcquireResult res;
373 SET_LOCKTAG_INT64(tag, key);
375 res = LockAcquire(&tag, ExclusiveLock, true, true);
377 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
381 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
383 * Returns true if successful, false if lock not available
386 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
388 int64 key = PG_GETARG_INT64(0);
390 LockAcquireResult res;
392 SET_LOCKTAG_INT64(tag, key);
394 res = LockAcquire(&tag, ShareLock, true, true);
396 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
400 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
402 * Returns true if successful, false if lock was not held
405 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
407 int64 key = PG_GETARG_INT64(0);
411 SET_LOCKTAG_INT64(tag, key);
413 res = LockRelease(&tag, ExclusiveLock, true);
419 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
421 * Returns true if successful, false if lock was not held
424 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
426 int64 key = PG_GETARG_INT64(0);
430 SET_LOCKTAG_INT64(tag, key);
432 res = LockRelease(&tag, ShareLock, true);
438 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
441 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
443 int32 key1 = PG_GETARG_INT32(0);
444 int32 key2 = PG_GETARG_INT32(1);
447 SET_LOCKTAG_INT32(tag, key1, key2);
449 (void) LockAcquire(&tag, ExclusiveLock, true, false);
455 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
458 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
460 int32 key1 = PG_GETARG_INT32(0);
461 int32 key2 = PG_GETARG_INT32(1);
464 SET_LOCKTAG_INT32(tag, key1, key2);
466 (void) LockAcquire(&tag, ShareLock, true, false);
472 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
474 * Returns true if successful, false if lock not available
477 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
479 int32 key1 = PG_GETARG_INT32(0);
480 int32 key2 = PG_GETARG_INT32(1);
482 LockAcquireResult res;
484 SET_LOCKTAG_INT32(tag, key1, key2);
486 res = LockAcquire(&tag, ExclusiveLock, true, true);
488 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
492 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
494 * Returns true if successful, false if lock not available
497 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
499 int32 key1 = PG_GETARG_INT32(0);
500 int32 key2 = PG_GETARG_INT32(1);
502 LockAcquireResult res;
504 SET_LOCKTAG_INT32(tag, key1, key2);
506 res = LockAcquire(&tag, ShareLock, true, true);
508 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
512 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
514 * Returns true if successful, false if lock was not held
517 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
519 int32 key1 = PG_GETARG_INT32(0);
520 int32 key2 = PG_GETARG_INT32(1);
524 SET_LOCKTAG_INT32(tag, key1, key2);
526 res = LockRelease(&tag, ExclusiveLock, true);
532 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
534 * Returns true if successful, false if lock was not held
537 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
539 int32 key1 = PG_GETARG_INT32(0);
540 int32 key2 = PG_GETARG_INT32(1);
544 SET_LOCKTAG_INT32(tag, key1, key2);
546 res = LockRelease(&tag, ShareLock, true);
552 * pg_advisory_unlock_all() - release all advisory locks
555 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
557 LockReleaseAll(USER_LOCKMETHOD, true);