1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

Restructure LOCKTAG as per discussions of a couple months ago.

Essentially, we shoehorn in a lockable-object-type field by taking
a byte away from the lockmethodid, which can surely fit in one byte
instead of two.  This allows less artificial definitions of all the
other fields of LOCKTAG; we can get rid of the special pg_xactlock
pseudo-relation, and also support locks on individual tuples and
general database objects (including shared objects).  None of those
possibilities are actually exploited just yet, however.

I removed pg_xactlock from pg_class, but did not force initdb for
that change.  At this point, relkind 's' (SPECIAL) is unused and
could be removed entirely.
This commit is contained in:
Tom Lane
2005-04-29 22:28:24 +00:00
parent 32d3b47e6f
commit 3a694bb0a1
14 changed files with 347 additions and 255 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.54 2004/12/31 21:59:16 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.55 2005/04/29 22:28:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -79,11 +79,6 @@ RelationPutHeapTuple(Relation relation,
* happen if space is freed in that page after heap_update finds there's not
* enough there). In that case, the page will be pinned and locked only once.
*
* Note that we use LockPage(rel, 0) to lock relation for extension.
* We can do this as long as in all other places we use page-level locking
* for indices only. Alternatively, we could define pseudo-table as
* we do for transactions with XactLockTable.
*
* ereport(ERROR) is allowed here, so this routine *must* be called
* before any (unlogged) changes are made in buffer pool.
*/
@@ -235,7 +230,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
needLock = !RELATION_IS_LOCAL(relation);
if (needLock)
LockPage(relation, 0, ExclusiveLock);
LockRelationForExtension(relation, ExclusiveLock);
/*
* XXX This does an lseek - rather expensive - but at the moment it is
@@ -251,7 +246,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
* extend the relation some more.
*/
if (needLock)
UnlockPage(relation, 0, ExclusiveLock);
UnlockRelationForExtension(relation, ExclusiveLock);
/*
* We can be certain that locking the otherBuffer first is OK, since

View File

@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.82 2005/03/22 06:17:03 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.83 2005/04/29 22:28:24 tgl Exp $
*
* NOTES
* Postgres btree pages look like ordinary relation pages. The opaque
@@ -487,7 +487,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
needLock = !RELATION_IS_LOCAL(rel);
if (needLock)
LockPage(rel, 0, ExclusiveLock);
LockRelationForExtension(rel, ExclusiveLock);
buf = ReadBuffer(rel, P_NEW);
@@ -496,7 +496,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
* to extend the relation some more.
*/
if (needLock)
UnlockPage(rel, 0, ExclusiveLock);
UnlockRelationForExtension(rel, ExclusiveLock);
/* Acquire appropriate buffer lock on new page */
LockBuffer(buf, access);

View File

@@ -1,4 +1,4 @@
$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.15 2004/08/27 17:07:41 tgl Exp $
$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.16 2005/04/29 22:28:24 tgl Exp $
LOCKING OVERVIEW
@@ -74,30 +74,14 @@ The lock manager's LOCK objects contain:
tag -
The key fields that are used for hashing locks in the shared memory
lock hash table. This is declared as a separate struct to ensure that
we always zero out the correct number of bytes. It is critical that
any alignment-padding bytes the compiler might insert in the struct
be zeroed out, else the hash computation will be random.
tag.relId -
Uniquely identifies the relation that the lock corresponds to.
tag.dbId -
Uniquely identifies the database in which the relation lives. If
this is a shared system relation (e.g. pg_database) the dbId must
be set to 0.
tag.objId -
Uniquely identifies the block/page within the relation and the
tuple within the block. If we are setting a table level lock
both the blockId and tupleId (in an item pointer this is called
the position) are set to invalid, if it is a page level lock the
blockId is valid, while the tupleId is still invalid. Finally if
this is a tuple level lock (we currently never do this) then both
the blockId and tupleId are set to valid specifications. This is
how we get the appearance of a multi-level lock table while using
only a single table (see Gray's paper on 2 phase locking if
you are puzzled about how multi-level lock tables work).
lock hash table. The contents of the tag essentially define an
individual lockable object. See include/storage/lock.h for details
about the supported types of lockable objects. This is declared as
a separate struct to ensure that we always zero out the correct number
of bytes. It is critical that any alignment-padding bytes the compiler
might insert in the struct be zeroed out, else the hash computation
will be random. (Currently, we are careful to define struct LOCKTAG
so that there are no padding bytes.)
grantMask -
This bitmask indicates what types of locks are currently held on the

View File

@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.33 2005/02/22 04:36:49 momjian Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.34 2005/04/29 22:28:24 tgl Exp $
*
* Interface:
*
@@ -836,6 +836,69 @@ PrintLockQueue(LOCK *lock, const char *info)
}
#endif
/*
* Append a description of a lockable object to buf.
*
* XXX probably this should be exported from lmgr.c or some such place.
*/
static void
DescribeLockTag(StringInfo buf, const LOCKTAG *lock)
{
switch (lock->locktag_type)
{
case LOCKTAG_RELATION:
appendStringInfo(buf,
_("relation %u of database %u"),
lock->locktag_field2,
lock->locktag_field1);
break;
case LOCKTAG_RELATION_EXTEND:
appendStringInfo(buf,
_("extension of relation %u of database %u"),
lock->locktag_field2,
lock->locktag_field1);
break;
case LOCKTAG_PAGE:
appendStringInfo(buf,
_("page %u of relation %u of database %u"),
lock->locktag_field3,
lock->locktag_field2,
lock->locktag_field1);
break;
case LOCKTAG_TUPLE:
appendStringInfo(buf,
_("tuple (%u,%u) of relation %u of database %u"),
lock->locktag_field3,
lock->locktag_field4,
lock->locktag_field2,
lock->locktag_field1);
break;
case LOCKTAG_TRANSACTION:
appendStringInfo(buf,
_("transaction %u"),
lock->locktag_field1);
break;
case LOCKTAG_OBJECT:
appendStringInfo(buf,
_("object %u of class %u of database %u"),
lock->locktag_field3,
lock->locktag_field2,
lock->locktag_field1);
break;
case LOCKTAG_USERLOCK:
appendStringInfo(buf,
_("user lock [%u,%u]"),
lock->locktag_field1,
lock->locktag_field2);
break;
default:
appendStringInfo(buf,
_("unknown locktag type %d"),
lock->locktag_type);
break;
}
}
/*
* Report a detected deadlock, with available details.
*/
@@ -843,9 +906,12 @@ void
DeadLockReport(void)
{
StringInfoData buf;
StringInfoData buf2;
int i;
initStringInfo(&buf);
initStringInfo(&buf2);
for (i = 0; i < nDeadlockDetails; i++)
{
DEADLOCK_INFO *info = &deadlockDetails[i];
@@ -860,27 +926,18 @@ DeadLockReport(void)
if (i > 0)
appendStringInfoChar(&buf, '\n');
if (info->locktag.relId == XactLockTableId && info->locktag.dbId == 0)
{
/* Lock is for transaction ID */
appendStringInfo(&buf,
_("Process %d waits for %s on transaction %u; blocked by process %d."),
info->pid,
GetLockmodeName(info->lockmode),
info->locktag.objId.xid,
nextpid);
}
else
{
/* Lock is for a relation */
appendStringInfo(&buf,
_("Process %d waits for %s on relation %u of database %u; blocked by process %d."),
info->pid,
GetLockmodeName(info->lockmode),
info->locktag.relId,
info->locktag.dbId,
nextpid);
}
/* reset buf2 to hold next object description */
buf2.len = 0;
buf2.data[0] = '\0';
DescribeLockTag(&buf2, &info->locktag);
appendStringInfo(&buf,
_("Process %d waits for %s on %s; blocked by process %d."),
info->pid,
GetLockmodeName(info->lockmode),
buf2.data,
nextpid);
}
ereport(ERROR,
(errcode(ERRCODE_T_R_DEADLOCK_DETECTED),

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.71 2004/12/31 22:01:05 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.72 2005/04/29 22:28:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,7 +25,10 @@
#include "utils/inval.h"
static LOCKMASK LockConflicts[] = {
/*
* This conflict table defines the semantics of the various lock modes.
*/
static const LOCKMASK LockConflicts[] = {
0,
/* AccessShareLock */
@@ -69,6 +72,7 @@ static LOCKMASK LockConflicts[] = {
static LOCKMETHODID LockTableId = INVALID_LOCKMETHOD;
/*
* Create the lock table described by LockConflicts
*/
@@ -96,11 +100,11 @@ InitLockTable(int maxBackends)
#ifdef USER_LOCKS
/*
* Allocate another tableId for long-term locks
* Allocate another tableId for user locks (same shared hashtable though)
*/
LongTermTableId = LockMethodTableRename(LockTableId);
if (!LockMethodIsValid(LongTermTableId))
elog(ERROR, "could not rename long-term lock table");
elog(ERROR, "could not rename user lock table");
Assert(LongTermTableId == USER_LOCKMETHOD);
#endif
}
@@ -133,10 +137,9 @@ LockRelation(Relation relation, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relation->rd_lockInfo.lockRelId.relId;
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
tag.objId.blkno = InvalidBlockNumber;
SET_LOCKTAG_RELATION(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, false))
@@ -167,10 +170,9 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relation->rd_lockInfo.lockRelId.relId;
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
tag.objId.blkno = InvalidBlockNumber;
SET_LOCKTAG_RELATION(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, true))
@@ -197,10 +199,9 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relation->rd_lockInfo.lockRelId.relId;
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
tag.objId.blkno = InvalidBlockNumber;
SET_LOCKTAG_RELATION(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
}
@@ -222,10 +223,7 @@ LockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relid->relId;
tag.dbId = relid->dbId;
tag.objId.blkno = InvalidBlockNumber;
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
if (!LockAcquire(LockTableId, &tag, InvalidTransactionId,
lockmode, false))
@@ -240,30 +238,65 @@ UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relid->relId;
tag.dbId = relid->dbId;
tag.objId.blkno = InvalidBlockNumber;
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode);
}
/*
* LockRelationForExtension
*
* This lock tag is used to interlock addition of pages to relations.
* We need such locking because bufmgr/smgr definition of P_NEW is not
* race-condition-proof.
*
* We assume the caller is already holding some type of regular lock on
* the relation, so no AcceptInvalidationMessages call is needed here.
*/
void
LockRelationForExtension(Relation relation, LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_RELATION_EXTEND(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, false))
elog(ERROR, "LockAcquire failed");
}
/*
* UnlockRelationForExtension
*/
void
UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
{
LOCKTAG tag;
SET_LOCKTAG_RELATION_EXTEND(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId);
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
}
/*
* LockPage
*
* Obtain a page-level lock. This is currently used by some index access
* methods to lock index pages. For heap relations, it is used only with
* blkno == 0 to signify locking the relation for extension.
* methods to lock individual index pages.
*/
void
LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relation->rd_lockInfo.lockRelId.relId;
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
tag.objId.blkno = blkno;
SET_LOCKTAG_PAGE(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId,
blkno);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, false))
@@ -281,10 +314,10 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relation->rd_lockInfo.lockRelId.relId;
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
tag.objId.blkno = blkno;
SET_LOCKTAG_PAGE(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId,
blkno);
return LockAcquire(LockTableId, &tag, GetTopTransactionId(),
lockmode, true);
@@ -298,10 +331,10 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = relation->rd_lockInfo.lockRelId.relId;
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
tag.objId.blkno = blkno;
SET_LOCKTAG_PAGE(tag,
relation->rd_lockInfo.lockRelId.dbId,
relation->rd_lockInfo.lockRelId.relId,
blkno);
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
}
@@ -318,10 +351,7 @@ XactLockTableInsert(TransactionId xid)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = XactLockTableId;
tag.dbId = InvalidOid; /* xids are globally unique */
tag.objId.xid = xid;
SET_LOCKTAG_TRANSACTION(tag, xid);
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
ExclusiveLock, false))
@@ -341,10 +371,7 @@ XactLockTableDelete(TransactionId xid)
{
LOCKTAG tag;
MemSet(&tag, 0, sizeof(tag));
tag.relId = XactLockTableId;
tag.dbId = InvalidOid; /* xids are globally unique */
tag.objId.xid = xid;
SET_LOCKTAG_TRANSACTION(tag, xid);
LockRelease(LockTableId, &tag, GetTopTransactionId(), ExclusiveLock);
}
@@ -372,10 +399,7 @@ XactLockTableWait(TransactionId xid)
Assert(TransactionIdIsValid(xid));
Assert(!TransactionIdEquals(xid, myxid));
MemSet(&tag, 0, sizeof(tag));
tag.relId = XactLockTableId;
tag.dbId = InvalidOid;
tag.objId.xid = xid;
SET_LOCKTAG_TRANSACTION(tag, xid);
if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, false))
elog(ERROR, "LockAcquire failed");

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.149 2005/04/13 18:54:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.150 2005/04/29 22:28:24 tgl Exp $
*
* NOTES
* Outside modules can create a lock table and acquire/release
@@ -108,10 +108,11 @@ inline static bool
LOCK_DEBUG_ENABLED(const LOCK *lock)
{
return
(((LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD && Trace_locks)
|| (LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD && Trace_userlocks))
&& (lock->tag.relId >= (Oid) Trace_lock_oidmin))
|| (Trace_lock_table && (lock->tag.relId == Trace_lock_table));
(((Trace_locks && LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD)
|| (Trace_userlocks && LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD))
&& ((Oid) lock->tag.locktag_field2 >= (Oid) Trace_lock_oidmin))
|| (Trace_lock_table
&& (lock->tag.locktag_field2 == Trace_lock_table));
}
@@ -120,12 +121,14 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
{
if (LOCK_DEBUG_ENABLED(lock))
elog(LOG,
"%s: lock(%lx) tbl(%d) rel(%u) db(%u) obj(%u) grantMask(%x) "
"%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
"req(%d,%d,%d,%d,%d,%d,%d)=%d "
"grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
where, MAKE_OFFSET(lock),
lock->tag.lockmethodid, lock->tag.relId, lock->tag.dbId,
lock->tag.objId.blkno, lock->grantMask,
lock->tag.locktag_field1, lock->tag.locktag_field2,
lock->tag.locktag_field3, lock->tag.locktag_field4,
lock->tag.locktag_type, lock->tag.locktag_lockmethodid,
lock->grantMask,
lock->requested[1], lock->requested[2], lock->requested[3],
lock->requested[4], lock->requested[5], lock->requested[6],
lock->requested[7], lock->nRequested,
@@ -139,14 +142,9 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
inline static void
PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
{
if (
(((PROCLOCK_LOCKMETHOD(*proclockP) == DEFAULT_LOCKMETHOD && Trace_locks)
|| (PROCLOCK_LOCKMETHOD(*proclockP) == USER_LOCKMETHOD && Trace_userlocks))
&& (((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
|| (Trace_lock_table && (((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag.relId == Trace_lock_table))
)
if (LOCK_DEBUG_ENABLED((LOCK *) MAKE_PTR(proclockP->tag.lock)))
elog(LOG,
"%s: proclock(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%x)",
"%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) xid(%u) hold(%x)",
where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
PROCLOCK_LOCKMETHOD(*(proclockP)),
proclockP->tag.proc, proclockP->tag.xid,
@@ -346,13 +344,9 @@ LockMethodTableInit(const char *tabName,
* LockMethodTableRename -- allocate another lockmethod ID to the same
* lock table.
*
* NOTES: Both the lock module and the lock chain (lchain.c)
* module use table id's to distinguish between different
* kinds of locks. Short term and long term locks look
* the same to the lock table, but are handled differently
* by the lock chain manager. This function allows the
* client to use different lockmethods when acquiring/releasing
* short term and long term locks, yet store them all in one hashtable.
* NOTES: This function makes it possible to have different lockmethodids,
* and hence different locking semantics, while still storing all
* the data in one shared-memory hashtable.
*/
LOCKMETHODID
@@ -404,33 +398,16 @@ LockMethodTableRename(LOCKMETHODID lockmethodid)
* the lock. While the lock is active other clients can still
* read and write the tuple but they can be aware that it has
* been locked at the application level by someone.
* User locks use lock tags made of an uint16 and an uint32, for
* example 0 and a tuple oid, or any other arbitrary pair of
* numbers following a convention established by the application.
* In this sense tags don't refer to tuples or database entities.
*
* User locks and normal locks are completely orthogonal and
* they don't interfere with each other, so it is possible
* to acquire a normal lock on an user-locked tuple or user-lock
* a tuple for which a normal write lock already exists.
* they don't interfere with each other.
*
* User locks are always non blocking, therefore they are never
* acquired if already held by another process. They must be
* released explicitly by the application but they are released
* automatically when a backend terminates.
* They are indicated by a lockmethod 2 which is an alias for the
* normal lock table, and are distinguished from normal locks
* by the following differences:
*
* normal lock user lock
*
* lockmethodid 1 2
* tag.dbId database oid database oid
* tag.relId rel oid or 0 0
* tag.objId block id lock id2
* or xact id
* tag.offnum 0 lock id1
* proclock.xid xid or 0 0
* persistence transaction user or backend
* or backend
* normal lock table.
*
* The lockmode parameter can have the same values for normal locks
* although probably only WRITE_LOCK can have some practical use.
@@ -456,13 +433,14 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
int i;
#ifdef LOCK_DEBUG
if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
elog(LOG, "LockAcquire: user lock [%u] %s",
locktag->objId.blkno, lock_mode_names[lockmode]);
if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
elog(LOG, "LockAcquire: user lock [%u,%u] %s",
locktag->locktag_field1, locktag->locktag_field2,
lock_mode_names[lockmode]);
#endif
/* ???????? This must be changed when short term locks will be used */
locktag->lockmethodid = lockmethodid;
/* ugly */
locktag->locktag_lockmethodid = lockmethodid;
Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid];
@@ -1231,12 +1209,14 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
bool wakeupNeeded;
#ifdef LOCK_DEBUG
if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
elog(LOG, "LockRelease: user lock tag [%u] %d", locktag->objId.blkno, lockmode);
if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
elog(LOG, "LockRelease: user lock [%u,%u] %s",
locktag->locktag_field1, locktag->locktag_field2,
lock_mode_names[lockmode]);
#endif
/* ???????? This must be changed when short term locks will be used */
locktag->lockmethodid = lockmethodid;
/* ugly */
locktag->locktag_lockmethodid = lockmethodid;
Assert(lockmethodid < NumLockMethods);
lockMethodTable = LockMethods[lockmethodid];

View File

@@ -6,7 +6,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.16 2005/01/01 05:43:07 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.17 2005/04/29 22:28:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -155,20 +155,24 @@ pg_lock_status(PG_FUNCTION_ARGS)
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
switch (lock->tag.locktag_type)
{
/* Lock is for transaction ID */
nulls[0] = 'n';
nulls[1] = 'n';
values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
}
else
{
/* Lock is for a relation */
values[0] = ObjectIdGetDatum(lock->tag.relId);
values[1] = ObjectIdGetDatum(lock->tag.dbId);
nulls[2] = 'n';
case LOCKTAG_RELATION:
case LOCKTAG_RELATION_EXTEND:
case LOCKTAG_PAGE:
case LOCKTAG_TUPLE:
values[0] = ObjectIdGetDatum(lock->tag.locktag_field2);
values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
nulls[2] = 'n';
break;
case LOCKTAG_TRANSACTION:
nulls[0] = 'n';
nulls[1] = 'n';
values[2] = TransactionIdGetDatum(lock->tag.locktag_field1);
break;
default:
/* XXX Ignore all other lock types for now */
continue;
}
values[3] = Int32GetDatum(proc->pid);