From 7c24bac64c3828d651abfd5e34bd0e0031ab9946 Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Thu, 8 Sep 2011 12:03:28 +0100 Subject: [PATCH] PublishStartupProcessInformation() to avoid rare hang in recovery. Bgwriter could cause hang in recovery during page concurrent cleaning. Bug report and testing by Bernd Helmle, fix by me --- src/backend/access/transam/xlog.c | 2 ++ src/backend/storage/lmgr/proc.c | 43 ++++++++++++++++++++++++++++++- src/include/storage/proc.h | 6 +++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index bb8971ce91..3da118b14e 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -44,6 +44,7 @@ #include "storage/fd.h" #include "storage/ipc.h" #include "storage/pmsignal.h" +#include "storage/proc.h" #include "storage/procarray.h" #include "storage/smgr.h" #include "storage/spin.h" @@ -5569,6 +5570,7 @@ StartupXLOG(void) */ if (InArchiveRecovery && IsUnderPostmaster) { + PublishStartupProcessInformation(); SetForwardFsyncRequests(); SendPostmasterSignal(PMSIGNAL_RECOVERY_STARTED); bgwriterLaunched = true; diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 4ae977154a..3248e136c9 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -1287,12 +1287,53 @@ ProcWaitForSignal(void) void ProcSendSignal(int pid) { - PGPROC *proc = BackendPidGetProc(pid); + PGPROC *proc = NULL; + + proc = BackendPidGetProc(pid); + + if (proc == NULL) + { + /* use volatile pointer to prevent code rearrangement */ + volatile PROC_HDR *procglobal = ProcGlobal; + + SpinLockAcquire(ProcStructLock); + + /* + * Check to see whether it is the Startup process we wish to signal. + * This call is made by the buffer manager when it wishes to wake up a + * process that has been waiting for a pin in so it can obtain a + * cleanup lock using LockBufferForCleanup(). Startup is not a normal + * backend, so BackendPidGetProc() will not return any pid at all. So + * we remember the information for this special case. + */ + if (pid == procglobal->startupProcPid) + proc = procglobal->startupProc; + + SpinLockRelease(ProcStructLock); + } if (proc != NULL) PGSemaphoreUnlock(&proc->sem); } +/* + * Record the PID and PGPROC structures for the Startup process, for use in + * ProcSendSignal(). See comments there for further explanation. + */ +void +PublishStartupProcessInformation(void) +{ + /* use volatile pointer to prevent code rearrangement */ + volatile PROC_HDR *procglobal = ProcGlobal; + + SpinLockAcquire(ProcStructLock); + + procglobal->startupProc = MyProc; + procglobal->startupProcPid = MyProcPid; + + SpinLockRelease(ProcStructLock); +} + /***************************************************************************** * SIGALRM interrupt support diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h index b250d3f0f2..e586572ef8 100644 --- a/src/include/storage/proc.h +++ b/src/include/storage/proc.h @@ -133,6 +133,11 @@ typedef struct PROC_HDR PGPROC *autovacFreeProcs; /* Current shared estimate of appropriate spins_per_delay value */ int spins_per_delay; + + /* PGPROC of Startup process */ + PGPROC *startupProc; + /* Pid of Startup process */ + int startupProcPid; } PROC_HDR; /* @@ -175,6 +180,7 @@ extern void LockWaitCancel(void); extern void ProcWaitForSignal(void); extern void ProcSendSignal(int pid); +extern void PublishStartupProcessInformation(void); extern bool enable_sig_alarm(int delayms, bool is_statement_timeout); extern bool disable_sig_alarm(bool is_statement_timeout);