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 <el...@magic.io> 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers