I have completed this TODO item with the following patch, patch applied:
* Merge LockMethodCtl and LockMethodTable into one shared structure
--
Bruce Momjian | http://candle.pha.pa.us
pgman@candle.pha.pa.us | (610) 853-3000
+ If your life is a hard drive, | 830 Blythe Avenue
+ Christ can be your backup. | Drexel Hill, Pennsylvania 19026
Index: src/backend/storage/lmgr/deadlock.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/storage/lmgr/deadlock.c,v
retrieving revision 1.10
diff -c -r1.10 deadlock.c
*** src/backend/storage/lmgr/deadlock.c 20 Jun 2002 20:29:35 -0000 1.10
--- src/backend/storage/lmgr/deadlock.c 18 Jul 2002 22:13:13 -0000
***************
*** 170,179 ****
* only look at regular locks.
*
* We must have already locked the master lock before being called.
- * NOTE: although the lockctl structure appears to allow each lock
- * table to have a different LWLock, all locks that can block had
- * better use the same LWLock, else this code will not be adequately
- * interlocked!
*/
bool
DeadLockCheck(PGPROC *proc)
--- 170,175 ----
***************
*** 384,390 ****
HOLDER *holder;
SHM_QUEUE *lockHolders;
LOCKMETHODTABLE *lockMethodTable;
- LOCKMETHODCTL *lockctl;
PROC_QUEUE *waitQueue;
int queue_size;
int conflictMask;
--- 380,385 ----
***************
*** 423,431 ****
if (lock == NULL)
return false;
lockMethodTable = GetLocksMethodTable(lock);
! lockctl = lockMethodTable->ctl;
! numLockModes = lockctl->numLockModes;
! conflictMask = lockctl->conflictTab[checkProc->waitLockMode];
/*
* Scan for procs that already hold conflicting locks. These are
--- 418,425 ----
if (lock == NULL)
return false;
lockMethodTable = GetLocksMethodTable(lock);
! numLockModes = lockMethodTable->numLockModes;
! conflictMask = lockMethodTable->conflictTab[checkProc->waitLockMode];
/*
* Scan for procs that already hold conflicting locks. These are
Index: src/backend/storage/lmgr/lock.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/storage/lmgr/lock.c,v
retrieving revision 1.108
diff -c -r1.108 lock.c
*** src/backend/storage/lmgr/lock.c 20 Jun 2002 20:29:35 -0000 1.108
--- src/backend/storage/lmgr/lock.c 18 Jul 2002 22:13:19 -0000
***************
*** 213,224 ****
{
int i;
! lockMethodTable->ctl->numLockModes = numModes;
numModes++;
for (i = 0; i < numModes; i++, prioP++, conflictsP++)
{
! lockMethodTable->ctl->conflictTab[i] = *conflictsP;
! lockMethodTable->ctl->prio[i] = *prioP;
}
}
--- 213,224 ----
{
int i;
! lockMethodTable->numLockModes = numModes;
numModes++;
for (i = 0; i < numModes; i++, prioP++, conflictsP++)
{
! lockMethodTable->conflictTab[i] = *conflictsP;
! lockMethodTable->prio[i] = *prioP;
}
}
***************
*** 263,269 ****
/* each lock table has a non-shared, permanent header */
lockMethodTable = (LOCKMETHODTABLE *)
! MemoryContextAlloc(TopMemoryContext, sizeof(LOCKMETHODTABLE));
/*
* Lock the LWLock for the table (probably not necessary here)
--- 263,272 ----
/* each lock table has a non-shared, permanent header */
lockMethodTable = (LOCKMETHODTABLE *)
! ShmemInitStruct(shmemName, sizeof(LOCKMETHODTABLE), &found);
!
! if (!lockMethodTable)
! elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);
/*
* Lock the LWLock for the table (probably not necessary here)
***************
*** 271,287 ****
LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
/*
- * allocate a control structure from shared memory or attach to it if
- * it already exists.
- */
- sprintf(shmemName, "%s (ctl)", tabName);
- lockMethodTable->ctl = (LOCKMETHODCTL *)
- ShmemInitStruct(shmemName, sizeof(LOCKMETHODCTL), &found);
-
- if (!lockMethodTable->ctl)
- elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);
-
- /*
* no zero-th table
*/
NumLockMethods = 1;
--- 274,279 ----
***************
*** 291,299 ****
*/
if (!found)
{
! MemSet(lockMethodTable->ctl, 0, sizeof(LOCKMETHODCTL));
! lockMethodTable->ctl->masterLock = LockMgrLock;
! lockMethodTable->ctl->lockmethod = NumLockMethods;
}
/*
--- 283,291 ----
*/
if (!found)
{
! MemSet(lockMethodTable, 0, sizeof(LOCKMETHODTABLE));
! lockMethodTable->masterLock = LockMgrLock;
! lockMethodTable->lockmethod = NumLockMethods;
}
/*
***************
*** 342,355 ****
if (!lockMethodTable->holderHash)
elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);
! /* init ctl data structures */
LockMethodInit(lockMethodTable, conflictsP, prioP, numModes);
LWLockRelease(LockMgrLock);
pfree(shmemName);
! return lockMethodTable->ctl->lockmethod;
}
/*
--- 334,347 ----
if (!lockMethodTable->holderHash)
elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);
! /* init data structures */
LockMethodInit(lockMethodTable, conflictsP, prioP, numModes);
LWLockRelease(LockMgrLock);
pfree(shmemName);
! return lockMethodTable->lockmethod;
}
/*
***************
*** 476,482 ****
return FALSE;
}
! masterLock = lockMethodTable->ctl->masterLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
--- 468,474 ----
return FALSE;
}
! masterLock = lockMethodTable->masterLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
***************
*** 576,582 ****
* XXX Doing numeric comparison on the lockmodes is a hack; it'd be
* better to use a table. For now, though, this works.
*/
! for (i = lockMethodTable->ctl->numLockModes; i > 0; i--)
{
if (holder->holding[i] > 0)
{
--- 568,574 ----
* XXX Doing numeric comparison on the lockmodes is a hack; it'd be
* better to use a table. For now, though, this works.
*/
! for (i = lockMethodTable->numLockModes; i > 0; i--)
{
if (holder->holding[i] > 0)
{
***************
*** 631,637 ****
* join wait queue. Otherwise, check for conflict with already-held
* locks. (That's last because most complex check.)
*/
! if (lockMethodTable->ctl->conflictTab[lockmode] & lock->waitMask)
status = STATUS_FOUND;
else
status = LockCheckConflicts(lockMethodTable, lockmode,
--- 623,629 ----
* join wait queue. Otherwise, check for conflict with already-held
* locks. (That's last because most complex check.)
*/
! if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
status = STATUS_FOUND;
else
status = LockCheckConflicts(lockMethodTable, lockmode,
***************
*** 683,689 ****
int tmpMask;
for (i = 1, tmpMask = 2;
! i <= lockMethodTable->ctl->numLockModes;
i++, tmpMask <<= 1)
{
if (myHolding[i] > 0)
--- 675,681 ----
int tmpMask;
for (i = 1, tmpMask = 2;
! i <= lockMethodTable->numLockModes;
i++, tmpMask <<= 1)
{
if (myHolding[i] > 0)
***************
*** 749,756 ****
PGPROC *proc,
int *myHolding) /* myHolding[] array or NULL */
{
! LOCKMETHODCTL *lockctl = lockMethodTable->ctl;
! int numLockModes = lockctl->numLockModes;
int bitmask;
int i,
tmpMask;
--- 741,747 ----
PGPROC *proc,
int *myHolding) /* myHolding[] array or NULL */
{
! int numLockModes = lockMethodTable->numLockModes;
int bitmask;
int i,
tmpMask;
***************
*** 765,771 ****
* each type of lock that conflicts with request. Bitwise compare
* tells if there is a conflict.
*/
! if (!(lockctl->conflictTab[lockmode] & lock->grantMask))
{
HOLDER_PRINT("LockCheckConflicts: no conflict", holder);
return STATUS_OK;
--- 756,762 ----
* each type of lock that conflicts with request. Bitwise compare
* tells if there is a conflict.
*/
! if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
{
HOLDER_PRINT("LockCheckConflicts: no conflict", holder);
return STATUS_OK;
***************
*** 798,804 ****
* locks held by other processes. If one of these conflicts with the
* kind of lock that I want, there is a conflict and I have to sleep.
*/
! if (!(lockctl->conflictTab[lockmode] & bitmask))
{
/* no conflict. OK to get the lock */
HOLDER_PRINT("LockCheckConflicts: resolved", holder);
--- 789,795 ----
* locks held by other processes. If one of these conflicts with the
* kind of lock that I want, there is a conflict and I have to sleep.
*/
! if (!(lockMethodTable->conflictTab[lockmode] & bitmask))
{
/* no conflict. OK to get the lock */
HOLDER_PRINT("LockCheckConflicts: resolved", holder);
***************
*** 918,924 ****
* needed, will happen in xact cleanup (see above for motivation).
*/
LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
! LWLockRelease(lockMethodTable->ctl->masterLock);
elog(ERROR, "deadlock detected");
/* not reached */
}
--- 909,915 ----
* needed, will happen in xact cleanup (see above for motivation).
*/
LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
! LWLockRelease(lockMethodTable->masterLock);
elog(ERROR, "deadlock detected");
/* not reached */
}
***************
*** 1014,1020 ****
return FALSE;
}
! masterLock = lockMethodTable->ctl->masterLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
/*
--- 1005,1011 ----
return FALSE;
}
! masterLock = lockMethodTable->masterLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
/*
***************
*** 1109,1115 ****
* granted locks might belong to some waiter, who could now be
* awakened because he doesn't conflict with his own locks.
*/
! if (lockMethodTable->ctl->conflictTab[lockmode] & lock->waitMask)
wakeupNeeded = true;
if (lock->nRequested == 0)
--- 1100,1106 ----
* granted locks might belong to some waiter, who could now be
* awakened because he doesn't conflict with his own locks.
*/
! if (lockMethodTable->conflictTab[lockmode] & lock->waitMask)
wakeupNeeded = true;
if (lock->nRequested == 0)
***************
*** 1208,1215 ****
return FALSE;
}
! numLockModes = lockMethodTable->ctl->numLockModes;
! masterLock = lockMethodTable->ctl->masterLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
--- 1199,1206 ----
return FALSE;
}
! numLockModes = lockMethodTable->numLockModes;
! masterLock = lockMethodTable->masterLock;
LWLockAcquire(masterLock, LW_EXCLUSIVE);
***************
*** 1264,1270 ****
* Read comments in LockRelease
*/
if (!wakeupNeeded &&
! lockMethodTable->ctl->conflictTab[i] & lock->waitMask)
wakeupNeeded = true;
}
}
--- 1255,1261 ----
* Read comments in LockRelease
*/
if (!wakeupNeeded &&
! lockMethodTable->conflictTab[i] & lock->waitMask)
wakeupNeeded = true;
}
}
***************
*** 1355,1362 ****
size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
size += maxBackends * MAXALIGN(sizeof(PGPROC)); /* each MyProc */
! size += MAX_LOCK_METHODS * MAXALIGN(sizeof(LOCKMETHODCTL)); /* each
! * lockMethodTable->ctl */
/* lockHash table */
size += hash_estimate_size(max_table_size, sizeof(LOCK));
--- 1346,1353 ----
size += MAXALIGN(sizeof(PROC_HDR)); /* ProcGlobal */
size += maxBackends * MAXALIGN(sizeof(PGPROC)); /* each MyProc */
! size += MAX_LOCK_METHODS * MAXALIGN(sizeof(LOCKMETHODTABLE)); /* each
! * lockMethodTable */
/* lockHash table */
size += hash_estimate_size(max_table_size, sizeof(LOCK));
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.122
diff -c -r1.122 proc.c
*** src/backend/storage/lmgr/proc.c 13 Jul 2002 01:02:14 -0000 1.122
--- src/backend/storage/lmgr/proc.c 18 Jul 2002 22:13:20 -0000
***************
*** 503,510 ****
LOCK *lock,
HOLDER *holder)
{
! LOCKMETHODCTL *lockctl = lockMethodTable->ctl;
! LWLockId masterLock = lockctl->masterLock;
PROC_QUEUE *waitQueue = &(lock->waitProcs);
int myHeldLocks = MyProc->heldLocks;
bool early_deadlock = false;
--- 503,509 ----
LOCK *lock,
HOLDER *holder)
{
! LWLockId masterLock = lockMethodTable->masterLock;
PROC_QUEUE *waitQueue = &(lock->waitProcs);
int myHeldLocks = MyProc->heldLocks;
bool early_deadlock = false;
***************
*** 537,546 ****
for (i = 0; i < waitQueue->size; i++)
{
/* Must he wait for me? */
! if (lockctl->conflictTab[proc->waitLockMode] & myHeldLocks)
{
/* Must I wait for him ? */
! if (lockctl->conflictTab[lockmode] & proc->heldLocks)
{
/*
* Yes, so we have a deadlock. Easiest way to clean
--- 536,545 ----
for (i = 0; i < waitQueue->size; i++)
{
/* Must he wait for me? */
! if (lockMethodTable->conflictTab[proc->waitLockMode] & myHeldLocks)
{
/* Must I wait for him ? */
! if (lockMethodTable->conflictTab[lockmode] & proc->heldLocks)
{
/*
* Yes, so we have a deadlock. Easiest way to clean
***************
*** 553,559 ****
break;
}
/* I must go before this waiter. Check special case. */
! if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable,
lockmode,
lock,
--- 552,558 ----
break;
}
/* I must go before this waiter. Check special case. */
! if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable,
lockmode,
lock,
***************
*** 725,731 ****
void
ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock)
{
- LOCKMETHODCTL *lockctl = lockMethodTable->ctl;
PROC_QUEUE *waitQueue = &(lock->waitProcs);
int queue_size = waitQueue->size;
PGPROC *proc;
--- 724,729 ----
***************
*** 746,752 ****
* Waken if (a) doesn't conflict with requests of earlier waiters,
* and (b) doesn't conflict with already-held locks.
*/
! if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable,
lockmode,
lock,
--- 744,750 ----
* Waken if (a) doesn't conflict with requests of earlier waiters,
* and (b) doesn't conflict with already-held locks.
*/
! if ((lockMethodTable->conflictTab[lockmode] & aheadRequests) == 0 &&
LockCheckConflicts(lockMethodTable,
lockmode,
lock,
Index: src/include/storage/lock.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/storage/lock.h,v
retrieving revision 1.61
diff -c -r1.61 lock.h
*** src/include/storage/lock.h 20 Jun 2002 20:29:52 -0000 1.61
--- src/include/storage/lock.h 18 Jul 2002 22:13:22 -0000
***************
*** 62,78 ****
* There is normally only one lock method, the default one.
* If user locks are enabled, an additional lock method is present.
*
- * LOCKMETHODCTL and LOCKMETHODTABLE are split because the first lives
- * in shared memory. (There isn't any really good reason for the split.)
- * LOCKMETHODTABLE exists in private memory. Both are created by the
- * postmaster and should be the same in all backends.
- */
-
- /*
* This is the control structure for a lock table. It
* lives in shared memory. This information is the same
* for all backends.
*
* lockmethod -- the handle used by the lock table's clients to
* refer to the type of lock table being used.
*
--- 62,75 ----
* There is normally only one lock method, the default one.
* If user locks are enabled, an additional lock method is present.
*
* This is the control structure for a lock table. It
* lives in shared memory. This information is the same
* for all backends.
*
+ * lockHash -- hash table holding per-locked-object lock information
+ *
+ * holderHash -- hash table holding per-lock-holder lock information
+ *
* lockmethod -- the handle used by the lock table's clients to
* refer to the type of lock table being used.
*
***************
*** 88,115 ****
* starvation). XXX this field is not actually used at present!
*
* masterLock -- synchronizes access to the table
*/
! typedef struct LOCKMETHODCTL
{
LOCKMETHOD lockmethod;
int numLockModes;
int conflictTab[MAX_LOCKMODES];
int prio[MAX_LOCKMODES];
LWLockId masterLock;
- } LOCKMETHODCTL;
-
- /*
- * Eack backend has a non-shared lock table header.
- *
- * lockHash -- hash table holding per-locked-object lock information
- * holderHash -- hash table holding per-lock-holder lock information
- * ctl - shared control structure described above.
- */
- typedef struct LOCKMETHODTABLE
- {
- HTAB *lockHash;
- HTAB *holderHash;
- LOCKMETHODCTL *ctl;
} LOCKMETHODTABLE;
--- 85,101 ----
* starvation). XXX this field is not actually used at present!
*
* masterLock -- synchronizes access to the table
+ *
*/
! typedef struct LOCKMETHODTABLE
{
+ HTAB *lockHash;
+ HTAB *holderHash;
LOCKMETHOD lockmethod;
int numLockModes;
int conflictTab[MAX_LOCKMODES];
int prio[MAX_LOCKMODES];
LWLockId masterLock;
} LOCKMETHODTABLE;