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:
parent
32d3b47e6f
commit
3a694bb0a1
|
@ -35,11 +35,11 @@ It could also be done with a begin/end block but in this case the entire
|
||||||
table would be locked by Postgres and it is not acceptable to do this for
|
table would be locked by Postgres and it is not acceptable to do this for
|
||||||
a long period because other transactions would block completely.
|
a long period because other transactions would block completely.
|
||||||
|
|
||||||
The generic user locks use two values, group and id, to identify a lock,
|
The generic user locks use two values, group and id, to identify a lock.
|
||||||
which correspond to ip_posid and ip_blkid of an ItemPointerData.
|
Each of these are 32-bit integers.
|
||||||
Group is a 16 bit value while id is a 32 bit integer which could also be
|
|
||||||
an oid. The oid user lock functions, which take only an oid as argument,
|
The oid user lock functions, which take only an OID as argument, store the
|
||||||
use a group equal to 0.
|
OID as "id" with a group equal to 0.
|
||||||
|
|
||||||
The meaning of group and id is defined by the application. The user
|
The meaning of group and id is defined by the application. The user
|
||||||
lock code just takes two numbers and tells you if the corresponding
|
lock code just takes two numbers and tells you if the corresponding
|
||||||
|
@ -47,7 +47,9 @@ entity has been successfully locked. What this means is up to you.
|
||||||
|
|
||||||
My suggestion is that you use the group to identify an area of your
|
My suggestion is that you use the group to identify an area of your
|
||||||
application and the id to identify an object in this area.
|
application and the id to identify an object in this area.
|
||||||
Or you can just lock the oid of the tuples which are by definition unique.
|
|
||||||
|
In all cases, user locks are local to individual databases within an
|
||||||
|
installation.
|
||||||
|
|
||||||
Note also that a process can acquire more than one lock on the same entity
|
Note also that a process can acquire more than one lock on the same entity
|
||||||
and it must release the lock the corresponding number of times. This can
|
and it must release the lock the corresponding number of times. This can
|
||||||
|
|
|
@ -18,16 +18,20 @@
|
||||||
#include "user_locks.h"
|
#include "user_locks.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SET_LOCKTAG_USERLOCK(locktag,id1,id2) \
|
||||||
|
((locktag).locktag_field1 = (id1), \
|
||||||
|
(locktag).locktag_field2 = (id2), \
|
||||||
|
(locktag).locktag_field3 = MyDatabaseId, \
|
||||||
|
(locktag).locktag_field4 = 0, \
|
||||||
|
(locktag).locktag_type = LOCKTAG_USERLOCK)
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
|
user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
memset(&tag, 0, sizeof(LOCKTAG));
|
SET_LOCKTAG_USERLOCK(tag, id1, id2);
|
||||||
tag.dbId = MyDatabaseId;
|
|
||||||
tag.relId = 0;
|
|
||||||
tag.objId.blkno = (BlockNumber) id2;
|
|
||||||
tag.offnum = (OffsetNumber) (id1 & 0xffff);
|
|
||||||
|
|
||||||
return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId,
|
return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId,
|
||||||
lockmode, true);
|
lockmode, true);
|
||||||
|
@ -38,11 +42,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
memset(&tag, 0, sizeof(LOCKTAG));
|
SET_LOCKTAG_USERLOCK(tag, id1, id2);
|
||||||
tag.dbId = MyDatabaseId;
|
|
||||||
tag.relId = 0;
|
|
||||||
tag.objId.blkno = (BlockNumber) id2;
|
|
||||||
tag.offnum = (OffsetNumber) (id1 & 0xffff);
|
|
||||||
|
|
||||||
return LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, lockmode);
|
return LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, lockmode);
|
||||||
}
|
}
|
||||||
|
@ -77,13 +77,3 @@ user_unlock_all(void)
|
||||||
{
|
{
|
||||||
return LockReleaseAll(USER_LOCKMETHOD, true);
|
return LockReleaseAll(USER_LOCKMETHOD, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* end of file */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Local Variables:
|
|
||||||
* tab-width: 4
|
|
||||||
* c-indent-level: 4
|
|
||||||
* c-basic-offset: 4
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
|
|
|
@ -1,19 +1,12 @@
|
||||||
#ifndef USER_LOCKS_H
|
#ifndef USER_LOCKS_H
|
||||||
#define USER_LOCKS_H
|
#define USER_LOCKS_H
|
||||||
|
|
||||||
int user_lock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
|
extern int user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode);
|
||||||
int user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
|
extern int user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode);
|
||||||
int user_write_lock(unsigned int id1, unsigned int id2);
|
extern int user_write_lock(uint32 id1, uint32 id2);
|
||||||
int user_write_unlock(unsigned int id1, unsigned int id2);
|
extern int user_write_unlock(uint32 id1, uint32 id2);
|
||||||
int user_write_lock_oid(Oid oid);
|
extern int user_write_lock_oid(Oid oid);
|
||||||
int user_write_unlock_oid(Oid oid);
|
extern int user_write_unlock_oid(Oid oid);
|
||||||
int user_unlock_all(void);
|
extern int user_unlock_all(void);
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
#endif
|
||||||
* Local Variables:
|
|
||||||
* tab-width: 4
|
|
||||||
* c-indent-level: 4
|
|
||||||
* c-basic-offset: 4
|
|
||||||
* End:
|
|
||||||
*/
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* 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.
|
* 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
|
* ereport(ERROR) is allowed here, so this routine *must* be called
|
||||||
* before any (unlogged) changes are made in buffer pool.
|
* before any (unlogged) changes are made in buffer pool.
|
||||||
*/
|
*/
|
||||||
|
@ -235,7 +230,7 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
needLock = !RELATION_IS_LOCAL(relation);
|
needLock = !RELATION_IS_LOCAL(relation);
|
||||||
|
|
||||||
if (needLock)
|
if (needLock)
|
||||||
LockPage(relation, 0, ExclusiveLock);
|
LockRelationForExtension(relation, ExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX This does an lseek - rather expensive - but at the moment it is
|
* 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.
|
* extend the relation some more.
|
||||||
*/
|
*/
|
||||||
if (needLock)
|
if (needLock)
|
||||||
UnlockPage(relation, 0, ExclusiveLock);
|
UnlockRelationForExtension(relation, ExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can be certain that locking the otherBuffer first is OK, since
|
* We can be certain that locking the otherBuffer first is OK, since
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
* 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);
|
needLock = !RELATION_IS_LOCAL(rel);
|
||||||
|
|
||||||
if (needLock)
|
if (needLock)
|
||||||
LockPage(rel, 0, ExclusiveLock);
|
LockRelationForExtension(rel, ExclusiveLock);
|
||||||
|
|
||||||
buf = ReadBuffer(rel, P_NEW);
|
buf = ReadBuffer(rel, P_NEW);
|
||||||
|
|
||||||
|
@ -496,7 +496,7 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
||||||
* to extend the relation some more.
|
* to extend the relation some more.
|
||||||
*/
|
*/
|
||||||
if (needLock)
|
if (needLock)
|
||||||
UnlockPage(rel, 0, ExclusiveLock);
|
UnlockRelationForExtension(rel, ExclusiveLock);
|
||||||
|
|
||||||
/* Acquire appropriate buffer lock on new page */
|
/* Acquire appropriate buffer lock on new page */
|
||||||
LockBuffer(buf, access);
|
LockBuffer(buf, access);
|
||||||
|
|
|
@ -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
|
LOCKING OVERVIEW
|
||||||
|
@ -74,30 +74,14 @@ The lock manager's LOCK objects contain:
|
||||||
|
|
||||||
tag -
|
tag -
|
||||||
The key fields that are used for hashing locks in the shared memory
|
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
|
lock hash table. The contents of the tag essentially define an
|
||||||
we always zero out the correct number of bytes. It is critical that
|
individual lockable object. See include/storage/lock.h for details
|
||||||
any alignment-padding bytes the compiler might insert in the struct
|
about the supported types of lockable objects. This is declared as
|
||||||
be zeroed out, else the hash computation will be random.
|
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
|
||||||
tag.relId -
|
might insert in the struct be zeroed out, else the hash computation
|
||||||
Uniquely identifies the relation that the lock corresponds to.
|
will be random. (Currently, we are careful to define struct LOCKTAG
|
||||||
|
so that there are no padding bytes.)
|
||||||
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).
|
|
||||||
|
|
||||||
grantMask -
|
grantMask -
|
||||||
This bitmask indicates what types of locks are currently held on the
|
This bitmask indicates what types of locks are currently held on the
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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:
|
* Interface:
|
||||||
*
|
*
|
||||||
|
@ -836,6 +836,69 @@ PrintLockQueue(LOCK *lock, const char *info)
|
||||||
}
|
}
|
||||||
#endif
|
#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.
|
* Report a detected deadlock, with available details.
|
||||||
*/
|
*/
|
||||||
|
@ -843,9 +906,12 @@ void
|
||||||
DeadLockReport(void)
|
DeadLockReport(void)
|
||||||
{
|
{
|
||||||
StringInfoData buf;
|
StringInfoData buf;
|
||||||
|
StringInfoData buf2;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
initStringInfo(&buf);
|
initStringInfo(&buf);
|
||||||
|
initStringInfo(&buf2);
|
||||||
|
|
||||||
for (i = 0; i < nDeadlockDetails; i++)
|
for (i = 0; i < nDeadlockDetails; i++)
|
||||||
{
|
{
|
||||||
DEADLOCK_INFO *info = &deadlockDetails[i];
|
DEADLOCK_INFO *info = &deadlockDetails[i];
|
||||||
|
@ -860,27 +926,18 @@ DeadLockReport(void)
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
appendStringInfoChar(&buf, '\n');
|
appendStringInfoChar(&buf, '\n');
|
||||||
|
|
||||||
if (info->locktag.relId == XactLockTableId && info->locktag.dbId == 0)
|
/* reset buf2 to hold next object description */
|
||||||
{
|
buf2.len = 0;
|
||||||
/* Lock is for transaction ID */
|
buf2.data[0] = '\0';
|
||||||
appendStringInfo(&buf,
|
|
||||||
_("Process %d waits for %s on transaction %u; blocked by process %d."),
|
DescribeLockTag(&buf2, &info->locktag);
|
||||||
info->pid,
|
|
||||||
GetLockmodeName(info->lockmode),
|
appendStringInfo(&buf,
|
||||||
info->locktag.objId.xid,
|
_("Process %d waits for %s on %s; blocked by process %d."),
|
||||||
nextpid);
|
info->pid,
|
||||||
}
|
GetLockmodeName(info->lockmode),
|
||||||
else
|
buf2.data,
|
||||||
{
|
nextpid);
|
||||||
/* 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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
|
(errcode(ERRCODE_T_R_DEADLOCK_DETECTED),
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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"
|
#include "utils/inval.h"
|
||||||
|
|
||||||
|
|
||||||
static LOCKMASK LockConflicts[] = {
|
/*
|
||||||
|
* This conflict table defines the semantics of the various lock modes.
|
||||||
|
*/
|
||||||
|
static const LOCKMASK LockConflicts[] = {
|
||||||
0,
|
0,
|
||||||
|
|
||||||
/* AccessShareLock */
|
/* AccessShareLock */
|
||||||
|
@ -69,6 +72,7 @@ static LOCKMASK LockConflicts[] = {
|
||||||
|
|
||||||
static LOCKMETHODID LockTableId = INVALID_LOCKMETHOD;
|
static LOCKMETHODID LockTableId = INVALID_LOCKMETHOD;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the lock table described by LockConflicts
|
* Create the lock table described by LockConflicts
|
||||||
*/
|
*/
|
||||||
|
@ -96,11 +100,11 @@ InitLockTable(int maxBackends)
|
||||||
#ifdef USER_LOCKS
|
#ifdef USER_LOCKS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate another tableId for long-term locks
|
* Allocate another tableId for user locks (same shared hashtable though)
|
||||||
*/
|
*/
|
||||||
LongTermTableId = LockMethodTableRename(LockTableId);
|
LongTermTableId = LockMethodTableRename(LockTableId);
|
||||||
if (!LockMethodIsValid(LongTermTableId))
|
if (!LockMethodIsValid(LongTermTableId))
|
||||||
elog(ERROR, "could not rename long-term lock table");
|
elog(ERROR, "could not rename user lock table");
|
||||||
Assert(LongTermTableId == USER_LOCKMETHOD);
|
Assert(LongTermTableId == USER_LOCKMETHOD);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -133,10 +137,9 @@ LockRelation(Relation relation, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_RELATION(tag,
|
||||||
tag.relId = relation->rd_lockInfo.lockRelId.relId;
|
relation->rd_lockInfo.lockRelId.dbId,
|
||||||
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
|
relation->rd_lockInfo.lockRelId.relId);
|
||||||
tag.objId.blkno = InvalidBlockNumber;
|
|
||||||
|
|
||||||
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
||||||
lockmode, false))
|
lockmode, false))
|
||||||
|
@ -167,10 +170,9 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_RELATION(tag,
|
||||||
tag.relId = relation->rd_lockInfo.lockRelId.relId;
|
relation->rd_lockInfo.lockRelId.dbId,
|
||||||
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
|
relation->rd_lockInfo.lockRelId.relId);
|
||||||
tag.objId.blkno = InvalidBlockNumber;
|
|
||||||
|
|
||||||
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
||||||
lockmode, true))
|
lockmode, true))
|
||||||
|
@ -197,10 +199,9 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_RELATION(tag,
|
||||||
tag.relId = relation->rd_lockInfo.lockRelId.relId;
|
relation->rd_lockInfo.lockRelId.dbId,
|
||||||
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
|
relation->rd_lockInfo.lockRelId.relId);
|
||||||
tag.objId.blkno = InvalidBlockNumber;
|
|
||||||
|
|
||||||
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
|
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
|
||||||
}
|
}
|
||||||
|
@ -222,10 +223,7 @@ LockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
|
||||||
tag.relId = relid->relId;
|
|
||||||
tag.dbId = relid->dbId;
|
|
||||||
tag.objId.blkno = InvalidBlockNumber;
|
|
||||||
|
|
||||||
if (!LockAcquire(LockTableId, &tag, InvalidTransactionId,
|
if (!LockAcquire(LockTableId, &tag, InvalidTransactionId,
|
||||||
lockmode, false))
|
lockmode, false))
|
||||||
|
@ -240,30 +238,65 @@ UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
|
||||||
tag.relId = relid->relId;
|
|
||||||
tag.dbId = relid->dbId;
|
|
||||||
tag.objId.blkno = InvalidBlockNumber;
|
|
||||||
|
|
||||||
LockRelease(LockTableId, &tag, InvalidTransactionId, lockmode);
|
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
|
* LockPage
|
||||||
*
|
*
|
||||||
* Obtain a page-level lock. This is currently used by some index access
|
* 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
|
* methods to lock individual index pages.
|
||||||
* blkno == 0 to signify locking the relation for extension.
|
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
|
LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_PAGE(tag,
|
||||||
tag.relId = relation->rd_lockInfo.lockRelId.relId;
|
relation->rd_lockInfo.lockRelId.dbId,
|
||||||
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
|
relation->rd_lockInfo.lockRelId.relId,
|
||||||
tag.objId.blkno = blkno;
|
blkno);
|
||||||
|
|
||||||
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
||||||
lockmode, false))
|
lockmode, false))
|
||||||
|
@ -281,10 +314,10 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_PAGE(tag,
|
||||||
tag.relId = relation->rd_lockInfo.lockRelId.relId;
|
relation->rd_lockInfo.lockRelId.dbId,
|
||||||
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
|
relation->rd_lockInfo.lockRelId.relId,
|
||||||
tag.objId.blkno = blkno;
|
blkno);
|
||||||
|
|
||||||
return LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
return LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
||||||
lockmode, true);
|
lockmode, true);
|
||||||
|
@ -298,10 +331,10 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_PAGE(tag,
|
||||||
tag.relId = relation->rd_lockInfo.lockRelId.relId;
|
relation->rd_lockInfo.lockRelId.dbId,
|
||||||
tag.dbId = relation->rd_lockInfo.lockRelId.dbId;
|
relation->rd_lockInfo.lockRelId.relId,
|
||||||
tag.objId.blkno = blkno;
|
blkno);
|
||||||
|
|
||||||
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
|
LockRelease(LockTableId, &tag, GetTopTransactionId(), lockmode);
|
||||||
}
|
}
|
||||||
|
@ -318,10 +351,7 @@ XactLockTableInsert(TransactionId xid)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_TRANSACTION(tag, xid);
|
||||||
tag.relId = XactLockTableId;
|
|
||||||
tag.dbId = InvalidOid; /* xids are globally unique */
|
|
||||||
tag.objId.xid = xid;
|
|
||||||
|
|
||||||
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
if (!LockAcquire(LockTableId, &tag, GetTopTransactionId(),
|
||||||
ExclusiveLock, false))
|
ExclusiveLock, false))
|
||||||
|
@ -341,10 +371,7 @@ XactLockTableDelete(TransactionId xid)
|
||||||
{
|
{
|
||||||
LOCKTAG tag;
|
LOCKTAG tag;
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_TRANSACTION(tag, xid);
|
||||||
tag.relId = XactLockTableId;
|
|
||||||
tag.dbId = InvalidOid; /* xids are globally unique */
|
|
||||||
tag.objId.xid = xid;
|
|
||||||
|
|
||||||
LockRelease(LockTableId, &tag, GetTopTransactionId(), ExclusiveLock);
|
LockRelease(LockTableId, &tag, GetTopTransactionId(), ExclusiveLock);
|
||||||
}
|
}
|
||||||
|
@ -372,10 +399,7 @@ XactLockTableWait(TransactionId xid)
|
||||||
Assert(TransactionIdIsValid(xid));
|
Assert(TransactionIdIsValid(xid));
|
||||||
Assert(!TransactionIdEquals(xid, myxid));
|
Assert(!TransactionIdEquals(xid, myxid));
|
||||||
|
|
||||||
MemSet(&tag, 0, sizeof(tag));
|
SET_LOCKTAG_TRANSACTION(tag, xid);
|
||||||
tag.relId = XactLockTableId;
|
|
||||||
tag.dbId = InvalidOid;
|
|
||||||
tag.objId.xid = xid;
|
|
||||||
|
|
||||||
if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, false))
|
if (!LockAcquire(LockTableId, &tag, myxid, ShareLock, false))
|
||||||
elog(ERROR, "LockAcquire failed");
|
elog(ERROR, "LockAcquire failed");
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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
|
* NOTES
|
||||||
* Outside modules can create a lock table and acquire/release
|
* Outside modules can create a lock table and acquire/release
|
||||||
|
@ -108,10 +108,11 @@ inline static bool
|
||||||
LOCK_DEBUG_ENABLED(const LOCK *lock)
|
LOCK_DEBUG_ENABLED(const LOCK *lock)
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
(((LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD && Trace_locks)
|
(((Trace_locks && LOCK_LOCKMETHOD(*lock) == DEFAULT_LOCKMETHOD)
|
||||||
|| (LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD && Trace_userlocks))
|
|| (Trace_userlocks && LOCK_LOCKMETHOD(*lock) == USER_LOCKMETHOD))
|
||||||
&& (lock->tag.relId >= (Oid) Trace_lock_oidmin))
|
&& ((Oid) lock->tag.locktag_field2 >= (Oid) Trace_lock_oidmin))
|
||||||
|| (Trace_lock_table && (lock->tag.relId == Trace_lock_table));
|
|| (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))
|
if (LOCK_DEBUG_ENABLED(lock))
|
||||||
elog(LOG,
|
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 "
|
"req(%d,%d,%d,%d,%d,%d,%d)=%d "
|
||||||
"grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
|
"grant(%d,%d,%d,%d,%d,%d,%d)=%d wait(%d) type(%s)",
|
||||||
where, MAKE_OFFSET(lock),
|
where, MAKE_OFFSET(lock),
|
||||||
lock->tag.lockmethodid, lock->tag.relId, lock->tag.dbId,
|
lock->tag.locktag_field1, lock->tag.locktag_field2,
|
||||||
lock->tag.objId.blkno, lock->grantMask,
|
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[1], lock->requested[2], lock->requested[3],
|
||||||
lock->requested[4], lock->requested[5], lock->requested[6],
|
lock->requested[4], lock->requested[5], lock->requested[6],
|
||||||
lock->requested[7], lock->nRequested,
|
lock->requested[7], lock->nRequested,
|
||||||
|
@ -139,14 +142,9 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
|
||||||
inline static void
|
inline static void
|
||||||
PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
|
PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
|
||||||
{
|
{
|
||||||
if (
|
if (LOCK_DEBUG_ENABLED((LOCK *) MAKE_PTR(proclockP->tag.lock)))
|
||||||
(((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))
|
|
||||||
)
|
|
||||||
elog(LOG,
|
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,
|
where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
|
||||||
PROCLOCK_LOCKMETHOD(*(proclockP)),
|
PROCLOCK_LOCKMETHOD(*(proclockP)),
|
||||||
proclockP->tag.proc, proclockP->tag.xid,
|
proclockP->tag.proc, proclockP->tag.xid,
|
||||||
|
@ -346,13 +344,9 @@ LockMethodTableInit(const char *tabName,
|
||||||
* LockMethodTableRename -- allocate another lockmethod ID to the same
|
* LockMethodTableRename -- allocate another lockmethod ID to the same
|
||||||
* lock table.
|
* lock table.
|
||||||
*
|
*
|
||||||
* NOTES: Both the lock module and the lock chain (lchain.c)
|
* NOTES: This function makes it possible to have different lockmethodids,
|
||||||
* module use table id's to distinguish between different
|
* and hence different locking semantics, while still storing all
|
||||||
* kinds of locks. Short term and long term locks look
|
* the data in one shared-memory hashtable.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOCKMETHODID
|
LOCKMETHODID
|
||||||
|
@ -404,33 +398,16 @@ LockMethodTableRename(LOCKMETHODID lockmethodid)
|
||||||
* the lock. While the lock is active other clients can still
|
* the lock. While the lock is active other clients can still
|
||||||
* read and write the tuple but they can be aware that it has
|
* read and write the tuple but they can be aware that it has
|
||||||
* been locked at the application level by someone.
|
* 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
|
* User locks and normal locks are completely orthogonal and
|
||||||
* they don't interfere with each other, so it is possible
|
* they don't interfere with each other.
|
||||||
* to acquire a normal lock on an user-locked tuple or user-lock
|
*
|
||||||
* a tuple for which a normal write lock already exists.
|
|
||||||
* User locks are always non blocking, therefore they are never
|
* User locks are always non blocking, therefore they are never
|
||||||
* acquired if already held by another process. They must be
|
* acquired if already held by another process. They must be
|
||||||
* released explicitly by the application but they are released
|
* released explicitly by the application but they are released
|
||||||
* automatically when a backend terminates.
|
* automatically when a backend terminates.
|
||||||
* They are indicated by a lockmethod 2 which is an alias for the
|
* They are indicated by a lockmethod 2 which is an alias for the
|
||||||
* normal lock table, and are distinguished from normal locks
|
* normal lock table.
|
||||||
* 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
|
|
||||||
*
|
*
|
||||||
* The lockmode parameter can have the same values for normal locks
|
* The lockmode parameter can have the same values for normal locks
|
||||||
* although probably only WRITE_LOCK can have some practical use.
|
* although probably only WRITE_LOCK can have some practical use.
|
||||||
|
@ -456,13 +433,14 @@ LockAcquire(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
#ifdef LOCK_DEBUG
|
#ifdef LOCK_DEBUG
|
||||||
if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
|
if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
|
||||||
elog(LOG, "LockAcquire: user lock [%u] %s",
|
elog(LOG, "LockAcquire: user lock [%u,%u] %s",
|
||||||
locktag->objId.blkno, lock_mode_names[lockmode]);
|
locktag->locktag_field1, locktag->locktag_field2,
|
||||||
|
lock_mode_names[lockmode]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ???????? This must be changed when short term locks will be used */
|
/* ugly */
|
||||||
locktag->lockmethodid = lockmethodid;
|
locktag->locktag_lockmethodid = lockmethodid;
|
||||||
|
|
||||||
Assert(lockmethodid < NumLockMethods);
|
Assert(lockmethodid < NumLockMethods);
|
||||||
lockMethodTable = LockMethods[lockmethodid];
|
lockMethodTable = LockMethods[lockmethodid];
|
||||||
|
@ -1231,12 +1209,14 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
|
||||||
bool wakeupNeeded;
|
bool wakeupNeeded;
|
||||||
|
|
||||||
#ifdef LOCK_DEBUG
|
#ifdef LOCK_DEBUG
|
||||||
if (lockmethodid == USER_LOCKMETHOD && Trace_userlocks)
|
if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
|
||||||
elog(LOG, "LockRelease: user lock tag [%u] %d", locktag->objId.blkno, lockmode);
|
elog(LOG, "LockRelease: user lock [%u,%u] %s",
|
||||||
|
locktag->locktag_field1, locktag->locktag_field2,
|
||||||
|
lock_mode_names[lockmode]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ???????? This must be changed when short term locks will be used */
|
/* ugly */
|
||||||
locktag->lockmethodid = lockmethodid;
|
locktag->locktag_lockmethodid = lockmethodid;
|
||||||
|
|
||||||
Assert(lockmethodid < NumLockMethods);
|
Assert(lockmethodid < NumLockMethods);
|
||||||
lockMethodTable = LockMethods[lockmethodid];
|
lockMethodTable = LockMethods[lockmethodid];
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
|
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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(values, 0, sizeof(values));
|
||||||
MemSet(nulls, ' ', sizeof(nulls));
|
MemSet(nulls, ' ', sizeof(nulls));
|
||||||
|
|
||||||
if (lock->tag.relId == XactLockTableId && lock->tag.dbId == 0)
|
switch (lock->tag.locktag_type)
|
||||||
{
|
{
|
||||||
/* Lock is for transaction ID */
|
case LOCKTAG_RELATION:
|
||||||
nulls[0] = 'n';
|
case LOCKTAG_RELATION_EXTEND:
|
||||||
nulls[1] = 'n';
|
case LOCKTAG_PAGE:
|
||||||
values[2] = TransactionIdGetDatum(lock->tag.objId.xid);
|
case LOCKTAG_TUPLE:
|
||||||
}
|
values[0] = ObjectIdGetDatum(lock->tag.locktag_field2);
|
||||||
else
|
values[1] = ObjectIdGetDatum(lock->tag.locktag_field1);
|
||||||
{
|
nulls[2] = 'n';
|
||||||
/* Lock is for a relation */
|
break;
|
||||||
values[0] = ObjectIdGetDatum(lock->tag.relId);
|
case LOCKTAG_TRANSACTION:
|
||||||
values[1] = ObjectIdGetDatum(lock->tag.dbId);
|
nulls[0] = 'n';
|
||||||
nulls[2] = '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);
|
values[3] = Int32GetDatum(proc->pid);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.116 2005/04/14 01:38:20 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.117 2005/04/29 22:28:24 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -461,14 +461,4 @@ DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
||||||
{ 0, {"indexprs"}, 25, -1, -1, 9, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 0, {"indexprs"}, 25, -1, -1, 9, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 0, {"indpred"}, 25, -1, -1, 10, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
|
{ 0, {"indpred"}, 25, -1, -1, 10, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* pg_xactlock - this is not a real relation, but is a placeholder
|
|
||||||
* to allow a relation OID to be used for transaction
|
|
||||||
* waits. We need a pg_xactlock entry in pg_class only to
|
|
||||||
* ensure that that OID can never be allocated to a real
|
|
||||||
* table; and this entry is just to link to that one.
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
DATA(insert ( 376 xactlockfoo 26 0 4 1 0 -1 -1 t p i t f f t 0));
|
|
||||||
|
|
||||||
#endif /* PG_ATTRIBUTE_H */
|
#endif /* PG_ATTRIBUTE_H */
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.87 2005/04/14 01:38:20 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.88 2005/04/29 22:28:24 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
|
@ -147,11 +147,6 @@ DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 18 0 0
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f _null_ ));
|
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 376 ( pg_xactlock PGNSP 0 PGUID 0 0 1664 0 0 0 0 f t s 1 0 0 0 0 0 f f f f _null_ ));
|
|
||||||
DESCR("");
|
|
||||||
|
|
||||||
/* Xact lock pseudo-table */
|
|
||||||
#define XactLockTableId 376
|
|
||||||
|
|
||||||
#define RELKIND_INDEX 'i' /* secondary index */
|
#define RELKIND_INDEX 'i' /* secondary index */
|
||||||
#define RELKIND_RELATION 'r' /* ordinary cataloged heap */
|
#define RELKIND_RELATION 'r' /* ordinary cataloged heap */
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.46 2005/04/28 21:47:18 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.47 2005/04/29 22:28:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +51,11 @@ extern void UnlockRelation(Relation relation, LOCKMODE lockmode);
|
||||||
extern void LockRelationForSession(LockRelId *relid, LOCKMODE lockmode);
|
extern void LockRelationForSession(LockRelId *relid, LOCKMODE lockmode);
|
||||||
extern void UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode);
|
extern void UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode);
|
||||||
|
|
||||||
/* Lock a page (mainly used for indexes) */
|
/* Lock a relation for extension */
|
||||||
|
extern void LockRelationForExtension(Relation relation, LOCKMODE lockmode);
|
||||||
|
extern void UnlockRelationForExtension(Relation relation, LOCKMODE lockmode);
|
||||||
|
|
||||||
|
/* Lock a page (currently only used within indexes) */
|
||||||
extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
|
extern void LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
|
||||||
extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
|
extern bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
|
||||||
extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
|
extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.84 2004/12/31 22:03:42 pgsql Exp $
|
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.85 2005/04/29 22:28:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -58,7 +58,8 @@ typedef int LOCKMODE;
|
||||||
/*
|
/*
|
||||||
* There is normally only one lock method, the default one.
|
* There is normally only one lock method, the default one.
|
||||||
* If user locks are enabled, an additional lock method is present.
|
* If user locks are enabled, an additional lock method is present.
|
||||||
* Lock methods are identified by LOCKMETHODID.
|
* Lock methods are identified by LOCKMETHODID. (Despite the declaration as
|
||||||
|
* uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.)
|
||||||
*/
|
*/
|
||||||
typedef uint16 LOCKMETHODID;
|
typedef uint16 LOCKMETHODID;
|
||||||
|
|
||||||
|
@ -103,27 +104,100 @@ typedef LockMethodData *LockMethod;
|
||||||
/*
|
/*
|
||||||
* LOCKTAG is the key information needed to look up a LOCK item in the
|
* LOCKTAG is the key information needed to look up a LOCK item in the
|
||||||
* lock hashtable. A LOCKTAG value uniquely identifies a lockable object.
|
* lock hashtable. A LOCKTAG value uniquely identifies a lockable object.
|
||||||
|
*
|
||||||
|
* The LockTagType enum defines the different kinds of objects we can lock.
|
||||||
|
* We can handle up to 256 different LockTagTypes.
|
||||||
|
*/
|
||||||
|
typedef enum LockTagType
|
||||||
|
{
|
||||||
|
LOCKTAG_RELATION, /* whole relation */
|
||||||
|
/* ID info for a relation is DB OID + REL OID; DB OID = 0 if shared */
|
||||||
|
LOCKTAG_RELATION_EXTEND, /* the right to extend a relation */
|
||||||
|
/* same ID info as RELATION */
|
||||||
|
LOCKTAG_PAGE, /* one page of a relation */
|
||||||
|
/* ID info for a page is RELATION info + BlockNumber */
|
||||||
|
LOCKTAG_TUPLE, /* one physical tuple */
|
||||||
|
/* ID info for a tuple is PAGE info + OffsetNumber */
|
||||||
|
LOCKTAG_TRANSACTION, /* transaction (for waiting for xact done) */
|
||||||
|
/* ID info for a transaction is its TransactionId */
|
||||||
|
LOCKTAG_OBJECT, /* non-relation database object */
|
||||||
|
/* ID info for an object is DB OID + CLASS OID + OBJECT OID + SUBID */
|
||||||
|
/*
|
||||||
|
* Note: object ID has same representation as in pg_depend and
|
||||||
|
* pg_description, but notice that we are constraining SUBID to 16 bits.
|
||||||
|
* Also, we use DB OID = 0 for shared objects such as tablespaces.
|
||||||
|
*/
|
||||||
|
LOCKTAG_USERLOCK /* reserved for contrib/userlock */
|
||||||
|
/* ID info for a userlock is defined by user_locks.c */
|
||||||
|
} LockTagType;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The LOCKTAG struct is defined with malice aforethought to fit into 16
|
||||||
|
* bytes with no padding. Note that this would need adjustment if we were
|
||||||
|
* to widen Oid, BlockNumber, or TransactionId to more than 32 bits.
|
||||||
|
*
|
||||||
|
* We include lockmethodid in the locktag so that a single hash table in
|
||||||
|
* shared memory can store locks of different lockmethods. For largely
|
||||||
|
* historical reasons, it's passed to the lock.c routines as a separate
|
||||||
|
* argument and then stored into the locktag.
|
||||||
*/
|
*/
|
||||||
typedef struct LOCKTAG
|
typedef struct LOCKTAG
|
||||||
{
|
{
|
||||||
Oid relId;
|
uint32 locktag_field1; /* a 32-bit ID field */
|
||||||
Oid dbId;
|
uint32 locktag_field2; /* a 32-bit ID field */
|
||||||
union
|
uint32 locktag_field3; /* a 32-bit ID field */
|
||||||
{
|
uint16 locktag_field4; /* a 16-bit ID field */
|
||||||
BlockNumber blkno;
|
uint8 locktag_type; /* see enum LockTagType */
|
||||||
TransactionId xid;
|
uint8 locktag_lockmethodid; /* lockmethod indicator */
|
||||||
} objId;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* offnum should be part of objId union above, but doing that would
|
|
||||||
* increase sizeof(LOCKTAG) due to padding. Currently used by
|
|
||||||
* userlocks only.
|
|
||||||
*/
|
|
||||||
OffsetNumber offnum;
|
|
||||||
|
|
||||||
LOCKMETHODID lockmethodid; /* needed by userlocks */
|
|
||||||
} LOCKTAG;
|
} LOCKTAG;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* These macros define how we map logical IDs of lockable objects into
|
||||||
|
* the physical fields of LOCKTAG. Use these to set up LOCKTAG values,
|
||||||
|
* rather than accessing the fields directly. Note multiple eval of target!
|
||||||
|
*/
|
||||||
|
#define SET_LOCKTAG_RELATION(locktag,dboid,reloid) \
|
||||||
|
((locktag).locktag_field1 = (dboid), \
|
||||||
|
(locktag).locktag_field2 = (reloid), \
|
||||||
|
(locktag).locktag_field3 = 0, \
|
||||||
|
(locktag).locktag_field4 = 0, \
|
||||||
|
(locktag).locktag_type = LOCKTAG_RELATION)
|
||||||
|
|
||||||
|
#define SET_LOCKTAG_RELATION_EXTEND(locktag,dboid,reloid) \
|
||||||
|
((locktag).locktag_field1 = (dboid), \
|
||||||
|
(locktag).locktag_field2 = (reloid), \
|
||||||
|
(locktag).locktag_field3 = 0, \
|
||||||
|
(locktag).locktag_field4 = 0, \
|
||||||
|
(locktag).locktag_type = LOCKTAG_RELATION_EXTEND)
|
||||||
|
|
||||||
|
#define SET_LOCKTAG_PAGE(locktag,dboid,reloid,blocknum) \
|
||||||
|
((locktag).locktag_field1 = (dboid), \
|
||||||
|
(locktag).locktag_field2 = (reloid), \
|
||||||
|
(locktag).locktag_field3 = (blocknum), \
|
||||||
|
(locktag).locktag_field4 = 0, \
|
||||||
|
(locktag).locktag_type = LOCKTAG_PAGE)
|
||||||
|
|
||||||
|
#define SET_LOCKTAG_TUPLE(locktag,dboid,reloid,blocknum,offnum) \
|
||||||
|
((locktag).locktag_field1 = (dboid), \
|
||||||
|
(locktag).locktag_field2 = (reloid), \
|
||||||
|
(locktag).locktag_field3 = (blocknum), \
|
||||||
|
(locktag).locktag_field4 = (offnum), \
|
||||||
|
(locktag).locktag_type = LOCKTAG_TUPLE)
|
||||||
|
|
||||||
|
#define SET_LOCKTAG_TRANSACTION(locktag,xid) \
|
||||||
|
((locktag).locktag_field1 = (xid), \
|
||||||
|
(locktag).locktag_field2 = 0, \
|
||||||
|
(locktag).locktag_field3 = 0, \
|
||||||
|
(locktag).locktag_field4 = 0, \
|
||||||
|
(locktag).locktag_type = LOCKTAG_TRANSACTION)
|
||||||
|
|
||||||
|
#define SET_LOCKTAG_OBJECT(locktag,dboid,classoid,objoid,objsubid) \
|
||||||
|
((locktag).locktag_field1 = (dboid), \
|
||||||
|
(locktag).locktag_field2 = (classoid), \
|
||||||
|
(locktag).locktag_field3 = (objoid), \
|
||||||
|
(locktag).locktag_field4 = (objsubid), \
|
||||||
|
(locktag).locktag_type = LOCKTAG_OBJECT)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per-locked-object lock information:
|
* Per-locked-object lock information:
|
||||||
|
@ -157,7 +231,7 @@ typedef struct LOCK
|
||||||
int nGranted; /* total of granted[] array */
|
int nGranted; /* total of granted[] array */
|
||||||
} LOCK;
|
} LOCK;
|
||||||
|
|
||||||
#define LOCK_LOCKMETHOD(lock) ((lock).tag.lockmethodid)
|
#define LOCK_LOCKMETHOD(lock) ((LOCKMETHODID) (lock).tag.locktag_lockmethodid)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -211,7 +285,7 @@ typedef struct PROCLOCK
|
||||||
} PROCLOCK;
|
} PROCLOCK;
|
||||||
|
|
||||||
#define PROCLOCK_LOCKMETHOD(proclock) \
|
#define PROCLOCK_LOCKMETHOD(proclock) \
|
||||||
(((LOCK *) MAKE_PTR((proclock).tag.lock))->tag.lockmethodid)
|
LOCK_LOCKMETHOD(*((LOCK *) MAKE_PTR((proclock).tag.lock)))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Each backend also maintains a local hash table with information about each
|
* Each backend also maintains a local hash table with information about each
|
||||||
|
@ -253,7 +327,7 @@ typedef struct LOCALLOCK
|
||||||
LOCALLOCKOWNER *lockOwners; /* dynamically resizable array */
|
LOCALLOCKOWNER *lockOwners; /* dynamically resizable array */
|
||||||
} LOCALLOCK;
|
} LOCALLOCK;
|
||||||
|
|
||||||
#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.lockmethodid)
|
#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.locktag_lockmethodid)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue