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.31 2008/01/01 19:45:52 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[] = {
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 DirectFunctionCall1(textin, CStringGetDatum(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_ADVISORY)
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] = DirectFunctionCall1(textin,
218 CStringGetDatum(locktypename));
220 switch (lock->tag.locktag_type)
222 case LOCKTAG_RELATION:
223 case LOCKTAG_RELATION_EXTEND:
224 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
225 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
235 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
236 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
237 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
246 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
247 values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
248 values[3] = UInt32GetDatum(lock->tag.locktag_field3);
249 values[4] = UInt16GetDatum(lock->tag.locktag_field4);
256 case LOCKTAG_TRANSACTION:
257 values[6] = TransactionIdGetDatum(lock->tag.locktag_field1);
267 case LOCKTAG_VIRTUALTRANSACTION:
268 values[5] = VXIDGetDatum(lock->tag.locktag_field1,
269 lock->tag.locktag_field2);
280 case LOCKTAG_USERLOCK:
281 case LOCKTAG_ADVISORY:
282 default: /* treat unknown locktags like OBJECT */
283 values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
284 values[7] = ObjectIdGetDatum(lock->tag.locktag_field2);
285 values[8] = ObjectIdGetDatum(lock->tag.locktag_field3);
286 values[9] = Int16GetDatum(lock->tag.locktag_field4);
295 values[10] = VXIDGetDatum(proc->backendId, proc->lxid);
297 values[11] = Int32GetDatum(proc->pid);
300 values[12] = DirectFunctionCall1(textin,
301 CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock),
303 values[13] = BoolGetDatum(granted);
305 tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
306 result = HeapTupleGetDatum(tuple);
307 SRF_RETURN_NEXT(funcctx, result);
310 SRF_RETURN_DONE(funcctx);
315 * Functions for manipulating advisory locks
317 * We make use of the locktag fields as follows:
319 * field1: MyDatabaseId ... ensures locks are local to each database
320 * field2: first of 2 int4 keys, or high-order half of an int8 key
321 * field3: second of 2 int4 keys, or low-order half of an int8 key
322 * field4: 1 if using an int8 key, 2 if using 2 int4 keys
324 #define SET_LOCKTAG_INT64(tag, key64) \
325 SET_LOCKTAG_ADVISORY(tag, \
327 (uint32) ((key64) >> 32), \
330 #define SET_LOCKTAG_INT32(tag, key1, key2) \
331 SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2)
334 * pg_advisory_lock(int8) - acquire exclusive lock on an int8 key
337 pg_advisory_lock_int8(PG_FUNCTION_ARGS)
339 int64 key = PG_GETARG_INT64(0);
342 SET_LOCKTAG_INT64(tag, key);
344 (void) LockAcquire(&tag, ExclusiveLock, true, false);
350 * pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
353 pg_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
355 int64 key = PG_GETARG_INT64(0);
358 SET_LOCKTAG_INT64(tag, key);
360 (void) LockAcquire(&tag, ShareLock, true, false);
366 * pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
368 * Returns true if successful, false if lock not available
371 pg_try_advisory_lock_int8(PG_FUNCTION_ARGS)
373 int64 key = PG_GETARG_INT64(0);
375 LockAcquireResult res;
377 SET_LOCKTAG_INT64(tag, key);
379 res = LockAcquire(&tag, ExclusiveLock, true, true);
381 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
385 * pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
387 * Returns true if successful, false if lock not available
390 pg_try_advisory_lock_shared_int8(PG_FUNCTION_ARGS)
392 int64 key = PG_GETARG_INT64(0);
394 LockAcquireResult res;
396 SET_LOCKTAG_INT64(tag, key);
398 res = LockAcquire(&tag, ShareLock, true, true);
400 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
404 * pg_advisory_unlock(int8) - release exclusive lock on an int8 key
406 * Returns true if successful, false if lock was not held
409 pg_advisory_unlock_int8(PG_FUNCTION_ARGS)
411 int64 key = PG_GETARG_INT64(0);
415 SET_LOCKTAG_INT64(tag, key);
417 res = LockRelease(&tag, ExclusiveLock, true);
423 * pg_advisory_unlock_shared(int8) - release share lock on an int8 key
425 * Returns true if successful, false if lock was not held
428 pg_advisory_unlock_shared_int8(PG_FUNCTION_ARGS)
430 int64 key = PG_GETARG_INT64(0);
434 SET_LOCKTAG_INT64(tag, key);
436 res = LockRelease(&tag, ShareLock, true);
442 * pg_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys
445 pg_advisory_lock_int4(PG_FUNCTION_ARGS)
447 int32 key1 = PG_GETARG_INT32(0);
448 int32 key2 = PG_GETARG_INT32(1);
451 SET_LOCKTAG_INT32(tag, key1, key2);
453 (void) LockAcquire(&tag, ExclusiveLock, true, false);
459 * pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
462 pg_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
464 int32 key1 = PG_GETARG_INT32(0);
465 int32 key2 = PG_GETARG_INT32(1);
468 SET_LOCKTAG_INT32(tag, key1, key2);
470 (void) LockAcquire(&tag, ShareLock, true, false);
476 * pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
478 * Returns true if successful, false if lock not available
481 pg_try_advisory_lock_int4(PG_FUNCTION_ARGS)
483 int32 key1 = PG_GETARG_INT32(0);
484 int32 key2 = PG_GETARG_INT32(1);
486 LockAcquireResult res;
488 SET_LOCKTAG_INT32(tag, key1, key2);
490 res = LockAcquire(&tag, ExclusiveLock, true, true);
492 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
496 * pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
498 * Returns true if successful, false if lock not available
501 pg_try_advisory_lock_shared_int4(PG_FUNCTION_ARGS)
503 int32 key1 = PG_GETARG_INT32(0);
504 int32 key2 = PG_GETARG_INT32(1);
506 LockAcquireResult res;
508 SET_LOCKTAG_INT32(tag, key1, key2);
510 res = LockAcquire(&tag, ShareLock, true, true);
512 PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
516 * pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
518 * Returns true if successful, false if lock was not held
521 pg_advisory_unlock_int4(PG_FUNCTION_ARGS)
523 int32 key1 = PG_GETARG_INT32(0);
524 int32 key2 = PG_GETARG_INT32(1);
528 SET_LOCKTAG_INT32(tag, key1, key2);
530 res = LockRelease(&tag, ExclusiveLock, true);
536 * pg_advisory_unlock_shared(int4, int4) - release share lock on 2 int4 keys
538 * Returns true if successful, false if lock was not held
541 pg_advisory_unlock_shared_int4(PG_FUNCTION_ARGS)
543 int32 key1 = PG_GETARG_INT32(0);
544 int32 key2 = PG_GETARG_INT32(1);
548 SET_LOCKTAG_INT32(tag, key1, key2);
550 res = LockRelease(&tag, ShareLock, true);
556 * pg_advisory_unlock_all() - release all advisory locks
559 pg_advisory_unlock_all(PG_FUNCTION_ARGS)
561 LockReleaseAll(USER_LOCKMETHOD, true);