Commit 1bab464e authored by Tom Lane's avatar Tom Lane

Code review for pg_locks feature. Make shmemoffset of PROCLOCK structs

available (else there's no way to interpret the list links).  Change
pg_locks view to show transaction ID locks separately from ordinary
relation locks.  Avoid showing N duplicate rows when the same lock is
held multiple times (seems unlikely that users care about exact hold
count).  Improve documentation.
parent 642fd38e
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/monitoring.sgml,v 1.12 2002/08/20 04:47:52 momjian Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/monitoring.sgml,v 1.13 2002/08/31 17:14:27 tgl Exp $
--> -->
<chapter id="monitoring"> <chapter id="monitoring">
...@@ -593,22 +593,25 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; ...@@ -593,22 +593,25 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
<note> <note>
<para> <para>
When the <literal>pg_locks</literal> view is accessed, an When the <literal>pg_locks</literal> view is accessed, the
exclusive lock on an internal lock manager data structure must be internal lock manager data structures are momentarily locked,
acquired to ensure that the data produced by the view is and a copy is made for the view to display. This ensures that
consistent. The lock held on this structure conflicts with normal the view produces a consistent set of results, while not blocking
database operations, and can therefore have an effect on overall normal lock manager operations longer than necessary. Nonetheless
database performance. Nevertheless, the performance impact of there could be some impact on database performance if this view is
accessing this view should be minimal in most situations. examined often.
</para> </para>
</note> </note>
<para> <para>
The <literal>pg_locks</literal> view contains one row per The <literal>pg_locks</literal> view contains one row per lockable
lock. This means that if there are multiple locks on a single object and requested lock mode. Thus, the same lockable object
relation (which may or may not conflict with one another), a may appear many times, if multiple transactions are holding or
single relation may show up many times. Furthermore, only waiting for locks on it. A lockable object is either a relation
table-level locks are displayed (not row-level ones). or a transaction ID. (Note that this view includes only table-level
locks, not row-level ones. If a transaction is waiting for a
row-level lock, it will appear in the view as waiting for the
transaction ID of the current holder of that row lock.)
</para> </para>
<table> <table>
...@@ -627,31 +630,50 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; ...@@ -627,31 +630,50 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
<row> <row>
<entry><structfield>relation</structfield></entry> <entry><structfield>relation</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry>The OID of the locked relation. When querying <entry>The OID of the locked relation, or NULL if the lockable
<literal>pg_locks</literal>, this column can be joined with the object is a transaction ID. This column can be joined
<literal>pg_class</literal> system catalog to get more with the <literal>pg_class</literal> system catalog to get more
information on the locked relation.</entry> information on the locked relation. Note however that this will
only work for relations in the current database (those for which
the <structfield>database</structfield> column is either the
current database's OID or zero).
</entry>
</row> </row>
<row> <row>
<entry><structfield>database</structfield></entry> <entry><structfield>database</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
<entry>The OID of the database in which the locked relation <entry>The OID of the database in which the locked relation
exists. If the lock is on a globally-shared object, this value exists, or NULL if the lockable object is a transaction ID.
will be 0. When querying <literal>pg_locks</literal>, this If the lock is on a globally-shared table, this field will be
column can be joined with the <literal>pg_database</literal> zero. This
system catalog to get more information on the locked object's column can be joined with the <literal>pg_database</literal>
database.</entry> system catalog to get more information on the locked object's
database.
</entry>
</row> </row>
<row> <row>
<entry><structfield>backendpid</structfield></entry> <entry><structfield>transaction</structfield></entry>
<entry><type>xid</type></entry>
<entry>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.
</entry>
</row>
<row>
<entry><structfield>pid</structfield></entry>
<entry><type>int4</type></entry> <entry><type>int4</type></entry>
<entry>The process ID of the <entry>The process ID of the
<productname>PostgreSQL</productname> backend that has <productname>PostgreSQL</productname> backend that has
acquired or is attempting to acquire the lock. If you have acquired or is attempting to acquire the lock. If you have
enabled the statistics collector, this column can be joined enabled the statistics collector, this column can be joined
with the <literal>pg_stat_activity</literal> view to access with the <literal>pg_stat_activity</literal> view to get
more information on the backend holding or waiting to hold the more information on the backend holding or waiting to hold the
lock.</entry> lock.</entry>
</row> </row>
...@@ -659,7 +681,8 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; ...@@ -659,7 +681,8 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
<row> <row>
<entry><structfield>mode</structfield></entry> <entry><structfield>mode</structfield></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
<entry>The mode of the lock. For more information on the <entry>The mode of the requested or held lock on the lockable
object. For more information on the
different lock modes available in different lock modes available in
<productname>PostgreSQL</productname>, refer to the <productname>PostgreSQL</productname>, refer to the
<citetitle>User's Guide</citetitle>.</entry> <citetitle>User's Guide</citetitle>.</entry>
...@@ -667,13 +690,14 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S; ...@@ -667,13 +690,14 @@ FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS S;
<row> <row>
<entry><structfield>isgranted</structfield></entry> <entry><structfield>isgranted</structfield></entry>
<entry><type>text</type></entry> <entry><type>bool</type></entry>
<entry>A boolean column indicating whether or not this <entry>True if this lock has been granted (is held by this
particular lock has been granted. If the lock has not been backend). False indicates that this backend is currently
granted, the backend atempting to acquire it will sleep until waiting to acquire this lock, which implies that some other
the lock is released (or a deadlock situation is detected). A backend is holding a conflicting lock mode on the same lockable
single backend can be waiting to acquire at most one lock at object. This backend will sleep until the other lock is released
any given time.</entry> (or a deadlock situation is detected). A single backend can be
waiting to acquire at most one lock at a time.</entry>
</row> </row>
</tbody> </tbody>
</tgroup> </tgroup>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Outside modules can create a lock table and acquire/release * Outside modules can create a lock table and acquire/release
...@@ -1361,59 +1361,68 @@ LockShmemSize(int maxBackends) ...@@ -1361,59 +1361,68 @@ LockShmemSize(int maxBackends)
/* /*
* GetLockStatusData - Return a summary of the lock manager's internal * 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 return data consists of an array of PROCLOCK objects, with the
* the structure with the appropriate information and returns. The goal * associated PGPROC and LOCK objects for each. Note that multiple
* is to hold the LockMgrLock for as short a time as possible; thus, the * copies of the same PGPROC and/or LOCK objects are likely to appear.
* function simply makes a copy of the necessary data and releases the * It is the caller's responsibility to match up duplicates if wanted.
* lock, allowing the caller to contemplate and format the data for *
* as long as it pleases. * 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 LockData *
GetLockStatusData(LockData *data) GetLockStatusData(void)
{ {
LockData *data;
HTAB *holderTable; HTAB *holderTable;
PROCLOCK *holder; PROCLOCK *holder;
HASH_SEQ_STATUS seqstat; HASH_SEQ_STATUS seqstat;
int i = 0; int i;
data->currIdx = 0; data = (LockData *) palloc(sizeof(LockData));
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE); LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
holderTable = LockMethodTable[DEFAULT_LOCKMETHOD]->holderHash; 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->holderaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * i);
data->locks = (LOCK *) palloc(sizeof(LOCK) * data->nelements); data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * i);
data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * data->nelements); data->procs = (PGPROC *) palloc(sizeof(PGPROC) * i);
data->locks = (LOCK *) palloc(sizeof(LOCK) * i);
hash_seq_init(&seqstat, holderTable); hash_seq_init(&seqstat, holderTable);
i = 0;
while ( (holder = hash_seq_search(&seqstat)) ) while ( (holder = hash_seq_search(&seqstat)) )
{ {
PGPROC *proc; PGPROC *proc = (PGPROC *) MAKE_PTR(holder->tag.proc);
LOCK *lock; LOCK *lock = (LOCK *) MAKE_PTR(holder->tag.lock);
/* Only do a shallow copy */
proc = (PGPROC *) MAKE_PTR(holder->tag.proc);
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->procs[i]), proc, sizeof(PGPROC));
memcpy(&(data->locks[i]), lock, sizeof(LOCK)); memcpy(&(data->locks[i]), lock, sizeof(LOCK));
memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK));
i++; i++;
} }
LWLockRelease(LockMgrLock);
Assert(i == data->nelements); Assert(i == data->nelements);
LWLockRelease(LockMgrLock); return data;
} }
char * /* Provide the textual name of any lock mode */
const char *
GetLockmodeName(LOCKMODE mode) GetLockmodeName(LOCKMODE mode)
{ {
Assert(mode <= MAX_LOCKMODES); Assert(mode <= MAX_LOCKMODES);
......
/* /*-------------------------------------------------------------------------
*
* lockfuncs.c * lockfuncs.c
* Set-returning functions to view the state of locks within the DB. * Set-returning functions to view the state of locks within the DB.
* *
* Copyright (c) 2002, PostgreSQL Global Development Group * Copyright (c) 2002, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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 "postgres.h"
#include "funcapi.h" #include "funcapi.h"
#include "access/heapam.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "storage/lmgr.h"
#include "storage/lock.h" #include "storage/lock.h"
#include "storage/lwlock.h"
#include "storage/proc.h" #include "storage/proc.h"
#include "utils/builtins.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 Datum
pg_lock_status(PG_FUNCTION_ARGS) pg_lock_status(PG_FUNCTION_ARGS)
{ {
FuncCallContext *funcctx; FuncCallContext *funcctx;
LockData *lockData; PG_Lock_Status *mystatus;
MemoryContext oldcontext; LockData *lockData;
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
{ {
TupleDesc tupdesc; TupleDesc tupdesc;
MemoryContext oldcontext;
/* create a function context for cross-call persistence */ /* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
...@@ -38,124 +48,132 @@ pg_lock_status(PG_FUNCTION_ARGS) ...@@ -38,124 +48,132 @@ pg_lock_status(PG_FUNCTION_ARGS)
/* switch to memory context appropriate for multiple function calls */ /* switch to memory context appropriate for multiple function calls */
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); 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", TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relation",
OIDOID, -1, 0, false); OIDOID, -1, 0, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database", TupleDescInitEntry(tupdesc, (AttrNumber) 2, "database",
OIDOID, -1, 0, false); 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); INT4OID, -1, 0, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "mode", TupleDescInitEntry(tupdesc, (AttrNumber) 5, "mode",
TEXTOID, -1, 0, false); TEXTOID, -1, 0, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "isgranted", TupleDescInitEntry(tupdesc, (AttrNumber) 6, "granted",
BOOLOID, -1, 0, false); BOOLOID, -1, 0, false);
funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->slot = TupleDescGetSlot(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
/* /*
* Preload all the locking information that we will eventually format * Collect all the locking information that we will format
* and send out as a result set. This is palloc'ed, but since the * and send out as a result set.
* MemoryContext is reset when the SRF finishes, we don't need to
* free it ourselves.
*/ */
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); MemoryContextSwitchTo(oldcontext);
} }
funcctx = SRF_PERCALL_SETUP(); 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; PROCLOCK *holder;
LOCK *lock; LOCK *lock;
PGPROC *proc; PGPROC *proc;
bool granted;
LOCKMODE mode;
Datum values[6];
char nulls[6];
HeapTuple tuple; HeapTuple tuple;
Datum result; 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 */ holder = &(lockData->holders[mystatus->currIdx]);
snprintf(values[0], 32, "%u", lock->tag.relId); lock = &(lockData->locks[mystatus->currIdx]);
/* The database the relation is in */ proc = &(lockData->procs[mystatus->currIdx]);
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);
/* /*
* We need to report both the locks held (i.e. successfully acquired) * Look to see if there are any held lock modes in this PROCLOCK.
* by this holder, as well as the locks upon which it is still * If so, report, and destructively modify lockData so we don't
* waiting, if any. Since a single PROCLOCK struct may contain * report again.
* multiple locks, we may need to loop several times before we
* advance the array index and continue on.
*/ */
if (holder->nHolding > 0) granted = false;
for (mode = 0; mode < MAX_LOCKMODES; mode++)
{ {
/* Already held locks */ if (holder->holding[mode] > 0)
mode = next_lock(holder->holding); {
holder->holding[mode]--; granted = true;
holder->nHolding--; holder->holding[mode] = 0;
break;
strcpy(values[4], "t"); }
} }
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 */ if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
mode = proc->waitLockMode; {
proc->waitLock = NULL; /* Yes, so report it with proper mode */
proc->waitLockMode = NoLock; 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 else
{ {
/* /* Lock is for a relation */
* Okay, we've displayed all the lock's belonging to this PROCLOCK, values[0] = ObjectIdGetDatum(lock->tag.relId);
* procede to the next one. values[1] = ObjectIdGetDatum(lock->tag.dbId);
*/ nulls[2] = 'n';
lockData->currIdx++;
continue;
} }
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); result = TupleGetDatum(funcctx->slot, tuple);
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
} }
SRF_RETURN_DONE(funcctx); 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;
}
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California # 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 $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
...@@ -978,15 +978,12 @@ CREATE VIEW pg_stat_database AS \ ...@@ -978,15 +978,12 @@ CREATE VIEW pg_stat_database AS \
FROM pg_database D; FROM pg_database D;
CREATE VIEW pg_locks AS \ CREATE VIEW pg_locks AS \
SELECT \ SELECT * \
L.relation, L.database, L.backendpid, L.mode, L.isgranted \ FROM pg_lock_status() AS L(relation oid, database oid, \
FROM pg_lock_status() AS L(relation oid, database oid, \ transaction xid, pid int4, mode text, granted boolean);
backendpid int4, mode text, isgranted boolean);
CREATE VIEW pg_settings AS \ CREATE VIEW pg_settings AS \
SELECT \ SELECT * \
A.name, \
A.setting \
FROM pg_show_all_settings() AS A(name text, setting text); FROM pg_show_all_settings() AS A(name text, setting text);
CREATE RULE pg_settings_u AS \ CREATE RULE pg_settings_u AS \
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200208301 #define CATALOG_VERSION_NO 200208311
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -204,19 +204,20 @@ typedef struct PROCLOCK ...@@ -204,19 +204,20 @@ typedef struct PROCLOCK
(((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod) (((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod)
/* /*
* This struct is used to encapsulate information passed from lmgr * This struct holds information passed from lmgr internals to the lock
* internals to the lock listing statistical functions (lockfuncs.c). * listing user-level functions (lockfuncs.c). For each PROCLOCK in the
* It's just a convenient bundle of other lock.h structures. All * system, the SHMEM_OFFSET, PROCLOCK itself, and associated PGPROC and
* the information at a given index (holders[i], procs[i], locks[i]) * LOCK objects are stored. (Note there will often be multiple copies
* is related. * 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 typedef struct
{ {
int nelements; /* The length of holders, procs, & locks */ int nelements; /* The length of each of the arrays */
int currIdx; /* Current element being examined */ SHMEM_OFFSET *holderaddrs;
PROCLOCK *holders;
PGPROC *procs; PGPROC *procs;
LOCK *locks; LOCK *locks;
PROCLOCK *holders;
} LockData; } LockData;
/* /*
...@@ -242,8 +243,8 @@ extern void RemoveFromWaitQueue(PGPROC *proc); ...@@ -242,8 +243,8 @@ extern void RemoveFromWaitQueue(PGPROC *proc);
extern int LockShmemSize(int maxBackends); extern int LockShmemSize(int maxBackends);
extern bool DeadLockCheck(PGPROC *proc); extern bool DeadLockCheck(PGPROC *proc);
extern void InitDeadLockChecking(void); extern void InitDeadLockChecking(void);
extern void GetLockStatusData(LockData *data); extern LockData *GetLockStatusData(void);
extern char *GetLockmodeName(LOCKMODE mode); extern const char *GetLockmodeName(LOCKMODE mode);
#ifdef LOCK_DEBUG #ifdef LOCK_DEBUG
extern void DumpLocks(void); extern void DumpLocks(void);
......
...@@ -1268,7 +1268,7 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname; ...@@ -1268,7 +1268,7 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname;
--------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
iexit | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath); 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_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_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_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)); 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));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment