1 /*-------------------------------------------------------------------------
4 * Functions for SQL access to various lock-manager capabilities.
6 * Copyright (c) 2002-2007, PostgreSQL Global Development Group
9 * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.28 2007/01/05 22:19:41 momjian 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[] = {
35 /* Working status for pg_lock_status */
38 LockData *lockData; /* state data from lmgr */
39 int currIdx; /* current PROCLOCK index */
43 * pg_lock_status - produce a view with one row per held or awaited lock mode
46 pg_lock_status(PG_FUNCTION_ARGS)
48 FuncCallContext *funcctx;
49 PG_Lock_Status *mystatus;
52 if (SRF_IS_FIRSTCALL())
55 MemoryContext oldcontext;
57 /* create a function context for cross-call persistence */
58 funcctx = SRF_FIRSTCALL_INIT();
61 * switch to memory context appropriate for multiple function calls
63 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
65 /* build tupdesc for result tuples */
66 /* this had better match pg_locks view in system_views.sql */
67 tupdesc = CreateTemplateTupleDesc(13, false);
68 TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
70 TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
72 TupleDescInitEntry(tupdesc, (AttrNumber) 3, "relation",
74 TupleDescInitEntry(tupdesc, (AttrNumber) 4, "page",
76 TupleDescInitEntry(tupdesc, (AttrNumber) 5, "tuple",
78 TupleDescInitEntry(tupdesc, (AttrNumber) 6, "transactionid",
80 TupleDescInitEntry(tupdesc, (AttrNumber) 7, "classid",
82 TupleDescInitEntry(tupdesc, (AttrNumber) 8, "objid",
84 TupleDescInitEntry(tupdesc, (AttrNumber) 9, "objsubid",
86 TupleDescInitEntry(tupdesc, (AttrNumber) 10, "transaction",
88 TupleDescInitEntry(tupdesc, (AttrNumber) 11, "pid",
90 TupleDescInitEntry(tupdesc, (AttrNumber) 12, "mode",
92 TupleDescInitEntry(tupdesc, (AttrNumber) 13, "granted",
95 funcctx->tuple_desc = BlessTupleDesc(tupdesc);
98 * Collect all the locking information that we will format and send
99 * out as a result set.
101 mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
102 funcctx->user_fctx = (void *) mystatus;
104 mystatus->lockData = GetLockStatusData();
105 mystatus->currIdx = 0;
107 MemoryContextSwitchTo(oldcontext);
110 funcctx = SRF_PERCALL_SETUP();
111 mystatus = (PG_Lock_Status *) funcctx->user_fctx;
112 lockData = mystatus->lockData;
114 while (mystatus->currIdx < lockData->nelements)
121 const char *locktypename;
128 proclock = &(lockData->proclocks[mystatus->currIdx]);
129 lock = &(lockData->locks[mystatus->currIdx]);
130 proc = &(lockData->procs[mystatus->currIdx]);
133 * Look to see if there are any held lock modes in this PROCLOCK. If
134 * so, report, and destructively modify lockData so we don't report
138 if (proclock->holdMask)
140 for (mode = 0; mode < MAX_LOCKMODES; mode++)
142 if (proclock->holdMask & LOCKBIT_ON(mode))
145 proclock->holdMask &= LOCKBIT_OFF(mode);
152 * If no (more) held modes to report, see if PROC is waiting for a
157 if (proc->waitLock == proclock->tag.myLock)
159 /* Yes, so report it with proper mode */
160 mode = proc->waitLockMode;
163 * We are now done with this PROCLOCK, so advance pointer to
164 * continue with next one on next call.
171 * Okay, we've displayed all the locks associated with this
172 * PROCLOCK, proceed to the next one.
180 * Form tuple with appropriate data.
182 MemSet(values, 0, sizeof(values));
183 MemSet(nulls, ' ', sizeof(nulls));
185 if (lock->tag.locktag_type <= LOCKTAG_ADVISORY)
186 locktypename = LockTagTypeNames[lock->tag.locktag_type];
189 snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
190 (int) lock->tag.locktag_type);
191 locktypename = tnbuf;
193 values[0] = DirectFunctionCall1(textin,
194 CStringGetDatum(locktypename));
197 switch (lock->tag.locktag_type)
199 case LOCKTAG_RELATION:
200 case LOCKTAG_RELATION_EXTEND:
201 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
202 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
211 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
212 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
213 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
221 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
222 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
223 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
224 values[4] = UInt16GetDatum(lock->tag.locktag_field4);
230 case LOCKTAG_TRANSACTION:
231 values[5] = TransactionIdGetDatum(lock->tag.locktag_field1);
241 case LOCKTAG_USERLOCK:
242 case LOCKTAG_ADVISORY:
243 default: /* treat unknown locktags like OBJECT */
244 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
245 values[6] = ObjectIdGetDatum(lock->tag.locktag_field2);
246 values[7] = ObjectIdGetDatum(lock->tag.locktag_field3);
247 values[8] = Int16GetDatum(lock->tag.locktag_field4);
255 values[9] = TransactionIdGetDatum(proc->xid);
257 values[10] = Int32GetDatum(proc->pid);
260 values[11] = DirectFunctionCall1(textin,
261 CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock),
263 values[12] = BoolGetDatum(granted);
265 tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
266 result = HeapTupleGetDatum(tuple);
267 SRF_RETURN_NEXT(funcctx, result);
270 SRF_RETURN_DONE(funcctx);
275 * Functions for manipulating advisory locks
277 * We make use of the locktag fields as follows:
279 * field1: MyDatabaseId ... ensures locks are local to each database
280 * field2: first of 2 int4 keys, or high-order half of an int8 key
281 * field3: second of 2 int4 keys, or low-order half of an int8 key
282 * field4: 1 if using an int8 key, 2 if using 2 int4 keys
284 #define SET_LOCKTAG_INT64(tag, key64) \
285 SET_LOCKTAG_ADVISORY(tag, \
287 (uint32) ((key64) >> 32), \
290 #define SET_LOCKTAG_INT32(tag, key1, key2) \
291 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
294 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
297 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
299 int64 key = PG_GETARG_INT64(0);
302 SET_LOCKTAG_INT64(tag, key);
304 (void) LockAcquire(&tag, ExclusiveLock, true, false);
310 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
313 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
315 int64 key = PG_GETARG_INT64(0);
318 SET_LOCKTAG_INT64(tag, key);
320 (void) LockAcquire(&tag, ShareLock, true, false);
326 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
328 * Returns true if successful, false if lock not available
331 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
333 int64 key = PG_GETARG_INT64(0);
335 LockAcquireResult res;
337 SET_LOCKTAG_INT64(tag, key);
339 res = LockAcquire(&tag, ExclusiveLock, true, true);
341 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
345 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
347 * Returns true if successful, false if lock not available
350 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
352 int64 key = PG_GETARG_INT64(0);
354 LockAcquireResult res;
356 SET_LOCKTAG_INT64(tag, key);
358 res = LockAcquire(&tag, ShareLock, true, true);
360 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
364 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
366 * Returns true if successful, false if lock was not held
369 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
371 int64 key = PG_GETARG_INT64(0);
375 SET_LOCKTAG_INT64(tag, key);
377 res = LockRelease(&tag, ExclusiveLock, true);
383 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
385 * Returns true if successful, false if lock was not held
388 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
390 int64 key = PG_GETARG_INT64(0);
394 SET_LOCKTAG_INT64(tag, key);
396 res = LockRelease(&tag, ShareLock, true);
402 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
405 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
407 int32 key1 = PG_GETARG_INT32(0);
408 int32 key2 = PG_GETARG_INT32(1);
411 SET_LOCKTAG_INT32(tag, key1, key2);
413 (void) LockAcquire(&tag, ExclusiveLock, true, false);
419 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
422 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
424 int32 key1 = PG_GETARG_INT32(0);
425 int32 key2 = PG_GETARG_INT32(1);
428 SET_LOCKTAG_INT32(tag, key1, key2);
430 (void) LockAcquire(&tag, ShareLock, true, false);
436 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
438 * Returns true if successful, false if lock not available
441 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
443 int32 key1 = PG_GETARG_INT32(0);
444 int32 key2 = PG_GETARG_INT32(1);
446 LockAcquireResult res;
448 SET_LOCKTAG_INT32(tag, key1, key2);
450 res = LockAcquire(&tag, ExclusiveLock, true, true);
452 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
456 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
458 * Returns true if successful, false if lock not available
461 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
463 int32 key1 = PG_GETARG_INT32(0);
464 int32 key2 = PG_GETARG_INT32(1);
466 LockAcquireResult res;
468 SET_LOCKTAG_INT32(tag, key1, key2);
470 res = LockAcquire(&tag, ShareLock, true, true);
472 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
476 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
478 * Returns true if successful, false if lock was not held
481 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
483 int32 key1 = PG_GETARG_INT32(0);
484 int32 key2 = PG_GETARG_INT32(1);
488 SET_LOCKTAG_INT32(tag, key1, key2);
490 res = LockRelease(&tag, ExclusiveLock, true);
496 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
498 * Returns true if successful, false if lock was not held
501 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
503 int32 key1 = PG_GETARG_INT32(0);
504 int32 key2 = PG_GETARG_INT32(1);
508 SET_LOCKTAG_INT32(tag, key1, key2);
510 res = LockRelease(&tag, ShareLock, true);
516 * pg_advisory_unlock_all() - release all advisory locks
519 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
521 LockReleaseAll(USER_LOCKMETHOD, true);