Hi,
Currently, clients wishing to know when the server exits hot standby
have to resort to polling, which is often suboptimal.
This adds the new "in_hot_standby" GUC variable that is reported via a
ParameterStatus message. This allows the clients to:
(a) know right away that they are connected to a server in hot
standby; and
(b) know immediately when a server exits hot standby.
This change will be most beneficial to various connection pooling
systems (pgpool etc.)
Elvis
>From bdf9a409005f0ea209c640935d9827369725e241 Mon Sep 17 00:00:00 2001
From: Elvis Pranskevichus <[email protected]>
Date: Fri, 17 Mar 2017 13:25:08 -0400
Subject: [PATCH v1] Add and report the new "in_hot_standby" GUC
pseudo-variable.
Currently, clients wishing to know when the server exits hot standby
have to resort to polling, which is suboptimal.
This adds the new "in_hot_standby" GUC variable that is reported via a
ParameterStatus message. This allows the clients to:
(a) know right away that they are connected to a server in hot
standby; and
(b) know immediately when a server exits hot standby.
This change will be most beneficial to various connection pooling
systems.
---
doc/src/sgml/high-availability.sgml | 4 +--
doc/src/sgml/libpq.sgml | 1 +
doc/src/sgml/protocol.sgml | 1 +
doc/src/sgml/ref/show.sgml | 9 +++++++
src/backend/access/transam/xlog.c | 4 ++-
src/backend/commands/async.c | 48 ++++++++++++++++++++++++++++++++++++
src/backend/storage/ipc/procarray.c | 30 ++++++++++++++++++++++
src/backend/storage/ipc/procsignal.c | 3 +++
src/backend/storage/ipc/standby.c | 9 +++++++
src/backend/tcop/postgres.c | 6 ++++-
src/backend/utils/init/postinit.c | 6 +++++
src/backend/utils/misc/check_guc | 10 ++++----
src/backend/utils/misc/guc.c | 15 +++++++++++
src/include/commands/async.h | 7 ++++++
src/include/storage/procarray.h | 2 ++
src/include/storage/procsignal.h | 2 ++
src/include/storage/standby.h | 1 +
17 files changed, 149 insertions(+), 9 deletions(-)
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index cc84b911b0..44795c5bcc 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -1831,8 +1831,8 @@ if (!triggered)
</para>
<para>
- Users will be able to tell whether their session is read-only by
- issuing <command>SHOW transaction_read_only</>. In addition, a set of
+ Users will be able to tell whether their session is in hot standby mode by
+ issuing <command>SHOW in_hot_standby</>. In addition, a set of
functions (<xref linkend="functions-recovery-info-table">) allow users to
access information about the standby server. These allow you to write
programs that are aware of the current state of the database. These
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 4bc5bf3192..367ec4460d 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1706,6 +1706,7 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
<varname>server_encoding</>,
<varname>client_encoding</>,
<varname>application_name</>,
+ <varname>in_hot_standby</>,
<varname>is_superuser</>,
<varname>session_authorization</>,
<varname>DateStyle</>,
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 7c82b48845..0fafaf6788 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1123,6 +1123,7 @@
<varname>server_encoding</>,
<varname>client_encoding</>,
<varname>application_name</>,
+ <varname>in_hot_standby</>,
<varname>is_superuser</>,
<varname>session_authorization</>,
<varname>DateStyle</>,
diff --git a/doc/src/sgml/ref/show.sgml b/doc/src/sgml/ref/show.sgml
index 46bb239baf..cf21bd961a 100644
--- a/doc/src/sgml/ref/show.sgml
+++ b/doc/src/sgml/ref/show.sgml
@@ -78,6 +78,15 @@ SHOW ALL
</varlistentry>
<varlistentry>
+ <term><literal>IN_HOT_STANDBY</literal></term>
+ <listitem>
+ <para>
+ True if the server is in Hot Standby mode.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><literal>LC_COLLATE</literal></term>
<listitem>
<para>
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index cdb3a8ac1d..acca53b12f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7654,8 +7654,10 @@ StartupXLOG(void)
* Shutdown the recovery environment. This must occur after
* RecoverPreparedTransactions(), see notes for lock_twophase_recover()
*/
- if (standbyState != STANDBY_DISABLED)
+ if (standbyState != STANDBY_DISABLED) {
ShutdownRecoveryTransactionEnvironment();
+ SendHotStandbyExitSignal();
+ }
/* Shut down xlogreader */
if (readFile >= 0)
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index e32d7a1d4e..8bc365489a 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -355,6 +355,8 @@ static List *upperPendingNotifies = NIL; /* list of upper-xact lists */
*/
volatile sig_atomic_t notifyInterruptPending = false;
+volatile sig_atomic_t hotStandbyExitInterruptPending = false;
+
/* True if we've registered an on_shmem_exit cleanup */
static bool unlistenExitRegistered = false;
@@ -1734,6 +1736,52 @@ ProcessNotifyInterrupt(void)
/*
+ * HandleHotStandbyExitInterrupt
+ *
+ * Signal handler portion of interrupt handling. Let the backend know
+ * that the server has exited the recovery mode.
+ */
+void
+HandleHotStandbyExitInterrupt(void)
+{
+ /*
+ * Note: this is called by a SIGNAL HANDLER. You must be very wary what
+ * you do here.
+ */
+
+ /* signal that work needs to be done */
+ hotStandbyExitInterruptPending = true;
+
+ /* make sure the event is processed in due course */
+ SetLatch(MyLatch);
+}
+
+
+/*
+ * ProcessHotStandbyExitInterrupt
+ *
+ * This is called just after waiting for a frontend command. If a
+ * interrupt arrives (via HandleHotStandbyExitInterrupt()) while reading,
+ * the read will be interrupted via the process's latch, and this routine
+ * will get called.
+ */
+void
+ProcessHotStandbyExitInterrupt(void)
+{
+ hotStandbyExitInterruptPending = false;
+
+ SetConfigOption("in_hot_standby", "off",
+ PGC_INTERNAL, PGC_S_OVERRIDE);
+
+ /*
+ * Flush output buffer so that clients receive the ParameterStatus
+ * message as soon as possible.
+ */
+ pq_flush();
+}
+
+
+/*
* Read all pending notifications from the queue, and deliver appropriate
* ones to my frontend. Stop when we reach queue head or an uncommitted
* notification.
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 0f8f435faf..b76ae35f87 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2937,6 +2937,36 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
}
/*
+ * SendSignalToAllBackends --- send a signal to all backends.
+ */
+void
+SendSignalToAllBackends(ProcSignalReason reason)
+{
+ ProcArrayStruct *arrayP = procArray;
+ int index;
+ pid_t pid = 0;
+
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+
+ for (index = 0; index < arrayP->numProcs; index++)
+ {
+ int pgprocno = arrayP->pgprocnos[index];
+ volatile PGPROC *proc = &allProcs[pgprocno];
+ VirtualTransactionId procvxid;
+
+ GET_VXID_FROM_PGPROC(procvxid, *proc);
+
+ pid = proc->pid;
+ if (pid != 0)
+ {
+ (void) SendProcSignal(pid, reason, procvxid.backendId);
+ }
+ }
+
+ LWLockRelease(ProcArrayLock);
+}
+
+/*
* ProcArraySetReplicationSlotXmin
*
* Install limits to future computations of the xmin horizon to prevent vacuum
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index 4a21d5512d..3918330ee3 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -288,6 +288,9 @@ procsignal_sigusr1_handler(SIGNAL_ARGS)
if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
+ if (CheckProcSignal(PROCSIG_HOTSTANDBY_EXIT))
+ HandleHotStandbyExitInterrupt();
+
SetLatch(MyLatch);
latch_sigusr1_handler();
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 6259070722..f5155dd80c 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -111,6 +111,15 @@ ShutdownRecoveryTransactionEnvironment(void)
VirtualXactLockTableCleanup();
}
+/*
+ * SendHotStandbyExitSignal
+ * Signal backends that the server has exited Hot Standby.
+ */
+void
+SendHotStandbyExitSignal(void)
+{
+ SendSignalToAllBackends(PROCSIG_HOTSTANDBY_EXIT);
+}
/*
* -----------------------------------------------------
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index b07d6c6cb9..4a2a4abb6f 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -532,9 +532,13 @@ ProcessClientReadInterrupt(bool blocked)
if (catchupInterruptPending)
ProcessCatchupInterrupt();
- /* Process sinval catchup interrupts that happened while reading */
+ /* Process NOTIFY interrupts that happened while reading */
if (notifyInterruptPending)
ProcessNotifyInterrupt();
+
+ /* Process recovery exit interrupts that happened while reading */
+ if (hotStandbyExitInterruptPending)
+ ProcessHotStandbyExitInterrupt();
}
else if (ProcDiePending && blocked)
{
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 9f938f2d27..d0041de00b 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -1013,6 +1013,12 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
* selected the active user and gotten the right GUC settings.
*/
+ /* set in_hot_standby */
+ if (HotStandbyActive()) {
+ SetConfigOption("in_hot_standby", "on",
+ PGC_INTERNAL, PGC_S_OVERRIDE);
+ }
+
/* set default namespace search path */
InitializeSearchPath();
diff --git a/src/backend/utils/misc/check_guc b/src/backend/utils/misc/check_guc
index d228bbed68..1795471fd4 100755
--- a/src/backend/utils/misc/check_guc
+++ b/src/backend/utils/misc/check_guc
@@ -17,11 +17,11 @@
## postgresql.conf.sample), it should be listed here so that it
## can be ignored
INTENTIONALLY_NOT_INCLUDED="debug_deadlocks \
-is_superuser lc_collate lc_ctype lc_messages lc_monetary lc_numeric lc_time \
-pre_auth_delay role seed server_encoding server_version server_version_int \
-session_authorization trace_lock_oidmin trace_lock_table trace_locks trace_lwlocks \
-trace_notify trace_userlocks transaction_isolation transaction_read_only \
-zero_damaged_pages"
+is_superuser in_hot_standby lc_collate lc_ctype lc_messages lc_monetary \
+lc_numeric lc_time pre_auth_delay role seed server_encoding server_version \
+server_version_int session_authorization trace_lock_oidmin trace_lock_table \
+trace_locks trace_lwlocks trace_notify trace_userlocks transaction_isolation \
+transaction_read_only zero_damaged_pages"
### What options are listed in postgresql.conf.sample, but don't appear
### in guc.c?
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 4feb26aa7a..b34553df81 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -496,6 +496,7 @@ int huge_pages;
*/
static char *syslog_ident_str;
static bool session_auth_is_superuser;
+static bool server_in_hot_standby;
static double phony_random_seed;
static char *client_encoding_string;
static char *datestyle_string;
@@ -934,6 +935,20 @@ static struct config_bool ConfigureNamesBool[] =
NULL, NULL, NULL
},
{
+ /*
+ * Not for general use --- used to indicate whether
+ * the server is in hot standby.
+ */
+ {"in_hot_standby", PGC_INTERNAL, UNGROUPED,
+ gettext_noop("Shows whether the server is in hot standby mode."),
+ NULL,
+ GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+ },
+ &server_in_hot_standby,
+ false,
+ NULL, NULL, NULL
+ },
+ {
{"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
gettext_noop("Enables advertising the server via Bonjour."),
NULL
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index b7842d1a0f..d21f8d59ae 100644
--- a/src/include/commands/async.h
+++ b/src/include/commands/async.h
@@ -24,6 +24,7 @@
extern bool Trace_notify;
extern volatile sig_atomic_t notifyInterruptPending;
+extern volatile sig_atomic_t hotStandbyExitInterruptPending;
extern Size AsyncShmemSize(void);
extern void AsyncShmemInit(void);
@@ -54,4 +55,10 @@ extern void HandleNotifyInterrupt(void);
/* process interrupts */
extern void ProcessNotifyInterrupt(void);
+/* signal handler for inbound notifies (PROCSIG_HOTSTANDBY_EXIT) */
+extern void HandleHotStandbyExitInterrupt(void);
+
+/* process recovery exit event */
+extern void ProcessHotStandbyExitInterrupt(void);
+
#endif /* ASYNC_H */
diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h
index 9d5a13eb3b..a35759e141 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -79,6 +79,8 @@ extern int CountUserBackends(Oid roleid);
extern bool CountOtherDBBackends(Oid databaseId,
int *nbackends, int *nprepared);
+extern void SendSignalToAllBackends(ProcSignalReason reason);
+
extern void XidCacheRemoveRunningXids(TransactionId xid,
int nxids, const TransactionId *xids,
TransactionId latestXid);
diff --git a/src/include/storage/procsignal.h b/src/include/storage/procsignal.h
index d068dde5d7..557318a4c1 100644
--- a/src/include/storage/procsignal.h
+++ b/src/include/storage/procsignal.h
@@ -41,6 +41,8 @@ typedef enum
PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
+ PROCSIG_HOTSTANDBY_EXIT, /* postmaster has exited hot standby */
+
NUM_PROCSIGNALS /* Must be last! */
} ProcSignalReason;
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index 3ecc446083..dabd8a3839 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -26,6 +26,7 @@ extern int max_standby_streaming_delay;
extern void InitRecoveryTransactionEnvironment(void);
extern void ShutdownRecoveryTransactionEnvironment(void);
+extern void SendHotStandbyExitSignal(void);
extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid,
RelFileNode node);
--
2.11.1
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers