diff --git a/contrib/userlock/user_locks.c b/contrib/userlock/user_locks.c
index 0cfc5a2d861c85c5bee4dc85ab2aeb8288d1c2b3..53c48bf0a7fc0afd4b2d288cef1359b12f54f3eb 100644
--- a/contrib/userlock/user_locks.c
+++ b/contrib/userlock/user_locks.c
@@ -23,7 +23,8 @@
 	 (locktag).locktag_field2 = (id1), \
 	 (locktag).locktag_field3 = (id2), \
 	 (locktag).locktag_field4 = 0, \
-	 (locktag).locktag_type = LOCKTAG_USERLOCK)
+	 (locktag).locktag_type = LOCKTAG_USERLOCK, \
+	 (locktag).locktag_lockmethodid = USER_LOCKMETHOD)
 
 
 int
@@ -33,7 +34,7 @@ user_lock(uint32 id1, uint32 id2, LOCKMODE lockmode)
 
 	SET_LOCKTAG_USERLOCK(tag, id1, id2);
 
-	return (LockAcquire(USER_LOCKMETHOD, &tag, false,
+	return (LockAcquire(&tag, false,
 						lockmode, true, true) != LOCKACQUIRE_NOT_AVAIL);
 }
 
@@ -44,7 +45,7 @@ user_unlock(uint32 id1, uint32 id2, LOCKMODE lockmode)
 
 	SET_LOCKTAG_USERLOCK(tag, id1, id2);
 
-	return LockRelease(USER_LOCKMETHOD, &tag, lockmode, true);
+	return LockRelease(&tag, lockmode, true);
 }
 
 int
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 997c38a45c8a765ce8f9963c8eda6a1204cf4ac6..bfe8d52af3028c77c18a49e3dfba2202f6069982 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.79 2005/10/15 02:49:25 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/ipc/ipci.c,v 1.80 2005/12/09 01:22:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,7 +25,7 @@
 #include "storage/bufmgr.h"
 #include "storage/freespace.h"
 #include "storage/ipc.h"
-#include "storage/lmgr.h"
+#include "storage/lock.h"
 #include "storage/lwlock.h"
 #include "storage/pg_sema.h"
 #include "storage/pg_shmem.h"
@@ -159,7 +159,6 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 	 * Set up lock manager
 	 */
 	InitLocks();
-	InitLockTable();
 
 	/*
 	 * Set up process table
diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README
index 943b2f5bc0300c7f86dcbdaa4d66628ed1e841b5..25820f4b73d9e418713a1d85a78ec6273b34e261 100644
--- a/src/backend/storage/lmgr/README
+++ b/src/backend/storage/lmgr/README
@@ -1,4 +1,4 @@
-$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.17 2005/06/14 22:15:32 tgl Exp $
+$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.18 2005/12/09 01:22:04 tgl Exp $
 
 
 LOCKING OVERVIEW
@@ -151,7 +151,7 @@ tag -
         SHMEM offset of the LOCK object this PROCLOCK is for.
 
     tag.proc
-        SHMEM offset of PROC of backend process that owns this PROCLOCK.
+        SHMEM offset of PGPROC of backend process that owns this PROCLOCK.
 
 holdMask -
     A bitmask for the lock types successfully acquired by this PROCLOCK.
@@ -415,3 +415,26 @@ seems a safer approach than trying to allocate workspace on the fly; we
 don't want to risk having the deadlock detector run out of memory, else
 we really have no guarantees at all that deadlock will be detected.
 
+
+USER LOCKS
+
+User locks are handled totally on the application side as long term
+cooperative locks which extend beyond the normal transaction boundaries.
+Their purpose is to indicate to an application that someone is `working'
+on an item.  So it is possible to put an user lock on a tuple's oid,
+retrieve the tuple, work on it for an hour and then update it and remove
+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 and normal locks are completely orthogonal and 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.
+
+The lockmode parameter can have the same values as for normal locks although
+probably only ExclusiveLock can have some practical use.
+
+	DZ - 22 Nov 1997
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index 3a2cdd82a093d56d0a3e6bddc6291e3813249a33..adbd373bb7f00642d2ad9ac641e2a0210b0b3682 100644
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -12,7 +12,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.36 2005/10/29 00:31:51 petere Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.37 2005/12/09 01:22:04 tgl Exp $
  *
  *	Interface:
  *
@@ -930,7 +930,8 @@ DeadLockReport(void)
 		appendStringInfo(&buf,
 				  _("Process %d waits for %s on %s; blocked by process %d."),
 						 info->pid,
-						 GetLockmodeName(info->lockmode),
+						 GetLockmodeName(info->locktag.locktag_lockmethodid,
+										 info->lockmode),
 						 buf2.data,
 						 nextpid);
 	}
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 8ffeced997922b91c2eabc3d103931893cbe9f68..60e374959b036a45bb462c93a3d8f2135b5f647c 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.79 2005/10/15 02:49:26 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lmgr.c,v 1.80 2005/12/09 01:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,96 +18,12 @@
 #include "access/subtrans.h"
 #include "access/transam.h"
 #include "access/xact.h"
-#include "catalog/catalog.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/procarray.h"
 #include "utils/inval.h"
 
 
-/*
- * This conflict table defines the semantics of the various lock modes.
- */
-static const LOCKMASK LockConflicts[] = {
-	0,
-
-	/* AccessShareLock */
-	(1 << AccessExclusiveLock),
-
-	/* RowShareLock */
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
-	/* RowExclusiveLock */
-	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
-	/* ShareUpdateExclusiveLock */
-	(1 << ShareUpdateExclusiveLock) |
-	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
-	/* ShareLock */
-	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
-	(1 << ShareRowExclusiveLock) |
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
-	/* ShareRowExclusiveLock */
-	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
-	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
-	/* ExclusiveLock */
-	(1 << RowShareLock) |
-	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
-	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
-
-	/* AccessExclusiveLock */
-	(1 << AccessShareLock) | (1 << RowShareLock) |
-	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
-	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
-	(1 << ExclusiveLock) | (1 << AccessExclusiveLock)
-
-};
-
-static LOCKMETHODID LockTableId = INVALID_LOCKMETHOD;
-
-
-/*
- * Create the lock table described by LockConflicts
- */
-void
-InitLockTable(void)
-{
-	LOCKMETHODID LongTermTableId;
-
-	/* there's no zero-th table */
-	NumLockMethods = 1;
-
-	/*
-	 * Create the default lock method table
-	 */
-
-	/* number of lock modes is lengthof()-1 because of dummy zero */
-	LockTableId = LockMethodTableInit("LockTable",
-									  LockConflicts,
-									  lengthof(LockConflicts) - 1);
-	if (!LockMethodIsValid(LockTableId))
-		elog(ERROR, "could not initialize lock table");
-	Assert(LockTableId == DEFAULT_LOCKMETHOD);
-
-#ifdef USER_LOCKS
-
-	/*
-	 * Allocate another tableId for user locks (same shared hashtable though)
-	 */
-	LongTermTableId = LockMethodTableRename(LockTableId);
-	if (!LockMethodIsValid(LongTermTableId))
-		elog(ERROR, "could not rename user lock table");
-	Assert(LongTermTableId == USER_LOCKMETHOD);
-#endif
-}
-
 /*
  * RelationInitLockInfo
  *		Initializes the lock information in a relation descriptor.
@@ -141,8 +57,7 @@ LockRelation(Relation relation, LOCKMODE lockmode)
 						 relation->rd_lockInfo.lockRelId.dbId,
 						 relation->rd_lockInfo.lockRelId.relId);
 
-	res = LockAcquire(LockTableId, &tag, relation->rd_istemp,
-					  lockmode, false, false);
+	res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
 
 	/*
 	 * Check to see if the relcache entry has been invalidated while we were
@@ -178,8 +93,7 @@ ConditionalLockRelation(Relation relation, LOCKMODE lockmode)
 						 relation->rd_lockInfo.lockRelId.dbId,
 						 relation->rd_lockInfo.lockRelId.relId);
 
-	res = LockAcquire(LockTableId, &tag, relation->rd_istemp,
-					  lockmode, false, true);
+	res = LockAcquire(&tag, relation->rd_istemp, lockmode, false, true);
 
 	if (res == LOCKACQUIRE_NOT_AVAIL)
 		return false;
@@ -213,7 +127,7 @@ UnlockRelation(Relation relation, LOCKMODE lockmode)
 						 relation->rd_lockInfo.lockRelId.dbId,
 						 relation->rd_lockInfo.lockRelId.relId);
 
-	LockRelease(LockTableId, &tag, lockmode, false);
+	LockRelease(&tag, lockmode, false);
 }
 
 /*
@@ -235,8 +149,7 @@ LockRelationForSession(LockRelId *relid, bool istemprel, LOCKMODE lockmode)
 
 	SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
 
-	(void) LockAcquire(LockTableId, &tag, istemprel,
-					   lockmode, true, false);
+	(void) LockAcquire(&tag, istemprel, lockmode, true, false);
 }
 
 /*
@@ -249,7 +162,7 @@ UnlockRelationForSession(LockRelId *relid, LOCKMODE lockmode)
 
 	SET_LOCKTAG_RELATION(tag, relid->dbId, relid->relId);
 
-	LockRelease(LockTableId, &tag, lockmode, true);
+	LockRelease(&tag, lockmode, true);
 }
 
 /*
@@ -271,8 +184,7 @@ LockRelationForExtension(Relation relation, LOCKMODE lockmode)
 								relation->rd_lockInfo.lockRelId.dbId,
 								relation->rd_lockInfo.lockRelId.relId);
 
-	(void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
-					   lockmode, false, false);
+	(void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
 }
 
 /*
@@ -287,7 +199,7 @@ UnlockRelationForExtension(Relation relation, LOCKMODE lockmode)
 								relation->rd_lockInfo.lockRelId.dbId,
 								relation->rd_lockInfo.lockRelId.relId);
 
-	LockRelease(LockTableId, &tag, lockmode, false);
+	LockRelease(&tag, lockmode, false);
 }
 
 /*
@@ -306,8 +218,7 @@ LockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 					 relation->rd_lockInfo.lockRelId.relId,
 					 blkno);
 
-	(void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
-					   lockmode, false, false);
+	(void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
 }
 
 /*
@@ -326,7 +237,7 @@ ConditionalLockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 					 relation->rd_lockInfo.lockRelId.relId,
 					 blkno);
 
-	return (LockAcquire(LockTableId, &tag, relation->rd_istemp,
+	return (LockAcquire(&tag, relation->rd_istemp,
 						lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
 }
 
@@ -343,7 +254,7 @@ UnlockPage(Relation relation, BlockNumber blkno, LOCKMODE lockmode)
 					 relation->rd_lockInfo.lockRelId.relId,
 					 blkno);
 
-	LockRelease(LockTableId, &tag, lockmode, false);
+	LockRelease(&tag, lockmode, false);
 }
 
 /*
@@ -364,8 +275,7 @@ LockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
 					  ItemPointerGetBlockNumber(tid),
 					  ItemPointerGetOffsetNumber(tid));
 
-	(void) LockAcquire(LockTableId, &tag, relation->rd_istemp,
-					   lockmode, false, false);
+	(void) LockAcquire(&tag, relation->rd_istemp, lockmode, false, false);
 }
 
 /*
@@ -385,7 +295,7 @@ ConditionalLockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
 					  ItemPointerGetBlockNumber(tid),
 					  ItemPointerGetOffsetNumber(tid));
 
-	return (LockAcquire(LockTableId, &tag, relation->rd_istemp,
+	return (LockAcquire(&tag, relation->rd_istemp,
 						lockmode, false, true) != LOCKACQUIRE_NOT_AVAIL);
 }
 
@@ -403,7 +313,7 @@ UnlockTuple(Relation relation, ItemPointer tid, LOCKMODE lockmode)
 					  ItemPointerGetBlockNumber(tid),
 					  ItemPointerGetOffsetNumber(tid));
 
-	LockRelease(LockTableId, &tag, lockmode, false);
+	LockRelease(&tag, lockmode, false);
 }
 
 /*
@@ -420,8 +330,7 @@ XactLockTableInsert(TransactionId xid)
 
 	SET_LOCKTAG_TRANSACTION(tag, xid);
 
-	(void) LockAcquire(LockTableId, &tag, false,
-					   ExclusiveLock, false, false);
+	(void) LockAcquire(&tag, false, ExclusiveLock, false, false);
 }
 
 /*
@@ -439,7 +348,7 @@ XactLockTableDelete(TransactionId xid)
 
 	SET_LOCKTAG_TRANSACTION(tag, xid);
 
-	LockRelease(LockTableId, &tag, ExclusiveLock, false);
+	LockRelease(&tag, ExclusiveLock, false);
 }
 
 /*
@@ -466,10 +375,9 @@ XactLockTableWait(TransactionId xid)
 
 		SET_LOCKTAG_TRANSACTION(tag, xid);
 
-		(void) LockAcquire(LockTableId, &tag, false,
-						   ShareLock, false, false);
+		(void) LockAcquire(&tag, false, ShareLock, false, false);
 
-		LockRelease(LockTableId, &tag, ShareLock, false);
+		LockRelease(&tag, ShareLock, false);
 
 		if (!TransactionIdIsInProgress(xid))
 			break;
@@ -502,11 +410,11 @@ ConditionalXactLockTableWait(TransactionId xid)
 
 		SET_LOCKTAG_TRANSACTION(tag, xid);
 
-		if (LockAcquire(LockTableId, &tag, false,
+		if (LockAcquire(&tag, false,
 						ShareLock, false, true) == LOCKACQUIRE_NOT_AVAIL)
 			return false;
 
-		LockRelease(LockTableId, &tag, ShareLock, false);
+		LockRelease(&tag, ShareLock, false);
 
 		if (!TransactionIdIsInProgress(xid))
 			break;
@@ -545,8 +453,7 @@ LockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
 					   objid,
 					   objsubid);
 
-	(void) LockAcquire(LockTableId, &tag, false,
-					   lockmode, false, false);
+	(void) LockAcquire(&tag, false, lockmode, false, false);
 }
 
 /*
@@ -564,7 +471,7 @@ UnlockDatabaseObject(Oid classid, Oid objid, uint16 objsubid,
 					   objid,
 					   objsubid);
 
-	LockRelease(LockTableId, &tag, lockmode, false);
+	LockRelease(&tag, lockmode, false);
 }
 
 /*
@@ -584,8 +491,7 @@ LockSharedObject(Oid classid, Oid objid, uint16 objsubid,
 					   objid,
 					   objsubid);
 
-	(void) LockAcquire(LockTableId, &tag, false,
-					   lockmode, false, false);
+	(void) LockAcquire(&tag, false, lockmode, false, false);
 }
 
 /*
@@ -603,5 +509,5 @@ UnlockSharedObject(Oid classid, Oid objid, uint16 objsubid,
 					   objid,
 					   objsubid);
 
-	LockRelease(LockTableId, &tag, lockmode, false);
+	LockRelease(&tag, lockmode, false);
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index d703432563c8e7c400c307a99da37765b9f11498..344d677cd2f29104e2e20f27370fe54b577202e8 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,11 +8,10 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.160 2005/11/22 18:17:21 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.161 2005/12/09 01:22:04 tgl Exp $
  *
  * NOTES
- *	  Outside modules can create a lock table and acquire/release
- *	  locks.  A lock table is a shared memory hash table.  When
+ *	  A lock table is a shared memory hash table.  When
  *	  a process tries to acquire a lock of a type that conflicts
  *	  with existing locks, it is put to sleep using the routines
  *	  in storage/lmgr/proc.c.
@@ -22,8 +21,8 @@
  *
  *	Interface:
  *
- *	LockAcquire(), LockRelease(), LockMethodTableInit(),
- *	LockMethodTableRename(), LockReleaseAll(),
+ *	InitLocks(), GetLocksMethodTable(),
+ *	LockAcquire(), LockRelease(), LockReleaseAll(),
  *	LockCheckConflicts(), GrantLock()
  *
  *-------------------------------------------------------------------------
@@ -50,31 +49,54 @@ int			max_locks_per_xact; /* set by guc.c */
 	mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
 
-/* Record that's written to 2PC state file when a lock is persisted */
-typedef struct TwoPhaseLockRecord
-{
-	LOCKTAG		locktag;
-	LOCKMODE	lockmode;
-} TwoPhaseLockRecord;
-
-
 /*
- * map from lock method id to the lock table data structures
+ * Data structures defining the semantics of the standard lock methods.
+ *
+ * The conflict table defines the semantics of the various lock modes.
  */
-static LockMethod LockMethods[MAX_LOCK_METHODS];
-static HTAB *LockMethodLockHash[MAX_LOCK_METHODS];
-static HTAB *LockMethodProcLockHash[MAX_LOCK_METHODS];
-static HTAB *LockMethodLocalHash[MAX_LOCK_METHODS];
-
-/* exported so lmgr.c can initialize it */
-int			NumLockMethods;
-
-
-/* private state for GrantAwaitedLock */
-static LOCALLOCK *awaitedLock;
-static ResourceOwner awaitedOwner;
+static const LOCKMASK LockConflicts[] = {
+	0,
+
+	/* AccessShareLock */
+	(1 << AccessExclusiveLock),
+
+	/* RowShareLock */
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+	/* RowExclusiveLock */
+	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+	/* ShareUpdateExclusiveLock */
+	(1 << ShareUpdateExclusiveLock) |
+	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+	/* ShareLock */
+	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+	(1 << ShareRowExclusiveLock) |
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+	/* ShareRowExclusiveLock */
+	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+	/* ExclusiveLock */
+	(1 << RowShareLock) |
+	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock),
+
+	/* AccessExclusiveLock */
+	(1 << AccessShareLock) | (1 << RowShareLock) |
+	(1 << RowExclusiveLock) | (1 << ShareUpdateExclusiveLock) |
+	(1 << ShareLock) | (1 << ShareRowExclusiveLock) |
+	(1 << ExclusiveLock) | (1 << AccessExclusiveLock)
 
+};
 
+/* Names of lock modes, for debug printouts */
 static const char *const lock_mode_names[] =
 {
 	"INVALID",
@@ -88,6 +110,70 @@ static const char *const lock_mode_names[] =
 	"AccessExclusiveLock"
 };
 
+#ifndef LOCK_DEBUG
+static bool		Dummy_trace = false;
+#endif
+
+static const LockMethodData default_lockmethod = {
+	AccessExclusiveLock,		/* highest valid lock mode number */
+	true,
+	LockConflicts,
+	lock_mode_names,
+#ifdef LOCK_DEBUG
+	&Trace_locks
+#else
+	&Dummy_trace
+#endif
+};
+
+#ifdef USER_LOCKS
+
+static const LockMethodData user_lockmethod = {
+	AccessExclusiveLock,		/* highest valid lock mode number */
+	false,
+	LockConflicts,
+	lock_mode_names,
+#ifdef LOCK_DEBUG
+	&Trace_userlocks
+#else
+	&Dummy_trace
+#endif
+};
+
+#endif /* USER_LOCKS */
+
+/*
+ * map from lock method id to the lock table data structures
+ */
+static const LockMethod LockMethods[] = {
+	NULL,
+	&default_lockmethod,
+#ifdef USER_LOCKS
+	&user_lockmethod
+#endif
+};
+
+
+/* Record that's written to 2PC state file when a lock is persisted */
+typedef struct TwoPhaseLockRecord
+{
+	LOCKTAG		locktag;
+	LOCKMODE	lockmode;
+} TwoPhaseLockRecord;
+
+
+/*
+ * Links to hash tables containing lock state
+ */
+static HTAB *LockMethodLockHash;
+static HTAB *LockMethodProcLockHash;
+static HTAB *LockMethodLocalHash;
+
+
+/* private state for GrantAwaitedLock */
+static LOCALLOCK *awaitedLock;
+static ResourceOwner awaitedOwner;
+
 
 #ifdef LOCK_DEBUG
 
@@ -116,21 +202,20 @@ bool		Debug_deadlocks = false;
 
 
 inline static bool
-LOCK_DEBUG_ENABLED(const LOCK *lock)
+LOCK_DEBUG_ENABLED(const LOCKTAG *tag)
 {
 	return
-		(((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));
+		(*(LockMethods[tag->locktag_lockmethodid]->trace_flag) &&
+		 ((Oid) tag->locktag_field2 >= (Oid) Trace_lock_oidmin))
+		|| (Trace_lock_table &&
+			(tag->locktag_field2 == Trace_lock_table));
 }
 
 
 inline static void
 LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
 {
-	if (LOCK_DEBUG_ENABLED(lock))
+	if (LOCK_DEBUG_ENABLED(&lock->tag))
 		elog(LOG,
 			 "%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
 			 "req(%d,%d,%d,%d,%d,%d,%d)=%d "
@@ -146,14 +231,15 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
 			 lock->granted[1], lock->granted[2], lock->granted[3],
 			 lock->granted[4], lock->granted[5], lock->granted[6],
 			 lock->granted[7], lock->nGranted,
-			 lock->waitProcs.size, lock_mode_names[type]);
+			 lock->waitProcs.size,
+			 LockMethods[LOCK_LOCKMETHOD(*lock)]->lockModeNames[type]);
 }
 
 
 inline static void
 PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
 {
-	if (LOCK_DEBUG_ENABLED((LOCK *) MAKE_PTR(proclockP->tag.lock)))
+	if (LOCK_DEBUG_ENABLED(&((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag))
 		elog(LOG,
 			 "%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) hold(%x)",
 			 where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
@@ -178,107 +264,21 @@ static void CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock,
 
 
 /*
- * InitLocks -- Init the lock module.  Nothing to do here at present.
+ * InitLocks -- Initialize the lock module's shared memory.
  */
 void
 InitLocks(void)
 {
-	/* NOP */
-}
-
-
-/*
- * Fetch the lock method table associated with a given lock
- */
-LockMethod
-GetLocksMethodTable(LOCK *lock)
-{
-	LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
-
-	Assert(0 < lockmethodid && lockmethodid < NumLockMethods);
-	return LockMethods[lockmethodid];
-}
-
-
-/*
- * LockMethodInit -- initialize the lock table's lock type
- *		structures
- *
- * Notes: just copying.  Should only be called once.
- */
-static void
-LockMethodInit(LockMethod lockMethodTable,
-			   const LOCKMASK *conflictsP,
-			   int numModes)
-{
-	int			i;
-
-	lockMethodTable->numLockModes = numModes;
-	/* copies useless zero element as well as the N lockmodes */
-	for (i = 0; i <= numModes; i++)
-		lockMethodTable->conflictTab[i] = conflictsP[i];
-}
-
-/*
- * LockMethodTableInit -- initialize a lock table structure
- *
- * NOTE: data structures allocated here are allocated permanently, using
- * TopMemoryContext and shared memory.	We don't ever release them anyway,
- * and in normal multi-backend operation the lock table structures set up
- * by the postmaster are inherited by each backend, so they must be in
- * TopMemoryContext.
- */
-LOCKMETHODID
-LockMethodTableInit(const char *tabName,
-					const LOCKMASK *conflictsP,
-					int numModes)
-{
-	LockMethod	newLockMethod;
-	LOCKMETHODID lockmethodid;
-	char	   *shmemName;
+	char		shmemName[64];
 	HASHCTL		info;
 	int			hash_flags;
-	bool		found;
 	long		init_table_size,
 				max_table_size;
 
-	if (numModes >= MAX_LOCKMODES)
-		elog(ERROR, "too many lock types %d (limit is %d)",
-			 numModes, MAX_LOCKMODES - 1);
-
 	/* Compute init/max size to request for lock hashtables */
 	max_table_size = NLOCKENTS();
 	init_table_size = max_table_size / 2;
 
-	/* Allocate a string for the shmem index table lookups. */
-	/* This is just temp space in this routine, so palloc is OK. */
-	shmemName = (char *) palloc(strlen(tabName) + 32);
-
-	/* each lock table has a header in shared memory */
-	sprintf(shmemName, "%s (lock method table)", tabName);
-	newLockMethod = (LockMethod)
-		ShmemInitStruct(shmemName, sizeof(LockMethodData), &found);
-
-	if (!newLockMethod)
-		elog(FATAL, "could not initialize lock table \"%s\"", tabName);
-
-	/*
-	 * we're first - initialize
-	 */
-	if (!found)
-	{
-		MemSet(newLockMethod, 0, sizeof(LockMethodData));
-		newLockMethod->masterLock = LockMgrLock;
-		LockMethodInit(newLockMethod, conflictsP, numModes);
-	}
-
-	/*
-	 * other modules refer to the lock table by a lockmethod ID
-	 */
-	Assert(NumLockMethods < MAX_LOCK_METHODS);
-	lockmethodid = NumLockMethods++;
-	LockMethods[lockmethodid] = newLockMethod;
-
 	/*
 	 * allocate a hash table for LOCK structs.	This is used to store
 	 * per-locked-object information.
@@ -289,15 +289,15 @@ LockMethodTableInit(const char *tabName,
 	info.hash = tag_hash;
 	hash_flags = (HASH_ELEM | HASH_FUNCTION);
 
-	sprintf(shmemName, "%s (lock hash)", tabName);
-	LockMethodLockHash[lockmethodid] = ShmemInitHash(shmemName,
-													 init_table_size,
-													 max_table_size,
-													 &info,
-													 hash_flags);
+	sprintf(shmemName, "LOCK hash");
+	LockMethodLockHash = ShmemInitHash(shmemName,
+									   init_table_size,
+									   max_table_size,
+									   &info,
+									   hash_flags);
 
-	if (!LockMethodLockHash[lockmethodid])
-		elog(FATAL, "could not initialize lock table \"%s\"", tabName);
+	if (!LockMethodLockHash)
+		elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
 
 	/*
 	 * allocate a hash table for PROCLOCK structs.	This is used to store
@@ -308,15 +308,15 @@ LockMethodTableInit(const char *tabName,
 	info.hash = tag_hash;
 	hash_flags = (HASH_ELEM | HASH_FUNCTION);
 
-	sprintf(shmemName, "%s (proclock hash)", tabName);
-	LockMethodProcLockHash[lockmethodid] = ShmemInitHash(shmemName,
-														 init_table_size,
-														 max_table_size,
-														 &info,
-														 hash_flags);
+	sprintf(shmemName, "PROCLOCK hash");
+	LockMethodProcLockHash = ShmemInitHash(shmemName,
+										   init_table_size,
+										   max_table_size,
+										   &info,
+										   hash_flags);
 
-	if (!LockMethodProcLockHash[lockmethodid])
-		elog(FATAL, "could not initialize lock table \"%s\"", tabName);
+	if (!LockMethodProcLockHash)
+		elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
 
 	/*
 	 * allocate a non-shared hash table for LOCALLOCK structs.	This is used
@@ -327,62 +327,39 @@ LockMethodTableInit(const char *tabName,
 	 * If so, delete and recreate it.  (We could simply leave it, since it
 	 * ought to be empty in the postmaster, but for safety let's zap it.)
 	 */
-	if (LockMethodLocalHash[lockmethodid])
-		hash_destroy(LockMethodLocalHash[lockmethodid]);
+	if (LockMethodLocalHash)
+		hash_destroy(LockMethodLocalHash);
 
 	info.keysize = sizeof(LOCALLOCKTAG);
 	info.entrysize = sizeof(LOCALLOCK);
 	info.hash = tag_hash;
 	hash_flags = (HASH_ELEM | HASH_FUNCTION);
 
-	sprintf(shmemName, "%s (locallock hash)", tabName);
-	LockMethodLocalHash[lockmethodid] = hash_create(shmemName,
-													128,
-													&info,
-													hash_flags);
-
-	pfree(shmemName);
-
-	return lockmethodid;
+	LockMethodLocalHash = hash_create("LOCALLOCK hash",
+									  128,
+									  &info,
+									  hash_flags);
 }
 
+
 /*
- * LockMethodTableRename -- allocate another lockmethod ID to the same
- *		lock table.
- *
- * 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.
+ * Fetch the lock method table associated with a given lock
  */
-
-LOCKMETHODID
-LockMethodTableRename(LOCKMETHODID lockmethodid)
+LockMethod
+GetLocksMethodTable(const LOCK *lock)
 {
-	LOCKMETHODID newLockMethodId;
-
-	if (NumLockMethods >= MAX_LOCK_METHODS)
-		return INVALID_LOCKMETHOD;
-	if (LockMethods[lockmethodid] == INVALID_LOCKMETHOD)
-		return INVALID_LOCKMETHOD;
-
-	/* other modules refer to the lock table by a lockmethod ID */
-	newLockMethodId = NumLockMethods;
-	NumLockMethods++;
-
-	LockMethods[newLockMethodId] = LockMethods[lockmethodid];
-	LockMethodLockHash[newLockMethodId] = LockMethodLockHash[lockmethodid];
-	LockMethodProcLockHash[newLockMethodId] = LockMethodProcLockHash[lockmethodid];
-	LockMethodLocalHash[newLockMethodId] = LockMethodLocalHash[lockmethodid];
+	LOCKMETHODID lockmethodid = LOCK_LOCKMETHOD(*lock);
 
-	return newLockMethodId;
+	Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
+	return LockMethods[lockmethodid];
 }
 
+
 /*
  * LockAcquire -- Check for lock conflicts, sleep if conflict found,
  *		set lock if/when no conflicts.
  *
  * Inputs:
- *	lockmethodid: identifies which lock table to use
  *	locktag: unique identifier for the lockable object
  *	isTempObject: is the lockable object a temporary object?  (Under 2PC,
  *		such locks cannot be persisted)
@@ -403,43 +380,16 @@ LockMethodTableRename(LOCKMETHODID lockmethodid)
  *
  * NOTE: if we wait for the lock, there is no way to abort the wait
  * short of aborting the transaction.
- *
- *
- * Note on User Locks:
- *
- *		User locks are handled totally on the application side as
- *		long term cooperative locks which extend beyond the normal
- *		transaction boundaries.  Their purpose is to indicate to an
- *		application that someone is `working' on an item.  So it is
- *		possible to put an user lock on a tuple's oid, retrieve the
- *		tuple, work on it for an hour and then update it and remove
- *		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 and normal locks are completely orthogonal and
- *		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.
- *
- *		The lockmode parameter can have the same values for normal locks
- *		although probably only WRITE_LOCK can have some practical use.
- *
- *														DZ - 22 Nov 1997
  */
 LockAcquireResult
-LockAcquire(LOCKMETHODID lockmethodid,
-			LOCKTAG *locktag,
+LockAcquire(const LOCKTAG *locktag,
 			bool isTempObject,
 			LOCKMODE lockmode,
 			bool sessionLock,
 			bool dontWait)
 {
+	LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
+	LockMethod	lockMethodTable;
 	LOCALLOCKTAG localtag;
 	LOCALLOCK  *locallock;
 	LOCK	   *lock;
@@ -448,26 +398,23 @@ LockAcquire(LOCKMETHODID lockmethodid,
 	bool		found;
 	ResourceOwner owner;
 	LWLockId	masterLock;
-	LockMethod	lockMethodTable;
 	int			status;
 
+	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
+		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+	lockMethodTable = LockMethods[lockmethodid];
+	if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
+		elog(ERROR, "unrecognized lock mode: %d", lockmode);
+
 #ifdef LOCK_DEBUG
-	if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
-		elog(LOG, "LockAcquire: user lock [%u,%u] %s",
+	if (LOCK_DEBUG_ENABLED(locktag))
+		elog(LOG, "LockAcquire: lock [%u,%u] %s",
 			 locktag->locktag_field1, locktag->locktag_field2,
-			 lock_mode_names[lockmode]);
+			 lockMethodTable->lockModeNames[lockmode]);
 #endif
 
-	/* ugly */
-	locktag->locktag_lockmethodid = lockmethodid;
-
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
-		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
-	/* Session locks and user locks are not transactional */
-	if (!sessionLock && lockmethodid == DEFAULT_LOCKMETHOD)
+	/* Session locks are never transactional, else check table */
+	if (!sessionLock && lockMethodTable->transactional)
 		owner = CurrentResourceOwner;
 	else
 		owner = NULL;
@@ -479,7 +426,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 	localtag.lock = *locktag;
 	localtag.mode = lockmode;
 
-	locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],
+	locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
 										  (void *) &localtag,
 										  HASH_ENTER, &found);
 
@@ -527,7 +474,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 	/*
 	 * Otherwise we've got to mess with the shared lock table.
 	 */
-	masterLock = lockMethodTable->masterLock;
+	masterLock = LockMgrLock;
 
 	LWLockAcquire(masterLock, LW_EXCLUSIVE);
 
@@ -539,7 +486,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 	 * pointer is valid, since a lock object with no locks can go away
 	 * anytime.
 	 */
-	lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
+	lock = (LOCK *) hash_search(LockMethodLockHash,
 								(void *) locktag,
 								HASH_ENTER_NULL, &found);
 	if (!lock)
@@ -585,7 +532,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 	/*
 	 * Find or create a proclock entry with this tag
 	 */
-	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
 										(void *) &proclocktag,
 										HASH_ENTER_NULL, &found);
 	if (!proclock)
@@ -600,7 +547,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 			 * anyone to release the lock object later.
 			 */
 			Assert(SHMQueueEmpty(&(lock->procLocks)));
-			if (!hash_search(LockMethodLockHash[lockmethodid],
+			if (!hash_search(LockMethodLockHash,
 							 (void *) &(lock->tag),
 							 HASH_REMOVE, NULL))
 				elog(PANIC, "lock table corrupted");
@@ -657,7 +604,8 @@ LockAcquire(LOCKMETHODID lockmethodid,
 						break;	/* safe: we have a lock >= req level */
 					elog(LOG, "deadlock risk: raising lock level"
 						 " from %s to %s on object %u/%u/%u",
-						 lock_mode_names[i], lock_mode_names[lockmode],
+						 lockMethodTable->lockModeNames[i],
+						 lockMethodTable->lockModeNames[lockmode],
 						 lock->tag.locktag_field1, lock->tag.locktag_field2,
 						 lock->tag.locktag_field3);
 					break;
@@ -682,7 +630,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 	 */
 	if (proclock->holdMask & LOCKBIT_ON(lockmode))
 		elog(ERROR, "lock %s on object %u/%u/%u is already held",
-			 lock_mode_names[lockmode],
+			 lockMethodTable->lockModeNames[lockmode],
 			 lock->tag.locktag_field1, lock->tag.locktag_field2,
 			 lock->tag.locktag_field3);
 
@@ -718,7 +666,7 @@ LockAcquire(LOCKMETHODID lockmethodid,
 			{
 				SHMQueueDelete(&proclock->lockLink);
 				SHMQueueDelete(&proclock->procLink);
-				if (!hash_search(LockMethodProcLockHash[lockmethodid],
+				if (!hash_search(LockMethodProcLockHash,
 								 (void *) &(proclock->tag),
 								 HASH_REMOVE, NULL))
 					elog(PANIC, "proclock table corrupted");
@@ -779,11 +727,9 @@ LockAcquire(LOCKMETHODID lockmethodid,
 static void
 RemoveLocalLock(LOCALLOCK *locallock)
 {
-	LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
-
 	pfree(locallock->lockOwners);
 	locallock->lockOwners = NULL;
-	if (!hash_search(LockMethodLocalHash[lockmethodid],
+	if (!hash_search(LockMethodLocalHash,
 					 (void *) &(locallock->tag),
 					 HASH_REMOVE, NULL))
 		elog(WARNING, "locallock table corrupted");
@@ -964,7 +910,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,
 		PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
 		SHMQueueDelete(&proclock->lockLink);
 		SHMQueueDelete(&proclock->procLink);
-		if (!hash_search(LockMethodProcLockHash[lockmethodid],
+		if (!hash_search(LockMethodProcLockHash,
 						 (void *) &(proclock->tag),
 						 HASH_REMOVE, NULL))
 			elog(PANIC, "proclock table corrupted");
@@ -978,7 +924,7 @@ CleanUpLock(LOCKMETHODID lockmethodid, LOCK *lock, PROCLOCK *proclock,
 		 */
 		LOCK_PRINT("CleanUpLock: deleting", lock, 0);
 		Assert(SHMQueueEmpty(&(lock->procLocks)));
-		if (!hash_search(LockMethodLockHash[lockmethodid],
+		if (!hash_search(LockMethodLockHash,
 						 (void *) &(lock->tag),
 						 HASH_REMOVE, NULL))
 			elog(PANIC, "lock table corrupted");
@@ -1053,8 +999,6 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
 	char	   *new_status;
 	int			len;
 
-	Assert(lockmethodid < NumLockMethods);
-
 	LOCK_PRINT("WaitOnLock: sleeping on lock",
 			   locallock->lock, locallock->tag.mode);
 
@@ -1092,7 +1036,7 @@ WaitOnLock(LOCKMETHODID lockmethodid, LOCALLOCK *locallock,
 		awaitedLock = NULL;
 		LOCK_PRINT("WaitOnLock: aborting on lock",
 				   locallock->lock, locallock->tag.mode);
-		LWLockRelease(lockMethodTable->masterLock);
+		LWLockRelease(LockMgrLock);
 
 		/*
 		 * Now that we aren't holding the LockMgrLock, we can give an error
@@ -1131,7 +1075,7 @@ RemoveFromWaitQueue(PGPROC *proc)
 	Assert(proc->links.next != INVALID_OFFSET);
 	Assert(waitLock);
 	Assert(waitLock->waitProcs.size > 0);
-	Assert(0 < lockmethodid && lockmethodid < NumLockMethods);
+	Assert(0 < lockmethodid && lockmethodid < lengthof(LockMethods));
 
 	/* Remove proc from lock's wait queue */
 	SHMQueueDelete(&(proc->links));
@@ -1162,9 +1106,9 @@ RemoveFromWaitQueue(PGPROC *proc)
 }
 
 /*
- * LockRelease -- look up 'locktag' in lock table 'lockmethodid' and
- *		release one 'lockmode' lock on it.	Release a session lock if
- *		'sessionLock' is true, else release a regular transaction lock.
+ * LockRelease -- look up 'locktag' and release one 'lockmode' lock on it.
+ *		Release a session lock if 'sessionLock' is true, else release a
+ *		regular transaction lock.
  *
  * Side Effects: find any waiting processes that are now wakable,
  *		grant them their requested locks and awaken them.
@@ -1173,32 +1117,30 @@ RemoveFromWaitQueue(PGPROC *proc)
  *		come along and request the lock.)
  */
 bool
-LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
-			LOCKMODE lockmode, bool sessionLock)
+LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 {
+	LOCKMETHODID lockmethodid = locktag->locktag_lockmethodid;
+	LockMethod	lockMethodTable;
 	LOCALLOCKTAG localtag;
 	LOCALLOCK  *locallock;
 	LOCK	   *lock;
 	PROCLOCK   *proclock;
 	LWLockId	masterLock;
-	LockMethod	lockMethodTable;
 	bool		wakeupNeeded;
 
+	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
+		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+	lockMethodTable = LockMethods[lockmethodid];
+	if (lockmode <= 0 || lockmode > lockMethodTable->numLockModes)
+		elog(ERROR, "unrecognized lock mode: %d", lockmode);
+
 #ifdef LOCK_DEBUG
-	if (Trace_userlocks && lockmethodid == USER_LOCKMETHOD)
-		elog(LOG, "LockRelease: user lock [%u,%u] %s",
+	if (LOCK_DEBUG_ENABLED(locktag))
+		elog(LOG, "LockRelease: lock [%u,%u] %s",
 			 locktag->locktag_field1, locktag->locktag_field2,
-			 lock_mode_names[lockmode]);
+			 lockMethodTable->lockModeNames[lockmode]);
 #endif
 
-	/* ugly */
-	locktag->locktag_lockmethodid = lockmethodid;
-
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
-		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
 	/*
 	 * Find the LOCALLOCK entry for this lock and lockmode
 	 */
@@ -1206,7 +1148,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
 	localtag.lock = *locktag;
 	localtag.mode = lockmode;
 
-	locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash[lockmethodid],
+	locallock = (LOCALLOCK *) hash_search(LockMethodLocalHash,
 										  (void *) &localtag,
 										  HASH_FIND, NULL);
 
@@ -1216,7 +1158,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
 	if (!locallock || locallock->nLocks <= 0)
 	{
 		elog(WARNING, "you don't own a lock of type %s",
-			 lock_mode_names[lockmode]);
+			 lockMethodTable->lockModeNames[lockmode]);
 		return FALSE;
 	}
 
@@ -1228,8 +1170,8 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
 		ResourceOwner owner;
 		int			i;
 
-		/* Session locks and user locks are not transactional */
-		if (!sessionLock && lockmethodid == DEFAULT_LOCKMETHOD)
+		/* Session locks are never transactional, else check table */
+		if (!sessionLock && lockMethodTable->transactional)
 			owner = CurrentResourceOwner;
 		else
 			owner = NULL;
@@ -1253,7 +1195,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
 		{
 			/* don't release a lock belonging to another owner */
 			elog(WARNING, "you don't own a lock of type %s",
-				 lock_mode_names[lockmode]);
+				 lockMethodTable->lockModeNames[lockmode]);
 			return FALSE;
 		}
 	}
@@ -1270,7 +1212,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
 	/*
 	 * Otherwise we've got to mess with the shared lock table.
 	 */
-	masterLock = lockMethodTable->masterLock;
+	masterLock = LockMgrLock;
 
 	LWLockAcquire(masterLock, LW_EXCLUSIVE);
 
@@ -1293,7 +1235,7 @@ LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
 		PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
 		LWLockRelease(masterLock);
 		elog(WARNING, "you don't own a lock of type %s",
-			 lock_mode_names[lockmode]);
+			 lockMethodTable->lockModeNames[lockmode]);
 		RemoveLocalLock(locallock);
 		return FALSE;
 	}
@@ -1332,18 +1274,17 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
 	PROCLOCK   *proclock;
 	LOCK	   *lock;
 
+	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
+		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+	lockMethodTable = LockMethods[lockmethodid];
+
 #ifdef LOCK_DEBUG
-	if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)
+	if (*(lockMethodTable->trace_flag))
 		elog(LOG, "LockReleaseAll: lockmethod=%d", lockmethodid);
 #endif
 
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
-		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
 	numLockModes = lockMethodTable->numLockModes;
-	masterLock = lockMethodTable->masterLock;
+	masterLock = LockMgrLock;
 
 	/*
 	 * First we run through the locallock table and get rid of unwanted
@@ -1352,7 +1293,7 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
 	 * pointing to the same proclock, and we daren't end up with any dangling
 	 * pointers.
 	 */
-	hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);
+	hash_seq_init(&status, LockMethodLocalHash);
 
 	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 	{
@@ -1480,7 +1421,7 @@ next_item:
 	LWLockRelease(masterLock);
 
 #ifdef LOCK_DEBUG
-	if (lockmethodid == USER_LOCKMETHOD ? Trace_userlocks : Trace_locks)
+	if (*(lockMethodTable->trace_flag))
 		elog(LOG, "LockReleaseAll done");
 #endif
 }
@@ -1488,8 +1429,6 @@ next_item:
 /*
  * LockReleaseCurrentOwner
  *		Release all locks belonging to CurrentResourceOwner
- *
- * Only DEFAULT_LOCKMETHOD locks can belong to a resource owner.
  */
 void
 LockReleaseCurrentOwner(void)
@@ -1499,12 +1438,12 @@ LockReleaseCurrentOwner(void)
 	LOCALLOCKOWNER *lockOwners;
 	int			i;
 
-	hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]);
+	hash_seq_init(&status, LockMethodLocalHash);
 
 	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 	{
 		/* Ignore items that must be nontransactional */
-		if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)
+		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 			continue;
 
 		/* Scan to see if there are any locks belonging to current owner */
@@ -1532,8 +1471,7 @@ LockReleaseCurrentOwner(void)
 					/* We want to call LockRelease just once */
 					lockOwners[i].nLocks = 1;
 					locallock->nLocks = 1;
-					if (!LockRelease(DEFAULT_LOCKMETHOD,
-									 &locallock->tag.lock,
+					if (!LockRelease(&locallock->tag.lock,
 									 locallock->tag.mode,
 									 false))
 						elog(WARNING, "LockReleaseCurrentOwner: failed??");
@@ -1559,7 +1497,7 @@ LockReassignCurrentOwner(void)
 
 	Assert(parent != NULL);
 
-	hash_seq_init(&status, LockMethodLocalHash[DEFAULT_LOCKMETHOD]);
+	hash_seq_init(&status, LockMethodLocalHash);
 
 	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 	{
@@ -1568,7 +1506,7 @@ LockReassignCurrentOwner(void)
 		int			ip = -1;
 
 		/* Ignore items that must be nontransactional */
-		if (LOCALLOCK_LOCKMETHOD(*locallock) != DEFAULT_LOCKMETHOD)
+		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 			continue;
 
 		/*
@@ -1610,7 +1548,7 @@ LockReassignCurrentOwner(void)
  *		Do the preparatory work for a PREPARE: make 2PC state file records
  *		for all locks currently held.
  *
- * User locks are non-transactional and are therefore ignored.
+ * Non-transactional locks are ignored.
  *
  * There are some special cases that we error out on: we can't be holding
  * any session locks (should be OK since only VACUUM uses those) and we
@@ -1621,7 +1559,6 @@ LockReassignCurrentOwner(void)
 void
 AtPrepare_Locks(void)
 {
-	LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
 	HASH_SEQ_STATUS status;
 	LOCALLOCK  *locallock;
 
@@ -1629,7 +1566,7 @@ AtPrepare_Locks(void)
 	 * We don't need to touch shared memory for this --- all the necessary
 	 * state information is in the locallock table.
 	 */
-	hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);
+	hash_seq_init(&status, LockMethodLocalHash);
 
 	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 	{
@@ -1637,8 +1574,8 @@ AtPrepare_Locks(void)
 		LOCALLOCKOWNER *lockOwners = locallock->lockOwners;
 		int			i;
 
-		/* Ignore items that are not of the lockmethod to be processed */
-		if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
+		/* Ignore nontransactional locks */
+		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 			continue;
 
 		/* Ignore it if we don't actually hold the lock */
@@ -1689,12 +1626,9 @@ void
 PostPrepare_Locks(TransactionId xid)
 {
 	PGPROC	   *newproc = TwoPhaseGetDummyProc(xid);
-	LOCKMETHODID lockmethodid = DEFAULT_LOCKMETHOD;
 	HASH_SEQ_STATUS status;
 	SHM_QUEUE  *procLocks = &(MyProc->procLocks);
 	LWLockId	masterLock;
-	LockMethod	lockMethodTable;
-	int			numLockModes;
 	LOCALLOCK  *locallock;
 	PROCLOCK   *proclock;
 	PROCLOCKTAG proclocktag;
@@ -1704,12 +1638,7 @@ PostPrepare_Locks(TransactionId xid)
 	/* This is a critical section: any error means big trouble */
 	START_CRIT_SECTION();
 
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
-		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
-
-	numLockModes = lockMethodTable->numLockModes;
-	masterLock = lockMethodTable->masterLock;
+	masterLock = LockMgrLock;
 
 	/*
 	 * First we run through the locallock table and get rid of unwanted
@@ -1720,7 +1649,7 @@ PostPrepare_Locks(TransactionId xid)
 	 * pointing to the same proclock, and we daren't end up with any dangling
 	 * pointers.
 	 */
-	hash_seq_init(&status, LockMethodLocalHash[lockmethodid]);
+	hash_seq_init(&status, LockMethodLocalHash);
 
 	while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
 	{
@@ -1735,8 +1664,8 @@ PostPrepare_Locks(TransactionId xid)
 			continue;
 		}
 
-		/* Ignore items that are not of the lockmethod to be removed */
-		if (LOCALLOCK_LOCKMETHOD(*locallock) != lockmethodid)
+		/* Ignore nontransactional locks */
+		if (!LockMethods[LOCALLOCK_LOCKMETHOD(*locallock)]->transactional)
 			continue;
 
 		/* We already checked there are no session locks */
@@ -1768,8 +1697,8 @@ PostPrepare_Locks(TransactionId xid)
 
 		lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
 
-		/* Ignore items that are not of the lockmethod to be removed */
-		if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
+		/* Ignore nontransactional locks */
+		if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
 			goto next_item;
 
 		PROCLOCK_PRINT("PostPrepare_Locks", proclock);
@@ -1798,7 +1727,7 @@ PostPrepare_Locks(TransactionId xid)
 		 */
 		SHMQueueDelete(&proclock->lockLink);
 		SHMQueueDelete(&proclock->procLink);
-		if (!hash_search(LockMethodProcLockHash[lockmethodid],
+		if (!hash_search(LockMethodProcLockHash,
 						 (void *) &(proclock->tag),
 						 HASH_REMOVE, NULL))
 			elog(PANIC, "proclock table corrupted");
@@ -1810,7 +1739,7 @@ PostPrepare_Locks(TransactionId xid)
 		proclocktag.lock = MAKE_OFFSET(lock);
 		proclocktag.proc = MAKE_OFFSET(newproc);
 
-		newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+		newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
 											   (void *) &proclocktag,
 											   HASH_ENTER_NULL, &found);
 		if (!newproclock)
@@ -1859,12 +1788,9 @@ next_item:
 Size
 LockShmemSize(void)
 {
-	Size		size;
+	Size		size = 0;
 	long		max_table_size = NLOCKENTS();
 
-	/* lock method headers */
-	size = MAX_LOCK_METHODS * MAXALIGN(sizeof(LockMethodData));
-
 	/* lockHash table */
 	size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
 
@@ -1910,7 +1836,7 @@ GetLockStatusData(void)
 
 	LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
 
-	proclockTable = LockMethodProcLockHash[DEFAULT_LOCKMETHOD];
+	proclockTable = LockMethodProcLockHash;
 
 	data->nelements = i = proclockTable->hctl->nentries;
 
@@ -1944,17 +1870,18 @@ GetLockStatusData(void)
 
 /* Provide the textual name of any lock mode */
 const char *
-GetLockmodeName(LOCKMODE mode)
+GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode)
 {
-	Assert(mode <= MAX_LOCKMODES);
-	return lock_mode_names[mode];
+	Assert(lockmethodid > 0 && lockmethodid < lengthof(LockMethods));
+	Assert(mode > 0 && mode <= LockMethods[lockmethodid]->numLockModes);
+	return LockMethods[lockmethodid]->lockModeNames[mode];
 }
 
 #ifdef LOCK_DEBUG
 /*
  * Dump all locks in the given proc's procLocks list.
  *
- * Must have already acquired the masterLock.
+ * Caller is responsible for having acquired appropriate LWLocks.
  */
 void
 DumpLocks(PGPROC *proc)
@@ -1962,19 +1889,12 @@ DumpLocks(PGPROC *proc)
 	SHM_QUEUE  *procLocks;
 	PROCLOCK   *proclock;
 	LOCK	   *lock;
-	int			lockmethodid = DEFAULT_LOCKMETHOD;
-	LockMethod	lockMethodTable;
 
 	if (proc == NULL)
 		return;
 
 	procLocks = &proc->procLocks;
 
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
-		return;
-
 	if (proc->waitLock)
 		LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
 
@@ -1996,7 +1916,9 @@ DumpLocks(PGPROC *proc)
 }
 
 /*
- * Dump all postgres locks. Must have already acquired the masterLock.
+ * Dump all lmgr locks.
+ *
+ * Caller is responsible for having acquired appropriate LWLocks.
  */
 void
 DumpAllLocks(void)
@@ -2004,23 +1926,13 @@ DumpAllLocks(void)
 	PGPROC	   *proc;
 	PROCLOCK   *proclock;
 	LOCK	   *lock;
-	int			lockmethodid = DEFAULT_LOCKMETHOD;
-	LockMethod	lockMethodTable;
 	HTAB	   *proclockTable;
 	HASH_SEQ_STATUS status;
 
 	proc = MyProc;
-	if (proc == NULL)
-		return;
-
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
-		return;
-
-	proclockTable = LockMethodProcLockHash[lockmethodid];
+	proclockTable = LockMethodProcLockHash;
 
-	if (proc->waitLock)
+	if (proc && proc->waitLock)
 		LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
 
 	hash_seq_init(&status, proclockTable);
@@ -2071,19 +1983,18 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 	lockmode = rec->lockmode;
 	lockmethodid = locktag->locktag_lockmethodid;
 
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
+	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+	lockMethodTable = LockMethods[lockmethodid];
 
-	masterLock = lockMethodTable->masterLock;
+	masterLock = LockMgrLock;
 
 	LWLockAcquire(masterLock, LW_EXCLUSIVE);
 
 	/*
 	 * Find or create a lock with this tag.
 	 */
-	lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
+	lock = (LOCK *) hash_search(LockMethodLockHash,
 								(void *) locktag,
 								HASH_ENTER_NULL, &found);
 	if (!lock)
@@ -2128,7 +2039,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 	/*
 	 * Find or create a proclock entry with this tag
 	 */
-	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
 										(void *) &proclocktag,
 										HASH_ENTER_NULL, &found);
 	if (!proclock)
@@ -2143,7 +2054,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 			 * anyone to release the lock object later.
 			 */
 			Assert(SHMQueueEmpty(&(lock->procLocks)));
-			if (!hash_search(LockMethodLockHash[lockmethodid],
+			if (!hash_search(LockMethodLockHash,
 							 (void *) &(lock->tag),
 							 HASH_REMOVE, NULL))
 				elog(PANIC, "lock table corrupted");
@@ -2186,7 +2097,7 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 	 */
 	if (proclock->holdMask & LOCKBIT_ON(lockmode))
 		elog(ERROR, "lock %s on object %u/%u/%u is already held",
-			 lock_mode_names[lockmode],
+			 lockMethodTable->lockModeNames[lockmode],
 			 lock->tag.locktag_field1, lock->tag.locktag_field2,
 			 lock->tag.locktag_field3);
 
@@ -2224,19 +2135,18 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
 	lockmode = rec->lockmode;
 	lockmethodid = locktag->locktag_lockmethodid;
 
-	Assert(lockmethodid < NumLockMethods);
-	lockMethodTable = LockMethods[lockmethodid];
-	if (!lockMethodTable)
+	if (lockmethodid <= 0 || lockmethodid >= lengthof(LockMethods))
 		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
+	lockMethodTable = LockMethods[lockmethodid];
 
-	masterLock = lockMethodTable->masterLock;
+	masterLock = LockMgrLock;
 
 	LWLockAcquire(masterLock, LW_EXCLUSIVE);
 
 	/*
 	 * Re-find the lock object (it had better be there).
 	 */
-	lock = (LOCK *) hash_search(LockMethodLockHash[lockmethodid],
+	lock = (LOCK *) hash_search(LockMethodLockHash,
 								(void *) locktag,
 								HASH_FIND, NULL);
 	if (!lock)
@@ -2248,7 +2158,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
 	MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG));		/* must clear padding */
 	proclocktag.lock = MAKE_OFFSET(lock);
 	proclocktag.proc = MAKE_OFFSET(proc);
-	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[lockmethodid],
+	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
 										(void *) &proclocktag,
 										HASH_FIND, NULL);
 	if (!proclock)
@@ -2263,7 +2173,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
 		PROCLOCK_PRINT("lock_twophase_postcommit: WRONGTYPE", proclock);
 		LWLockRelease(masterLock);
 		elog(WARNING, "you don't own a lock of type %s",
-			 lock_mode_names[lockmode]);
+			 lockMethodTable->lockModeNames[lockmode]);
 		return;
 	}
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 072059d3d4c99240daa2a40fe26e5a1dc2fe0cff..8d8269041e7f2ba24fcb38603930dc8de5f7e262 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.168 2005/11/22 18:17:21 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.169 2005/12/09 01:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -630,7 +630,7 @@ ProcSleep(LockMethod lockMethodTable,
 		  LOCK *lock,
 		  PROCLOCK *proclock)
 {
-	LWLockId	masterLock = lockMethodTable->masterLock;
+	LWLockId	masterLock = LockMgrLock;
 	PROC_QUEUE *waitQueue = &(lock->waitProcs);
 	LOCKMASK	myHeldLocks = MyProc->heldLocks;
 	bool		early_deadlock = false;
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index bf7ee788c4233512db357c67eec8cd32ea1d13c0..368822d3934f9da113581af4dee317f167e49e74 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2002-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *		$PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.20 2005/10/15 02:49:28 momjian Exp $
+ *		$PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.21 2005/12/09 01:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -256,7 +256,8 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		else
 			nulls[10] = 'n';
 		values[11] = DirectFunctionCall1(textin,
-									 CStringGetDatum(GetLockmodeName(mode)));
+									 CStringGetDatum(GetLockmodeName(LOCK_LOCKMETHOD(*lock),
+																	 mode)));
 		values[12] = BoolGetDatum(granted);
 
 		tuple = heap_formtuple(funcctx->tuple_desc, values, nulls);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 7ad8f7d0241bfea26619f74a6afb45ec55ce5006..9854291df8ccf583a19350fcbb956e7c534bbf65 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.232 2005/11/22 18:17:24 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.233 2005/12/09 01:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -3362,7 +3362,7 @@ RelationIdIsInInitFile(Oid relationId)
  * just after sending them.  The unlink before ensures that a backend that's
  * currently starting cannot read the now-obsolete init file and then miss
  * the SI messages that will force it to update its relcache entries.  (This
- * works because the backend startup sequence gets into the PROC array before
+ * works because the backend startup sequence gets into the PGPROC array before
  * trying to load the init file.)  The unlink after is to synchronize with a
  * backend that may currently be trying to write an init file based on data
  * that we've just rendered invalid.  Such a backend will see the SI messages,
diff --git a/src/include/storage/lmgr.h b/src/include/storage/lmgr.h
index 730060a3480dbfa77f68ee79ecb602506690a55c..3e64dea91f820a421244e8488bf4abb9d3de99b5 100644
--- a/src/include/storage/lmgr.h
+++ b/src/include/storage/lmgr.h
@@ -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.52 2005/10/15 02:49:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lmgr.h,v 1.53 2005/12/09 01:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,29 +18,6 @@
 #include "utils/rel.h"
 
 
-/* These are the valid values of type LOCKMODE: */
-
-/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */
-#define NoLock					0
-
-#define AccessShareLock			1		/* SELECT */
-#define RowShareLock			2		/* SELECT FOR UPDATE/FOR SHARE */
-#define RowExclusiveLock		3		/* INSERT, UPDATE, DELETE */
-#define ShareUpdateExclusiveLock 4		/* VACUUM (non-FULL) */
-#define ShareLock				5		/* CREATE INDEX */
-#define ShareRowExclusiveLock	6		/* like EXCLUSIVE MODE, but allows ROW
-										 * SHARE */
-#define ExclusiveLock			7		/* blocks ROW SHARE/SELECT...FOR
-										 * UPDATE */
-#define AccessExclusiveLock		8		/* ALTER TABLE, DROP TABLE, VACUUM
-										 * FULL, and unqualified LOCK TABLE */
-
-/*
- * Note: all lock mode numbers must be less than lock.h's MAX_LOCKMODES,
- * so increase that if you want to add more modes.
- */
-
-extern void InitLockTable(void);
 extern void RelationInitLockInfo(Relation relation);
 
 /* Lock a relation */
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index e6b9e94b6573f84ce148ad92d04067888642a0d6..e289632054cc6fe70ad83454866005a3b73dfb24 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -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.91 2005/10/15 02:49:46 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.92 2005/12/09 01:22:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -55,50 +55,68 @@ typedef int LOCKMODE;
 #define LOCKBIT_ON(lockmode) (1 << (lockmode))
 #define LOCKBIT_OFF(lockmode) (~(1 << (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.  (Despite the declaration as
- * uint16, we are constrained to 256 lockmethods by the layout of LOCKTAG.)
- */
-typedef uint16 LOCKMETHODID;
-
-/* MAX_LOCK_METHODS is the number of distinct lock control tables allowed */
-#define MAX_LOCK_METHODS	3
-
-#define INVALID_LOCKMETHOD	0
-#define DEFAULT_LOCKMETHOD	1
-#define USER_LOCKMETHOD		2
-
-#define LockMethodIsValid(lockmethodid) ((lockmethodid) != INVALID_LOCKMETHOD)
-
-extern int	NumLockMethods;
-
 
 /*
- * This is the control structure for a lock table. It lives in shared
- * memory.	Currently, none of these fields change after startup.  In addition
- * to the LockMethodData, a lock table has a shared "lockHash" table holding
- * per-locked-object lock information, and a shared "proclockHash" table
- * holding per-lock-holder/waiter lock information.
+ * This data structure defines the locking semantics associated with a
+ * "lock method".  The semantics specify the meaning of each lock mode
+ * (by defining which lock modes it conflicts with), and also whether locks
+ * of this method are transactional (ie, are released at transaction end).
+ * All of this data is constant and is kept in const tables.
  *
- * masterLock -- LWLock used to synchronize access to the table
+ * numLockModes -- number of lock modes (READ,WRITE,etc) that
+ *		are defined in this lock method.  Must be less than MAX_LOCKMODES.
  *
- * numLockModes -- number of lock types (READ,WRITE,etc) that
- *		are defined on this lock table
+ * transactional -- TRUE if locks are released automatically at xact end.
  *
  * conflictTab -- this is an array of bitmasks showing lock
- *		type conflicts. conflictTab[i] is a mask with the j-th bit
- *		turned on if lock types i and j conflict.
+ *		mode conflicts.  conflictTab[i] is a mask with the j-th bit
+ *		turned on if lock modes i and j conflict.  Lock modes are
+ *		numbered 1..numLockModes; conflictTab[0] is unused.
+ *
+ * lockModeNames -- ID strings for debug printouts.
+ *
+ * trace_flag -- pointer to GUC trace flag for this lock method.
  */
 typedef struct LockMethodData
 {
-	LWLockId	masterLock;
 	int			numLockModes;
-	LOCKMASK	conflictTab[MAX_LOCKMODES];
+	bool		transactional;
+	const LOCKMASK *conflictTab;
+	const char * const *lockModeNames;
+	const bool *trace_flag;
 } LockMethodData;
 
-typedef LockMethodData *LockMethod;
+typedef const LockMethodData *LockMethod;
+
+/*
+ * 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;
+
+/* These identify the known lock methods */
+#define DEFAULT_LOCKMETHOD	1
+#define USER_LOCKMETHOD		2
+
+/*
+ * These are the valid values of type LOCKMODE for all the standard lock
+ * methods (both DEFAULT and USER).
+ */
+
+/* NoLock is not a lock mode, but a flag value meaning "don't get a lock" */
+#define NoLock					0
+
+#define AccessShareLock			1		/* SELECT */
+#define RowShareLock			2		/* SELECT FOR UPDATE/FOR SHARE */
+#define RowExclusiveLock		3		/* INSERT, UPDATE, DELETE */
+#define ShareUpdateExclusiveLock 4		/* VACUUM (non-FULL) */
+#define ShareLock				5		/* CREATE INDEX */
+#define ShareRowExclusiveLock	6		/* like EXCLUSIVE MODE, but allows ROW
+										 * SHARE */
+#define ExclusiveLock			7		/* blocks ROW SHARE/SELECT...FOR
+										 * UPDATE */
+#define AccessExclusiveLock		8		/* ALTER TABLE, DROP TABLE, VACUUM
+										 * FULL, and unqualified LOCK TABLE */
 
 
 /*
@@ -138,9 +156,7 @@ typedef enum LockTagType
  * 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.
+ * shared memory can store locks of different lockmethods.
  */
 typedef struct LOCKTAG
 {
@@ -162,42 +178,48 @@ typedef struct LOCKTAG
 	 (locktag).locktag_field2 = (reloid), \
 	 (locktag).locktag_field3 = 0, \
 	 (locktag).locktag_field4 = 0, \
-	 (locktag).locktag_type = LOCKTAG_RELATION)
+	 (locktag).locktag_type = LOCKTAG_RELATION, \
+	 (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
 
 #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)
+	 (locktag).locktag_type = LOCKTAG_RELATION_EXTEND, \
+	 (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
 
 #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)
+	 (locktag).locktag_type = LOCKTAG_PAGE, \
+	 (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
 
 #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)
+	 (locktag).locktag_type = LOCKTAG_TUPLE, \
+	 (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
 
 #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)
+	 (locktag).locktag_type = LOCKTAG_TRANSACTION, \
+	 (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
 
 #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)
+	 (locktag).locktag_type = LOCKTAG_OBJECT, \
+	 (locktag).locktag_lockmethodid = DEFAULT_LOCKMETHOD)
 
 
 /*
@@ -366,18 +388,13 @@ typedef enum
  * function prototypes
  */
 extern void InitLocks(void);
-extern LockMethod GetLocksMethodTable(LOCK *lock);
-extern LOCKMETHODID LockMethodTableInit(const char *tabName,
-					const LOCKMASK *conflictsP,
-					int numModes);
-extern LOCKMETHODID LockMethodTableRename(LOCKMETHODID lockmethodid);
-extern LockAcquireResult LockAcquire(LOCKMETHODID lockmethodid,
-			LOCKTAG *locktag,
+extern LockMethod GetLocksMethodTable(const LOCK *lock);
+extern LockAcquireResult LockAcquire(const LOCKTAG *locktag,
 			bool isTempObject,
 			LOCKMODE lockmode,
 			bool sessionLock,
 			bool dontWait);
-extern bool LockRelease(LOCKMETHODID lockmethodid, LOCKTAG *locktag,
+extern bool LockRelease(const LOCKTAG *locktag,
 			LOCKMODE lockmode, bool sessionLock);
 extern void LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks);
 extern void LockReleaseCurrentOwner(void);
@@ -399,7 +416,7 @@ extern void RememberSimpleDeadLock(PGPROC *proc1,
 					   PGPROC *proc2);
 extern void InitDeadLockChecking(void);
 extern LockData *GetLockStatusData(void);
-extern const char *GetLockmodeName(LOCKMODE mode);
+extern const char *GetLockmodeName(LOCKMETHODID lockmethodid, LOCKMODE mode);
 
 extern void lock_twophase_recover(TransactionId xid, uint16 info,
 					  void *recdata, uint32 len);
diff --git a/src/tools/backend/index.html b/src/tools/backend/index.html
index af255f912fed3fc3d19b91d71535652b402f3c7c..db53174465316e585ebfa156cff1e7a6876dc5e9 100644
--- a/src/tools/backend/index.html
+++ b/src/tools/backend/index.html
@@ -128,31 +128,16 @@ Block</a> - data/index buffer cache block</li>
 addresses using table name and block number( <a
 href="../../include/storage/buf_internals.h">BufferTag</a>)</li>
 
-<li>MultiLevelLockTable (ctl) - control structure for each locking
-method. Currently, only multi-level locking is used(<a
-href="../../include/storage/lock.h">LOCKMETHODCTL</a>).</li>
-
-<li>MultiLevelLockTable (lock hash) - the <a
+<li>Lock Manager Tables (lock hash) - the <a
 href="../../include/storage/lock.h">LOCK</a> structure, looked up
-using relation, database object ids(<a
-href="../../include/storage/lock.h">LOCKTAG)</a>. The lock table
-structure contains the lock modes(read/write or shared/exclusive)
-and circular linked list of backends (<a
-href="../../include/storage/proc.h">PROC</a> structure pointers)
-waiting on the lock.</li>
-
-<li>MultiLevelLockTable (xid hash) - lookup of LOCK structure
-address using transaction id, LOCK address. It is used to quickly
-check if the current transaction already has any locks on a table,
-rather than having to search through all the held locks. It also
-stores the modes (read/write) of the locks held by the current
-transaction. The returned <a
-href="../../include/storage/lock.h">XIDLookupEnt</a> structure also
-contains a pointer to the backend's PROC.lockQueue.</li>
-
-<li><a href="../../include/storage/proc.h">Proc Header</a> -
-information about each backend, including locks held/waiting,
-indexed by process id</li>
+using a <a href="../../include/storage/lock.h">LOCKTAG</a>.
+A LOCK structure exists for each lockable object that is currently
+locked by any backend.  Also, there is a subsidiary <a
+href="../../include/storage/lock.h">PROCLOCK</a> structure for each
+backend currently interested in a given LOCK</li>
+
+<li><a href="../../include/storage/proc.h">PGPROC Structures</a> -
+information about each backend, including locks held/waiting</li>
 </ul>
 
 <p>Each data structure is created by calling <a