diff --git a/src/backend/storage/lmgr/README b/src/backend/storage/lmgr/README
index fdda5bf82a44d2e3c30fbf8c550a121adabde367..6720a5579f54dd8df9c8f90fbd53d7de96874881 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.19 2005/12/11 21:02:18 tgl Exp $
+$PostgreSQL: pgsql/src/backend/storage/lmgr/README,v 1.20 2006/07/23 23:08:46 tgl Exp $
 
 
 LOCKING OVERVIEW
@@ -148,13 +148,21 @@ The lock manager's PROCLOCK objects contain:
 tag -
     The key fields that are used for hashing entries in the shared memory
     PROCLOCK hash table.  This is declared as a separate struct to ensure that
-    we always zero out the correct number of bytes.
+    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 PROCLOCKTAG so that there are no padding bytes.)
 
-    tag.lock
-        SHMEM offset of the LOCK object this PROCLOCK is for.
+    tag.myLock
+        Pointer to the shared LOCK object this PROCLOCK is for.
 
-    tag.proc
-        SHMEM offset of PGPROC of backend process that owns this PROCLOCK.
+    tag.myProc
+        Pointer to the PGPROC of backend process that owns this PROCLOCK.
+
+    Note: it's OK to use pointers here because a PROCLOCK never outlives
+    either its lock or its proc.  The tag is therefore unique for as long
+    as it needs to be, even though the same tag values might mean something
+    else at other times.
 
 holdMask -
     A bitmask for the lock modes successfully acquired by this PROCLOCK.
@@ -191,12 +199,18 @@ Most operations only need to lock the single partition they are working in.
 Here are the details:
 
 * Each possible lock is assigned to one partition according to a hash of
-its LOCKTAG value (see LockTagToPartition()).  The partition's LWLock is
-considered to protect all the LOCK objects of that partition as well as
-their subsidiary PROCLOCKs.  The shared-memory hash tables for LOCKs and
-PROCLOCKs are divided into separate hash tables for each partition, and
-operations on each hash table are likewise protected by the partition
-lock.
+its LOCKTAG value.  The partition's LWLock is considered to protect all the
+LOCK objects of that partition as well as their subsidiary PROCLOCKs.
+
+* The shared-memory hash tables for LOCKs and PROCLOCKs are organized
+so that different partitions use different hash chains, and thus there
+is no conflict in working with objects in different partitions.  This
+is supported directly by dynahash.c's "partitioned table" mechanism
+for the LOCK table: we need only ensure that the partition number is
+taken from the low-order bits of the dynahash hash value for the LOCKTAG.
+To make it work for PROCLOCKs, we have to ensure that a PROCLOCK's hash
+value has the same low-order bits as its associated LOCK.  This requires
+a specialized hash function (see proclock_hash).
 
 * Formerly, each PGPROC had a single list of PROCLOCKs belonging to it.
 This has now been split into per-partition lists, so that access to a
@@ -226,9 +240,10 @@ deadlock checking should not occur often enough to be performance-critical,
 trying to make this work does not seem a productive use of effort.
 
 A backend's internal LOCALLOCK hash table is not partitioned.  We do store
-the partition number in LOCALLOCK table entries, but this is a straight
-speed-for-space tradeoff: we could instead recalculate the partition
-number from the LOCKTAG when needed.
+a copy of the locktag hash code in LOCALLOCK table entries, from which the
+partition number can be computed, but this is a straight speed-for-space
+tradeoff: we could instead recalculate the partition number from the LOCKTAG
+when needed.
 
 
 THE DEADLOCK DETECTION ALGORITHM
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index f889f4342d479629a32dc81e133a402a13f89f22..0e4acd5c164c086e696d70599567c508ddc98a36 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.40 2006/07/14 14:52:23 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/deadlock.c,v 1.41 2006/07/23 23:08:46 tgl Exp $
  *
  *	Interface:
  *
@@ -480,7 +480,7 @@ FindLockCycleRecurse(PGPROC *checkProc,
 
 	while (proclock)
 	{
-		proc = (PGPROC *) MAKE_PTR(proclock->tag.proc);
+		proc = proclock->tag.myProc;
 
 		/* A proc never blocks itself */
 		if (proc != checkProc)
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index cf78869a0b2d12d30ee3a42ca632c7143380a594..2b3a4c63c4f483134dd9771f525f50cc304d0c6e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.167 2006/07/22 23:04:39 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.168 2006/07/23 23:08:46 tgl Exp $
  *
  * NOTES
  *	  A lock table is a shared memory hash table.  When
@@ -32,6 +32,7 @@
 #include <signal.h>
 #include <unistd.h>
 
+#include "access/transam.h"
 #include "access/twophase.h"
 #include "access/twophase_rmgr.h"
 #include "miscadmin.h"
@@ -166,8 +167,8 @@ typedef struct TwoPhaseLockRecord
  * The LockMethodLockHash and LockMethodProcLockHash hash tables are in
  * shared memory; LockMethodLocalHash is local to each backend.
  */
-static HTAB *LockMethodLockHash[NUM_LOCK_PARTITIONS];
-static HTAB *LockMethodProcLockHash[NUM_LOCK_PARTITIONS];
+static HTAB *LockMethodLockHash;
+static HTAB *LockMethodProcLockHash;
 static HTAB *LockMethodLocalHash;
 
 
@@ -218,10 +219,10 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
 {
 	if (LOCK_DEBUG_ENABLED(&lock->tag))
 		elog(LOG,
-			 "%s: lock(%lx) id(%u,%u,%u,%u,%u,%u) grantMask(%x) "
+			 "%s: lock(%p) 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),
+			 where, lock,
 			 lock->tag.locktag_field1, lock->tag.locktag_field2,
 			 lock->tag.locktag_field3, lock->tag.locktag_field4,
 			 lock->tag.locktag_type, lock->tag.locktag_lockmethodid,
@@ -240,12 +241,12 @@ LOCK_PRINT(const char *where, const LOCK *lock, LOCKMODE type)
 inline static void
 PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
 {
-	if (LOCK_DEBUG_ENABLED(&((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag))
+	if (LOCK_DEBUG_ENABLED(&proclockP->tag.myLock->tag))
 		elog(LOG,
-			 "%s: proclock(%lx) lock(%lx) method(%u) proc(%lx) hold(%x)",
-			 where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
+			 "%s: proclock(%p) lock(%p) method(%u) proc(%p) hold(%x)",
+			 where, proclockP, proclockP->tag.myLock,
 			 PROCLOCK_LOCKMETHOD(*(proclockP)),
-			 proclockP->tag.proc, (int) proclockP->holdMask);
+			 proclockP->tag.myProc, (int) proclockP->holdMask);
 }
 #else							/* not LOCK_DEBUG */
 
@@ -254,13 +255,14 @@ PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
 #endif   /* not LOCK_DEBUG */
 
 
+static uint32 proclock_hash(const void *key, Size keysize);
 static void RemoveLocalLock(LOCALLOCK *locallock);
 static void GrantLockLocal(LOCALLOCK *locallock, ResourceOwner owner);
 static void WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner);
 static bool UnGrantLock(LOCK *lock, LOCKMODE lockmode,
 			PROCLOCK *proclock, LockMethod lockMethodTable);
 static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
-			LockMethod lockMethodTable, int partition,
+			LockMethod lockMethodTable, uint32 hashcode,
 			bool wakeupNeeded);
 
 
@@ -279,71 +281,62 @@ static void CleanUpLock(LOCK *lock, PROCLOCK *proclock,
 void
 InitLocks(void)
 {
-	char		shmemName[64];
 	HASHCTL		info;
 	int			hash_flags;
 	long		init_table_size,
 				max_table_size;
-	int			i;
 
 	/*
 	 * Compute init/max size to request for lock hashtables.  Note these
 	 * calculations must agree with LockShmemSize!
 	 */
 	max_table_size = NLOCKENTS();
-	max_table_size = (max_table_size - 1) / NUM_LOCK_PARTITIONS + 1;
 	init_table_size = max_table_size / 2;
 
 	/*
-	 * Allocate hash tables for LOCK structs.  These are used to store
+	 * Allocate hash table for LOCK structs.  This stores
 	 * per-locked-object information.
 	 */
 	MemSet(&info, 0, sizeof(info));
 	info.keysize = sizeof(LOCKTAG);
 	info.entrysize = sizeof(LOCK);
 	info.hash = tag_hash;
-	hash_flags = (HASH_ELEM | HASH_FUNCTION);
+	info.num_partitions = NUM_LOCK_PARTITIONS;
+	hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
 
-	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
-	{
-		sprintf(shmemName, "LOCK hash %d", i);
-		LockMethodLockHash[i] = ShmemInitHash(shmemName,
-											  init_table_size,
-											  max_table_size,
-											  &info,
-											  hash_flags);
-		if (!LockMethodLockHash[i])
-			elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
-	}
+	LockMethodLockHash = ShmemInitHash("LOCK hash",
+									   init_table_size,
+									   max_table_size,
+									   &info,
+									   hash_flags);
+	if (!LockMethodLockHash)
+		elog(FATAL, "could not initialize lock hash table");
 
 	/* Assume an average of 2 holders per lock */
 	max_table_size *= 2;
 	init_table_size *= 2;
 
 	/*
-	 * Allocate hash tables for PROCLOCK structs.  These are used to store
+	 * Allocate hash table for PROCLOCK structs.  This stores
 	 * per-lock-per-holder information.
 	 */
 	info.keysize = sizeof(PROCLOCKTAG);
 	info.entrysize = sizeof(PROCLOCK);
-	info.hash = tag_hash;
-	hash_flags = (HASH_ELEM | HASH_FUNCTION);
-
-	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
-	{
-		sprintf(shmemName, "PROCLOCK hash %d", i);
-		LockMethodProcLockHash[i] = ShmemInitHash(shmemName,
-												  init_table_size,
-												  max_table_size,
-												  &info,
-												  hash_flags);
-		if (!LockMethodProcLockHash[i])
-			elog(FATAL, "could not initialize lock table \"%s\"", shmemName);
-	}
+	info.hash = proclock_hash;
+	info.num_partitions = NUM_LOCK_PARTITIONS;
+	hash_flags = (HASH_ELEM | HASH_FUNCTION | HASH_PARTITION);
+
+	LockMethodProcLockHash = ShmemInitHash("PROCLOCK hash",
+										   init_table_size,
+										   max_table_size,
+										   &info,
+										   hash_flags);
+	if (!LockMethodProcLockHash)
+		elog(FATAL, "could not initialize proclock hash table");
 
 	/*
-	 * Allocate one non-shared hash table for LOCALLOCK structs.  This is used
-	 * to store lock counts and resource owner information.
+	 * Allocate non-shared hash table for LOCALLOCK structs.  This stores
+	 * lock counts and resource owner information.
 	 *
 	 * The non-shared table could already exist in this process (this occurs
 	 * when the postmaster is recreating shared memory after a backend crash).
@@ -379,35 +372,74 @@ GetLocksMethodTable(const LOCK *lock)
 
 
 /*
- * Given a LOCKTAG, determine which partition the lock belongs in.
+ * Compute the hash code associated with a LOCKTAG.
  *
- * Basically what we want to do here is hash the locktag.  However, it
- * seems unwise to use hash_any() because that is the same function that
- * will be used to distribute the locks within each partition's hash table;
- * if we use it, we run a big risk of having uneven distribution of hash
- * codes within each hash table.  Instead, we use a simple linear XOR of the
- * bits of the locktag.
+ * To avoid unnecessary recomputations of the hash code, we try to do this
+ * just once per function, and then pass it around as needed.  Aside from
+ * passing the hashcode to hash_search_with_hash_value(), we can extract
+ * the lock partition number from the hashcode.
  */
-int
-LockTagToPartition(const LOCKTAG *locktag)
+uint32
+LockTagHashCode(const LOCKTAG *locktag)
 {
-	const uint8 *ptr = (const uint8 *) locktag;
-	int			result = 0;
-	int			i;
+	return get_hash_value(LockMethodLockHash, (const void *) locktag);
+}
 
-	for (i = 0; i < sizeof(LOCKTAG); i++)
-		result ^= *ptr++;
-#if NUM_LOCK_PARTITIONS == 16
-	result ^= result >> 4;
-	result &= 0x0F;
-#elif NUM_LOCK_PARTITIONS == 4
-	result ^= result >> 4;
-	result ^= result >> 2;
-	result &= 0x03;
-#else
-#error unsupported NUM_LOCK_PARTITIONS
-#endif
-	return result;
+/*
+ * Compute the hash code associated with a PROCLOCKTAG.
+ *
+ * Because we want to use just one set of partition locks for both the
+ * LOCK and PROCLOCK hash tables, we have to make sure that PROCLOCKs
+ * fall into the same partition number as their associated LOCKs.
+ * dynahash.c expects the partition number to be the low-order bits of
+ * the hash code, and therefore a PROCLOCKTAG's hash code must have the
+ * same low-order bits as the associated LOCKTAG's hash code.  We achieve
+ * this with this specialized hash function.
+ */
+static uint32
+proclock_hash(const void *key, Size keysize)
+{
+	const PROCLOCKTAG *proclocktag = (const PROCLOCKTAG *) key;
+	uint32	lockhash;
+	Datum	procptr;
+
+	Assert(keysize == sizeof(PROCLOCKTAG));
+
+	/* Look into the associated LOCK object, and compute its hash code */
+	lockhash = LockTagHashCode(&proclocktag->myLock->tag);
+
+	/*
+	 * To make the hash code also depend on the PGPROC, we xor the proc
+	 * struct's address into the hash code, left-shifted so that the
+	 * partition-number bits don't change.  Since this is only a hash,
+	 * we don't care if we lose high-order bits of the address; use
+	 * an intermediate variable to suppress cast-pointer-to-int warnings.
+	 */
+	procptr = PointerGetDatum(proclocktag->myProc);
+	lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
+
+	return lockhash;
+}
+
+/*
+ * Compute the hash code associated with a PROCLOCKTAG, given the hashcode
+ * for its underlying LOCK.
+ *
+ * We use this just to avoid redundant calls of LockTagHashCode().
+ */
+static inline uint32
+ProcLockHashCode(const PROCLOCKTAG *proclocktag, uint32 hashcode)
+{
+	uint32	lockhash = hashcode;
+	Datum	procptr;
+
+	/*
+	 * This must match proclock_hash()!
+	 */
+	procptr = PointerGetDatum(proclocktag->myProc);
+	lockhash ^= ((uint32) procptr) << LOG2_NUM_LOCK_PARTITIONS;
+
+	return lockhash;
 }
 
 
@@ -453,6 +485,8 @@ LockAcquire(const LOCKTAG *locktag,
 	PROCLOCKTAG proclocktag;
 	bool		found;
 	ResourceOwner owner;
+	uint32		hashcode;
+	uint32		proclock_hashcode;
 	int			partition;
 	LWLockId	partitionLock;
 	int			status;
@@ -495,7 +529,7 @@ LockAcquire(const LOCKTAG *locktag,
 		locallock->lock = NULL;
 		locallock->proclock = NULL;
 		locallock->isTempObject = isTempObject;
-		locallock->partition = LockTagToPartition(&(localtag.lock));
+		locallock->hashcode = LockTagHashCode(&(localtag.lock));
 		locallock->nLocks = 0;
 		locallock->numLockOwners = 0;
 		locallock->maxLockOwners = 8;
@@ -532,8 +566,9 @@ LockAcquire(const LOCKTAG *locktag,
 	/*
 	 * Otherwise we've got to mess with the shared lock table.
 	 */
-	partition = locallock->partition;
-	partitionLock = FirstLockMgrLock + partition;
+	hashcode = locallock->hashcode;
+	partition = LockHashPartition(hashcode);
+	partitionLock = LockHashPartitionLock(hashcode);
 
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
@@ -545,9 +580,11 @@ LockAcquire(const LOCKTAG *locktag,
 	 * pointer is valid, since a lock object with no locks can go away
 	 * anytime.
 	 */
-	lock = (LOCK *) hash_search(LockMethodLockHash[partition],
-								(void *) locktag,
-								HASH_ENTER_NULL, &found);
+	lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
+												(void *) locktag,
+												hashcode,
+												HASH_ENTER_NULL,
+												&found);
 	if (!lock)
 	{
 		LWLockRelease(partitionLock);
@@ -584,16 +621,19 @@ LockAcquire(const LOCKTAG *locktag,
 	/*
 	 * Create the hash key for the proclock table.
 	 */
-	MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG));		/* must clear padding */
-	proclocktag.lock = MAKE_OFFSET(lock);
-	proclocktag.proc = MAKE_OFFSET(MyProc);
+	proclocktag.myLock = lock;
+	proclocktag.myProc = MyProc;
+
+	proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
 
 	/*
 	 * Find or create a proclock entry with this tag
 	 */
-	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[partition],
-										(void *) &proclocktag,
-										HASH_ENTER_NULL, &found);
+	proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
+														(void *) &proclocktag,
+														proclock_hashcode,
+														HASH_ENTER_NULL,
+														&found);
 	if (!proclock)
 	{
 		/* Ooops, not enough shmem for the proclock */
@@ -606,9 +646,11 @@ LockAcquire(const LOCKTAG *locktag,
 			 * anyone to release the lock object later.
 			 */
 			Assert(SHMQueueEmpty(&(lock->procLocks)));
-			if (!hash_search(LockMethodLockHash[partition],
-							 (void *) &(lock->tag),
-							 HASH_REMOVE, NULL))
+			if (!hash_search_with_hash_value(LockMethodLockHash,
+											 (void *) &(lock->tag),
+											 hashcode,
+											 HASH_REMOVE,
+											 NULL))
 				elog(PANIC, "lock table corrupted");
 		}
 		LWLockRelease(partitionLock);
@@ -726,9 +768,11 @@ LockAcquire(const LOCKTAG *locktag,
 			{
 				SHMQueueDelete(&proclock->lockLink);
 				SHMQueueDelete(&proclock->procLink);
-				if (!hash_search(LockMethodProcLockHash[partition],
-								 (void *) &(proclock->tag),
-								 HASH_REMOVE, NULL))
+				if (!hash_search_with_hash_value(LockMethodProcLockHash,
+												 (void *) &(proclock->tag),
+												 proclock_hashcode,
+												 HASH_REMOVE,
+												 NULL))
 					elog(PANIC, "proclock table corrupted");
 			}
 			else
@@ -954,12 +998,12 @@ UnGrantLock(LOCK *lock, LOCKMODE lockmode,
  * should be called after UnGrantLock, and wakeupNeeded is the result from
  * UnGrantLock.)
  *
- * The lock table's partition lock must be held at entry, and will be
+ * The appropriate partition lock must be held at entry, and will be
  * held at exit.
  */
 static void
 CleanUpLock(LOCK *lock, PROCLOCK *proclock,
-			LockMethod lockMethodTable, int partition,
+			LockMethod lockMethodTable, uint32 hashcode,
 			bool wakeupNeeded)
 {
 	/*
@@ -968,12 +1012,17 @@ CleanUpLock(LOCK *lock, PROCLOCK *proclock,
 	 */
 	if (proclock->holdMask == 0)
 	{
+		uint32		proclock_hashcode;
+
 		PROCLOCK_PRINT("CleanUpLock: deleting", proclock);
 		SHMQueueDelete(&proclock->lockLink);
 		SHMQueueDelete(&proclock->procLink);
-		if (!hash_search(LockMethodProcLockHash[partition],
-						 (void *) &(proclock->tag),
-						 HASH_REMOVE, NULL))
+		proclock_hashcode = ProcLockHashCode(&proclock->tag, hashcode);
+		if (!hash_search_with_hash_value(LockMethodProcLockHash,
+										 (void *) &(proclock->tag),
+										 proclock_hashcode,
+										 HASH_REMOVE,
+										 NULL))
 			elog(PANIC, "proclock table corrupted");
 	}
 
@@ -985,9 +1034,11 @@ CleanUpLock(LOCK *lock, PROCLOCK *proclock,
 		 */
 		LOCK_PRINT("CleanUpLock: deleting", lock, 0);
 		Assert(SHMQueueEmpty(&(lock->procLocks)));
-		if (!hash_search(LockMethodLockHash[partition],
-						 (void *) &(lock->tag),
-						 HASH_REMOVE, NULL))
+		if (!hash_search_with_hash_value(LockMethodLockHash,
+										 (void *) &(lock->tag),
+										 hashcode,
+										 HASH_REMOVE,
+										 NULL))
 			elog(PANIC, "lock table corrupted");
 	}
 	else if (wakeupNeeded)
@@ -1097,7 +1148,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 		awaitedLock = NULL;
 		LOCK_PRINT("WaitOnLock: aborting on lock",
 				   locallock->lock, locallock->tag.mode);
-		LWLockRelease(FirstLockMgrLock + locallock->partition);
+		LWLockRelease(LockHashPartitionLock(locallock->hashcode));
 
 		/*
 		 * Now that we aren't holding the partition lock, we can give an error
@@ -1130,7 +1181,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
  * NB: this does not clean up any locallock object that may exist for the lock.
  */
 void
-RemoveFromWaitQueue(PGPROC *proc, int partition)
+RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode)
 {
 	LOCK	   *waitLock = proc->waitLock;
 	PROCLOCK   *proclock = proc->waitProcLock;
@@ -1171,7 +1222,7 @@ RemoveFromWaitQueue(PGPROC *proc, int partition)
 	 * any other waiters for the lock can be woken up now.
 	 */
 	CleanUpLock(waitLock, proclock,
-				LockMethods[lockmethodid], partition,
+				LockMethods[lockmethodid], hashcode,
 				true);
 }
 
@@ -1195,7 +1246,6 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 	LOCALLOCK  *locallock;
 	LOCK	   *lock;
 	PROCLOCK   *proclock;
-	int			partition;
 	LWLockId	partitionLock;
 	bool		wakeupNeeded;
 
@@ -1283,8 +1333,7 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 	/*
 	 * Otherwise we've got to mess with the shared lock table.
 	 */
-	partition = locallock->partition;
-	partitionLock = FirstLockMgrLock + partition;
+	partitionLock = LockHashPartitionLock(locallock->hashcode);
 
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
@@ -1318,7 +1367,7 @@ LockRelease(const LOCKTAG *locktag, LOCKMODE lockmode, bool sessionLock)
 	wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
 
 	CleanUpLock(lock, proclock,
-				lockMethodTable, partition,
+				lockMethodTable, locallock->hashcode,
 				wakeupNeeded);
 
 	LWLockRelease(partitionLock);
@@ -1449,9 +1498,9 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
 				SHMQueueNext(procLocks, &proclock->procLink,
 							 offsetof(PROCLOCK, procLink));
 
-			Assert(proclock->tag.proc == MAKE_OFFSET(MyProc));
+			Assert(proclock->tag.myProc == MyProc);
 
-			lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
+			lock = proclock->tag.myLock;
 
 			/* Ignore items that are not of the lockmethod to be removed */
 			if (LOCK_LOCKMETHOD(*lock) != lockmethodid)
@@ -1497,7 +1546,8 @@ LockReleaseAll(LOCKMETHODID lockmethodid, bool allLocks)
 
 			/* CleanUpLock will wake up waiters if needed. */
 			CleanUpLock(lock, proclock,
-						lockMethodTable, partition,
+						lockMethodTable,
+						LockTagHashCode(&lock->tag),
 						wakeupNeeded);
 
 		next_item:
@@ -1789,9 +1839,9 @@ PostPrepare_Locks(TransactionId xid)
 				SHMQueueNext(procLocks, &proclock->procLink,
 							 offsetof(PROCLOCK, procLink));
 
-			Assert(proclock->tag.proc == MAKE_OFFSET(MyProc));
+			Assert(proclock->tag.myProc == MyProc);
 
-			lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
+			lock = proclock->tag.myLock;
 
 			/* Ignore nontransactional locks */
 			if (!LockMethods[LOCK_LOCKMETHOD(*lock)]->transactional)
@@ -1814,7 +1864,7 @@ PostPrepare_Locks(TransactionId xid)
 			holdMask = proclock->holdMask;
 
 			/*
-			 * We cannot simply modify proclock->tag.proc to reassign
+			 * We cannot simply modify proclock->tag.myProc to reassign
 			 * ownership of the lock, because that's part of the hash key and
 			 * the proclock would then be in the wrong hash chain.  So, unlink
 			 * and delete the old proclock; create a new one with the right
@@ -1825,7 +1875,7 @@ PostPrepare_Locks(TransactionId xid)
 			 */
 			SHMQueueDelete(&proclock->lockLink);
 			SHMQueueDelete(&proclock->procLink);
-			if (!hash_search(LockMethodProcLockHash[partition],
+			if (!hash_search(LockMethodProcLockHash,
 							 (void *) &(proclock->tag),
 							 HASH_REMOVE, NULL))
 				elog(PANIC, "proclock table corrupted");
@@ -1833,11 +1883,10 @@ PostPrepare_Locks(TransactionId xid)
 			/*
 			 * Create the hash key for the new proclock table.
 			 */
-			MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG));
-			proclocktag.lock = MAKE_OFFSET(lock);
-			proclocktag.proc = MAKE_OFFSET(newproc);
+			proclocktag.myLock = lock;
+			proclocktag.myProc = newproc;
 
-			newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[partition],
+			newproclock = (PROCLOCK *) hash_search(LockMethodProcLockHash,
 												   (void *) &proclocktag,
 												   HASH_ENTER_NULL, &found);
 			if (!newproclock)
@@ -1889,23 +1938,18 @@ Size
 LockShmemSize(void)
 {
 	Size		size = 0;
-	Size		tabsize;
 	long		max_table_size;
 
-	/* lock hash tables */
+	/* lock hash table */
 	max_table_size = NLOCKENTS();
-	max_table_size = (max_table_size - 1) / NUM_LOCK_PARTITIONS + 1;
-	tabsize = hash_estimate_size(max_table_size, sizeof(LOCK));
-	size = add_size(size, mul_size(tabsize, NUM_LOCK_PARTITIONS));
+	size = add_size(size, hash_estimate_size(max_table_size, sizeof(LOCK)));
 
-	/* proclock hash tables */
+	/* proclock hash table */
 	max_table_size *= 2;
-	tabsize = hash_estimate_size(max_table_size, sizeof(PROCLOCK));
-	size = add_size(size, mul_size(tabsize, NUM_LOCK_PARTITIONS));
+	size = add_size(size, hash_estimate_size(max_table_size, sizeof(PROCLOCK)));
 
 	/*
-	 * Since there is likely to be some space wastage due to uneven use
-	 * of the partitions, add 10% safety margin.
+	 * Since NLOCKENTS is only an estimate, add 10% safety margin.
 	 */
 	size = add_size(size, size / 10);
 
@@ -1930,7 +1974,6 @@ LockData *
 GetLockStatusData(void)
 {
 	LockData   *data;
-	HTAB	   *proclockTable;
 	PROCLOCK   *proclock;
 	HASH_SEQ_STATUS seqstat;
 	int			els;
@@ -1940,7 +1983,7 @@ GetLockStatusData(void)
 	data = (LockData *) palloc(sizeof(LockData));
 
 	/*
-	 * Acquire lock on the entire shared lock data structures.  We can't
+	 * Acquire lock on the entire shared lock data structure.  We can't
 	 * operate one partition at a time if we want to deliver a self-consistent
 	 * view of the state.
 	 *
@@ -1950,43 +1993,32 @@ GetLockStatusData(void)
 	 * It will at least allow two backends to do GetLockStatusData in parallel.
 	 *
 	 * Must grab LWLocks in partition-number order to avoid LWLock deadlock.
-	 *
-	 * Use same loop to count up the total number of PROCLOCK objects.
 	 */
-	els = 0;
 	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
-	{
 		LWLockAcquire(FirstLockMgrLock + i, LW_SHARED);
-		proclockTable = LockMethodProcLockHash[i];
-		els += hash_get_num_entries(proclockTable);
-	}
+
+	/* Now we can safely count the number of proclocks */
+	els = hash_get_num_entries(LockMethodProcLockHash);
 
 	data->nelements = els;
-	data->proclockaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * els);
 	data->proclocks = (PROCLOCK *) palloc(sizeof(PROCLOCK) * els);
 	data->procs = (PGPROC *) palloc(sizeof(PGPROC) * els);
 	data->locks = (LOCK *) palloc(sizeof(LOCK) * els);
 
-	el = 0;
-
 	/* Now scan the tables to copy the data */
-	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
-	{
-		proclockTable = LockMethodProcLockHash[i];
-		hash_seq_init(&seqstat, proclockTable);
+	hash_seq_init(&seqstat, LockMethodProcLockHash);
 
-		while ((proclock = hash_seq_search(&seqstat)))
-		{
-			PGPROC	   *proc = (PGPROC *) MAKE_PTR(proclock->tag.proc);
-			LOCK	   *lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
+	el = 0;
+	while ((proclock = (PROCLOCK *) hash_seq_search(&seqstat)))
+	{
+		PGPROC	   *proc = proclock->tag.myProc;
+		LOCK	   *lock = proclock->tag.myLock;
 
-			data->proclockaddrs[el] = MAKE_OFFSET(proclock);
-			memcpy(&(data->proclocks[el]), proclock, sizeof(PROCLOCK));
-			memcpy(&(data->procs[el]), proc, sizeof(PGPROC));
-			memcpy(&(data->locks[el]), lock, sizeof(LOCK));
+		memcpy(&(data->proclocks[el]), proclock, sizeof(PROCLOCK));
+		memcpy(&(data->procs[el]), proc, sizeof(PGPROC));
+		memcpy(&(data->locks[el]), lock, sizeof(LOCK));
 
-			el++;
-		}
+		el++;
 	}
 
 	/* And release locks */
@@ -2036,9 +2068,9 @@ DumpLocks(PGPROC *proc)
 
 		while (proclock)
 		{
-			Assert(proclock->tag.proc == MAKE_OFFSET(proc));
+			Assert(proclock->tag.myProc == proc);
 
-			lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
+			lock = proclock->tag.myLock;
 
 			PROCLOCK_PRINT("DumpLocks", proclock);
 			LOCK_PRINT("DumpLocks", lock, 0);
@@ -2061,32 +2093,24 @@ DumpAllLocks(void)
 	PGPROC	   *proc;
 	PROCLOCK   *proclock;
 	LOCK	   *lock;
-	HTAB	   *proclockTable;
 	HASH_SEQ_STATUS status;
-	int			i;
 
 	proc = MyProc;
 
 	if (proc && proc->waitLock)
 		LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
 
-	for (i = 0; i < NUM_LOCK_PARTITIONS; i++)
-	{
-		proclockTable = LockMethodProcLockHash[i];
-		hash_seq_init(&status, proclockTable);
+	hash_seq_init(&status, LockMethodProcLockHash);
 
-		while ((proclock = (PROCLOCK *) hash_seq_search(&status)) != NULL)
-		{
-			PROCLOCK_PRINT("DumpAllLocks", proclock);
+	while ((proclock = (PROCLOCK *) hash_seq_search(&status)) != NULL)
+	{
+		PROCLOCK_PRINT("DumpAllLocks", proclock);
 
-			if (proclock->tag.lock)
-			{
-				lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
-				LOCK_PRINT("DumpAllLocks", lock, 0);
-			}
-			else
-				elog(LOG, "DumpAllLocks: proclock->tag.lock = NULL");
-		}
+		lock = proclock->tag.myLock;
+		if (lock)
+			LOCK_PRINT("DumpAllLocks", lock, 0);
+		else
+			elog(LOG, "DumpAllLocks: proclock->tag.myLock = NULL");
 	}
 }
 #endif   /* LOCK_DEBUG */
@@ -2115,6 +2139,8 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 	PROCLOCK   *proclock;
 	PROCLOCKTAG proclocktag;
 	bool		found;
+	uint32		hashcode;
+	uint32		proclock_hashcode;
 	int			partition;
 	LWLockId	partitionLock;
 	LockMethod	lockMethodTable;
@@ -2128,17 +2154,20 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 	lockMethodTable = LockMethods[lockmethodid];
 
-	partition = LockTagToPartition(locktag);
-	partitionLock = FirstLockMgrLock + partition;
+	hashcode = LockTagHashCode(locktag);
+	partition = LockHashPartition(hashcode);
+	partitionLock = LockHashPartitionLock(hashcode);
 
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
 	/*
 	 * Find or create a lock with this tag.
 	 */
-	lock = (LOCK *) hash_search(LockMethodLockHash[partition],
-								(void *) locktag,
-								HASH_ENTER_NULL, &found);
+	lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
+												(void *) locktag,
+												hashcode,
+												HASH_ENTER_NULL,
+												&found);
 	if (!lock)
 	{
 		LWLockRelease(partitionLock);
@@ -2174,16 +2203,19 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 	/*
 	 * Create the hash key for the proclock table.
 	 */
-	MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG));		/* must clear padding */
-	proclocktag.lock = MAKE_OFFSET(lock);
-	proclocktag.proc = MAKE_OFFSET(proc);
+	proclocktag.myLock = lock;
+	proclocktag.myProc = proc;
+
+	proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
 
 	/*
 	 * Find or create a proclock entry with this tag
 	 */
-	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[partition],
-										(void *) &proclocktag,
-										HASH_ENTER_NULL, &found);
+	proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
+														(void *) &proclocktag,
+														proclock_hashcode,
+														HASH_ENTER_NULL,
+														&found);
 	if (!proclock)
 	{
 		/* Ooops, not enough shmem for the proclock */
@@ -2196,9 +2228,11 @@ lock_twophase_recover(TransactionId xid, uint16 info,
 			 * anyone to release the lock object later.
 			 */
 			Assert(SHMQueueEmpty(&(lock->procLocks)));
-			if (!hash_search(LockMethodLockHash[partition],
-							 (void *) &(lock->tag),
-							 HASH_REMOVE, NULL))
+			if (!hash_search_with_hash_value(LockMethodLockHash,
+											 (void *) &(lock->tag),
+											 hashcode,
+											 HASH_REMOVE,
+											 NULL))
 				elog(PANIC, "lock table corrupted");
 		}
 		LWLockRelease(partitionLock);
@@ -2269,7 +2303,8 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
 	LOCK	   *lock;
 	PROCLOCK   *proclock;
 	PROCLOCKTAG proclocktag;
-	int			partition;
+	uint32		hashcode;
+	uint32		proclock_hashcode;
 	LWLockId	partitionLock;
 	LockMethod	lockMethodTable;
 	bool		wakeupNeeded;
@@ -2283,29 +2318,35 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
 		elog(ERROR, "unrecognized lock method: %d", lockmethodid);
 	lockMethodTable = LockMethods[lockmethodid];
 
-	partition = LockTagToPartition(locktag);
-	partitionLock = FirstLockMgrLock + partition;
+	hashcode = LockTagHashCode(locktag);
+	partitionLock = LockHashPartitionLock(hashcode);
 
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
 	/*
 	 * Re-find the lock object (it had better be there).
 	 */
-	lock = (LOCK *) hash_search(LockMethodLockHash[partition],
-								(void *) locktag,
-								HASH_FIND, NULL);
+	lock = (LOCK *) hash_search_with_hash_value(LockMethodLockHash,
+												(void *) locktag,
+												hashcode,
+												HASH_FIND,
+												NULL);
 	if (!lock)
 		elog(PANIC, "failed to re-find shared lock object");
 
 	/*
 	 * Re-find the proclock object (ditto).
 	 */
-	MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG));		/* must clear padding */
-	proclocktag.lock = MAKE_OFFSET(lock);
-	proclocktag.proc = MAKE_OFFSET(proc);
-	proclock = (PROCLOCK *) hash_search(LockMethodProcLockHash[partition],
-										(void *) &proclocktag,
-										HASH_FIND, NULL);
+	proclocktag.myLock = lock;
+	proclocktag.myProc = proc;
+
+	proclock_hashcode = ProcLockHashCode(&proclocktag, hashcode);
+
+	proclock = (PROCLOCK *) hash_search_with_hash_value(LockMethodProcLockHash,
+														(void *) &proclocktag,
+														proclock_hashcode,
+														HASH_FIND,
+														NULL);
 	if (!proclock)
 		elog(PANIC, "failed to re-find shared proclock object");
 
@@ -2328,7 +2369,7 @@ lock_twophase_postcommit(TransactionId xid, uint16 info,
 	wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
 
 	CleanUpLock(lock, proclock,
-				lockMethodTable, partition,
+				lockMethodTable, hashcode,
 				wakeupNeeded);
 
 	LWLockRelease(partitionLock);
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index b3ec3330d0dfb297fc70402d5631ac7c96bae51d..04cd338aac7e29308b5f5b344f33bdfeabdd0c75 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.177 2006/07/14 14:52:23 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.178 2006/07/23 23:08:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -461,13 +461,13 @@ LockWaitCancel(void)
 	disable_sig_alarm(false);
 
 	/* Unlink myself from the wait queue, if on it (might not be anymore!) */
-	partitionLock = FirstLockMgrLock + lockAwaited->partition;
+	partitionLock = LockHashPartitionLock(lockAwaited->hashcode);
 	LWLockAcquire(partitionLock, LW_EXCLUSIVE);
 
 	if (MyProc->links.next != INVALID_OFFSET)
 	{
 		/* We could not have been granted the lock yet */
-		RemoveFromWaitQueue(MyProc, lockAwaited->partition);
+		RemoveFromWaitQueue(MyProc, lockAwaited->hashcode);
 	}
 	else
 	{
@@ -673,8 +673,8 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	LOCKMODE	lockmode = locallock->tag.mode;
 	LOCK	   *lock = locallock->lock;
 	PROCLOCK   *proclock = locallock->proclock;
-	int			partition = locallock->partition;
-	LWLockId	partitionLock = FirstLockMgrLock + partition;
+	uint32		hashcode = locallock->hashcode;
+	LWLockId	partitionLock = LockHashPartitionLock(hashcode);
 	PROC_QUEUE *waitQueue = &(lock->waitProcs);
 	LOCKMASK	myHeldLocks = MyProc->heldLocks;
 	bool		early_deadlock = false;
@@ -776,7 +776,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
 	 */
 	if (early_deadlock)
 	{
-		RemoveFromWaitQueue(MyProc, partition);
+		RemoveFromWaitQueue(MyProc, hashcode);
 		return STATUS_ERROR;
 	}
 
@@ -1025,7 +1025,7 @@ CheckDeadLock(void)
 	 * ProcSleep will report an error after we return from the signal handler.
 	 */
 	Assert(MyProc->waitLock != NULL);
-	RemoveFromWaitQueue(MyProc, LockTagToPartition(&(MyProc->waitLock->tag)));
+	RemoveFromWaitQueue(MyProc, LockTagHashCode(&(MyProc->waitLock->tag)));
 
 	/*
 	 * Unlock my semaphore so that the interrupted ProcSleep() call can
diff --git a/src/backend/utils/adt/lockfuncs.c b/src/backend/utils/adt/lockfuncs.c
index 6d4eddc7bd81ac538662535b8469688b15858436..40046a020a004a1726e3e32ce5db6b6b92ffd51e 100644
--- a/src/backend/utils/adt/lockfuncs.c
+++ b/src/backend/utils/adt/lockfuncs.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2002-2006, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *		$PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.23 2006/07/14 14:52:24 momjian Exp $
+ *		$PostgreSQL: pgsql/src/backend/utils/adt/lockfuncs.c,v 1.24 2006/07/23 23:08:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -152,7 +152,7 @@ pg_lock_status(PG_FUNCTION_ARGS)
 		 */
 		if (!granted)
 		{
-			if (proc->waitLock == (LOCK *) MAKE_PTR(proclock->tag.lock))
+			if (proc->waitLock == proclock->tag.myLock)
 			{
 				/* Yes, so report it with proper mode */
 				mode = proc->waitLockMode;
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index d471293b702ad639f5443b298d6d8295d77ab61d..7a2651cd28f32d5760fecbee63c9e3f42b006464 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.95 2006/07/23 03:07:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.96 2006/07/23 23:08:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -266,7 +266,9 @@ typedef struct LOCK
  *
  * PROCLOCKTAG is the key information needed to look up a PROCLOCK item in the
  * proclock hashtable.	A PROCLOCKTAG value uniquely identifies the combination
- * of a lockable object and a holder/waiter for that object.
+ * of a lockable object and a holder/waiter for that object.  (We can use
+ * pointers here because the PROCLOCKTAG need only be unique for the lifespan
+ * of the PROCLOCK, and it will never outlive the lock or the proc.)
  *
  * Internally to a backend, it is possible for the same lock to be held
  * for different purposes: the backend tracks transaction locks separately
@@ -292,8 +294,9 @@ typedef struct LOCK
  */
 typedef struct PROCLOCKTAG
 {
-	SHMEM_OFFSET lock;			/* link to per-lockable-object information */
-	SHMEM_OFFSET proc;			/* link to PGPROC of owning backend */
+	/* NB: we assume this struct contains no padding! */
+	LOCK	   *myLock;			/* link to per-lockable-object information */
+	PGPROC	   *myProc;			/* link to PGPROC of owning backend */
 } PROCLOCKTAG;
 
 typedef struct PROCLOCK
@@ -309,7 +312,7 @@ typedef struct PROCLOCK
 } PROCLOCK;
 
 #define PROCLOCK_LOCKMETHOD(proclock) \
-	LOCK_LOCKMETHOD(*((LOCK *) MAKE_PTR((proclock).tag.lock)))
+	LOCK_LOCKMETHOD(*((proclock).tag.myLock))
 
 /*
  * Each backend also maintains a local hash table with information about each
@@ -347,7 +350,7 @@ typedef struct LOCALLOCK
 	LOCK	   *lock;			/* associated LOCK object in shared mem */
 	PROCLOCK   *proclock;		/* associated PROCLOCK object in shmem */
 	bool		isTempObject;	/* true if lock is on a temporary object */
-	int			partition;		/* ID of partition containing this lock */
+	uint32		hashcode;		/* copy of LOCKTAG's hash value */
 	int			nLocks;			/* total number of times lock is held */
 	int			numLockOwners;	/* # of relevant ResourceOwners */
 	int			maxLockOwners;	/* allocated size of array */
@@ -360,15 +363,14 @@ typedef struct LOCALLOCK
 /*
  * This struct holds information passed from lmgr internals to the lock
  * listing user-level functions (lockfuncs.c).	For each PROCLOCK in the
- * system, the SHMEM_OFFSET, PROCLOCK itself, and associated PGPROC and
- * LOCK objects are stored.  (Note there will often be multiple copies
- * of the same PGPROC or LOCK.)  We do not store the SHMEM_OFFSET of the
- * PGPROC or LOCK separately, since they're in the PROCLOCK's tag fields.
+ * system, copies of the PROCLOCK object and associated PGPROC and
+ * LOCK objects are stored.  Note there will often be multiple copies
+ * of the same PGPROC or LOCK --- to detect whether two are the same,
+ * compare the PROCLOCK tag fields.
  */
-typedef struct
+typedef struct LockData
 {
 	int			nelements;		/* The length of each of the arrays */
-	SHMEM_OFFSET *proclockaddrs;
 	PROCLOCK   *proclocks;
 	PGPROC	   *procs;
 	LOCK	   *locks;
@@ -384,12 +386,24 @@ typedef enum
 } LockAcquireResult;
 
 
+/*
+ * The lockmgr's shared hash tables are partitioned to reduce contention.
+ * To determine which partition a given locktag belongs to, compute the tag's
+ * hash code with LockTagHashCode(), then apply one of these macros.
+ * NB: NUM_LOCK_PARTITIONS must be a power of 2!
+ */
+#define LockHashPartition(hashcode) \
+	((hashcode) % NUM_LOCK_PARTITIONS)
+#define LockHashPartitionLock(hashcode) \
+	((LWLockId) (FirstLockMgrLock + LockHashPartition(hashcode)))
+
+
 /*
  * function prototypes
  */
 extern void InitLocks(void);
 extern LockMethod GetLocksMethodTable(const LOCK *lock);
-extern int	LockTagToPartition(const LOCKTAG *locktag);
+extern uint32 LockTagHashCode(const LOCKTAG *locktag);
 extern LockAcquireResult LockAcquire(const LOCKTAG *locktag,
 			bool isTempObject,
 			LOCKMODE lockmode,
@@ -407,7 +421,7 @@ extern int LockCheckConflicts(LockMethod lockMethodTable,
 				   LOCK *lock, PROCLOCK *proclock, PGPROC *proc);
 extern void GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode);
 extern void GrantAwaitedLock(void);
-extern void RemoveFromWaitQueue(PGPROC *proc, int partition);
+extern void RemoveFromWaitQueue(PGPROC *proc, uint32 hashcode);
 extern Size LockShmemSize(void);
 extern bool DeadLockCheck(PGPROC *proc);
 extern void DeadLockReport(void);
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index 2810326597ea81e5da3a625b62580ca1f9c2d89a..ce7799324301464febed477e30c74970b24001b8 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.29 2006/07/23 03:07:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/lwlock.h,v 1.30 2006/07/23 23:08:46 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -24,7 +24,8 @@
 #define NUM_BUFFER_PARTITIONS  16
 
 /* Number of partitions the shared lock tables are divided into */
-#define NUM_LOCK_PARTITIONS  16
+#define LOG2_NUM_LOCK_PARTITIONS  4
+#define NUM_LOCK_PARTITIONS  (1 << LOG2_NUM_LOCK_PARTITIONS)
 
 /*
  * We have a number of predefined LWLocks, plus a bunch of LWLocks that are