Skip to content

Commit c85c941

Browse files
Detect early deadlock in Hot Standby when Startup is already waiting. First
stage of required deadlock detection to allow re-enabling max_standby_delay setting of -1, which is now essential in the absence of improved relation- specific conflict resoluton. Requested by Greg Stark et al.
1 parent 034fffb commit c85c941

File tree

3 files changed

+46
-4
lines changed

3 files changed

+46
-4
lines changed

src/backend/storage/ipc/standby.c

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
* Portions Copyright (c) 1994, Regents of the University of California
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.8 2010/01/29 17:10:05 sriggs Exp $
14+
* $PostgreSQL: pgsql/src/backend/storage/ipc/standby.c,v 1.9 2010/01/31 19:01:11 sriggs Exp $
1515
*
1616
*-------------------------------------------------------------------------
1717
*/
@@ -22,6 +22,7 @@
2222
#include "access/xlog.h"
2323
#include "miscadmin.h"
2424
#include "pgstat.h"
25+
#include "storage/bufmgr.h"
2526
#include "storage/lmgr.h"
2627
#include "storage/proc.h"
2728
#include "storage/procarray.h"
@@ -384,7 +385,7 @@ ResolveRecoveryConflictWithBufferPin(void)
384385
TimestampDifference(GetLatestXLogTime(), now,
385386
&standby_delay_secs, &standby_delay_usecs);
386387

387-
if (standby_delay_secs >= (long) MaxStandbyDelay)
388+
if (standby_delay_secs >= MaxStandbyDelay)
388389
SendRecoveryConflictWithBufferPin();
389390
else
390391
{
@@ -445,6 +446,39 @@ SendRecoveryConflictWithBufferPin(void)
445446
CancelDBBackends(InvalidOid, PROCSIG_RECOVERY_CONFLICT_BUFFERPIN, false);
446447
}
447448

449+
/*
450+
* In Hot Standby perform early deadlock detection. We abort the lock
451+
* wait if are about to sleep while holding the buffer pin that Startup
452+
* process is waiting for. The deadlock occurs because we can only be
453+
* waiting behind an AccessExclusiveLock, which can only clear when a
454+
* transaction completion record is replayed, which can only occur when
455+
* Startup process is not waiting. So if Startup process is waiting we
456+
* never will clear that lock, so if we wait we cause deadlock. If we
457+
* are the Startup process then no need to check for deadlocks.
458+
*/
459+
void
460+
CheckRecoveryConflictDeadlock(LWLockId partitionLock)
461+
{
462+
Assert(!InRecovery);
463+
464+
if (!HoldingBufferPinThatDelaysRecovery())
465+
return;
466+
467+
LWLockRelease(partitionLock);
468+
469+
/*
470+
* Error message should match ProcessInterrupts() but we avoid calling
471+
* that because we aren't handling an interrupt at this point. Note
472+
* that we only cancel the current transaction here, so if we are in a
473+
* subtransaction and the pin is held by a parent, then the Startup
474+
* process will continue to wait even though we have avoided deadlock.
475+
*/
476+
ereport(ERROR,
477+
(errcode(ERRCODE_QUERY_CANCELED),
478+
errmsg("canceling statement due to conflict with recovery"),
479+
errdetail("User transaction caused buffer deadlock with recovery.")));
480+
}
481+
448482
/*
449483
* -----------------------------------------------------
450484
* Locking in Recovery Mode

src/backend/storage/lmgr/lock.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.193 2010/01/29 19:45:12 sriggs Exp $
11+
* $PostgreSQL: pgsql/src/backend/storage/lmgr/lock.c,v 1.194 2010/01/31 19:01:11 sriggs Exp $
1212
*
1313
* NOTES
1414
* A lock table is a shared memory hash table. When
@@ -814,6 +814,13 @@ LockAcquireExtended(const LOCKTAG *locktag,
814814
return LOCKACQUIRE_NOT_AVAIL;
815815
}
816816

817+
/*
818+
* In Hot Standby perform early deadlock detection in normal backends.
819+
* If deadlock found we release partition lock but do not return.
820+
*/
821+
if (RecoveryInProgress() && !InRecovery)
822+
CheckRecoveryConflictDeadlock(partitionLock);
823+
817824
/*
818825
* Set bitmask of locks this process already holds on this object.
819826
*/

src/include/storage/standby.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.6 2010/01/29 17:10:05 sriggs Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/standby.h,v 1.7 2010/01/31 19:01:11 sriggs Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -31,6 +31,7 @@ extern void ResolveRecoveryConflictWithDatabase(Oid dbid);
3131

3232
extern void ResolveRecoveryConflictWithBufferPin(void);
3333
extern void SendRecoveryConflictWithBufferPin(void);
34+
extern void CheckRecoveryConflictDeadlock(LWLockId partitionLock);
3435

3536
/*
3637
* Standby Rmgr (RM_STANDBY_ID)

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy