aboutsummaryrefslogtreecommitdiff
path: root/src/backend/storage/lmgr/proc.c
diff options
context:
space:
mode:
authorSimon Riggs <simon@2ndQuadrant.com>2010-01-23 16:37:12 +0000
committerSimon Riggs <simon@2ndQuadrant.com>2010-01-23 16:37:12 +0000
commit959ac58c04130d467fb05e63a3ceb8e2ded404c7 (patch)
tree314eeeea7c6c8afa7cbe35bfe5ecde04eff35f71 /src/backend/storage/lmgr/proc.c
parent4fa69e566cf1b836ae8aa9bee24ab0c556cfe94e (diff)
downloadpostgresql-959ac58c04130d467fb05e63a3ceb8e2ded404c7.tar.gz
postgresql-959ac58c04130d467fb05e63a3ceb8e2ded404c7.zip
In HS, Startup process sets SIGALRM when waiting for buffer pin. If
woken by alarm we send SIGUSR1 to all backends requesting that they check to see if they are blocking Startup process. If so, they throw ERROR/FATAL as for other conflict resolutions. Deadlock stop gap removed. max_standby_delay = -1 option removed to prevent deadlock.
Diffstat (limited to 'src/backend/storage/lmgr/proc.c')
-rw-r--r--src/backend/storage/lmgr/proc.c150
1 files changed, 148 insertions, 2 deletions
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index ac891827ec1..da64e1953a3 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.213 2010/01/16 10:05:50 sriggs Exp $
+ * $PostgreSQL: pgsql/src/backend/storage/lmgr/proc.c,v 1.214 2010/01/23 16:37:12 sriggs Exp $
*
*-------------------------------------------------------------------------
*/
@@ -73,6 +73,7 @@ NON_EXEC_STATIC PGPROC *AuxiliaryProcs = NULL;
static LOCALLOCK *lockAwaited = NULL;
/* Mark these volatile because they can be changed by signal handler */
+static volatile bool standby_timeout_active = false;
static volatile bool statement_timeout_active = false;
static volatile bool deadlock_timeout_active = false;
static volatile DeadLockState deadlock_state = DS_NOT_YET_CHECKED;
@@ -89,6 +90,7 @@ static void RemoveProcFromArray(int code, Datum arg);
static void ProcKill(int code, Datum arg);
static void AuxiliaryProcKill(int code, Datum arg);
static bool CheckStatementTimeout(void);
+static bool CheckStandbyTimeout(void);
/*
@@ -107,6 +109,8 @@ ProcGlobalShmemSize(void)
size = add_size(size, mul_size(MaxBackends, sizeof(PGPROC)));
/* ProcStructLock */
size = add_size(size, sizeof(slock_t));
+ /* startupBufferPinWaitBufId */
+ size = add_size(size, sizeof(NBuffers));
return size;
}
@@ -487,11 +491,44 @@ PublishStartupProcessInformation(void)
procglobal->startupProc = MyProc;
procglobal->startupProcPid = MyProcPid;
+ procglobal->startupBufferPinWaitBufId = 0;
SpinLockRelease(ProcStructLock);
}
/*
+ * Used from bufgr to share the value of the buffer that Startup waits on,
+ * or to reset the value to "not waiting" (-1). This allows processing
+ * of recovery conflicts for buffer pins. Set is made before backends look
+ * at this value, so locking not required, especially since the set is
+ * an atomic integer set operation.
+ */
+void
+SetStartupBufferPinWaitBufId(int bufid)
+{
+ /* use volatile pointer to prevent code rearrangement */
+ volatile PROC_HDR *procglobal = ProcGlobal;
+
+ procglobal->startupBufferPinWaitBufId = bufid;
+}
+
+/*
+ * Used by backends when they receive a request to check for buffer pin waits.
+ */
+int
+GetStartupBufferPinWaitBufId(void)
+{
+ int bufid;
+
+ /* use volatile pointer to prevent code rearrangement */
+ volatile PROC_HDR *procglobal = ProcGlobal;
+
+ bufid = procglobal->startupBufferPinWaitBufId;
+
+ return bufid;
+}
+
+/*
* Check whether there are at least N free PGPROC objects.
*
* Note: this is designed on the assumption that N will generally be small.
@@ -1542,7 +1579,7 @@ CheckStatementTimeout(void)
/*
- * Signal handler for SIGALRM
+ * Signal handler for SIGALRM for normal user backends
*
* Process deadlock check and/or statement timeout check, as needed.
* To avoid various edge cases, we must be careful to do nothing
@@ -1565,3 +1602,112 @@ handle_sig_alarm(SIGNAL_ARGS)
errno = save_errno;
}
+
+/*
+ * Signal handler for SIGALRM in Startup process
+ *
+ * To avoid various edge cases, we must be careful to do nothing
+ * when there is nothing to be done. We also need to be able to
+ * reschedule the timer interrupt if called before end of statement.
+ */
+bool
+enable_standby_sig_alarm(long delay_s, int delay_us, TimestampTz fin_time)
+{
+ struct itimerval timeval;
+
+ Assert(delay_s >= 0 && delay_us >= 0);
+
+ statement_fin_time = fin_time;
+
+ standby_timeout_active = true;
+
+ MemSet(&timeval, 0, sizeof(struct itimerval));
+ timeval.it_value.tv_sec = delay_s;
+ timeval.it_value.tv_usec = delay_us;
+ if (setitimer(ITIMER_REAL, &timeval, NULL))
+ return false;
+ return true;
+}
+
+bool
+disable_standby_sig_alarm(void)
+{
+ /*
+ * Always disable the interrupt if it is active; this avoids being
+ * interrupted by the signal handler and thereby possibly getting
+ * confused.
+ *
+ * We will re-enable the interrupt if necessary in CheckStandbyTimeout.
+ */
+ if (standby_timeout_active)
+ {
+ struct itimerval timeval;
+
+ MemSet(&timeval, 0, sizeof(struct itimerval));
+ if (setitimer(ITIMER_REAL, &timeval, NULL))
+ {
+ standby_timeout_active = false;
+ return false;
+ }
+ }
+
+ standby_timeout_active = false;
+
+ return true;
+}
+
+/*
+ * CheckStandbyTimeout() runs unconditionally in the Startup process
+ * SIGALRM handler. Timers will only be set when InHotStandby.
+ * We simply ignore any signals unless the timer has been set.
+ */
+static bool
+CheckStandbyTimeout(void)
+{
+ TimestampTz now;
+
+ standby_timeout_active = false;
+
+ now = GetCurrentTimestamp();
+
+ if (now >= statement_fin_time)
+ SendRecoveryConflictWithBufferPin();
+ else
+ {
+ /* Not time yet, so (re)schedule the interrupt */
+ long secs;
+ int usecs;
+ struct itimerval timeval;
+
+ TimestampDifference(now, statement_fin_time,
+ &secs, &usecs);
+
+ /*
+ * It's possible that the difference is less than a microsecond;
+ * ensure we don't cancel, rather than set, the interrupt.
+ */
+ if (secs == 0 && usecs == 0)
+ usecs = 1;
+
+ standby_timeout_active = true;
+
+ MemSet(&timeval, 0, sizeof(struct itimerval));
+ timeval.it_value.tv_sec = secs;
+ timeval.it_value.tv_usec = usecs;
+ if (setitimer(ITIMER_REAL, &timeval, NULL))
+ return false;
+ }
+
+ return true;
+}
+
+void
+handle_standby_sig_alarm(SIGNAL_ARGS)
+{
+ int save_errno = errno;
+
+ if (standby_timeout_active)
+ (void) CheckStandbyTimeout();
+
+ errno = save_errno;
+}