|
relation
oid
- The OID of the locked relation. When querying
- pg_locks, this column can be joined with the
- pg_class system catalog to get more
- information on the locked relation.
+ The OID of the locked relation, or NULL if the lockable
+ object is a transaction ID. This column can be joined
+ with the pg_class system catalog to get more
+ information on the locked relation. Note however that this will
+ only work for relations in the current database (those for which
+ the database column is either the
+ current database's OID or zero).
+
|
database
oid
The OID of the database in which the locked relation
- exists. If the lock is on a globally-shared object, this value
- will be 0. When querying pg_locks, this
- column can be joined with the pg_database
- system catalog to get more information on the locked object's
- database.
+ exists, or NULL if the lockable object is a transaction ID.
+ If the lock is on a globally-shared table, this field will be
+ zero. This
+ column can be joined with the pg_database
+ system catalog to get more information on the locked object's
+ database.
+
|
- backendpid
+ transaction
+ xid
+ The ID of a transaction, or NULL if the lockable object
+ is a relation. Every transaction holds ExclusiveLock on its
+ transaction ID for its entire duration. If one transaction finds
+ it necessary to wait specifically for another transaction, it
+ does so by attempting to acquire ShareLock on the other transaction
+ ID. That will succeed only when the other transaction terminates
+ and releases its locks.
+
+
+
+ |
+ pid
int4
The process ID of the
PostgreSQL backend that has
acquired or is attempting to acquire the lock. If you have
enabled the statistics collector, this column can be joined
- with the pg_stat_activity view to access
+ with the pg_stat_activity view to get
more information on the backend holding or waiting to hold the
lock.
|
mode
text
- The mode of the lock. For more information on the
+ The mode of the requested or held lock on the lockable
+ object. For more information on the
different lock modes available in
User's Guide.
|
isgranted
- text
- A boolean column indicating whether or not this
- particular lock has been granted. If the lock has not been
- granted, the backend atempting to acquire it will sleep until
- the lock is released (or a deadlock situation is detected). A
- single backend can be waiting to acquire at most one lock at
- any given time.
+ bool
+ True if this lock has been granted (is held by this
+ backend). False indicates that this backend is currently
+ waiting to acquire this lock, which implies that some other
+ backend is holding a conflicting lock mode on the same lockable
+ object. This backend will sleep until the other lock is released
+ (or a deadlock situation is detected). A single backend can be
+ waiting to acquire at most one lock at a time.
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.112 2002/08/17 13:04:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v 1.113 2002/08/31 17:14:27 tgl Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
/*
* GetLockStatusData - Return a summary of the lock manager's internal
- * status, for use in a user-level statistical reporting function.
+ * status, for use in a user-level reporting function.
*
- * This function should be passed a pointer to a LockData struct. It fills
- * the structure with the appropriate information and returns. The goal
- * is to hold the LockMgrLock for as short a time as possible; thus, the
- * function simply makes a copy of the necessary data and releases the
- * lock, allowing the caller to contemplate and format the data for
- * as long as it pleases.
+ * The return data consists of an array of PROCLOCK objects, with the
+ * associated PGPROC and LOCK objects for each. Note that multiple
+ * copies of the same PGPROC and/or LOCK objects are likely to appear.
+ * It is the caller's responsibility to match up duplicates if wanted.
+ *
+ * The design goal is to hold the LockMgrLock for as short a time as possible;
+ * thus, this function simply makes a copy of the necessary data and releases
+ * the lock, allowing the caller to contemplate and format the data for as
+ * long as it pleases.
*/
-void
-GetLockStatusData(LockData *data)
+LockData *
+GetLockStatusData(void)
{
+ LockData *data;
HTAB *holderTable;
PROCLOCK *holder;
HASH_SEQ_STATUS seqstat;
- int i = 0;
+ int i;
- data->currIdx = 0;
+ data = (LockData *) palloc(sizeof(LockData));
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
holderTable = LockMethodTable[DEFAULT_LOCKMETHOD]->holderHash;
- data->nelements = holderTable->hctl->nentries;
+ data->nelements = i = holderTable->hctl->nentries;
+
+ if (i == 0)
+ i = 1; /* avoid palloc(0) if empty table */
- data->procs = (PGPROC *) palloc(sizeof(PGPROC) * data->nelements);
- data->locks = (LOCK *) palloc(sizeof(LOCK) * data->nelements);
- data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * data->nelements);
+ data->holderaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * i);
+ data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * i);
+ data->procs = (PGPROC *) palloc(sizeof(PGPROC) * i);
+ data->locks = (LOCK *) palloc(sizeof(LOCK) * i);
hash_seq_init(&seqstat, holderTable);
+ i = 0;
while ( (holder = hash_seq_search(&seqstat)) )
{
- PGPROC *proc;
- LOCK *lock;
-
- /* Only do a shallow copy */
- proc = (PGPROC *) MAKE_PTR(holder->tag.proc);
- lock = (LOCK *) MAKE_PTR(holder->tag.lock);
+ PGPROC *proc = (PGPROC *) MAKE_PTR(holder->tag.proc);
+ LOCK *lock = (LOCK *) MAKE_PTR(holder->tag.lock);
+ data->holderaddrs[i] = MAKE_OFFSET(holder);
+ memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK));
memcpy(&(data->procs[i]), proc, sizeof(PGPROC));
memcpy(&(data->locks[i]), lock, sizeof(LOCK));
- memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK));
i++;
}
+ LWLockRelease(LockMgrLock);
+
Assert(i == data->nelements);
- LWLockRelease(LockMgrLock);
+ return data;
}
-char *
+/* Provide the textual name of any lock mode */
+const char *
GetLockmodeName(LOCKMODE mode)
{
Assert(mode <= MAX_LOCKMODES);
-/*
+/*-------------------------------------------------------------------------
+ *
* lockfuncs.c
* Set-returning functions to view the state of locks within the DB.
*
* Copyright (c) 2002, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.4 2002/08/29 17:14:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/lockfuncs.c,v 1.5 2002/08/31 17:14:28 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "funcapi.h"
+#include "access/heapam.h"
#include "catalog/pg_type.h"
-#include "storage/lmgr.h"
#include "storage/lock.h"
-#include "storage/lwlock.h"
#include "storage/proc.h"
#include "utils/builtins.h"
-static int next_lock(int locks[]);
-
+/* Working status for pg_lock_status */
+typedef struct
+{
+ LockData *lockData; /* state data from lmgr */
+ int currIdx; /* current PROCLOCK index */
+} PG_Lock_Status;
+/*
+ * pg_lock_status - produce a view with one row per held or awaited lock mode
+ */
Datum
pg_lock_status(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
- LockData *lockData;
- MemoryContext oldcontext;
+ PG_Lock_Status *mystatus;
+ LockData *lockData;
if (SRF_IS_FIRSTCALL())
{
TupleDesc tupdesc;
+ MemoryContext oldcontext;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/* switch to memory context appropriate for multiple function calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
- tupdesc = CreateTemplateTupleDesc(5, WITHOUTOID);
+ /* build tupdesc for result tuples */
+ /* this had better match pg_locks view in initdb.sh */
+ tupdesc = CreateTemplateTupleDesc(6, WITHOUTOID);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
OIDOID, -1, 0, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
OIDOID, -1, 0, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 3, "backendpid",
+ TupleDescInitEntry(tupdesc, (AttrNumber) 3, "transaction",
+ XIDOID, -1, 0, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 4, "pid",
INT4OID, -1, 0, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 4, "mode",
+ TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
TEXTOID, -1, 0, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isgranted",
+ TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
BOOLOID, -1, 0, false);
funcctx->slot = TupleDescGetSlot(tupdesc);
- funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
/*
- * Preload all the locking information that we will eventually format
- * and send out as a result set. This is palloc'ed, but since the
- * MemoryContext is reset when the SRF finishes, we don't need to
- * free it ourselves.
+ * Collect all the locking information that we will format
+ * and send out as a result set.
*/
- funcctx->user_fctx = (LockData *) palloc(sizeof(LockData));
+ mystatus = (PG_Lock_Status *) palloc(sizeof(PG_Lock_Status));
+ funcctx->user_fctx = (void *) mystatus;
- GetLockStatusData(funcctx->user_fctx);
+ mystatus->lockData = GetLockStatusData();
+ mystatus->currIdx = 0;
MemoryContextSwitchTo(oldcontext);
}
funcctx = SRF_PERCALL_SETUP();
- lockData = (LockData *) funcctx->user_fctx;
+ mystatus = (PG_Lock_Status *) funcctx->user_fctx;
+ lockData = mystatus->lockData;
- while (lockData->currIdx < lockData->nelements)
+ while (mystatus->currIdx < lockData->nelements)
{
PROCLOCK *holder;
LOCK *lock;
PGPROC *proc;
+ bool granted;
+ LOCKMODE mode;
+ Datum values[6];
+ char nulls[6];
HeapTuple tuple;
Datum result;
- char **values;
- LOCKMODE mode;
- int num_attrs;
- int i;
- int currIdx = lockData->currIdx;
-
- holder = &(lockData->holders[currIdx]);
- lock = &(lockData->locks[currIdx]);
- proc = &(lockData->procs[currIdx]);
- num_attrs = funcctx->attinmeta->tupdesc->natts;
-
- values = (char **) palloc(sizeof(*values) * num_attrs);
-
- for (i = 0; i < num_attrs; i++)
- values[i] = (char *) palloc(32);
- /* The OID of the locked relation */
- snprintf(values[0], 32, "%u", lock->tag.relId);
- /* The database the relation is in */
- snprintf(values[1], 32, "%u", lock->tag.dbId);
- /* The PID of the backend holding or waiting for the lock */
- snprintf(values[2], 32, "%d", proc->pid);
+ holder = &(lockData->holders[mystatus->currIdx]);
+ lock = &(lockData->locks[mystatus->currIdx]);
+ proc = &(lockData->procs[mystatus->currIdx]);
/*
- * We need to report both the locks held (i.e. successfully acquired)
- * by this holder, as well as the locks upon which it is still
- * waiting, if any. Since a single PROCLOCK struct may contain
- * multiple locks, we may need to loop several times before we
- * advance the array index and continue on.
+ * Look to see if there are any held lock modes in this PROCLOCK.
+ * If so, report, and destructively modify lockData so we don't
+ * report again.
*/
- if (holder->nHolding > 0)
+ granted = false;
+ for (mode = 0; mode < MAX_LOCKMODES; mode++)
{
- /* Already held locks */
- mode = next_lock(holder->holding);
- holder->holding[mode]--;
- holder->nHolding--;
-
- strcpy(values[4], "t");
+ if (holder->holding[mode] > 0)
+ {
+ granted = true;
+ holder->holding[mode] = 0;
+ break;
+ }
}
- else if (proc->waitLock != NULL)
+
+ /*
+ * If no (more) held modes to report, see if PROC is waiting for
+ * a lock on this lock.
+ */
+ if (!granted)
{
- /* Lock that is still being waited on */
- mode = proc->waitLockMode;
- proc->waitLock = NULL;
- proc->waitLockMode = NoLock;
+ if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
+ {
+ /* Yes, so report it with proper mode */
+ mode = proc->waitLockMode;
+ /*
+ * We are now done with this PROCLOCK, so advance pointer
+ * to continue with next one on next call.
+ */
+ mystatus->currIdx++;
+ }
+ else
+ {
+ /*
+ * Okay, we've displayed all the locks associated with this
+ * PROCLOCK, proceed to the next one.
+ */
+ mystatus->currIdx++;
+ continue;
+ }
+ }
- strcpy(values[4], "f");
+ /*
+ * Form tuple with appropriate data.
+ */
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, ' ', sizeof(nulls));
+
+ if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
+ {
+ /* Lock is for transaction ID */
+ nulls[0] = 'n';
+ nulls[1] = 'n';
+ values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
}
else
{
- /*
- * Okay, we've displayed all the lock's belonging to this PROCLOCK,
- * procede to the next one.
- */
- lockData->currIdx++;
- continue;
+ /* Lock is for a relation */
+ values[0] = ObjectIdGetDatum(lock->tag.relId);
+ values[1] = ObjectIdGetDatum(lock->tag.dbId);
+ nulls[2] = 'n';
+
}
- strncpy(values[3], GetLockmodeName(mode), 32);
+ values[3] = Int32GetDatum(proc->pid);
+ values[4] = DirectFunctionCall1(textin,
+ CStringGetDatum(GetLockmodeName(mode)));
+ values[5] = BoolGetDatum(granted);
- tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
+ tuple = heap_formtuple(funcctx->slot->ttc_tupleDescriptor,
+ values, nulls);
result = TupleGetDatum(funcctx->slot, tuple);
SRF_RETURN_NEXT(funcctx, result);
}
SRF_RETURN_DONE(funcctx);
}
-
-static LOCKMODE
-next_lock(int locks[])
-{
- LOCKMODE i;
-
- for (i = 0; i < MAX_LOCKMODES; i++)
- {
- if (locks[i] != 0)
- return i;
- }
-
- /* No locks found: this should not occur */
- Assert(false);
- return -1;
-}
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
-# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.169 2002/08/27 04:00:28 momjian Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.170 2002/08/31 17:14:28 tgl Exp $
#
#-------------------------------------------------------------------------
FROM pg_database D;
CREATE VIEW pg_locks AS \
- SELECT \
- L.relation, L.database, L.backendpid, L.mode, L.isgranted \
- FROM pg_lock_status() AS L(relation oid, database oid, \
- backendpid int4, mode text, isgranted boolean);
+ SELECT * \
+ FROM pg_lock_status() AS L(relation oid, database oid, \
+ transaction xid, pid int4, mode text, granted boolean);
CREATE VIEW pg_settings AS \
- SELECT \
- A.name, \
- A.setting \
+ SELECT * \
FROM pg_show_all_settings() AS A(name text, setting text);
CREATE RULE pg_settings_u AS \
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.155 2002/08/30 19:23:20 tgl Exp $
+ * $Id: catversion.h,v 1.156 2002/08/31 17:14:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200208301
+#define CATALOG_VERSION_NO 200208311
#endif
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: lock.h,v 1.65 2002/08/17 13:04:18 momjian Exp $
+ * $Id: lock.h,v 1.66 2002/08/31 17:14:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
(((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod)
/*
- * This struct is used to encapsulate information passed from lmgr
- * internals to the lock listing statistical functions (lockfuncs.c).
- * It's just a convenient bundle of other lock.h structures. All
- * the information at a given index (holders[i], procs[i], locks[i])
- * is related.
+ * This struct holds information passed from lmgr internals to the lock
+ * listing user-level functions (lockfuncs.c). For each PROCLOCK in the
+ * system, the SHMEM_OFFSET, PROCLOCK itself, and associated PGPROC and
+ * LOCK objects are stored. (Note there will often be multiple copies
+ * of the same PGPROC or LOCK.) We do not store the SHMEM_OFFSET of the
+ * PGPROC or LOCK separately, since they're in the PROCLOCK's tag fields.
*/
typedef struct
{
- int nelements; /* The length of holders, procs, & locks */
- int currIdx; /* Current element being examined */
+ int nelements; /* The length of each of the arrays */
+ SHMEM_OFFSET *holderaddrs;
+ PROCLOCK *holders;
PGPROC *procs;
LOCK *locks;
- PROCLOCK *holders;
} LockData;
/*
extern int LockShmemSize(int maxBackends);
extern bool DeadLockCheck(PGPROC *proc);
extern void InitDeadLockChecking(void);
-extern void GetLockStatusData(LockData *data);
-extern char *GetLockmodeName(LOCKMODE mode);
+extern LockData *GetLockStatusData(void);
+extern const char *GetLockmodeName(LOCKMODE mode);
#ifdef LOCK_DEBUG
extern void DumpLocks(void);
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
- pg_locks | SELECT l.relation, l."database", l.backendpid, l."mode", l.isgranted FROM pg_lock_status() l(relation oid, "database" oid, backendpid integer, "mode" text, isgranted boolean);
+ pg_locks | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean);
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
pg_settings | SELECT a.name, a.setting FROM pg_show_all_settings() a(name text, setting text);
pg_stat_activity | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.usename, pg_stat_get_backend_activity(s.backendid) AS current_query FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_shadow u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.usesysid));