* lockfuncs.c
* Functions for SQL access to various lock-manager capabilities.
*
- * Copyright (c) 2002-2008, PostgreSQL Global Development Group
+ * Copyright (c) 2002-2012, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.33 2008/03/25 22:42:44 tgl Exp $
+ * src/backend/utils/adt/lockfuncs.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include "access/heapam.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "miscadmin.h"
-#include "storage/proc.h"
+#include "storage/predicate_internals.h"
#include "utils/builtins.h"
"advisory"
};
+/* This must match enum PredicateLockTargetType (predicate_internals.h) */
+static const char *const PredicateLockTagTypeNames[] = {
+ "relation",
+ "page",
+ "tuple"
+};
+
/* Working status for pg_lock_status */
typedef struct
{
LockData *lockData; /* state data from lmgr */
int currIdx; /* current PROCLOCK index */
+ PredicateLockData *predLockData; /* state data for pred locks */
+ int predLockIdx; /* current index for pred lock */
} PG_Lock_Status;
+/* Number of columns in pg_locks output */
+#define NUM_LOCK_STATUS_COLUMNS 15
/*
* VXIDGetDatum - Construct a text representation of a VXID
FuncCallContext *funcctx;
PG_Lock_Status *mystatus;
LockData *lockData;
+ PredicateLockData *predLockData;
if (SRF_IS_FIRSTCALL())
{
/* build tupdesc for result tuples */
/* this had better match pg_locks view in system_views.sql */
- tupdesc = CreateTemplateTupleDesc(14, false);
+ tupdesc = CreateTemplateTupleDesc(NUM_LOCK_STATUS_COLUMNS, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "locktype",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 14, "granted",
BOOLOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 15, "fastpath",
+ BOOLOID, -1, 0);
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
mystatus->lockData = GetLockStatusData();
mystatus->currIdx = 0;
+ mystatus->predLockData = GetPredicateLockStatusData();
+ mystatus->predLockIdx = 0;
MemoryContextSwitchTo(oldcontext);
}
while (mystatus->currIdx < lockData->nelements)
{
- PROCLOCK *proclock;
- LOCK *lock;
- PGPROC *proc;
bool granted;
LOCKMODE mode = 0;
const char *locktypename;
char tnbuf[32];
- Datum values[14];
- char nulls[14];
+ Datum values[NUM_LOCK_STATUS_COLUMNS];
+ bool nulls[NUM_LOCK_STATUS_COLUMNS];
HeapTuple tuple;
Datum result;
+ LockInstanceData *instance;
- proclock = &(lockData->proclocks[mystatus->currIdx]);
- lock = &(lockData->locks[mystatus->currIdx]);
- proc = &(lockData->procs[mystatus->currIdx]);
+ instance = &(lockData->locks[mystatus->currIdx]);
/*
* Look to see if there are any held lock modes in this PROCLOCK. If
* again.
*/
granted = false;
- if (proclock->holdMask)
+ if (instance->holdMask)
{
for (mode = 0; mode < MAX_LOCKMODES; mode++)
{
- if (proclock->holdMask & LOCKBIT_ON(mode))
+ if (instance->holdMask & LOCKBIT_ON(mode))
{
granted = true;
- proclock->holdMask &= LOCKBIT_OFF(mode);
+ instance->holdMask &= LOCKBIT_OFF(mode);
break;
}
}
*/
if (!granted)
{
- if (proc->waitLock == proclock->tag.myLock)
+ if (instance->waitLockMode != NoLock)
{
/* Yes, so report it with proper mode */
- mode = proc->waitLockMode;
+ mode = instance->waitLockMode;
/*
* We are now done with this PROCLOCK, so advance pointer to
* Form tuple with appropriate data.
*/
MemSet(values, 0, sizeof(values));
- MemSet(nulls, ' ', sizeof(nulls));
+ MemSet(nulls, false, sizeof(nulls));
- if (lock->tag.locktag_type <= LOCKTAG_LAST_TYPE)
- locktypename = LockTagTypeNames[lock->tag.locktag_type];
+ if (instance->locktag.locktag_type <= LOCKTAG_LAST_TYPE)
+ locktypename = LockTagTypeNames[instance->locktag.locktag_type];
else
{
snprintf(tnbuf, sizeof(tnbuf), "unknown %d",
- (int) lock->tag.locktag_type);
+ (int) instance->locktag.locktag_type);
locktypename = tnbuf;
}
values[0] = CStringGetTextDatum(locktypename);
- switch ((LockTagType) lock->tag.locktag_type)
+ switch ((LockTagType) instance->locktag.locktag_type)
{
case LOCKTAG_RELATION:
case LOCKTAG_RELATION_EXTEND:
- values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
- values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
- nulls[3] = 'n';
- nulls[4] = 'n';
- nulls[5] = 'n';
- nulls[6] = 'n';
- nulls[7] = 'n';
- nulls[8] = 'n';
- nulls[9] = 'n';
+ values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
+ values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
+ nulls[3] = true;
+ nulls[4] = true;
+ nulls[5] = true;
+ nulls[6] = true;
+ nulls[7] = true;
+ nulls[8] = true;
+ nulls[9] = true;
break;
case LOCKTAG_PAGE:
- values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
- values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
- values[3] = UInt32GetDatum(lock->tag.locktag_field3);
- nulls[4] = 'n';
- nulls[5] = 'n';
- nulls[6] = 'n';
- nulls[7] = 'n';
- nulls[8] = 'n';
- nulls[9] = 'n';
+ values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
+ values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
+ values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
+ nulls[4] = true;
+ nulls[5] = true;
+ nulls[6] = true;
+ nulls[7] = true;
+ nulls[8] = true;
+ nulls[9] = true;
break;
case LOCKTAG_TUPLE:
- values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
- values[2] = ObjectIdGetDatum(lock->tag.locktag_field2);
- values[3] = UInt32GetDatum(lock->tag.locktag_field3);
- values[4] = UInt16GetDatum(lock->tag.locktag_field4);
- nulls[5] = 'n';
- nulls[6] = 'n';
- nulls[7] = 'n';
- nulls[8] = 'n';
- nulls[9] = 'n';
+ values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
+ values[2] = ObjectIdGetDatum(instance->locktag.locktag_field2);
+ values[3] = UInt32GetDatum(instance->locktag.locktag_field3);
+ values[4] = UInt16GetDatum(instance->locktag.locktag_field4);
+ nulls[5] = true;
+ nulls[6] = true;
+ nulls[7] = true;
+ nulls[8] = true;
+ nulls[9] = true;
break;
case LOCKTAG_TRANSACTION:
- values[6] = TransactionIdGetDatum(lock->tag.locktag_field1);
- nulls[1] = 'n';
- nulls[2] = 'n';
- nulls[3] = 'n';
- nulls[4] = 'n';
- nulls[5] = 'n';
- nulls[7] = 'n';
- nulls[8] = 'n';
- nulls[9] = 'n';
+ values[6] =
+ TransactionIdGetDatum(instance->locktag.locktag_field1);
+ nulls[1] = true;
+ nulls[2] = true;
+ nulls[3] = true;
+ nulls[4] = true;
+ nulls[5] = true;
+ nulls[7] = true;
+ nulls[8] = true;
+ nulls[9] = true;
break;
case LOCKTAG_VIRTUALTRANSACTION:
- values[5] = VXIDGetDatum(lock->tag.locktag_field1,
- lock->tag.locktag_field2);
- nulls[1] = 'n';
- nulls[2] = 'n';
- nulls[3] = 'n';
- nulls[4] = 'n';
- nulls[6] = 'n';
- nulls[7] = 'n';
- nulls[8] = 'n';
- nulls[9] = 'n';
+ values[5] = VXIDGetDatum(instance->locktag.locktag_field1,
+ instance->locktag.locktag_field2);
+ nulls[1] = true;
+ nulls[2] = true;
+ nulls[3] = true;
+ nulls[4] = true;
+ nulls[6] = true;
+ nulls[7] = true;
+ nulls[8] = true;
+ nulls[9] = true;
break;
case LOCKTAG_OBJECT:
case LOCKTAG_USERLOCK:
case LOCKTAG_ADVISORY:
default: /* treat unknown locktags like OBJECT */
- values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
- values[7] = ObjectIdGetDatum(lock->tag.locktag_field2);
- values[8] = ObjectIdGetDatum(lock->tag.locktag_field3);
- values[9] = Int16GetDatum(lock->tag.locktag_field4);
- nulls[2] = 'n';
- nulls[3] = 'n';
- nulls[4] = 'n';
- nulls[5] = 'n';
- nulls[6] = 'n';
+ values[1] = ObjectIdGetDatum(instance->locktag.locktag_field1);
+ values[7] = ObjectIdGetDatum(instance->locktag.locktag_field2);
+ values[8] = ObjectIdGetDatum(instance->locktag.locktag_field3);
+ values[9] = Int16GetDatum(instance->locktag.locktag_field4);
+ nulls[2] = true;
+ nulls[3] = true;
+ nulls[4] = true;
+ nulls[5] = true;
+ nulls[6] = true;
break;
}
- values[10] = VXIDGetDatum(proc->backendId, proc->lxid);
- if (proc->pid != 0)
- values[11] = Int32GetDatum(proc->pid);
+ values[10] = VXIDGetDatum(instance->backend, instance->lxid);
+ if (instance->pid != 0)
+ values[11] = Int32GetDatum(instance->pid);
else
- nulls[11] = 'n';
- values[12] = CStringGetTextDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock), mode));
+ nulls[11] = true;
+ values[12] = CStringGetTextDatum(GetLockmodeName(instance->locktag.locktag_lockmethodid, mode));
values[13] = BoolGetDatum(granted);
+ values[14] = BoolGetDatum(instance->fastpath);
+
+ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
+ result = HeapTupleGetDatum(tuple);
+ SRF_RETURN_NEXT(funcctx, result);
+ }
+
+ /*
+ * Have returned all regular locks. Now start on the SIREAD predicate
+ * locks.
+ */
+ predLockData = mystatus->predLockData;
+ if (mystatus->predLockIdx < predLockData->nelements)
+ {
+ PredicateLockTargetType lockType;
+
+ PREDICATELOCKTARGETTAG *predTag = &(predLockData->locktags[mystatus->predLockIdx]);
+ SERIALIZABLEXACT *xact = &(predLockData->xacts[mystatus->predLockIdx]);
+ Datum values[NUM_LOCK_STATUS_COLUMNS];
+ bool nulls[NUM_LOCK_STATUS_COLUMNS];
+ HeapTuple tuple;
+ Datum result;
+
+ mystatus->predLockIdx++;
+
+ /*
+ * Form tuple with appropriate data.
+ */
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, false, sizeof(nulls));
+
+ /* lock type */
+ lockType = GET_PREDICATELOCKTARGETTAG_TYPE(*predTag);
+
+ values[0] = CStringGetTextDatum(PredicateLockTagTypeNames[lockType]);
- tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
+ /* lock target */
+ values[1] = GET_PREDICATELOCKTARGETTAG_DB(*predTag);
+ values[2] = GET_PREDICATELOCKTARGETTAG_RELATION(*predTag);
+ if (lockType == PREDLOCKTAG_TUPLE)
+ values[4] = GET_PREDICATELOCKTARGETTAG_OFFSET(*predTag);
+ else
+ nulls[4] = true;
+ if ((lockType == PREDLOCKTAG_TUPLE) ||
+ (lockType == PREDLOCKTAG_PAGE))
+ values[3] = GET_PREDICATELOCKTARGETTAG_PAGE(*predTag);
+ else
+ nulls[3] = true;
+
+ /* these fields are targets for other types of locks */
+ nulls[5] = true; /* virtualxid */
+ nulls[6] = true; /* transactionid */
+ nulls[7] = true; /* classid */
+ nulls[8] = true; /* objid */
+ nulls[9] = true; /* objsubid */
+
+ /* lock holder */
+ values[10] = VXIDGetDatum(xact->vxid.backendId,
+ xact->vxid.localTransactionId);
+ if (xact->pid != 0)
+ values[11] = Int32GetDatum(xact->pid);
+ else
+ nulls[11] = true;
+
+ /*
+ * Lock mode. Currently all predicate locks are SIReadLocks, which are
+ * always held (never waiting) and have no fast path
+ */
+ values[12] = CStringGetTextDatum("SIReadLock");
+ values[13] = BoolGetDatum(true);
+ values[14] = BoolGetDatum(false);
+
+ tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
result = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, result);
}
PG_RETURN_VOID();
}
+/*
+ * pg_advisory_xact_lock(int8) - acquire xact scoped
+ * exclusive lock on an int8 key
+ */
+Datum
+pg_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ (void) LockAcquire(&tag, ExclusiveLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
/*
* pg_advisory_lock_shared(int8) - acquire share lock on an int8 key
*/
PG_RETURN_VOID();
}
+/*
+ * pg_advisory_xact_lock_shared(int8) - acquire xact scoped
+ * share lock on an int8 key
+ */
+Datum
+pg_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ (void) LockAcquire(&tag, ShareLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
/*
* pg_try_advisory_lock(int8) - acquire exclusive lock on an int8 key, no wait
*
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
+/*
+ * pg_try_advisory_xact_lock(int8) - acquire xact scoped
+ * exclusive lock on an int8 key, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ res = LockAcquire(&tag, ExclusiveLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
/*
* pg_try_advisory_lock_shared(int8) - acquire share lock on an int8 key, no wait
*
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
+/*
+ * pg_try_advisory_xact_lock_shared(int8) - acquire xact scoped
+ * share lock on an int8 key, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_shared_int8(PG_FUNCTION_ARGS)
+{
+ int64 key = PG_GETARG_INT64(0);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT64(tag, key);
+
+ res = LockAcquire(&tag, ShareLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
/*
* pg_advisory_unlock(int8) - release exclusive lock on an int8 key
*
PG_RETURN_VOID();
}
+/*
+ * pg_advisory_xact_lock(int4, int4) - acquire xact scoped
+ * exclusive lock on 2 int4 keys
+ */
+Datum
+pg_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ (void) LockAcquire(&tag, ExclusiveLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
/*
* pg_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys
*/
PG_RETURN_VOID();
}
+/*
+ * pg_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
+ * share lock on 2 int4 keys
+ */
+Datum
+pg_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ (void) LockAcquire(&tag, ShareLock, false, false);
+
+ PG_RETURN_VOID();
+}
+
/*
* pg_try_advisory_lock(int4, int4) - acquire exclusive lock on 2 int4 keys, no wait
*
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
+/*
+ * pg_try_advisory_xact_lock(int4, int4) - acquire xact scoped
+ * exclusive lock on 2 int4 keys, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ res = LockAcquire(&tag, ExclusiveLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
/*
* pg_try_advisory_lock_shared(int4, int4) - acquire share lock on 2 int4 keys, no wait
*
PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
}
+/*
+ * pg_try_advisory_xact_lock_shared(int4, int4) - acquire xact scoped
+ * share lock on 2 int4 keys, no wait
+ *
+ * Returns true if successful, false if lock not available
+ */
+Datum
+pg_try_advisory_xact_lock_shared_int4(PG_FUNCTION_ARGS)
+{
+ int32 key1 = PG_GETARG_INT32(0);
+ int32 key2 = PG_GETARG_INT32(1);
+ LOCKTAG tag;
+ LockAcquireResult res;
+
+ SET_LOCKTAG_INT32(tag, key1, key2);
+
+ res = LockAcquire(&tag, ShareLock, false, true);
+
+ PG_RETURN_BOOL(res != LOCKACQUIRE_NOT_AVAIL);
+}
+
/*
* pg_advisory_unlock(int4, int4) - release exclusive lock on 2 int4 keys
*
Datum
pg_advisory_unlock_all(PG_FUNCTION_ARGS)
{
- LockReleaseAll(USER_LOCKMETHOD, true);
+ LockReleaseSession(USER_LOCKMETHOD);
PG_RETURN_VOID();
}