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.
This commit is contained in:
parent
642fd38e42
commit
1bab464eb4
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$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;
|
|||||||
|
|
||||||
<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;
|
|||||||
<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;
|
|||||||
<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;
|
|||||||
|
|
||||||
<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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* 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;
|
||||||
|
|
||||||
data->procs = (PGPROC *) palloc(sizeof(PGPROC) * data->nelements);
|
if (i == 0)
|
||||||
data->locks = (LOCK *) palloc(sizeof(LOCK) * data->nelements);
|
i = 1; /* avoid palloc(0) if empty table */
|
||||||
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);
|
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);
|
||||||
|
@ -1,36 +1,46 @@
|
|||||||
/*
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
* 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)
|
|||||||
/* 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]);
|
holder = &(lockData->holders[mystatus->currIdx]);
|
||||||
lock = &(lockData->locks[currIdx]);
|
lock = &(lockData->locks[mystatus->currIdx]);
|
||||||
proc = &(lockData->procs[currIdx]);
|
proc = &(lockData->procs[mystatus->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);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
/* Lock that is still being waited on */
|
|
||||||
mode = proc->waitLockMode;
|
|
||||||
proc->waitLock = NULL;
|
|
||||||
proc->waitLockMode = NoLock;
|
|
||||||
|
|
||||||
strcpy(values[4], "f");
|
/*
|
||||||
|
* If no (more) held modes to report, see if PROC is waiting for
|
||||||
|
* a lock on this lock.
|
||||||
|
*/
|
||||||
|
if (!granted)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 @@
|
|||||||
# 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 \
|
|||||||
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 @@
|
|||||||
* 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 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200208301
|
#define CATALOG_VERSION_NO 200208311
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -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
|
|||||||
(((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);
|
|||||||
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;
|
|||||||
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
--------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
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));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user