*
*
* 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
#include
#include
+#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "miscadmin.h"
* 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;
{
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,
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 */
#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);
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).
/*
- * 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;
}
PROCLOCKTAG proclocktag;
bool found;
ResourceOwner owner;
+ uint32 hashcode;
+ uint32 proclock_hashcode;
int partition;
LWLockId partitionLock;
int status;
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;
/*
* 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);
* 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);
/*
* 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 */
* 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);
{
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
* 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)
{
/*
*/
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");
}
*/
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)
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
* 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;
* any other waiters for the lock can be woken up now.
*/
CleanUpLock(waitLock, proclock,
- LockMethods[lockmethodid], partition,
+ LockMethods[lockmethodid], hashcode,
true);
}
LOCALLOCK *locallock;
LOCK *lock;
PROCLOCK *proclock;
- int partition;
LWLockId partitionLock;
bool wakeupNeeded;
/*
* 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);
wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
CleanUpLock(lock, proclock,
- lockMethodTable, partition,
+ lockMethodTable, locallock->hashcode,
wakeupNeeded);
LWLockRelease(partitionLock);
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)
/* CleanUpLock will wake up waiters if needed. */
CleanUpLock(lock, proclock,
- lockMethodTable, partition,
+ lockMethodTable,
+ LockTagHashCode(&lock->tag),
wakeupNeeded);
next_item:
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)
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
*/
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");
/*
* 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)
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);
GetLockStatusData(void)
{
LockData *data;
- HTAB *proclockTable;
PROCLOCK *proclock;
HASH_SEQ_STATUS seqstat;
int els;
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.
*
* 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 */
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);
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 */
PROCLOCK *proclock;
PROCLOCKTAG proclocktag;
bool found;
+ uint32 hashcode;
+ uint32 proclock_hashcode;
int partition;
LWLockId partitionLock;
LockMethod lockMethodTable;
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);
/*
* 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 */
* 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);
LOCK *lock;
PROCLOCK *proclock;
PROCLOCKTAG proclocktag;
- int partition;
+ uint32 hashcode;
+ uint32 proclock_hashcode;
LWLockId partitionLock;
LockMethod lockMethodTable;
bool wakeupNeeded;
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");
wakeupNeeded = UnGrantLock(lock, lockmode, proclock, lockMethodTable);
CleanUpLock(lock, proclock,
- lockMethodTable, partition,
+ lockMethodTable, hashcode,
wakeupNeeded);
LWLockRelease(partitionLock);