Index: src/backend/storage/lmgr/deadlock.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/storage/lmgr/deadlock.c,v
retrieving revision 1.16
diff -c -c -r1.16 deadlock.c
*** src/backend/storage/lmgr/deadlock.c	16 Jan 2003 21:01:44 -0000	1.16
--- src/backend/storage/lmgr/deadlock.c	18 Feb 2003 02:07:46 -0000
***************
*** 425,431 ****
  {
  	PGPROC	   *proc;
  	LOCK	   *lock;
! 	PROCLOCK   *holder;
  	SHM_QUEUE  *lockHolders;
  	LOCKMETHODTABLE *lockMethodTable;
  	PROC_QUEUE *waitQueue;
--- 425,431 ----
  {
  	PGPROC	   *proc;
  	LOCK	   *lock;
! 	PROCLOCK   *proclock;
  	SHM_QUEUE  *lockHolders;
  	LOCKMETHODTABLE *lockMethodTable;
  	PROC_QUEUE *waitQueue;
***************
*** 484,502 ****
  	 */
  	lockHolders = &(lock->lockHolders);
  
! 	holder = (PROCLOCK *) SHMQueueNext(lockHolders, lockHolders,
  									   offsetof(PROCLOCK, lockLink));
  
! 	while (holder)
  	{
! 		proc = (PGPROC *) MAKE_PTR(holder->tag.proc);
  
  		/* A proc never blocks itself */
  		if (proc != checkProc)
  		{
  			for (lm = 1; lm <= numLockModes; lm++)
  			{
! 				if (holder->holding[lm] > 0 &&
  					((1 << lm) & conflictMask) != 0)
  				{
  					/* This proc hard-blocks checkProc */
--- 484,502 ----
  	 */
  	lockHolders = &(lock->lockHolders);
  
! 	proclock = (PROCLOCK *) SHMQueueNext(lockHolders, lockHolders,
  									   offsetof(PROCLOCK, lockLink));
  
! 	while (proclock)
  	{
! 		proc = (PGPROC *) MAKE_PTR(proclock->tag.proc);
  
  		/* A proc never blocks itself */
  		if (proc != checkProc)
  		{
  			for (lm = 1; lm <= numLockModes; lm++)
  			{
! 				if (proclock->holding[lm] > 0 &&
  					((1 << lm) & conflictMask) != 0)
  				{
  					/* This proc hard-blocks checkProc */
***************
*** 512,524 ****
  
  						return true;
  					}
! 					/* If no deadlock, we're done looking at this holder */
  					break;
  				}
  			}
  		}
  
! 		holder = (PROCLOCK *) SHMQueueNext(lockHolders, &holder->lockLink,
  										   offsetof(PROCLOCK, lockLink));
  	}
  
--- 512,524 ----
  
  						return true;
  					}
! 					/* If no deadlock, we're done looking at this proclock */
  					break;
  				}
  			}
  		}
  
! 		proclock = (PROCLOCK *) SHMQueueNext(lockHolders, &proclock->lockLink,
  										   offsetof(PROCLOCK, lockLink));
  	}
  
Index: src/backend/storage/lmgr/lock.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/storage/lmgr/lock.c,v
retrieving revision 1.119
diff -c -c -r1.119 lock.c
*** src/backend/storage/lmgr/lock.c	16 Jan 2003 21:01:44 -0000	1.119
--- src/backend/storage/lmgr/lock.c	18 Feb 2003 02:07:48 -0000
***************
*** 47,53 ****
  
  
  static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
! 		   LOCK *lock, PROCLOCK *holder);
  static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc,
  				 int *myHolding);
  
--- 47,53 ----
  
  
  static int WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
! 		   LOCK *lock, PROCLOCK *proclock);
  static void LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc,
  				 int *myHolding);
  
***************
*** 124,151 ****
  
  
  inline static void
! PROCLOCK_PRINT(const char *where, const PROCLOCK *holderP)
  {
  	if (
! 	(((PROCLOCK_LOCKMETHOD(*holderP) == DEFAULT_LOCKMETHOD && Trace_locks)
! 	  || (PROCLOCK_LOCKMETHOD(*holderP) == USER_LOCKMETHOD && Trace_userlocks))
! 	 && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
! 		|| (Trace_lock_table && (((LOCK *) MAKE_PTR(holderP->tag.lock))->tag.relId == Trace_lock_table))
  		)
  		elog(LOG,
! 			 "%s: holder(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d",
! 			 where, MAKE_OFFSET(holderP), holderP->tag.lock,
! 			 PROCLOCK_LOCKMETHOD(*(holderP)),
! 			 holderP->tag.proc, holderP->tag.xid,
! 		   holderP->holding[1], holderP->holding[2], holderP->holding[3],
! 		   holderP->holding[4], holderP->holding[5], holderP->holding[6],
! 			 holderP->holding[7], holderP->nHolding);
  }
  
  #else							/* not LOCK_DEBUG */
  
  #define LOCK_PRINT(where, lock, type)
! #define PROCLOCK_PRINT(where, holderP)
  #endif   /* not LOCK_DEBUG */
  
  
--- 124,151 ----
  
  
  inline static void
! PROCLOCK_PRINT(const char *where, const PROCLOCK *proclockP)
  {
  	if (
! 	(((PROCLOCK_LOCKMETHOD(*proclockP) == DEFAULT_LOCKMETHOD && Trace_locks)
! 	  || (PROCLOCK_LOCKMETHOD(*proclockP) == USER_LOCKMETHOD && Trace_userlocks))
! 	 && (((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag.relId >= (Oid) Trace_lock_oidmin))
! 		|| (Trace_lock_table && (((LOCK *) MAKE_PTR(proclockP->tag.lock))->tag.relId == Trace_lock_table))
  		)
  		elog(LOG,
! 			 "%s: proclock(%lx) lock(%lx) tbl(%d) proc(%lx) xid(%u) hold(%d,%d,%d,%d,%d,%d,%d)=%d",
! 			 where, MAKE_OFFSET(proclockP), proclockP->tag.lock,
! 			 PROCLOCK_LOCKMETHOD(*(proclockP)),
! 			 proclockP->tag.proc, proclockP->tag.xid,
! 		   proclockP->holding[1], proclockP->holding[2], proclockP->holding[3],
! 		   proclockP->holding[4], proclockP->holding[5], proclockP->holding[6],
! 			 proclockP->holding[7], proclockP->nHolding);
  }
  
  #else							/* not LOCK_DEBUG */
  
  #define LOCK_PRINT(where, lock, type)
! #define PROCLOCK_PRINT(where, proclockP)
  #endif   /* not LOCK_DEBUG */
  
  
***************
*** 312,332 ****
  
  	/*
  	 * allocate a hash table for PROCLOCK structs.	This is used to store
! 	 * per-lock-holder information.
  	 */
  	info.keysize = sizeof(PROCLOCKTAG);
  	info.entrysize = sizeof(PROCLOCK);
  	info.hash = tag_hash;
  	hash_flags = (HASH_ELEM | HASH_FUNCTION);
  
! 	sprintf(shmemName, "%s (holder hash)", tabName);
! 	lockMethodTable->holderHash = ShmemInitHash(shmemName,
  												init_table_size,
  												max_table_size,
  												&info,
  												hash_flags);
  
! 	if (!lockMethodTable->holderHash)
  		elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);
  
  	/* init data structures */
--- 312,332 ----
  
  	/*
  	 * allocate a hash table for PROCLOCK structs.	This is used to store
! 	 * per-lock-proclock information.
  	 */
  	info.keysize = sizeof(PROCLOCKTAG);
  	info.entrysize = sizeof(PROCLOCK);
  	info.hash = tag_hash;
  	hash_flags = (HASH_ELEM | HASH_FUNCTION);
  
! 	sprintf(shmemName, "%s (proclock hash)", tabName);
! 	lockMethodTable->proclockHash = ShmemInitHash(shmemName,
  												init_table_size,
  												max_table_size,
  												&info,
  												hash_flags);
  
! 	if (!lockMethodTable->proclockHash)
  		elog(FATAL, "LockMethodTableInit: couldn't initialize %s", tabName);
  
  	/* init data structures */
***************
*** 421,427 ****
   *		tag.objId						block id		lock id2
   *										or xact id
   *		tag.offnum						0				lock id1
!  *		holder.xid						xid or 0		0
   *		persistence						transaction		user or backend
   *										or backend
   *
--- 421,427 ----
   *		tag.objId						block id		lock id2
   *										or xact id
   *		tag.offnum						0				lock id1
!  *		proclock.xid					xid or 0		0
   *		persistence						transaction		user or backend
   *										or backend
   *
***************
*** 435,443 ****
  LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
  			TransactionId xid, LOCKMODE lockmode, bool dontWait)
  {
! 	PROCLOCK   *holder;
! 	PROCLOCKTAG holdertag;
! 	HTAB	   *holderTable;
  	bool		found;
  	LOCK	   *lock;
  	LWLockId	masterLock;
--- 435,443 ----
  LockAcquire(LOCKMETHOD lockmethod, LOCKTAG *locktag,
  			TransactionId xid, LOCKMODE lockmode, bool dontWait)
  {
! 	PROCLOCK   *proclock;
! 	PROCLOCKTAG proclocktag;
! 	HTAB	   *proclockTable;
  	bool		found;
  	LOCK	   *lock;
  	LWLockId	masterLock;
***************
*** 506,530 ****
  	}
  
  	/*
! 	 * Create the hash key for the holder table.
  	 */
! 	MemSet(&holdertag, 0, sizeof(PROCLOCKTAG)); /* must clear padding,
  												 * needed */
! 	holdertag.lock = MAKE_OFFSET(lock);
! 	holdertag.proc = MAKE_OFFSET(MyProc);
! 	TransactionIdStore(xid, &holdertag.xid);
  
  	/*
! 	 * Find or create a holder entry with this tag
  	 */
! 	holderTable = lockMethodTable->holderHash;
! 	holder = (PROCLOCK *) hash_search(holderTable,
! 									  (void *) &holdertag,
  									  HASH_ENTER, &found);
! 	if (!holder)
  	{
  		LWLockRelease(masterLock);
! 		elog(ERROR, "LockAcquire: holder table out of memory");
  		return FALSE;
  	}
  
--- 506,530 ----
  	}
  
  	/*
! 	 * Create the hash key for the proclock table.
  	 */
! 	MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding,
  												 * needed */
! 	proclocktag.lock = MAKE_OFFSET(lock);
! 	proclocktag.proc = MAKE_OFFSET(MyProc);
! 	TransactionIdStore(xid, &proclocktag.xid);
  
  	/*
! 	 * Find or create a proclock entry with this tag
  	 */
! 	proclockTable = lockMethodTable->proclockHash;
! 	proclock = (PROCLOCK *) hash_search(proclockTable,
! 									  (void *) &proclocktag,
  									  HASH_ENTER, &found);
! 	if (!proclock)
  	{
  		LWLockRelease(masterLock);
! 		elog(ERROR, "LockAcquire: proclock table out of memory");
  		return FALSE;
  	}
  
***************
*** 533,550 ****
  	 */
  	if (!found)
  	{
! 		holder->nHolding = 0;
! 		MemSet((char *) holder->holding, 0, sizeof(int) * MAX_LOCKMODES);
! 		/* Add holder to appropriate lists */
! 		SHMQueueInsertBefore(&lock->lockHolders, &holder->lockLink);
! 		SHMQueueInsertBefore(&MyProc->procHolders, &holder->procLink);
! 		PROCLOCK_PRINT("LockAcquire: new", holder);
  	}
  	else
  	{
! 		PROCLOCK_PRINT("LockAcquire: found", holder);
! 		Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
! 		Assert(holder->nHolding <= lock->nGranted);
  
  #ifdef CHECK_DEADLOCK_RISK
  
--- 533,550 ----
  	 */
  	if (!found)
  	{
! 		proclock->nHolding = 0;
! 		MemSet((char *) proclock->holding, 0, sizeof(int) * MAX_LOCKMODES);
! 		/* Add proclock to appropriate lists */
! 		SHMQueueInsertBefore(&lock->lockHolders, &proclock->lockLink);
! 		SHMQueueInsertBefore(&MyProc->procHolders, &proclock->procLink);
! 		PROCLOCK_PRINT("LockAcquire: new", proclock);
  	}
  	else
  	{
! 		PROCLOCK_PRINT("LockAcquire: found", proclock);
! 		Assert((proclock->nHolding >= 0) && (proclock->holding[lockmode] >= 0));
! 		Assert(proclock->nHolding <= lock->nGranted);
  
  #ifdef CHECK_DEADLOCK_RISK
  
***************
*** 565,571 ****
  		 */
  		for (i = lockMethodTable->numLockModes; i > 0; i--)
  		{
! 			if (holder->holding[i] > 0)
  			{
  				if (i >= (int) lockmode)
  					break;		/* safe: we have a lock >= req level */
--- 565,571 ----
  		 */
  		for (i = lockMethodTable->numLockModes; i > 0; i--)
  		{
! 			if (proclock->holding[i] > 0)
  			{
  				if (i >= (int) lockmode)
  					break;		/* safe: we have a lock >= req level */
***************
*** 592,614 ****
  	 * If I already hold one or more locks of the requested type, just
  	 * grant myself another one without blocking.
  	 */
! 	if (holder->holding[lockmode] > 0)
  	{
! 		GrantLock(lock, holder, lockmode);
! 		PROCLOCK_PRINT("LockAcquire: owning", holder);
  		LWLockRelease(masterLock);
  		return TRUE;
  	}
  
  	/*
! 	 * If this process (under any XID) is a holder of the lock, also grant
  	 * myself another one without blocking.
  	 */
! 	LockCountMyLocks(holder->tag.lock, MyProc, myHolding);
  	if (myHolding[lockmode] > 0)
  	{
! 		GrantLock(lock, holder, lockmode);
! 		PROCLOCK_PRINT("LockAcquire: my other XID owning", holder);
  		LWLockRelease(masterLock);
  		return TRUE;
  	}
--- 592,614 ----
  	 * If I already hold one or more locks of the requested type, just
  	 * grant myself another one without blocking.
  	 */
! 	if (proclock->holding[lockmode] > 0)
  	{
! 		GrantLock(lock, proclock, lockmode);
! 		PROCLOCK_PRINT("LockAcquire: owning", proclock);
  		LWLockRelease(masterLock);
  		return TRUE;
  	}
  
  	/*
! 	 * If this process (under any XID) is a proclock of the lock, also grant
  	 * myself another one without blocking.
  	 */
! 	LockCountMyLocks(proclock->tag.lock, MyProc, myHolding);
  	if (myHolding[lockmode] > 0)
  	{
! 		GrantLock(lock, proclock, lockmode);
! 		PROCLOCK_PRINT("LockAcquire: my other XID owning", proclock);
  		LWLockRelease(masterLock);
  		return TRUE;
  	}
***************
*** 622,634 ****
  		status = STATUS_FOUND;
  	else
  		status = LockCheckConflicts(lockMethodTable, lockmode,
! 									lock, holder,
  									MyProc, myHolding);
  
  	if (status == STATUS_OK)
  	{
  		/* No conflict with held or previously requested locks */
! 		GrantLock(lock, holder, lockmode);
  	}
  	else
  	{
--- 622,634 ----
  		status = STATUS_FOUND;
  	else
  		status = LockCheckConflicts(lockMethodTable, lockmode,
! 									lock, proclock,
  									MyProc, myHolding);
  
  	if (status == STATUS_OK)
  	{
  		/* No conflict with held or previously requested locks */
! 		GrantLock(lock, proclock, lockmode);
  	}
  	else
  	{
***************
*** 636,658 ****
  
  		/*
  		 * We can't acquire the lock immediately.  If caller specified no
! 		 * blocking, remove the holder entry and return FALSE without
  		 * waiting.
  		 */
  		if (dontWait)
  		{
! 			if (holder->nHolding == 0)
  			{
! 				SHMQueueDelete(&holder->lockLink);
! 				SHMQueueDelete(&holder->procLink);
! 				holder = (PROCLOCK *) hash_search(holderTable,
! 												  (void *) holder,
  												  HASH_REMOVE, NULL);
! 				if (!holder)
! 					elog(WARNING, "LockAcquire: remove holder, table corrupted");
  			}
  			else
! 				PROCLOCK_PRINT("LockAcquire: NHOLDING", holder);
  			lock->nRequested--;
  			lock->requested[lockmode]--;
  			LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
--- 636,658 ----
  
  		/*
  		 * We can't acquire the lock immediately.  If caller specified no
! 		 * blocking, remove the proclock entry and return FALSE without
  		 * waiting.
  		 */
  		if (dontWait)
  		{
! 			if (proclock->nHolding == 0)
  			{
! 				SHMQueueDelete(&proclock->lockLink);
! 				SHMQueueDelete(&proclock->procLink);
! 				proclock = (PROCLOCK *) hash_search(proclockTable,
! 												  (void *) proclock,
  												  HASH_REMOVE, NULL);
! 				if (!proclock)
! 					elog(WARNING, "LockAcquire: remove proclock, table corrupted");
  			}
  			else
! 				PROCLOCK_PRINT("LockAcquire: NHOLDING", proclock);
  			lock->nRequested--;
  			lock->requested[lockmode]--;
  			LOCK_PRINT("LockAcquire: conditional lock failed", lock, lockmode);
***************
*** 682,688 ****
  		/*
  		 * Sleep till someone wakes me up.
  		 */
! 		status = WaitOnLock(lockmethod, lockmode, lock, holder);
  
  		/*
  		 * NOTE: do not do any material change of state between here and
--- 682,688 ----
  		/*
  		 * Sleep till someone wakes me up.
  		 */
! 		status = WaitOnLock(lockmethod, lockmode, lock, proclock);
  
  		/*
  		 * NOTE: do not do any material change of state between here and
***************
*** 692,709 ****
  		 */
  
  		/*
! 		 * Check the holder entry status, in case something in the ipc
  		 * communication doesn't work correctly.
  		 */
! 		if (!((holder->nHolding > 0) && (holder->holding[lockmode] > 0)))
  		{
! 			PROCLOCK_PRINT("LockAcquire: INCONSISTENT", holder);
  			LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
  			/* Should we retry ? */
  			LWLockRelease(masterLock);
  			return FALSE;
  		}
! 		PROCLOCK_PRINT("LockAcquire: granted", holder);
  		LOCK_PRINT("LockAcquire: granted", lock, lockmode);
  	}
  
--- 692,709 ----
  		 */
  
  		/*
! 		 * Check the proclock entry status, in case something in the ipc
  		 * communication doesn't work correctly.
  		 */
! 		if (!((proclock->nHolding > 0) && (proclock->holding[lockmode] > 0)))
  		{
! 			PROCLOCK_PRINT("LockAcquire: INCONSISTENT", proclock);
  			LOCK_PRINT("LockAcquire: INCONSISTENT", lock, lockmode);
  			/* Should we retry ? */
  			LWLockRelease(masterLock);
  			return FALSE;
  		}
! 		PROCLOCK_PRINT("LockAcquire: granted", proclock);
  		LOCK_PRINT("LockAcquire: granted", lock, lockmode);
  	}
  
***************
*** 732,738 ****
  LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
  				   LOCKMODE lockmode,
  				   LOCK *lock,
! 				   PROCLOCK *holder,
  				   PGPROC *proc,
  				   int *myHolding)		/* myHolding[] array or NULL */
  {
--- 732,738 ----
  LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
  				   LOCKMODE lockmode,
  				   LOCK *lock,
! 				   PROCLOCK *proclock,
  				   PGPROC *proc,
  				   int *myHolding)		/* myHolding[] array or NULL */
  {
***************
*** 753,759 ****
  	 */
  	if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
  	{
! 		PROCLOCK_PRINT("LockCheckConflicts: no conflict", holder);
  		return STATUS_OK;
  	}
  
--- 753,759 ----
  	 */
  	if (!(lockMethodTable->conflictTab[lockmode] & lock->grantMask))
  	{
! 		PROCLOCK_PRINT("LockCheckConflicts: no conflict", proclock);
  		return STATUS_OK;
  	}
  
***************
*** 766,772 ****
  	if (myHolding == NULL)
  	{
  		/* Caller didn't do calculation of total holding for me */
! 		LockCountMyLocks(holder->tag.lock, proc, localHolding);
  		myHolding = localHolding;
  	}
  
--- 766,772 ----
  	if (myHolding == NULL)
  	{
  		/* Caller didn't do calculation of total holding for me */
! 		LockCountMyLocks(proclock->tag.lock, proc, localHolding);
  		myHolding = localHolding;
  	}
  
***************
*** 787,797 ****
  	if (!(lockMethodTable->conflictTab[lockmode] & bitmask))
  	{
  		/* no conflict. OK to get the lock */
! 		PROCLOCK_PRINT("LockCheckConflicts: resolved", holder);
  		return STATUS_OK;
  	}
  
! 	PROCLOCK_PRINT("LockCheckConflicts: conflicting", holder);
  	return STATUS_FOUND;
  }
  
--- 787,797 ----
  	if (!(lockMethodTable->conflictTab[lockmode] & bitmask))
  	{
  		/* no conflict. OK to get the lock */
! 		PROCLOCK_PRINT("LockCheckConflicts: resolved", proclock);
  		return STATUS_OK;
  	}
  
! 	PROCLOCK_PRINT("LockCheckConflicts: conflicting", proclock);
  	return STATUS_FOUND;
  }
  
***************
*** 809,844 ****
  LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
  {
  	SHM_QUEUE  *procHolders = &(proc->procHolders);
! 	PROCLOCK   *holder;
  	int			i;
  
  	MemSet(myHolding, 0, MAX_LOCKMODES * sizeof(int));
  
! 	holder = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
  									   offsetof(PROCLOCK, procLink));
  
! 	while (holder)
  	{
! 		if (lockOffset == holder->tag.lock)
  		{
  			for (i = 1; i < MAX_LOCKMODES; i++)
! 				myHolding[i] += holder->holding[i];
  		}
  
! 		holder = (PROCLOCK *) SHMQueueNext(procHolders, &holder->procLink,
  										   offsetof(PROCLOCK, procLink));
  	}
  }
  
  /*
!  * GrantLock -- update the lock and holder data structures to show
   *		the lock request has been granted.
   *
   * NOTE: if proc was blocked, it also needs to be removed from the wait list
   * and have its waitLock/waitHolder fields cleared.  That's not done here.
   */
  void
! GrantLock(LOCK *lock, PROCLOCK *holder, LOCKMODE lockmode)
  {
  	lock->nGranted++;
  	lock->granted[lockmode]++;
--- 809,844 ----
  LockCountMyLocks(SHMEM_OFFSET lockOffset, PGPROC *proc, int *myHolding)
  {
  	SHM_QUEUE  *procHolders = &(proc->procHolders);
! 	PROCLOCK   *proclock;
  	int			i;
  
  	MemSet(myHolding, 0, MAX_LOCKMODES * sizeof(int));
  
! 	proclock = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
  									   offsetof(PROCLOCK, procLink));
  
! 	while (proclock)
  	{
! 		if (lockOffset == proclock->tag.lock)
  		{
  			for (i = 1; i < MAX_LOCKMODES; i++)
! 				myHolding[i] += proclock->holding[i];
  		}
  
! 		proclock = (PROCLOCK *) SHMQueueNext(procHolders, &proclock->procLink,
  										   offsetof(PROCLOCK, procLink));
  	}
  }
  
  /*
!  * GrantLock -- update the lock and proclock data structures to show
   *		the lock request has been granted.
   *
   * NOTE: if proc was blocked, it also needs to be removed from the wait list
   * and have its waitLock/waitHolder fields cleared.  That's not done here.
   */
  void
! GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode)
  {
  	lock->nGranted++;
  	lock->granted[lockmode]++;
***************
*** 848,856 ****
  	LOCK_PRINT("GrantLock", lock, lockmode);
  	Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
  	Assert(lock->nGranted <= lock->nRequested);
! 	holder->holding[lockmode]++;
! 	holder->nHolding++;
! 	Assert((holder->nHolding > 0) && (holder->holding[lockmode] > 0));
  }
  
  /*
--- 848,856 ----
  	LOCK_PRINT("GrantLock", lock, lockmode);
  	Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
  	Assert(lock->nGranted <= lock->nRequested);
! 	proclock->holding[lockmode]++;
! 	proclock->nHolding++;
! 	Assert((proclock->nHolding > 0) && (proclock->holding[lockmode] > 0));
  }
  
  /*
***************
*** 863,869 ****
   */
  static int
  WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
! 		   LOCK *lock, PROCLOCK *holder)
  {
  	LOCKMETHODTABLE *lockMethodTable = LockMethodTable[lockmethod];
  	char	   *new_status,
--- 863,869 ----
   */
  static int
  WaitOnLock(LOCKMETHOD lockmethod, LOCKMODE lockmode,
! 		   LOCK *lock, PROCLOCK *proclock)
  {
  	LOCKMETHODTABLE *lockMethodTable = LockMethodTable[lockmethod];
  	char	   *new_status,
***************
*** 896,906 ****
  	if (ProcSleep(lockMethodTable,
  				  lockmode,
  				  lock,
! 				  holder) != STATUS_OK)
  	{
  		/*
  		 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
! 		 * now.  Removal of the holder and lock objects, if no longer
  		 * needed, will happen in xact cleanup (see above for motivation).
  		 */
  		LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
--- 896,906 ----
  	if (ProcSleep(lockMethodTable,
  				  lockmode,
  				  lock,
! 				  proclock) != STATUS_OK)
  	{
  		/*
  		 * We failed as a result of a deadlock, see CheckDeadLock(). Quit
! 		 * now.  Removal of the proclock and lock objects, if no longer
  		 * needed, will happen in xact cleanup (see above for motivation).
  		 */
  		LOCK_PRINT("WaitOnLock: aborting on lock", lock, lockmode);
***************
*** 930,936 ****
   *
   * Locktable lock must be held by caller.
   *
!  * NB: this does not remove the process' holder object, nor the lock object,
   * even though their counts might now have gone to zero.  That will happen
   * during a subsequent LockReleaseAll call, which we expect will happen
   * during transaction cleanup.	(Removal of a proc from its wait queue by
--- 930,936 ----
   *
   * Locktable lock must be held by caller.
   *
!  * NB: this does not remove the process' proclock object, nor the lock object,
   * even though their counts might now have gone to zero.  That will happen
   * during a subsequent LockReleaseAll call, which we expect will happen
   * during transaction cleanup.	(Removal of a proc from its wait queue by
***************
*** 986,994 ****
  	LOCK	   *lock;
  	LWLockId	masterLock;
  	LOCKMETHODTABLE *lockMethodTable;
! 	PROCLOCK   *holder;
! 	PROCLOCKTAG holdertag;
! 	HTAB	   *holderTable;
  	bool		wakeupNeeded = false;
  
  #ifdef LOCK_DEBUG
--- 986,994 ----
  	LOCK	   *lock;
  	LWLockId	masterLock;
  	LOCKMETHODTABLE *lockMethodTable;
! 	PROCLOCK   *proclock;
! 	PROCLOCKTAG proclocktag;
! 	HTAB	   *proclockTable;
  	bool		wakeupNeeded = false;
  
  #ifdef LOCK_DEBUG
***************
*** 1031,1049 ****
  	LOCK_PRINT("LockRelease: found", lock, lockmode);
  
  	/*
! 	 * Find the holder entry for this holder.
  	 */
! 	MemSet(&holdertag, 0, sizeof(PROCLOCKTAG)); /* must clear padding,
  												 * needed */
! 	holdertag.lock = MAKE_OFFSET(lock);
! 	holdertag.proc = MAKE_OFFSET(MyProc);
! 	TransactionIdStore(xid, &holdertag.xid);
! 
! 	holderTable = lockMethodTable->holderHash;
! 	holder = (PROCLOCK *) hash_search(holderTable,
! 									  (void *) &holdertag,
  									  HASH_FIND_SAVE, NULL);
! 	if (!holder)
  	{
  		LWLockRelease(masterLock);
  #ifdef USER_LOCKS
--- 1031,1049 ----
  	LOCK_PRINT("LockRelease: found", lock, lockmode);
  
  	/*
! 	 * Find the proclock entry for this proclock.
  	 */
! 	MemSet(&proclocktag, 0, sizeof(PROCLOCKTAG)); /* must clear padding,
  												 * needed */
! 	proclocktag.lock = MAKE_OFFSET(lock);
! 	proclocktag.proc = MAKE_OFFSET(MyProc);
! 	TransactionIdStore(xid, &proclocktag.xid);
! 
! 	proclockTable = lockMethodTable->proclockHash;
! 	proclock = (PROCLOCK *) hash_search(proclockTable,
! 									  (void *) &proclocktag,
  									  HASH_FIND_SAVE, NULL);
! 	if (!proclock)
  	{
  		LWLockRelease(masterLock);
  #ifdef USER_LOCKS
***************
*** 1051,1075 ****
  			elog(WARNING, "LockRelease: no lock with this tag");
  		else
  #endif
! 			elog(WARNING, "LockRelease: holder table corrupted");
  		return FALSE;
  	}
! 	PROCLOCK_PRINT("LockRelease: found", holder);
  
  	/*
  	 * Check that we are actually holding a lock of the type we want to
  	 * release.
  	 */
! 	if (!(holder->holding[lockmode] > 0))
  	{
! 		PROCLOCK_PRINT("LockRelease: WRONGTYPE", holder);
! 		Assert(holder->holding[lockmode] >= 0);
  		LWLockRelease(masterLock);
  		elog(WARNING, "LockRelease: you don't own a lock of type %s",
  			 lock_mode_names[lockmode]);
  		return FALSE;
  	}
! 	Assert(holder->nHolding > 0);
  	Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
  	Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
  	Assert(lock->nGranted <= lock->nRequested);
--- 1051,1075 ----
  			elog(WARNING, "LockRelease: no lock with this tag");
  		else
  #endif
! 			elog(WARNING, "LockRelease: proclock table corrupted");
  		return FALSE;
  	}
! 	PROCLOCK_PRINT("LockRelease: found", proclock);
  
  	/*
  	 * Check that we are actually holding a lock of the type we want to
  	 * release.
  	 */
! 	if (!(proclock->holding[lockmode] > 0))
  	{
! 		PROCLOCK_PRINT("LockRelease: WRONGTYPE", proclock);
! 		Assert(proclock->holding[lockmode] >= 0);
  		LWLockRelease(masterLock);
  		elog(WARNING, "LockRelease: you don't own a lock of type %s",
  			 lock_mode_names[lockmode]);
  		return FALSE;
  	}
! 	Assert(proclock->nHolding > 0);
  	Assert((lock->nRequested > 0) && (lock->requested[lockmode] > 0));
  	Assert((lock->nGranted > 0) && (lock->granted[lockmode] > 0));
  	Assert(lock->nGranted <= lock->nRequested);
***************
*** 1126,1154 ****
  	}
  
  	/*
! 	 * Now fix the per-holder lock stats.
  	 */
! 	holder->holding[lockmode]--;
! 	holder->nHolding--;
! 	PROCLOCK_PRINT("LockRelease: updated", holder);
! 	Assert((holder->nHolding >= 0) && (holder->holding[lockmode] >= 0));
  
  	/*
  	 * If this was my last hold on this lock, delete my entry in the
! 	 * holder table.
  	 */
! 	if (holder->nHolding == 0)
  	{
! 		PROCLOCK_PRINT("LockRelease: deleting", holder);
! 		SHMQueueDelete(&holder->lockLink);
! 		SHMQueueDelete(&holder->procLink);
! 		holder = (PROCLOCK *) hash_search(holderTable,
! 										  (void *) &holder,
  										  HASH_REMOVE_SAVED, NULL);
! 		if (!holder)
  		{
  			LWLockRelease(masterLock);
! 			elog(WARNING, "LockRelease: remove holder, table corrupted");
  			return FALSE;
  		}
  	}
--- 1126,1154 ----
  	}
  
  	/*
! 	 * Now fix the per-proclock lock stats.
  	 */
! 	proclock->holding[lockmode]--;
! 	proclock->nHolding--;
! 	PROCLOCK_PRINT("LockRelease: updated", proclock);
! 	Assert((proclock->nHolding >= 0) && (proclock->holding[lockmode] >= 0));
  
  	/*
  	 * If this was my last hold on this lock, delete my entry in the
! 	 * proclock table.
  	 */
! 	if (proclock->nHolding == 0)
  	{
! 		PROCLOCK_PRINT("LockRelease: deleting", proclock);
! 		SHMQueueDelete(&proclock->lockLink);
! 		SHMQueueDelete(&proclock->procLink);
! 		proclock = (PROCLOCK *) hash_search(proclockTable,
! 										  (void *) &proclock,
  										  HASH_REMOVE_SAVED, NULL);
! 		if (!proclock)
  		{
  			LWLockRelease(masterLock);
! 			elog(WARNING, "LockRelease: remove proclock, table corrupted");
  			return FALSE;
  		}
  	}
***************
*** 1179,1185 ****
  			   bool allxids, TransactionId xid)
  {
  	SHM_QUEUE  *procHolders = &(proc->procHolders);
! 	PROCLOCK   *holder;
  	PROCLOCK   *nextHolder;
  	LWLockId	masterLock;
  	LOCKMETHODTABLE *lockMethodTable;
--- 1179,1185 ----
  			   bool allxids, TransactionId xid)
  {
  	SHM_QUEUE  *procHolders = &(proc->procHolders);
! 	PROCLOCK   *proclock;
  	PROCLOCK   *nextHolder;
  	LWLockId	masterLock;
  	LOCKMETHODTABLE *lockMethodTable;
***************
*** 1206,1254 ****
  
  	LWLockAcquire(masterLock, LW_EXCLUSIVE);
  
! 	holder = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
  									   offsetof(PROCLOCK, procLink));
  
! 	while (holder)
  	{
  		bool		wakeupNeeded = false;
  
! 		/* Get link first, since we may unlink/delete this holder */
! 		nextHolder = (PROCLOCK *) SHMQueueNext(procHolders, &holder->procLink,
  										   offsetof(PROCLOCK, procLink));
  
! 		Assert(holder->tag.proc == MAKE_OFFSET(proc));
  
! 		lock = (LOCK *) MAKE_PTR(holder->tag.lock);
  
  		/* Ignore items that are not of the lockmethod to be removed */
  		if (LOCK_LOCKMETHOD(*lock) != lockmethod)
  			goto next_item;
  
  		/* If not allxids, ignore items that are of the wrong xid */
! 		if (!allxids && !TransactionIdEquals(xid, holder->tag.xid))
  			goto next_item;
  
! 		PROCLOCK_PRINT("LockReleaseAll", holder);
  		LOCK_PRINT("LockReleaseAll", lock, 0);
  		Assert(lock->nRequested >= 0);
  		Assert(lock->nGranted >= 0);
  		Assert(lock->nGranted <= lock->nRequested);
! 		Assert(holder->nHolding >= 0);
! 		Assert(holder->nHolding <= lock->nRequested);
  
  		/*
  		 * fix the general lock stats
  		 */
! 		if (lock->nRequested != holder->nHolding)
  		{
  			for (i = 1; i <= numLockModes; i++)
  			{
! 				Assert(holder->holding[i] >= 0);
! 				if (holder->holding[i] > 0)
  				{
! 					lock->requested[i] -= holder->holding[i];
! 					lock->granted[i] -= holder->holding[i];
  					Assert(lock->requested[i] >= 0 && lock->granted[i] >= 0);
  					if (lock->granted[i] == 0)
  						lock->grantMask &= BITS_OFF[i];
--- 1206,1254 ----
  
  	LWLockAcquire(masterLock, LW_EXCLUSIVE);
  
! 	proclock = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
  									   offsetof(PROCLOCK, procLink));
  
! 	while (proclock)
  	{
  		bool		wakeupNeeded = false;
  
! 		/* Get link first, since we may unlink/delete this proclock */
! 		nextHolder = (PROCLOCK *) SHMQueueNext(procHolders, &proclock->procLink,
  										   offsetof(PROCLOCK, procLink));
  
! 		Assert(proclock->tag.proc == MAKE_OFFSET(proc));
  
! 		lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
  
  		/* Ignore items that are not of the lockmethod to be removed */
  		if (LOCK_LOCKMETHOD(*lock) != lockmethod)
  			goto next_item;
  
  		/* If not allxids, ignore items that are of the wrong xid */
! 		if (!allxids && !TransactionIdEquals(xid, proclock->tag.xid))
  			goto next_item;
  
! 		PROCLOCK_PRINT("LockReleaseAll", proclock);
  		LOCK_PRINT("LockReleaseAll", lock, 0);
  		Assert(lock->nRequested >= 0);
  		Assert(lock->nGranted >= 0);
  		Assert(lock->nGranted <= lock->nRequested);
! 		Assert(proclock->nHolding >= 0);
! 		Assert(proclock->nHolding <= lock->nRequested);
  
  		/*
  		 * fix the general lock stats
  		 */
! 		if (lock->nRequested != proclock->nHolding)
  		{
  			for (i = 1; i <= numLockModes; i++)
  			{
! 				Assert(proclock->holding[i] >= 0);
! 				if (proclock->holding[i] > 0)
  				{
! 					lock->requested[i] -= proclock->holding[i];
! 					lock->granted[i] -= proclock->holding[i];
  					Assert(lock->requested[i] >= 0 && lock->granted[i] >= 0);
  					if (lock->granted[i] == 0)
  						lock->grantMask &= BITS_OFF[i];
***************
*** 1261,1275 ****
  						wakeupNeeded = true;
  				}
  			}
! 			lock->nRequested -= holder->nHolding;
! 			lock->nGranted -= holder->nHolding;
  			Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
  			Assert(lock->nGranted <= lock->nRequested);
  		}
  		else
  		{
  			/*
! 			 * This holder accounts for all the requested locks on the
  			 * object, so we can be lazy and just zero things out.
  			 */
  			lock->nRequested = 0;
--- 1261,1275 ----
  						wakeupNeeded = true;
  				}
  			}
! 			lock->nRequested -= proclock->nHolding;
! 			lock->nGranted -= proclock->nHolding;
  			Assert((lock->nRequested >= 0) && (lock->nGranted >= 0));
  			Assert(lock->nGranted <= lock->nRequested);
  		}
  		else
  		{
  			/*
! 			 * This proclock accounts for all the requested locks on the
  			 * object, so we can be lazy and just zero things out.
  			 */
  			lock->nRequested = 0;
***************
*** 1283,1307 ****
  		}
  		LOCK_PRINT("LockReleaseAll: updated", lock, 0);
  
! 		PROCLOCK_PRINT("LockReleaseAll: deleting", holder);
  
  		/*
! 		 * Remove the holder entry from the linked lists
  		 */
! 		SHMQueueDelete(&holder->lockLink);
! 		SHMQueueDelete(&holder->procLink);
  
  		/*
! 		 * remove the holder entry from the hashtable
  		 */
! 		holder = (PROCLOCK *) hash_search(lockMethodTable->holderHash,
! 										  (void *) holder,
  										  HASH_REMOVE,
  										  NULL);
! 		if (!holder)
  		{
  			LWLockRelease(masterLock);
! 			elog(WARNING, "LockReleaseAll: holder table corrupted");
  			return FALSE;
  		}
  
--- 1283,1307 ----
  		}
  		LOCK_PRINT("LockReleaseAll: updated", lock, 0);
  
! 		PROCLOCK_PRINT("LockReleaseAll: deleting", proclock);
  
  		/*
! 		 * Remove the proclock entry from the linked lists
  		 */
! 		SHMQueueDelete(&proclock->lockLink);
! 		SHMQueueDelete(&proclock->procLink);
  
  		/*
! 		 * remove the proclock entry from the hashtable
  		 */
! 		proclock = (PROCLOCK *) hash_search(lockMethodTable->proclockHash,
! 										  (void *) proclock,
  										  HASH_REMOVE,
  										  NULL);
! 		if (!proclock)
  		{
  			LWLockRelease(masterLock);
! 			elog(WARNING, "LockReleaseAll: proclock table corrupted");
  			return FALSE;
  		}
  
***************
*** 1327,1333 ****
  			ProcLockWakeup(lockMethodTable, lock);
  
  next_item:
! 		holder = nextHolder;
  	}
  
  	LWLockRelease(masterLock);
--- 1327,1333 ----
  			ProcLockWakeup(lockMethodTable, lock);
  
  next_item:
! 		proclock = nextHolder;
  	}
  
  	LWLockRelease(masterLock);
***************
*** 1353,1359 ****
  	/* lockHash table */
  	size += hash_estimate_size(max_table_size, sizeof(LOCK));
  
! 	/* holderHash table */
  	size += hash_estimate_size(max_table_size, sizeof(PROCLOCK));
  
  	/*
--- 1353,1359 ----
  	/* lockHash table */
  	size += hash_estimate_size(max_table_size, sizeof(LOCK));
  
! 	/* proclockHash table */
  	size += hash_estimate_size(max_table_size, sizeof(PROCLOCK));
  
  	/*
***************
*** 1383,1390 ****
  GetLockStatusData(void)
  {
  	LockData   *data;
! 	HTAB	   *holderTable;
! 	PROCLOCK   *holder;
  	HASH_SEQ_STATUS seqstat;
  	int			i;
  
--- 1383,1390 ----
  GetLockStatusData(void)
  {
  	LockData   *data;
! 	HTAB	   *proclockTable;
! 	PROCLOCK   *proclock;
  	HASH_SEQ_STATUS seqstat;
  	int			i;
  
***************
*** 1392,1419 ****
  
  	LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
  
! 	holderTable = LockMethodTable[DEFAULT_LOCKMETHOD]->holderHash;
  
! 	data->nelements = i = holderTable->hctl->nentries;
  
  	if (i == 0)
  		i = 1;					/* avoid palloc(0) if empty table */
  
! 	data->holderaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * i);
! 	data->holders = (PROCLOCK *) palloc(sizeof(PROCLOCK) * i);
  	data->procs = (PGPROC *) palloc(sizeof(PGPROC) * i);
  	data->locks = (LOCK *) palloc(sizeof(LOCK) * i);
  
! 	hash_seq_init(&seqstat, holderTable);
  
  	i = 0;
! 	while ((holder = hash_seq_search(&seqstat)))
  	{
! 		PGPROC	   *proc = (PGPROC *) MAKE_PTR(holder->tag.proc);
! 		LOCK	   *lock = (LOCK *) MAKE_PTR(holder->tag.lock);
  
! 		data->holderaddrs[i] = MAKE_OFFSET(holder);
! 		memcpy(&(data->holders[i]), holder, sizeof(PROCLOCK));
  		memcpy(&(data->procs[i]), proc, sizeof(PGPROC));
  		memcpy(&(data->locks[i]), lock, sizeof(LOCK));
  
--- 1392,1419 ----
  
  	LWLockAcquire(LockMgrLock, LW_EXCLUSIVE);
  
! 	proclockTable = LockMethodTable[DEFAULT_LOCKMETHOD]->proclockHash;
  
! 	data->nelements = i = proclockTable->hctl->nentries;
  
  	if (i == 0)
  		i = 1;					/* avoid palloc(0) if empty table */
  
! 	data->proclockaddrs = (SHMEM_OFFSET *) palloc(sizeof(SHMEM_OFFSET) * i);
! 	data->proclocks = (PROCLOCK *) palloc(sizeof(PROCLOCK) * i);
  	data->procs = (PGPROC *) palloc(sizeof(PGPROC) * i);
  	data->locks = (LOCK *) palloc(sizeof(LOCK) * i);
  
! 	hash_seq_init(&seqstat, proclockTable);
  
  	i = 0;
! 	while ((proclock = hash_seq_search(&seqstat)))
  	{
! 		PGPROC	   *proc = (PGPROC *) MAKE_PTR(proclock->tag.proc);
! 		LOCK	   *lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
  
! 		data->proclockaddrs[i] = MAKE_OFFSET(proclock);
! 		memcpy(&(data->proclocks[i]), proclock, sizeof(PROCLOCK));
  		memcpy(&(data->procs[i]), proc, sizeof(PGPROC));
  		memcpy(&(data->locks[i]), lock, sizeof(LOCK));
  
***************
*** 1446,1452 ****
  {
  	PGPROC	   *proc;
  	SHM_QUEUE  *procHolders;
! 	PROCLOCK   *holder;
  	LOCK	   *lock;
  	int			lockmethod = DEFAULT_LOCKMETHOD;
  	LOCKMETHODTABLE *lockMethodTable;
--- 1446,1452 ----
  {
  	PGPROC	   *proc;
  	SHM_QUEUE  *procHolders;
! 	PROCLOCK   *proclock;
  	LOCK	   *lock;
  	int			lockmethod = DEFAULT_LOCKMETHOD;
  	LOCKMETHODTABLE *lockMethodTable;
***************
*** 1465,1483 ****
  	if (proc->waitLock)
  		LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
  
! 	holder = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
  									   offsetof(PROCLOCK, procLink));
  
! 	while (holder)
  	{
! 		Assert(holder->tag.proc == MAKE_OFFSET(proc));
  
! 		lock = (LOCK *) MAKE_PTR(holder->tag.lock);
  
! 		PROCLOCK_PRINT("DumpLocks", holder);
  		LOCK_PRINT("DumpLocks", lock, 0);
  
! 		holder = (PROCLOCK *) SHMQueueNext(procHolders, &holder->procLink,
  										   offsetof(PROCLOCK, procLink));
  	}
  }
--- 1465,1483 ----
  	if (proc->waitLock)
  		LOCK_PRINT("DumpLocks: waiting on", proc->waitLock, 0);
  
! 	proclock = (PROCLOCK *) SHMQueueNext(procHolders, procHolders,
  									   offsetof(PROCLOCK, procLink));
  
! 	while (proclock)
  	{
! 		Assert(proclock->tag.proc == MAKE_OFFSET(proc));
  
! 		lock = (LOCK *) MAKE_PTR(proclock->tag.lock);
  
! 		PROCLOCK_PRINT("DumpLocks", proclock);
  		LOCK_PRINT("DumpLocks", lock, 0);
  
! 		proclock = (PROCLOCK *) SHMQueueNext(procHolders, &proclock->procLink,
  										   offsetof(PROCLOCK, procLink));
  	}
  }
***************
*** 1489,1499 ****
  DumpAllLocks(void)
  {
  	PGPROC	   *proc;
! 	PROCLOCK   *holder;
  	LOCK	   *lock;
  	int			lockmethod = DEFAULT_LOCKMETHOD;
  	LOCKMETHODTABLE *lockMethodTable;
! 	HTAB	   *holderTable;
  	HASH_SEQ_STATUS status;
  
  	proc = MyProc;
--- 1489,1499 ----
  DumpAllLocks(void)
  {
  	PGPROC	   *proc;
! 	PROCLOCK   *proclock;
  	LOCK	   *lock;
  	int			lockmethod = DEFAULT_LOCKMETHOD;
  	LOCKMETHODTABLE *lockMethodTable;
! 	HTAB	   *proclockTable;
  	HASH_SEQ_STATUS status;
  
  	proc = MyProc;
***************
*** 1505,1527 ****
  	if (!lockMethodTable)
  		return;
  
! 	holderTable = lockMethodTable->holderHash;
  
  	if (proc->waitLock)
  		LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
  
! 	hash_seq_init(&status, holderTable);
! 	while ((holder = (PROCLOCK *) hash_seq_search(&status)) != NULL)
  	{
! 		PROCLOCK_PRINT("DumpAllLocks", holder);
  
! 		if (holder->tag.lock)
  		{
! 			lock = (LOCK *) MAKE_PTR(holder->tag.lock);
  			LOCK_PRINT("DumpAllLocks", lock, 0);
  		}
  		else
! 			elog(LOG, "DumpAllLocks: holder->tag.lock = NULL");
  	}
  }
  
--- 1505,1527 ----
  	if (!lockMethodTable)
  		return;
  
! 	proclockTable = lockMethodTable->proclockHash;
  
  	if (proc->waitLock)
  		LOCK_PRINT("DumpAllLocks: waiting on", proc->waitLock, 0);
  
! 	hash_seq_init(&status, proclockTable);
! 	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");
  	}
  }
  
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.128
diff -c -c -r1.128 proc.c
*** src/backend/storage/lmgr/proc.c	16 Jan 2003 21:01:44 -0000	1.128
--- src/backend/storage/lmgr/proc.c	18 Feb 2003 02:07:49 -0000
***************
*** 521,527 ****
  ProcSleep(LOCKMETHODTABLE *lockMethodTable,
  		  LOCKMODE lockmode,
  		  LOCK *lock,
! 		  PROCLOCK *holder)
  {
  	LWLockId	masterLock = lockMethodTable->masterLock;
  	PROC_QUEUE *waitQueue = &(lock->waitProcs);
--- 521,527 ----
  ProcSleep(LOCKMETHODTABLE *lockMethodTable,
  		  LOCKMODE lockmode,
  		  LOCK *lock,
! 		  PROCLOCK *proclock)
  {
  	LWLockId	masterLock = lockMethodTable->masterLock;
  	PROC_QUEUE *waitQueue = &(lock->waitProcs);
***************
*** 577,588 ****
  					LockCheckConflicts(lockMethodTable,
  									   lockmode,
  									   lock,
! 									   holder,
  									   MyProc,
  									   NULL) == STATUS_OK)
  				{
  					/* Skip the wait and just grant myself the lock. */
! 					GrantLock(lock, holder, lockmode);
  					return STATUS_OK;
  				}
  				/* Break out of loop to put myself before him */
--- 577,588 ----
  					LockCheckConflicts(lockMethodTable,
  									   lockmode,
  									   lock,
! 									   proclock,
  									   MyProc,
  									   NULL) == STATUS_OK)
  				{
  					/* Skip the wait and just grant myself the lock. */
! 					GrantLock(lock, proclock, lockmode);
  					return STATUS_OK;
  				}
  				/* Break out of loop to put myself before him */
***************
*** 615,621 ****
  
  	/* Set up wait information in PGPROC object, too */
  	MyProc->waitLock = lock;
! 	MyProc->waitHolder = holder;
  	MyProc->waitLockMode = lockmode;
  
  	MyProc->errType = STATUS_OK;	/* initialize result for success */
--- 615,621 ----
  
  	/* Set up wait information in PGPROC object, too */
  	MyProc->waitLock = lock;
! 	MyProc->waitHolder = proclock;
  	MyProc->waitLockMode = lockmode;
  
  	MyProc->errType = STATUS_OK;	/* initialize result for success */
Index: src/backend/utils/adt/lockfuncs.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/adt/lockfuncs.c,v
retrieving revision 1.7
diff -c -c -r1.7 lockfuncs.c
*** src/backend/utils/adt/lockfuncs.c	4 Sep 2002 20:31:28 -0000	1.7
--- src/backend/utils/adt/lockfuncs.c	18 Feb 2003 02:07:49 -0000
***************
*** 88,94 ****
  
  	while (mystatus->currIdx < lockData->nelements)
  	{
! 		PROCLOCK   *holder;
  		LOCK	   *lock;
  		PGPROC	   *proc;
  		bool		granted;
--- 88,94 ----
  
  	while (mystatus->currIdx < lockData->nelements)
  	{
! 		PROCLOCK   *proclock;
  		LOCK	   *lock;
  		PGPROC	   *proc;
  		bool		granted;
***************
*** 98,104 ****
  		HeapTuple	tuple;
  		Datum		result;
  
! 		holder = &(lockData->holders[mystatus->currIdx]);
  		lock = &(lockData->locks[mystatus->currIdx]);
  		proc = &(lockData->procs[mystatus->currIdx]);
  
--- 98,104 ----
  		HeapTuple	tuple;
  		Datum		result;
  
! 		proclock = &(lockData->proclocks[mystatus->currIdx]);
  		lock = &(lockData->locks[mystatus->currIdx]);
  		proc = &(lockData->procs[mystatus->currIdx]);
  
***************
*** 110,119 ****
  		granted = false;
  		for (mode = 0; mode < MAX_LOCKMODES; mode++)
  		{
! 			if (holder->holding[mode] > 0)
  			{
  				granted = true;
! 				holder->holding[mode] = 0;
  				break;
  			}
  		}
--- 110,119 ----
  		granted = false;
  		for (mode = 0; mode < MAX_LOCKMODES; mode++)
  		{
! 			if (proclock->holding[mode] > 0)
  			{
  				granted = true;
! 				proclock->holding[mode] = 0;
  				break;
  			}
  		}
***************
*** 124,130 ****
  		 */
  		if (!granted)
  		{
! 			if (proc->waitLock == (LOCK *) MAKE_PTR(holder->tag.lock))
  			{
  				/* Yes, so report it with proper mode */
  				mode = proc->waitLockMode;
--- 124,130 ----
  		 */
  		if (!granted)
  		{
! 			if (proc->waitLock == (LOCK *) MAKE_PTR(proclock->tag.lock))
  			{
  				/* Yes, so report it with proper mode */
  				mode = proc->waitLockMode;
Index: src/include/storage/lock.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/storage/lock.h,v
retrieving revision 1.68
diff -c -c -r1.68 lock.h
*** src/include/storage/lock.h	16 Jan 2003 21:01:45 -0000	1.68
--- src/include/storage/lock.h	18 Feb 2003 02:07:50 -0000
***************
*** 68,74 ****
   *
   * 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.
--- 68,74 ----
   *
   * lockHash -- hash table holding per-locked-object lock information
   *
!  * proclockHash -- hash table holding per-lock-waiter/holder lock information
   *
   * lockmethod -- the handle used by the lock table's clients to
   *		refer to the type of lock table being used.
***************
*** 86,92 ****
  typedef struct LOCKMETHODTABLE
  {
  	HTAB	   *lockHash;
! 	HTAB	   *holderHash;
  	LOCKMETHOD	lockmethod;
  	int			numLockModes;
  	int			conflictTab[MAX_LOCKMODES];
--- 86,92 ----
  typedef struct LOCKMETHODTABLE
  {
  	HTAB	   *lockHash;
! 	HTAB	   *proclockHash;
  	LOCKMETHOD	lockmethod;
  	int			numLockModes;
  	int			conflictTab[MAX_LOCKMODES];
***************
*** 156,179 ****
  
  /*
   * We may have several different transactions holding or awaiting locks
!  * on the same lockable object.  We need to store some per-holder information
!  * for each such holder (or would-be holder).
   *
   * PROCLOCKTAG is the key information needed to look up a PROCLOCK item in the
!  * holder hashtable.  A PROCLOCKTAG value uniquely identifies a lock holder.
   *
!  * There are two possible kinds of holder tags: a transaction (identified
   * both by the PGPROC of the backend running it, and the xact's own ID) and
   * a session (identified by backend PGPROC, with xid = InvalidTransactionId).
   *
!  * Currently, session holders are used for user locks and for cross-xact
   * locks obtained for VACUUM.  We assume that a session lock never conflicts
   * with per-transaction locks obtained by the same backend.
   *
   * The holding[] array counts the granted locks (of each type) represented
!  * by this holder.	Note that there will be a holder object, possibly with
   * zero holding[], for any lock that the process is currently waiting on.
!  * Otherwise, holder objects whose counts have gone to zero are recycled
   * as soon as convenient.
   *
   * Each PROCLOCK object is linked into lists for both the associated LOCK object
--- 156,180 ----
  
  /*
   * We may have several different transactions holding or awaiting locks
!  * on the same lockable object.  We need to store some per-waiter/holder
!  * information for each such holder (or would-be holder).
   *
   * PROCLOCKTAG is the key information needed to look up a PROCLOCK item in the
!  * proclock hashtable.  A PROCLOCKTAG value uniquely identifies a lock
!  * holder/waiter.
   *
!  * There are two possible kinds of proclock tags: a transaction (identified
   * both by the PGPROC of the backend running it, and the xact's own ID) and
   * a session (identified by backend PGPROC, with xid = InvalidTransactionId).
   *
!  * Currently, session proclocks are used for user locks and for cross-xact
   * locks obtained for VACUUM.  We assume that a session lock never conflicts
   * with per-transaction locks obtained by the same backend.
   *
   * The holding[] array counts the granted locks (of each type) represented
!  * by this proclock. Note that there will be a proclock object, possibly with
   * zero holding[], for any lock that the process is currently waiting on.
!  * Otherwise, proclock objects whose counts have gone to zero are recycled
   * as soon as convenient.
   *
   * Each PROCLOCK object is linked into lists for both the associated LOCK object
***************
*** 192,208 ****
  typedef struct PROCLOCK
  {
  	/* tag */
! 	PROCLOCKTAG tag;			/* unique identifier of holder object */
  
  	/* data */
  	int			holding[MAX_LOCKMODES]; /* count of locks currently held */
  	int			nHolding;		/* total of holding[] array */
! 	SHM_QUEUE	lockLink;		/* list link for lock's list of holders */
! 	SHM_QUEUE	procLink;		/* list link for process's list of holders */
  } PROCLOCK;
  
! #define PROCLOCK_LOCKMETHOD(holder) \
! 		(((LOCK *) MAKE_PTR((holder).tag.lock))->tag.lockmethod)
  
  /*
   * This struct holds information passed from lmgr internals to the lock
--- 193,209 ----
  typedef struct PROCLOCK
  {
  	/* tag */
! 	PROCLOCKTAG tag;			/* unique identifier of proclock object */
  
  	/* data */
  	int			holding[MAX_LOCKMODES]; /* count of locks currently held */
  	int			nHolding;		/* total of holding[] array */
! 	SHM_QUEUE	lockLink;		/* list link for lock's list of proclocks */
! 	SHM_QUEUE	procLink;		/* list link for process's list of proclocks */
  } PROCLOCK;
  
! #define PROCLOCK_LOCKMETHOD(proclock) \
! 		(((LOCK *) MAKE_PTR((proclock).tag.lock))->tag.lockmethod)
  
  /*
   * This struct holds information passed from lmgr internals to the lock
***************
*** 215,222 ****
  typedef struct
  {
  	int			nelements;		/* The length of each of the arrays */
! 	SHMEM_OFFSET *holderaddrs;
! 	PROCLOCK   *holders;
  	PGPROC	   *procs;
  	LOCK	   *locks;
  } LockData;
--- 216,223 ----
  typedef struct
  {
  	int			nelements;		/* The length of each of the arrays */
! 	SHMEM_OFFSET *proclockaddrs;
! 	PROCLOCK   *proclocks;
  	PGPROC	   *procs;
  	LOCK	   *locks;
  } LockData;
***************
*** 237,245 ****
  			   bool allxids, TransactionId xid);
  extern int LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
  				   LOCKMODE lockmode,
! 				   LOCK *lock, PROCLOCK *holder, PGPROC *proc,
  				   int *myHolding);
! extern void GrantLock(LOCK *lock, PROCLOCK *holder, LOCKMODE lockmode);
  extern void RemoveFromWaitQueue(PGPROC *proc);
  extern int	LockShmemSize(int maxBackends);
  extern bool DeadLockCheck(PGPROC *proc);
--- 238,246 ----
  			   bool allxids, TransactionId xid);
  extern int LockCheckConflicts(LOCKMETHODTABLE *lockMethodTable,
  				   LOCKMODE lockmode,
! 				   LOCK *lock, PROCLOCK *proclock, PGPROC *proc,
  				   int *myHolding);
! extern void GrantLock(LOCK *lock, PROCLOCK *proclock, LOCKMODE lockmode);
  extern void RemoveFromWaitQueue(PGPROC *proc);
  extern int	LockShmemSize(int maxBackends);
  extern bool DeadLockCheck(PGPROC *proc);
Index: src/include/storage/proc.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/storage/proc.h,v
retrieving revision 1.62
diff -c -c -r1.62 proc.h
*** src/include/storage/proc.h	31 Oct 2002 21:34:17 -0000	1.62
--- src/include/storage/proc.h	18 Feb 2003 02:07:51 -0000
***************
*** 102,108 ****
  
  extern void ProcQueueInit(PROC_QUEUE *queue);
  extern int ProcSleep(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode,
! 		  LOCK *lock, PROCLOCK *holder);
  extern PGPROC *ProcWakeup(PGPROC *proc, int errType);
  extern void ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock);
  extern bool LockWaitCancel(void);
--- 102,108 ----
  
  extern void ProcQueueInit(PROC_QUEUE *queue);
  extern int ProcSleep(LOCKMETHODTABLE *lockMethodTable, LOCKMODE lockmode,
! 		  LOCK *lock, PROCLOCK *proclock);
  extern PGPROC *ProcWakeup(PGPROC *proc, int errType);
  extern void ProcLockWakeup(LOCKMETHODTABLE *lockMethodTable, LOCK *lock);
  extern bool LockWaitCancel(void);
