Thread

  1. Fix for many lock problems

    Bruce Momjian <maillist@candle.pha.pa.us> — 1998-01-23T21:09:57Z

    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