]> granicus.if.org Git - postgresql/commitdiff
Restructure LOCKTAG as per discussions of a couple months ago.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 29 Apr 2005 22:28:24 +0000 (22:28 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 29 Apr 2005 22:28:24 +0000 (22:28 +0000)
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.

14 files changed:
contrib/userlock/README.user_locks
contrib/userlock/user_locks.c
contrib/userlock/user_locks.h
src/backend/access/heap/hio.c
src/backend/access/nbtree/nbtpage.c
src/backend/storage/lmgr/README
src/backend/storage/lmgr/deadlock.c
src/backend/storage/lmgr/lmgr.c
src/backend/storage/lmgr/lock.c
src/backend/utils/adt/lockfuncs.c
src/include/catalog/pg_attribute.h
src/include/catalog/pg_class.h
src/include/storage/lmgr.h
src/include/storage/lock.h

index 48acdd1d5fe5214de012c4393b1d145524d021d9..5e61d4eea0463fa0dfd3ac299f626f43b874eda9 100644 (file)
@@ -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
 a long period because other transactions would block completely.
 
-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.
-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,
-use a group equal to 0.
+The generic user locks use two values, group and id, to identify a lock.
+Each of these are 32-bit integers.
+
+The oid user lock functions, which take only an OID as argument, store the
+OID as "id" with a group equal to 0.
 
 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
@@ -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
 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
 and it must release the lock the corresponding number of times. This can
index 3dee92ea3168834dd600a6e9bf59cbae1e4c3c61..207610084b1ef3913f33be750f4e1dd41a51344a 100644 (file)
 #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
 user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
 {
        LOCKTAG         tag;
 
-       memset(&tag, 0, sizeof(LOCKTAG));
-       tag.dbId = MyDatabaseId;
-       tag.relId = 0;
-       tag.objId.blkno = (BlockNumber) id2;
-       tag.offnum = (OffsetNumber) (id1 & 0xffff);
+       SET_LOCKTAG_USERLOCK(tag, id1, id2);
 
        return LockAcquire(USER_LOCKMETHOD, &tag, InvalidTransactionId,
                                           lockmode, true);
@@ -38,11 +42,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode)
 {
        LOCKTAG         tag;
 
-       memset(&tag, 0, sizeof(LOCKTAG));
-       tag.dbId = MyDatabaseId;
-       tag.relId = 0;
-       tag.objId.blkno = (BlockNumber) id2;
-       tag.offnum = (OffsetNumber) (id1 & 0xffff);
+       SET_LOCKTAG_USERLOCK(tag, id1, id2);
 
        return LockRelease(USER_LOCKMETHOD, &tag, InvalidTransactionId, lockmode);
 }
@@ -77,13 +77,3 @@ user_unlock_all(void)
 {
        return LockReleaseAll(USER_LOCKMETHOD, true);
 }
-
-/* end of file */
-
-/*
- * Local Variables:
- *     tab-width: 4
- *     c-indent-level: 4
- *     c-basic-offset: 4
- * End:
- */
index 526e864661578a4c83a42c0f75cbe0003f1b0124..e00735d693dd801a5bb68843081d8df99fda75fe 100644 (file)
@@ -1,19 +1,12 @@
 #ifndef USER_LOCKS_H
 #define USER_LOCKS_H
 
-int                    user_lock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
-int                    user_unlock(unsigned int id1, unsigned int id2, LOCKMODE lockmode);
-int                    user_write_lock(unsigned int id1, unsigned int id2);
-int                    user_write_unlock(unsigned int id1, unsigned int id2);
-int                    user_write_lock_oid(Oid oid);
-int                    user_write_unlock_oid(Oid oid);
-int                    user_unlock_all(void);
-#endif
+extern int     user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode);
+extern int     user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode);
+extern int     user_write_lock(uint32 id1, uint32 id2);
+extern int     user_write_unlock(uint32 id1, uint32 id2);
+extern int     user_write_lock_oid(Oid oid);
+extern int     user_write_unlock_oid(Oid oid);
+extern int     user_unlock_all(void);
 
-/*
- * Local Variables:
- *     tab-width: 4
- *     c-indent-level: 4
- *     c-basic-offset: 4
- * End:
- */
+#endif
index 27af323ed11ed3af3958b4bd8696773784dbc62b..db0bda6699b3e47f30a1f9168c23a205c37bcd26 100644 (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
index 2b82a87a1d4f4e614f6bd177d2c4e5f83ac9fb5f..222ed764357af7164d122d4a87d7ab0765c28b70 100644 (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);
index d8489ab12111c74d083ea06faa64853fb3cb9d50..6e5c36e1373e22e354b310d32466b09f6678b6fa 100644 (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
index 7b4ca899b62e2da8b04a155bffb9d290c033fbad..7edabff6dd43f3107cb3926e31e932f4c0484ecd 100644 (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),
index c1a69401ce1788f578afa1aea5ae5431fdc750b4..d527724b9a66981a0d3ad8e2723ee1e1c855dbcf 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 #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");
index 7c7b2b1abdd284ffa8c32eb578fbf6d983b4ebca..576fc205299eebe48047cab9f3dcdf5169ab35fe 100644 (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];
index e6e14647dafe618e12b8b407139de7efccae9bb0..6878662b79f53b77cf5e4f7ff7021f7f49119d9b 100644 (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);
index a58f1d886b9a5103bc9cc40ab0b01ad0daaa708b..ddca993a68a2f68a1c6362c3dd9c39110fc44138 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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
  *       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, {"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 */
index 9ffc79ad8caa0e64ea9214def6c8082729ddebbf..e08d6d60d338df3e53f54c43cc21e60a373f9c82 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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
  *       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("");
 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("");
-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_RELATION                'r'           /* ordinary cataloged heap */
index 8d63294f5cdeb9a82094a68777461efbc90fd040..4d1027c174eda65f0fec960c4c95b7b28959eb17 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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 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 bool ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
 extern void UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode);
index 7f67a3ac3a9007989ced940fe661447b953cd43f..b1744325ff29f7d8c77d27e06d919e21a2118dac 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * 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.
  * 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;
 
@@ -103,27 +104,100 @@ typedef LockMethodData *LockMethod;
 /*
  * LOCKTAG is the key information needed to look up a LOCK item in the
  * 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 struct LOCKTAG
+typedef enum LockTagType
 {
-       Oid                     relId;
-       Oid                     dbId;
-       union
-       {
-               BlockNumber blkno;
-               TransactionId xid;
-       }                       objId;
-
+       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 */
        /*
-        * offnum should be part of objId union above, but doing that would
-        * increase sizeof(LOCKTAG) due to padding.  Currently used by
-        * userlocks only.
+        * 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.
         */
-       OffsetNumber offnum;
+       LOCKTAG_USERLOCK                        /* reserved for contrib/userlock */
+       /* ID info for a userlock is defined by user_locks.c */
+} LockTagType;
 
-       LOCKMETHODID lockmethodid;      /* needed by userlocks */
+/*
+ * 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
+{
+       uint32          locktag_field1;         /* a 32-bit ID field */
+       uint32          locktag_field2;         /* a 32-bit ID field */
+       uint32          locktag_field3;         /* a 32-bit ID field */
+       uint16          locktag_field4;         /* a 16-bit ID field */
+       uint8           locktag_type;           /* see enum LockTagType */
+       uint8           locktag_lockmethodid;   /* lockmethod indicator */
 } 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:
@@ -157,7 +231,7 @@ typedef struct LOCK
        int                     nGranted;               /* total of granted[] array */
 } 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;
 
 #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
@@ -253,7 +327,7 @@ typedef struct LOCALLOCK
        LOCALLOCKOWNER *lockOwners; /* dynamically resizable array */
 } LOCALLOCK;
 
-#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.lockmethodid)
+#define LOCALLOCK_LOCKMETHOD(llock) ((llock).tag.lock.locktag_lockmethodid)
 
 
 /*