Re: Error in backend/storage/lmgr/proc.c: ProcSleep() - Mailing list pgsql-bugs

From Tom Lane
Subject Re: Error in backend/storage/lmgr/proc.c: ProcSleep()
Date
Msg-id 24206.999571031@sss.pgh.pa.us
Whole thread Raw
In response to Error in backend/storage/lmgr/proc.c: ProcSleep()  (Tomasz Zielonka <tomek@mult.i.pl>)
List pgsql-bugs
Tomasz Zielonka <tomek@mult.i.pl> writes:
> Platform: PostgreSQL 7.1.3, Linux 2.4.8, egcs 2.91.66
> PostgreSQL forgets to release lock until shutdown in this scenario:

Good catch!  This has been broken since 7.1 ... surprising that no one
discovered the problem sooner.

I think that rather than removing the early-deadlock-detection code as
you suggest, it's better to make it work correctly.  I have applied a
patch that allows RemoveFromWaitQueue() to be used, so that the recovery
path is the same as if HandleDeadLock had been invoked.

            regards, tom lane


*** /home/postgres/pgsql/src/backend/storage/lmgr/proc.c.orig    Fri Jul  6 17:04:26 2001
--- /home/postgres/pgsql/src/backend/storage/lmgr/proc.c    Mon Sep  3 22:26:57 2001
***************
*** 506,521 ****
      SPINLOCK    spinlock = lockctl->masterLock;
      PROC_QUEUE *waitQueue = &(lock->waitProcs);
      int            myHeldLocks = MyProc->heldLocks;
      PROC       *proc;
      int            i;
-
  #ifndef __BEOS__
      struct itimerval timeval,
                  dummy;
-
  #else
      bigtime_t    time_interval;
-
  #endif

      /*
--- 506,519 ----
      SPINLOCK    spinlock = lockctl->masterLock;
      PROC_QUEUE *waitQueue = &(lock->waitProcs);
      int            myHeldLocks = MyProc->heldLocks;
+     bool        early_deadlock = false;
      PROC       *proc;
      int            i;
  #ifndef __BEOS__
      struct itimerval timeval,
                  dummy;
  #else
      bigtime_t    time_interval;
  #endif

      /*
***************
*** 535,541 ****
       * immediately.  This is the same as the test for immediate grant in
       * LockAcquire, except we are only considering the part of the wait
       * queue before my insertion point.
-      *
       */
      if (myHeldLocks != 0)
      {
--- 533,538 ----
***************
*** 550,558 ****
                  /* Must I wait for him ? */
                  if (lockctl->conflictTab[lockmode] & proc->heldLocks)
                  {
!                     /* Yes, can report deadlock failure immediately */
!                     MyProc->errType = STATUS_ERROR;
!                     return STATUS_ERROR;
                  }
                  /* I must go before this waiter.  Check special case. */
                  if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
--- 547,560 ----
                  /* Must I wait for him ? */
                  if (lockctl->conflictTab[lockmode] & proc->heldLocks)
                  {
!                     /*
!                      * Yes, so we have a deadlock.  Easiest way to clean up
!                      * correctly is to call RemoveFromWaitQueue(), but we
!                      * can't do that until we are *on* the wait queue.
!                      * So, set a flag to check below, and break out of loop.
!                      */
!                     early_deadlock = true;
!                     break;
                  }
                  /* I must go before this waiter.  Check special case. */
                  if ((lockctl->conflictTab[lockmode] & aheadRequests) == 0 &&
***************
*** 600,606 ****
      MyProc->waitHolder = holder;
      MyProc->waitLockMode = lockmode;

!     MyProc->errType = STATUS_OK;/* initialize result for success */

      /* mark that we are waiting for a lock */
      waitingForLock = true;
--- 602,620 ----
      MyProc->waitHolder = holder;
      MyProc->waitLockMode = lockmode;

!     MyProc->errType = STATUS_OK; /* initialize result for success */
!
!     /*
!      * If we detected deadlock, give up without waiting.  This must agree
!      * with HandleDeadLock's recovery code, except that we shouldn't release
!      * the semaphore since we haven't tried to lock it yet.
!      */
!     if (early_deadlock)
!     {
!         RemoveFromWaitQueue(MyProc);
!         MyProc->errType = STATUS_ERROR;
!         return STATUS_ERROR;
!     }

      /* mark that we are waiting for a lock */
      waitingForLock = true;

pgsql-bugs by date:

Previous
From: Stephan Szabo
Date:
Subject: Re: Odp: PD: triggered data change violation on relation
Next
From: pgsql-bugs@postgresql.org
Date:
Subject: Bug #437: postgresql-python rpm fails on mx dependency