Move CheckRecoveryConflictDeadlock() call to a safer place.
authorTom Lane <[email protected]>
Tue, 2 Aug 2011 19:16:44 +0000 (15:16 -0400)
committerTom Lane <[email protected]>
Tue, 2 Aug 2011 19:16:44 +0000 (15:16 -0400)
This kluge was inserted in a spot apparently chosen at random: the lock
manager's state is not yet fully set up for the wait, and in particular
LockWaitCancel hasn't been armed by setting lockAwaited, so the ProcLock
will not get cleaned up if the ereport is thrown.  This seems to not cause
any observable problem in trivial test cases, because LockReleaseAll will
silently clean up the debris; but I was able to cause failures with tests
involving subtransactions.

Fixes breakage induced by commit c85c941470efc44494fd7a5f426ee85fc65c268c.
Back-patch to all affected branches.

src/backend/storage/ipc/standby.c
src/backend/storage/lmgr/lock.c
src/backend/storage/lmgr/proc.c
src/include/storage/standby.h

index ce02fe76049beea508f95893a8c455b5bfcdd0a0..e6b1fce61e617a36f60a95ce409f70770a213799 100644 (file)
@@ -463,24 +463,25 @@ SendRecoveryConflictWithBufferPin(ProcSignalReason reason)
 
 /*
  * In Hot Standby perform early deadlock detection.  We abort the lock
- * wait if are about to sleep while holding the buffer pin that Startup
- * process is waiting for. The deadlock occurs because we can only be
- * waiting behind an AccessExclusiveLock, which can only clear when a
- * transaction completion record is replayed, which can only occur when
- * Startup process is not waiting. So if Startup process is waiting we
- * never will clear that lock, so if we wait we cause deadlock. If we
- * are the Startup process then no need to check for deadlocks.
+ * wait if we are about to sleep while holding the buffer pin that Startup
+ * process is waiting for.
+ *
+ * Note: this code is pessimistic, because there is no way for it to
+ * determine whether an actual deadlock condition is present: the lock we
+ * need to wait for might be unrelated to any held by the Startup process.
+ * Sooner or later, this mechanism should get ripped out in favor of somehow
+ * accounting for buffer locks in DeadLockCheck().  However, errors here
+ * seem to be very low-probability in practice, so for now it's not worth
+ * the trouble.
  */
 void
-CheckRecoveryConflictDeadlock(LWLockId partitionLock)
+CheckRecoveryConflictDeadlock(void)
 {
-   Assert(!InRecovery);
+   Assert(!InRecovery);        /* do not call in Startup process */
 
    if (!HoldingBufferPinThatDelaysRecovery())
        return;
 
-   LWLockRelease(partitionLock);
-
    /*
     * Error message should match ProcessInterrupts() but we avoid calling
     * that because we aren't handling an interrupt at this point. Note that
index f48193c8e732129dae5f8a325309b944d57e891d..73cfea2baa0232c0215c8b1c096ba078128e9bf1 100644 (file)
@@ -829,13 +829,6 @@ LockAcquireExtended(const LOCKTAG *locktag,
            return LOCKACQUIRE_NOT_AVAIL;
        }
 
-       /*
-        * In Hot Standby perform early deadlock detection in normal backends.
-        * If deadlock found we release partition lock but do not return.
-        */
-       if (RecoveryInProgress() && !InRecovery)
-           CheckRecoveryConflictDeadlock(partitionLock);
-
        /*
         * Set bitmask of locks this process already holds on this object.
         */
index 2608fea94510d141210745f8c5d7fcd9df16c02e..8896f6c2dbb07f616ae84e387ea472a6bd3181db 100644 (file)
@@ -927,6 +927,15 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
     */
    LWLockRelease(partitionLock);
 
+   /*
+    * Also, now that we will successfully clean up after an ereport, it's
+    * safe to check to see if there's a buffer pin deadlock against the
+    * Startup process.  Of course, that's only necessary if we're doing
+    * Hot Standby and are not the Startup process ourselves.
+    */
+   if (RecoveryInProgress() && !InRecovery)
+       CheckRecoveryConflictDeadlock();
+
    /* Reset deadlock_state before enabling the signal handler */
    deadlock_state = DS_NOT_YET_CHECKED;
 
index 42fa0c04a1788d4fe182c66309fc34e555bbdfa8..2df838f40fc5170089d909b5c841f82226b45163 100644 (file)
@@ -35,7 +35,7 @@ extern void ResolveRecoveryConflictWithDatabase(Oid dbid);
 
 extern void ResolveRecoveryConflictWithBufferPin(void);
 extern void SendRecoveryConflictWithBufferPin(ProcSignalReason reason);
-extern void CheckRecoveryConflictDeadlock(LWLockId partitionLock);
+extern void CheckRecoveryConflictDeadlock(void);
 
 /*
  * Standby Rmgr (RM_STANDBY_ID)