I am submitting this patch for people to review.

It fixes several problems in the lock manager.  Let me show you how to
reproduce them.  Try this before applying the patch and you will see the
old bugs.

First, set up three psql sessions.  Do a 'begin;' in each one to start a
transaction.

---------------------------------------------------------------------------

OK, pick a single table to use.  In the first one, do an UPDATE, in the
second psql session, do an UPDATE, in the third, do an UPDATE.  Now, do
'end;' in the first psql, and you will find the third finishes, even
though the second was first to request the lock.

---------------------------------------------------------------------------

OK, exit all your psql's, and start them again, with a 'begin;' for
each.

Do an UPDATE in the first, a SELECT in the second, and an UPDATE in the
third, in that order.  Now do an 'end;' in the first.  The second
completes, even though the write should have higher priority over a read
WHEN THEN ARE BOTH ASLEEP waiting for a lock.

---------------------------------------------------------------------------

OK, exit all your psql's, and start them again, with a 'begin;' for
each.

Now, do a SELECT in the first, and UPDATE in the second, and a SELECT in
the third.  The third completes right away, even though it should wait
behind the higher-priority second UPDATE and not share the existing
lock.

---------------------------------------------------------------------------

The following patch fixes this.  The proc.c priority queue condition was
backwards, and did not put newer requesters behind older requesters. 
The lock.c change adds code to check the wait queue and not allow
sharing a lock if someone of higher priority is waiting for it.

This should eliminate writer starvation in 6.3, and fix other problems
people might have been experiencing with this buggy behavior.

This will be in 6.3.  I will apply it now.

Comments?

---------------------------------------------------------------------------

*** ./backend/storage/lmgr/lock.c.orig	Fri Jan 23 01:01:03 1998
--- ./backend/storage/lmgr/lock.c	Fri Jan 23 15:59:06 1998
***************
*** 708,713 ****
--- 708,727 ----
  		result->nHolding = 0;
  	}
  
+ 	{
+ 		/* ------------------------
+ 		 * If someone with a greater priority is waiting for the lock,
+ 		 * do not continue and share the lock, even if we can.  bjm
+ 		 * ------------------------
+ 		 */
+ 		int				myprio = ltable->ctl->prio[lockt];
+ 		PROC_QUEUE		*waitQueue = &(lock->waitProcs);
+ 		PROC			*topproc = (PROC *) MAKE_PTR(waitQueue->links.prev);
+ 
+ 		if (waitQueue->size && topproc->prio > myprio)
+ 			return STATUS_FOUND;
+ 	}
+ 
  	/* ----------------------------
  	 * first check for global conflicts: If no locks conflict
  	 * with mine, then I get the lock.
*** ./backend/storage/lmgr/proc.c.orig	Fri Jan 23 14:34:27 1998
--- ./backend/storage/lmgr/proc.c	Fri Jan 23 15:22:11 1998
***************
*** 469,475 ****
  	proc = (PROC *) MAKE_PTR(queue->links.prev);
  	for (i = 0; i < queue->size; i++)
  	{
! 		if (proc->prio < prio)
  			proc = (PROC *) MAKE_PTR(proc->links.prev);
  		else
  			break;
--- 469,475 ----
  	proc = (PROC *) MAKE_PTR(queue->links.prev);
  	for (i = 0; i < queue->size; i++)
  	{
! 		if (proc->prio >= prio)
  			proc = (PROC *) MAKE_PTR(proc->links.prev);
  		else
  			break;

-- 
Bruce Momjian
maillist@candle.pha.pa.us

Fri, 23 Jan 1998 16:09:57 -0500 (EST)
Bruce Momjian <maillist@candle.pha.pa.us>
Fix for many lock problems