|
|
|
@ -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); |
|
|
|
|