[PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

Started by Elvis Pranskevichusalmost 9 years ago43 messages
#1Elvis Pranskevichus
elprans@gmail.com
1 attachment(s)

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

Attachments:

v1-0001-Add-and-report-the-new-in_hot_standby-GUC-pseudo-.patchtext/x-patch; charset=UTF-8; name=v1-0001-Add-and-report-the-new-in_hot_standby-GUC-pseudo-.patchDownload
From bdf9a409005f0ea209c640935d9827369725e241 Mon Sep 17 00:00:00 2001
From: Elvis Pranskevichus <elvis@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

#2Michael Paquier
michael.paquier@gmail.com
In reply to: Elvis Pranskevichus (#1)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Sat, Mar 18, 2017 at 2:56 AM, Elvis Pranskevichus <elprans@gmail.com> wrote:

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.)

Why adding a good chunk of code instead of using pg_is_in_recovery(),
which switches to false once a server exits recovery?
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Elvis Pranskevichus
elprans@gmail.com
In reply to: Michael Paquier (#2)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Saturday, March 18, 2017 3:33:16 AM EDT Michael Paquier wrote:

On Sat, Mar 18, 2017 at 2:56 AM, Elvis Pranskevichus

<elprans@gmail.com> wrote:

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.)

Why adding a good chunk of code instead of using pg_is_in_recovery(),
which switches to false once a server exits recovery?

That requires polling the database continuously, which may not be
possible or desirable.

My main motivation here is to gain the ability to manage a pool of
connections in asyncpg efficiently. A part of the connection release
protocol is "UNLISTEN *;", which the server in Hot Standby would fail to
process. Polling the database for pg_is_in_recovery() is not feasible
in this case, unfortunately.

Elvis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#4Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Elvis Pranskevichus (#1)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 3/17/17 13:56, Elvis Pranskevichus wrote:

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.

The terminology chosen here is not very clear. What is the opposite of
"in hot standby"? Warm standby? Cold standby? Not standby at all?
Promoted to primary (writable)?

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#5Elvis Pranskevichus
elprans@gmail.com
In reply to: Peter Eisentraut (#4)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Tuesday, March 21, 2017 11:50:38 PM EDT Peter Eisentraut wrote:

On 3/17/17 13:56, Elvis Pranskevichus wrote:

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.

The terminology chosen here is not very clear. What is the opposite
of "in hot standby"? Warm standby? Cold standby? Not standby at
all? Promoted to primary (writable)?

The opposite means primary. I can flip the GUC name to "is_primary", if
that's clearer.

Elvis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Robert Haas
robertmhaas@gmail.com
In reply to: Elvis Pranskevichus (#5)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, Mar 22, 2017 at 8:25 AM, Elvis Pranskevichus <elprans@gmail.com> wrote:

On Tuesday, March 21, 2017 11:50:38 PM EDT Peter Eisentraut wrote:

On 3/17/17 13:56, Elvis Pranskevichus wrote:

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.

The terminology chosen here is not very clear. What is the opposite
of "in hot standby"? Warm standby? Cold standby? Not standby at
all? Promoted to primary (writable)?

The opposite means primary. I can flip the GUC name to "is_primary", if
that's clearer.

Hmm, I don't find that clearer. "hot standby" has a very specific
meaning; "primary" isn't vague, but I would say it's less specific.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#7Jaime Casanova
jaime.casanova@2ndquadrant.com
In reply to: Elvis Pranskevichus (#3)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 18 March 2017 at 14:01, Elvis Pranskevichus <elprans@gmail.com> wrote:

On Saturday, March 18, 2017 3:33:16 AM EDT Michael Paquier wrote:

Why adding a good chunk of code instead of using pg_is_in_recovery(),
which switches to false once a server exits recovery?

That requires polling the database continuously, which may not be
possible or desirable.

My main motivation here is to gain the ability to manage a pool of
connections in asyncpg efficiently. A part of the connection release
protocol is "UNLISTEN *;", which the server in Hot Standby would fail to
process. Polling the database for pg_is_in_recovery() is not feasible
in this case, unfortunately.

Sorry, i still don't understand the motivation for this.
At one point you're going to poll for the value of the GUC in pg_settings, no?
Or how are you going to know the current value of the GUC that makes it
different to just poll for pg_is_in_recovery()?

--
Jaime Casanova www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Elvis Pranskevichus
elprans@gmail.com
In reply to: Jaime Casanova (#7)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wednesday, March 22, 2017 2:17:27 PM EDT Jaime Casanova wrote:

On 18 March 2017 at 14:01, Elvis Pranskevichus <elprans@gmail.com> wrote:

On Saturday, March 18, 2017 3:33:16 AM EDT Michael Paquier wrote:

Why adding a good chunk of code instead of using
pg_is_in_recovery(),
which switches to false once a server exits recovery?

That requires polling the database continuously, which may not be
possible or desirable.

My main motivation here is to gain the ability to manage a pool of
connections in asyncpg efficiently. A part of the connection
release
protocol is "UNLISTEN *;", which the server in Hot Standby would
fail to process. Polling the database for pg_is_in_recovery() is
not feasible in this case, unfortunately.

Sorry, i still don't understand the motivation for this.
At one point you're going to poll for the value of the GUC in
pg_settings, no? Or how are you going to know the current value of
the GUC that makes it different to just poll for pg_is_in_recovery()?

It is marked as GUC_REPORT and is reported by the server on
connection and on every change:

https://www.postgresql.org/docs/current/static/protocol-flow.html#PROTOCOL-ASYNC

Elvis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Peter Eisentraut
peter.eisentraut@2ndquadrant.com
In reply to: Robert Haas (#6)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 3/22/17 14:09, Robert Haas wrote:

The opposite means primary. I can flip the GUC name to "is_primary", if
that's clearer.

Hmm, I don't find that clearer. "hot standby" has a very specific
meaning; "primary" isn't vague, but I would say it's less specific.

The problem I have is that there is already a GUC named "hot_standby",
which determines whether an instance is in hot (as opposed to warm?)
mode if it is a standby. This is proposing to add a setting named
"in_hot_standby" which says nothing about the hotness, but something
about the standbyness. Note that these are all in the same namespace.

I think we could use "in_recovery", which would be consistent with
existing naming.

--
Peter Eisentraut http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Robert Haas
robertmhaas@gmail.com
In reply to: Peter Eisentraut (#9)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, Mar 22, 2017 at 4:00 PM, Peter Eisentraut
<peter.eisentraut@2ndquadrant.com> wrote:

On 3/22/17 14:09, Robert Haas wrote:

The opposite means primary. I can flip the GUC name to "is_primary", if
that's clearer.

Hmm, I don't find that clearer. "hot standby" has a very specific
meaning; "primary" isn't vague, but I would say it's less specific.

The problem I have is that there is already a GUC named "hot_standby",
which determines whether an instance is in hot (as opposed to warm?)
mode if it is a standby. This is proposing to add a setting named
"in_hot_standby" which says nothing about the hotness, but something
about the standbyness. Note that these are all in the same namespace.

Good point.

I think we could use "in_recovery", which would be consistent with
existing naming.

True.

(Jaime's question is also on point, I think.)

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Elvis Pranskevichus
elprans@gmail.com
In reply to: Robert Haas (#10)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wednesday, March 22, 2017 4:28:18 PM EDT Robert Haas wrote:

On Wed, Mar 22, 2017 at 4:00 PM, Peter Eisentraut

I think we could use "in_recovery", which would be consistent with
existing naming.

True.

Ironically, that was the name I originally used. I'll update the patch.

(Jaime's question is also on point, I think.)

The main (and only) point of this patch is to avoid polling. Since
"in_recovery" is marked as GUC_REPORT, it will be sent to the client
asynchronously in a ParamStatus message. Other GUC_REPORT variables set
a good precedent.

My argument is that Hot Standby is a major mode of operation, which
significantly alters how connected clients work with the server, and
this bit of knowledge is no less important than the other GUC_REPORT
vars.

Elvis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Magnus Hagander
magnus@hagander.net
In reply to: Peter Eisentraut (#9)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, Mar 22, 2017 at 9:00 PM, Peter Eisentraut <
peter.eisentraut@2ndquadrant.com> wrote:

On 3/22/17 14:09, Robert Haas wrote:

The opposite means primary. I can flip the GUC name to "is_primary", if
that's clearer.

Hmm, I don't find that clearer. "hot standby" has a very specific
meaning; "primary" isn't vague, but I would say it's less specific.

The problem I have is that there is already a GUC named "hot_standby",
which determines whether an instance is in hot (as opposed to warm?)
mode if it is a standby. This is proposing to add a setting named
"in_hot_standby" which says nothing about the hotness, but something
about the standbyness. Note that these are all in the same namespace.

I think we could use "in_recovery", which would be consistent with
existing naming.

One thing we might want to consider around this -- in 10 we have
target_session_attrs=read-write (since
721f7bd3cbccaf8c07cad2707826b83f84694832), which will issue a SHOW
transaction_read_only on the connection.

We should probably consider if there is some way we can implement these two
things the same way. If we're inventing a new variable that gets pushed on
each connection, perhaps we can use that one and avoid the SHOW command? Is
the read-write thing really interesting in the aspect of the general case,
or is it more about detectinv readonly standbys as well? Or to flip that,
would sending the transaction_read_only parameter be enough for the usecase
in this thread, without having to invent a new variable?

(I haven't thought it through all the way, but figured I should mention the
thought as I'm working through my email backlog.)

--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/

#13Elvis Pranskevichus
elprans@gmail.com
In reply to: Magnus Hagander (#12)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Thursday, March 23, 2017 4:50:20 AM EDT Magnus Hagander wrote:

We should probably consider if there is some way we can implement
these two things the same way. If we're inventing a new variable that
gets pushed on each connection, perhaps we can use that one and avoid
the SHOW command? Is the read-write thing really interesting in the
aspect of the general case, or is it more about detectinv readonly
standbys as well? Or to flip that, would sending the
transaction_read_only parameter be enough for the usecase in this
thread, without having to invent a new variable?

Hot standby differs from regular read-only transactions in a number of
ways. Most importantly, it prohibits LISTEN/NOTIFY. Grep for
PreventCommandDuringRecovery() if you're interested in the scope.

Elvis

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Robert Haas
robertmhaas@gmail.com
In reply to: Magnus Hagander (#12)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Thu, Mar 23, 2017 at 4:50 AM, Magnus Hagander <magnus@hagander.net> wrote:

One thing we might want to consider around this -- in 10 we have
target_session_attrs=read-write (since
721f7bd3cbccaf8c07cad2707826b83f84694832), which will issue a SHOW
transaction_read_only on the connection.

We should probably consider if there is some way we can implement these two
things the same way. If we're inventing a new variable that gets pushed on
each connection, perhaps we can use that one and avoid the SHOW command?

I think that would be a good idea. It was, in fact, proposed to do
exactly that as part of the patch that added
target_session_attrs=read-write, but we ended up not doing anything
about it because the SHOW mechanism would still be needed when
connecting to pre-10 versions of PostgreSQL. Therefore, it seemed
like a separate improvement. But if we're adding a GUC_REPORT value
that could be used for the same or a similar purpose, I think it would
make sense to consider revising that mechanism to leverage it as well,
obviously only on releases that have the GUC.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Magnus Hagander
magnus@hagander.net
In reply to: Robert Haas (#14)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, Apr 5, 2017 at 6:22 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Mar 23, 2017 at 4:50 AM, Magnus Hagander <magnus@hagander.net>
wrote:

One thing we might want to consider around this -- in 10 we have
target_session_attrs=read-write (since
721f7bd3cbccaf8c07cad2707826b83f84694832), which will issue a SHOW
transaction_read_only on the connection.

We should probably consider if there is some way we can implement these

two

things the same way. If we're inventing a new variable that gets pushed

on

each connection, perhaps we can use that one and avoid the SHOW command?

I think that would be a good idea. It was, in fact, proposed to do
exactly that as part of the patch that added
target_session_attrs=read-write, but we ended up not doing anything
about it because the SHOW mechanism would still be needed when
connecting to pre-10 versions of PostgreSQL. Therefore, it seemed
like a separate improvement. But if we're adding a GUC_REPORT value
that could be used for the same or a similar purpose, I think it would
make sense to consider revising that mechanism to leverage it as well,
obviously only on releases that have the GUC.

Based on that we seem to agree here, should we add this as an open item?
Clearly if we want to change this, we should do so before 10.

I also came up with another case where the current one won't work but it
could be really useful -- if we make a replication connection (with say
pg_receivewal) it would be good to be able to say "i want the master" (or
"i want a standby") the same way. And that will fail today if it needs SHOW
to work, right?

So having it send that information across in the startup package when
talking to a 10 server, but falling back to using SHOW if talking to an
earlier server, would make a lot of sense I think.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#16Michael Paquier
michael.paquier@gmail.com
In reply to: Magnus Hagander (#15)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Mon, Apr 10, 2017 at 5:47 PM, Magnus Hagander <magnus@hagander.net> wrote:

Based on that we seem to agree here, should we add this as an open item?
Clearly if we want to change this, we should do so before 10.

This really is a new feature, so as the focus is to stabilize things I
think that we should not make the code more complicated because...

I also came up with another case where the current one won't work but it
could be really useful -- if we make a replication connection (with say
pg_receivewal) it would be good to be able to say "i want the master" (or "i
want a standby") the same way. And that will fail today if it needs SHOW to
work, right?

So having it send that information across in the startup package when
talking to a 10 server, but falling back to using SHOW if talking to an
earlier server, would make a lot of sense I think.

Of this reason, as libpq needs to be compliant with past server
versions as well we are never going to save a set of version-dependent
if/else code to handle target_session_attrs properly using either a
SHOW or a new mechanism.
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Magnus Hagander
magnus@hagander.net
In reply to: Michael Paquier (#16)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Tue, Apr 11, 2017 at 3:26 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:

On Mon, Apr 10, 2017 at 5:47 PM, Magnus Hagander <magnus@hagander.net>
wrote:

Based on that we seem to agree here, should we add this as an open item?
Clearly if we want to change this, we should do so before 10.

This really is a new feature, so as the focus is to stabilize things I
think that we should not make the code more complicated because...

The part I'm talking about is the potential adjustment of the patch that's
already committed. That's not a new feature, that's exactly the sort of
thing we'd want to adjust before we get to release. Because once released
we really can't change it.

I also came up with another case where the current one won't work but it

could be really useful -- if we make a replication connection (with say
pg_receivewal) it would be good to be able to say "i want the master"

(or "i

want a standby") the same way. And that will fail today if it needs SHOW

to

work, right?

So having it send that information across in the startup package when
talking to a 10 server, but falling back to using SHOW if talking to an
earlier server, would make a lot of sense I think.

Of this reason, as libpq needs to be compliant with past server
versions as well we are never going to save a set of version-dependent
if/else code to handle target_session_attrs properly using either a
SHOW or a new mechanism.

We'd have to cache the status recived yes. I don't see how that makes it a
"set of" if/else code when there is only one if/else now, though? Though
admittedly I haven't looked at the actual code for it.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#18Simon Riggs
simon@2ndquadrant.com
In reply to: Magnus Hagander (#17)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 11 April 2017 at 09:05, Magnus Hagander <magnus@hagander.net> wrote:

On Tue, Apr 11, 2017 at 3:26 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:

On Mon, Apr 10, 2017 at 5:47 PM, Magnus Hagander <magnus@hagander.net>
wrote:

Based on that we seem to agree here, should we add this as an open item?
Clearly if we want to change this, we should do so before 10.

This really is a new feature, so as the focus is to stabilize things I
think that we should not make the code more complicated because...

The part I'm talking about is the potential adjustment of the patch that's
already committed. That's not a new feature, that's exactly the sort of
thing we'd want to adjust before we get to release. Because once released we
really can't change it.

I agree if we introduce target_session_attrs it would be better to
have a complete feature in one release.

It does seem quite strange to have
target_session_attrs=read-write
but not
target_session_attrs=read-only

And it would be even better to have these session attrs as well
notify-on-promote - sent when standby is promoted
notify-on-write - sent when an xid is assigned

"notify-on-promotion" being my suggested name for the feature being
discussed here. In terms of the feature as submitted, I wonder whether
having a GUC parameter like this makes sense, but I think its ok for
us to send a protocol message, maybe a NotificationResponse, but there
isn't any material difference between those two protocol messages.

Rather than the special case code in the patch, I imagine more generic
code like this...

if (sessionInterruptPending)
ProcessSessionInterrupt();

I'm happy to work on the patch, if that's OK.

--
Simon Riggs http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Magnus Hagander
magnus@hagander.net
In reply to: Simon Riggs (#18)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Tue, Apr 11, 2017 at 2:38 PM, Simon Riggs <simon@2ndquadrant.com> wrote:

On 11 April 2017 at 09:05, Magnus Hagander <magnus@hagander.net> wrote:

On Tue, Apr 11, 2017 at 3:26 AM, Michael Paquier <

michael.paquier@gmail.com>

wrote:

On Mon, Apr 10, 2017 at 5:47 PM, Magnus Hagander <magnus@hagander.net>
wrote:

Based on that we seem to agree here, should we add this as an open

item?

Clearly if we want to change this, we should do so before 10.

This really is a new feature, so as the focus is to stabilize things I
think that we should not make the code more complicated because...

The part I'm talking about is the potential adjustment of the patch

that's

already committed. That's not a new feature, that's exactly the sort of
thing we'd want to adjust before we get to release. Because once

released we

really can't change it.

I agree if we introduce target_session_attrs it would be better to
have a complete feature in one release.

It does seem quite strange to have
target_session_attrs=read-write
but not
target_session_attrs=read-only

And it would be even better to have these session attrs as well
notify-on-promote - sent when standby is promoted
notify-on-write - sent when an xid is assigned

Well, one of those could come automatically with a GUC_REPORT variable of
the correct type, no? So if we were to use the transaction_read_only one,
you'd get a notification on promotion because your transaction became
read/write, wouldn't it?

"notify-on-promotion" being my suggested name for the feature being
discussed here. In terms of the feature as submitted, I wonder whether
having a GUC parameter like this makes sense, but I think its ok for
us to send a protocol message, maybe a NotificationResponse, but there
isn't any material difference between those two protocol messages.

Rather than the special case code in the patch, I imagine more generic
code like this...

if (sessionInterruptPending)
ProcessSessionInterrupt();

I'm happy to work on the patch, if that's OK.

I think going through all those steps is moving the goalposts a bit too far
for the 10 release.

But if adjustment to the already applied patch is needed to make sure we
can improve on it to get to this point in 11, that's more on topic I think.

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#20Robert Haas
robertmhaas@gmail.com
In reply to: Magnus Hagander (#17)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Tue, Apr 11, 2017 at 4:05 AM, Magnus Hagander <magnus@hagander.net> wrote:

On Tue, Apr 11, 2017 at 3:26 AM, Michael Paquier <michael.paquier@gmail.com> wrote:

On Mon, Apr 10, 2017 at 5:47 PM, Magnus Hagander <magnus@hagander.net>
wrote:

Based on that we seem to agree here, should we add this as an open item?
Clearly if we want to change this, we should do so before 10.

This really is a new feature, so as the focus is to stabilize things I
think that we should not make the code more complicated because...

The part I'm talking about is the potential adjustment of the patch that's
already committed. That's not a new feature, that's exactly the sort of
thing we'd want to adjust before we get to release. Because once released we
really can't change it.

I don't really agree. I think if we go and install a GUC_REPORT GUC
now, we're much less likely to flush out the bugs in the 'show
transaction_read_only' mechanism. Also, now that I think about, the
reason why we settled on 'show transaction_read_only' against
alternate queries is because there's some ability for the DBA to make
that return 'false' rather than 'true' even when not in recovery, so
that if for example you are using logical replication rather than
physical replication, you have a way to make
target_session_attrs=read-write still do something useful. If you add
an in_hot_standby GUC that's used instead, you lose that.

Now, we can decide what we want to do about that, but I don't see that
a change in this area *must* go into v10. Maybe the answer is that
target_session_attrs grows additional values like 'primary' and
'standby' alongside 'read-write' (and Simon's suggested 'read-only').
Or maybe we have another idea. But I don't really see the urgency of
whacking this around right this minute. There's nothing broken here;
there's just more stuff people would like to have. It can be added
next time around.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Magnus Hagander
magnus@hagander.net
In reply to: Robert Haas (#20)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, Apr 12, 2017 at 2:36 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 11, 2017 at 4:05 AM, Magnus Hagander <magnus@hagander.net>
wrote:

On Tue, Apr 11, 2017 at 3:26 AM, Michael Paquier <

michael.paquier@gmail.com> wrote:

On Mon, Apr 10, 2017 at 5:47 PM, Magnus Hagander <magnus@hagander.net>
wrote:

Based on that we seem to agree here, should we add this as an open

item?

Clearly if we want to change this, we should do so before 10.

This really is a new feature, so as the focus is to stabilize things I
think that we should not make the code more complicated because...

The part I'm talking about is the potential adjustment of the patch

that's

already committed. That's not a new feature, that's exactly the sort of
thing we'd want to adjust before we get to release. Because once

released we

really can't change it.

I don't really agree. I think if we go and install a GUC_REPORT GUC
now, we're much less likely to flush out the bugs in the 'show
transaction_read_only' mechanism. Also, now that I think about, the
reason why we settled on 'show transaction_read_only' against
alternate queries is because there's some ability for the DBA to make
that return 'false' rather than 'true' even when not in recovery, so
that if for example you are using logical replication rather than
physical replication, you have a way to make
target_session_attrs=read-write still do something useful. If you add
an in_hot_standby GUC that's used instead, you lose that.

Now, we can decide what we want to do about that, but I don't see that
a change in this area *must* go into v10. Maybe the answer is that
target_session_attrs grows additional values like 'primary' and
'standby' alongside 'read-write' (and Simon's suggested 'read-only').
Or maybe we have another idea. But I don't really see the urgency of
whacking this around right this minute. There's nothing broken here;
there's just more stuff people would like to have. It can be added
next time around.

Fair enough, sounds reasonable. I wasn't engaged in the original thread, so
you clearly have thought about this more than I have. I just wanted to make
sure we're not creating something that's going to cause a head-ache for
such a feature in the future.

(And this is why I was specifically asking you if you wanted it on the open
items list or not!)

--
Magnus Hagander
Me: https://www.hagander.net/ <http://www.hagander.net/&gt;
Work: https://www.redpill-linpro.com/ <http://www.redpill-linpro.com/&gt;

#22Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Robert Haas (#20)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

Hello,

I didn't realize that my target_session_attrs naming proposal was committed. I didn't think half way it would be adopted, because the name is less intuitive than the original target_server_type, and is different from the PgJDBC's targetServerType.

From: pgsql-hackers-owner@postgresql.org

[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Simon Riggs
I agree if we introduce target_session_attrs it would be better to have
a complete feature in one release.

It does seem quite strange to have
target_session_attrs=read-write
but not
target_session_attrs=read-only

I totally agree. I'm a bit disappointed with and worried about the current situation. I could easily imagine that people around me would say a stern opinion on the specification...

I think these are necessary in descending order of priority, if based on target_session_attrs:

[PG10]
1. target_session_attrs=read-only
This is mainly to connect to the standby. People will naturally expect that this is available, because PostgreSQL provides hot standby feature, and other DBMSs and even PgJDBC has the functionality.

2. Make transaction_read_only GUC_REPORT
This is to avoid the added round-trip by SHOW command. It also benefits client apps that want to know when the server gets promoted? And this may simplify the libpq code.
I don't understand yet why we need to provide this feature for older servers by using SHOW. Those who are already using <= 9.6 in production completed the system or application, and their business is running. Why would they want to just replace libpq and use this feature?

[PG 11]
3. target_session_attrs=prefer-read-only
This is mainly to prefer standbys, but allows to connect to the primary if no standby is available. Honestly, this is also required in PG 10 because PgJDBC already provides this by "preferSlave".

From: pgsql-hackers-owner@postgresql.org

[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Robert Haas
On Tue, Apr 11, 2017 at 4:05 AM, Magnus Hagander <magnus@hagander.net>
wrote:

The part I'm talking about is the potential adjustment of the patch
that's already committed. That's not a new feature, that's exactly the
sort of thing we'd want to adjust before we get to release. Because
once released we really can't change it.

I don't really agree. I think if we go and install a GUC_REPORT GUC now,
we're much less likely to flush out the bugs in the 'show
transaction_read_only' mechanism.

I'm sorry I couldn't get this part (maybe purely English nuance. Are you concerned about some bugs? We can't do anything if we fear of bugs. Is it OK instead to make transaction_read_only GUC_REPORT?

Also, now that I think about, the reason
why we settled on 'show transaction_read_only' against alternate queries
is because there's some ability for the DBA to make that return 'false'
rather than 'true' even when not in recovery, so that if for example you
are using logical replication rather than physical replication, you have
a way to make target_session_attrs=read-write still do something useful.
If you add an in_hot_standby GUC that's used instead, you lose that.

Agreed. Again, is this satisfied by GUC_REPORTing transaction_read_only as well?

Now, we can decide what we want to do about that, but I don't see that a
change in this area *must* go into v10. Maybe the answer is that
target_session_attrs grows additional values like 'primary' and 'standby'
alongside 'read-write' (and Simon's suggested 'read-only').
Or maybe we have another idea. But I don't really see the urgency of
whacking this around right this minute. There's nothing broken here;
there's just more stuff people would like to have. It can be added next
time around.

But if completeness of the functionality is below people's expectations, it may unnecessarily compromise the reputation of PostgreSQL.

Is there any chance to incorporate a patch into PG 10? May I add this as a PG 10 open item?

Regards
Takayuki Tsunakawa

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Craig Ringer
craig@2ndquadrant.com
In reply to: Tsunakawa, Takayuki (#22)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 13 April 2017 at 14:59, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:

2. Make transaction_read_only GUC_REPORT
This is to avoid the added round-trip by SHOW command. It also benefits client apps that want to know when the server gets promoted? And this may simplify the libpq code.
I don't understand yet why we need to provide this feature for older servers by using SHOW. Those who are already using <= 9.6 in production completed the system or application, and their business is running. Why would they want to just replace libpq and use this feature?

I think "transaction_read_only" is a bit confusing for something we're
expecting to change under us.

To me, a "read only" xact is one created with

BEGIN READ ONLY TRANSACTION;

.... which I would not expect to become read/write under me, since I
explicitly asked for read-only.

It's more like "session read only" that we're interested in IMO.

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#24Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Craig Ringer (#23)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

From: pgsql-hackers-owner@postgresql.org

[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Craig Ringer
On 13 April 2017 at 14:59, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:

2. Make transaction_read_only GUC_REPORT This is to avoid the added
round-trip by SHOW command. It also benefits client apps that want to

know when the server gets promoted? And this may simplify the libpq code.

I don't understand yet why we need to provide this feature for older servers

by using SHOW. Those who are already using <= 9.6 in production completed
the system or application, and their business is running. Why would they
want to just replace libpq and use this feature?

I think "transaction_read_only" is a bit confusing for something we're
expecting to change under us.

To me, a "read only" xact is one created with

BEGIN READ ONLY TRANSACTION;

.... which I would not expect to become read/write under me, since I
explicitly asked for read-only.

It's more like "session read only" that we're interested in IMO.

Are you suggest thating we provide a GUC_REPORT read-only variable "session_read_only" and the libpq should use it?

Anyway, I added this item in the PostgreSQL 10 Open Items page under
"Design Decisions to Recheck Mid-Beta". I'm willing to submit a patch for PG10.

Regards
Takayuki Tsunakawa

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#25Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Craig Ringer (#23)
1 attachment(s)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

From: pgsql-hackers-owner@postgresql.org

[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Craig Ringer
On 13 April 2017 at 14:59, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:

2. Make transaction_read_only GUC_REPORT This is to avoid the added
round-trip by SHOW command. It also benefits client apps that want to

know when the server gets promoted? And this may simplify the libpq code.

I don't understand yet why we need to provide this feature for older servers

by using SHOW. Those who are already using <= 9.6 in production completed
the system or application, and their business is running. Why would they
want to just replace libpq and use this feature?

I think "transaction_read_only" is a bit confusing for something we're
expecting to change under us.

To me, a "read only" xact is one created with

BEGIN READ ONLY TRANSACTION;

.... which I would not expect to become read/write under me, since I
explicitly asked for read-only.

It's more like "session read only" that we're interested in IMO.

I confirmed that the attached patch successfully provides:

* target_session_attrs=read-only
* If the server is >= 10, avoid the round-trip for SHOW transaction_read_only.

For this, I added a GUC_REPORT variable session_read_only which indicates the session's default read-only status. The characteristics are:

* It cannot be changed directly by the user (postgresql.conf, SET, etc.)
* Its value is the same as default_transaction_read_only when not in recovery.
* Its value is false during recovery.

Could you include this in PG 10? I think these are necessary as the bottom line to meet the average expectation of users (please don't ask me what's the average; the main reasons are that PostgreSQL provides hot standby, PgJDBC enables connection to the standby (targetServerType=slave), and PostgreSQL emphasizes performance.) Ideally, I wanted to add other features of PgJDBC (e.g. targetServerType=preferSlave), but I thought this is the limit not to endanger the quality of the final release.

Regards
Takayuki Tsunakawa

Attachments:

libpq-fast-connect-read-only.patchapplication/octet-stream; name=libpq-fast-connect-read-only.patchDownload
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 493cc12..b359333 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1425,10 +1425,14 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
        <para>
         If this parameter is set to <literal>read-write</literal>, only a
         connection in which read-write transactions are accepted by default
+        is considered acceptable.
+        If this parameter is set to <literal>read-only</literal>, only a
+        connection in which read-write transactions are rejected by default
         is considered acceptable.  The query
         <literal>SHOW transaction_read_only</literal> will be sent upon any
-        successful connection; if it returns <literal>on</>, the connection
-        will be closed.  If multiple hosts were specified in the connection
+        successful connection if the server is prior to version 10.
+        If the session attribute does not match the requested one, the connection will be closed.
+        If multiple hosts were specified in the connection
         string, any remaining servers will be tried just as if the connection
         attempt had failed.  The default value of this parameter,
         <literal>any</>, regards all connections as acceptable.
@@ -1709,6 +1713,7 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
        <varname>application_name</>,
        <varname>is_superuser</>,
        <varname>session_authorization</>,
+       <varname>session_read_only</>,
        <varname>DateStyle</>,
        <varname>IntervalStyle</>,
        <varname>TimeZone</>,
@@ -1719,7 +1724,8 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
        <varname>standard_conforming_strings</> was not reported by releases
        before 8.1;
        <varname>IntervalStyle</> was not reported by releases before 8.4;
-       <varname>application_name</> was not reported by releases before 9.0.)
+       <varname>application_name</> was not reported by releases before 9.0;
+       <varname>session_read_only</> was not reported by releases before 10.0.)
        Note that
        <varname>server_version</>,
        <varname>server_encoding</> and
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index d23df02..291d564 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1136,6 +1136,7 @@
     <varname>application_name</>,
     <varname>is_superuser</>,
     <varname>session_authorization</>,
+    <varname>session_read_only</>,
     <varname>DateStyle</>,
     <varname>IntervalStyle</>,
     <varname>TimeZone</>,
@@ -1146,7 +1147,8 @@
     <varname>standard_conforming_strings</> was not reported by releases
     before 8.1;
     <varname>IntervalStyle</> was not reported by releases before 8.4;
-    <varname>application_name</> was not reported by releases before 9.0.)
+    <varname>application_name</> was not reported by releases before 9.0;
+    <varname>session_read_only</> was not reported by releases before 10.0.)
     Note that
     <varname>server_version</>,
     <varname>server_encoding</> and
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 399822d..bf0bae8 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7904,6 +7904,10 @@ RecoveryInProgress(void)
 			 */
 			pg_memory_barrier();
 			InitXLOGAccess();
+
+			/* Update session read-only status. */
+			SetConfigOption("session_read_only", DefaultXactReadOnly,
+							PGC_INTERNAL, PGC_S_OVERRIDE);
 		}
 
 		/*
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 75c2d9a..8933f4f 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -3722,6 +3722,14 @@ PostgresMain(int argc, char *argv[],
 	InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
 
 	/*
+	 * Update session read-only status if in recovery.
+	 */
+	if (IsUnderPostmaster && !DefaultXactReadOnly &&
+		RecoveryInProgress())
+		SetConfigOption("session_read_only", "on",
+						PGC_INTERNAL, PGC_S_OVERRIDE);
+
+	/*
 	 * If the PostmasterContext is still around, recycle the space; we don't
 	 * need it anymore after InitPostgres completes.  Note this does not trash
 	 * *MyProcPort, because ConnCreate() allocated that space with malloc()
diff --git a/src/backend/utils/misc/check_guc b/src/backend/utils/misc/check_guc
index d228bbe..da96df2 100755
--- a/src/backend/utils/misc/check_guc
+++ b/src/backend/utils/misc/check_guc
@@ -21,7 +21,7 @@ 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"
+zero_damaged_pages session_read_only"
 
 ### 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 92e1d63..2aff993 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -147,6 +147,8 @@ static bool call_string_check_hook(struct config_string * conf, char **newval,
 static bool call_enum_check_hook(struct config_enum * conf, int *newval,
 					 void **extra, GucSource source, int elevel);
 
+static void assign_default_transaction_read_only(bool newval, void *extra);
+
 static bool check_log_destination(char **newval, void **extra, GucSource source);
 static void assign_log_destination(const char *newval, void *extra);
 
@@ -493,6 +495,7 @@ int			huge_pages;
  */
 static char *syslog_ident_str;
 static bool session_auth_is_superuser;
+static bool session_read_only;
 static double phony_random_seed;
 static char *client_encoding_string;
 static char *datestyle_string;
@@ -933,6 +936,16 @@ static struct config_bool ConfigureNamesBool[] =
 		NULL, NULL, NULL
 	},
 	{
+		{"session_read_only", PGC_INTERNAL, UNGROUPED,
+			gettext_noop("Shows whether the session is read-only by default."),
+			NULL,
+			GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&session_read_only,
+		false,
+		NULL, NULL, NULL
+	},
+	{
 		{"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
 			gettext_noop("Enables advertising the server via Bonjour."),
 			NULL
@@ -1366,7 +1379,7 @@ static struct config_bool ConfigureNamesBool[] =
 		},
 		&DefaultXactReadOnly,
 		false,
-		NULL, NULL, NULL
+		NULL, assign_default_transaction_read_only, NULL
 	},
 	{
 		{"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -10038,6 +10051,30 @@ assign_wal_consistency_checking(const char *newval, void *extra)
 	wal_consistency_checking = (bool *) extra;
 }
 
+static void
+assign_default_transaction_read_only(bool newval, void *extra)
+{
+	if (newval == DefaultXactReadOnly)
+		return;
+
+	/*
+	 * We clamp manually-set values to at least 1MB.  Since
+	 * Also set the session read-only parameter.  We only need
+	 * to set the correct value in processes that have database
+	 * sessions, but there's no mechanism to know that there's
+	 * a session.  Instead, we use the shared memory segment
+	 * pointer because the processes with database sessions are
+	 * attached to the shared memory.  Without this check,
+	 * RecoveryInProgress() would crash the processes which
+	 * are not attached to the shared memory.
+	 */
+	if (IsUnderPostmaster && UsedShmemSegAddr != NULL &&
+		RecoveryInProgress())
+		newval = true;
+	SetConfigOption("session_read_only", newval ? "on" : "off",
+					PGC_INTERNAL, PGC_S_OVERRIDE);
+}
+
 static bool
 check_log_destination(char **newval, void **extra, GucSource source)
 {
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index f2c9bf7..e63e16b 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1066,7 +1066,8 @@ connectOptions2(PGconn *conn)
 	if (conn->target_session_attrs)
 	{
 		if (strcmp(conn->target_session_attrs, "any") != 0
-			&& strcmp(conn->target_session_attrs, "read-write") != 0)
+			&& strcmp(conn->target_session_attrs, "read-write") != 0
+			&& strcmp(conn->target_session_attrs, "read-only") != 0)
 		{
 			conn->status = CONNECTION_BAD;
 			printfPQExpBuffer(&conn->errorMessage,
@@ -2848,10 +2849,12 @@ keep_going:						/* We will come back to here until there is
 				}
 
 				/*
-				 * If a read-write connection is required, see if we have one.
+				 * If a specific type of connection is required, see if we have one.
 				 */
-				if (conn->target_session_attrs != NULL &&
-					strcmp(conn->target_session_attrs, "read-write") == 0)
+				/* If the server version is before 10.0, issue an SQL query. */
+				if (conn->sversion < 100000 &&
+					conn->target_session_attrs != NULL &&
+					strcmp(conn->target_session_attrs, "any") != 0)
 				{
 					/*
 					 * We are yet to make a connection. Save all existing
@@ -2876,6 +2879,34 @@ keep_going:						/* We will come back to here until there is
 					return PGRES_POLLING_READING;
 				}
 
+				/* Otherwise, check parameter status sent by backend to avoid round-trip for a query. */
+				if (conn->target_session_attrs != NULL &&
+					((strcmp(conn->target_session_attrs, "read-write") == 0 && !conn->session_read_only) ||
+					 (strcmp(conn->target_session_attrs, "read-only") == 0 && conn->session_read_only)))
+				{
+					/* Not suitable; close connection. */
+					appendPQExpBuffer(&conn->errorMessage,
+									  libpq_gettext("could not make a suitable "
+													"connection to server "
+													"\"%s:%s\"\n"),
+									  conn->connhost[conn->whichhost].host,
+									  conn->connhost[conn->whichhost].port);
+					conn->status = CONNECTION_OK;
+					sendTerminateConn(conn);
+					pqDropConnection(conn, true);
+
+					/* Skip any remaining addresses for this host. */
+					conn->addr_cur = NULL;
+					if (conn->whichhost + 1 < conn->nconnhost)
+					{
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+
+					/* No more addresses to try. So we fail. */
+					goto error_return;
+				}
+
 				/* We can release the address lists now. */
 				release_all_addrinfo(conn);
 
@@ -2912,10 +2943,10 @@ keep_going:						/* We will come back to here until there is
 			}
 
 			/*
-			 * If a read-write connection is requested check for same.
+			 * If a specific type of connection is required, see if we have one.
 			 */
 			if (conn->target_session_attrs != NULL &&
-				strcmp(conn->target_session_attrs, "read-write") == 0)
+				strcmp(conn->target_session_attrs, "any") != 0)
 			{
 				if (!saveErrorMessage(conn, &savedMessage))
 					goto error_return;
@@ -2991,16 +3022,29 @@ keep_going:						/* We will come back to here until there is
 					PQntuples(res) == 1)
 				{
 					char	   *val;
+					char	   *expected_val;
+					int			expected_len;
+
+					if (strcmp(conn->target_session_attrs, "read-write") == 0)
+					{
+						expected_val = "on";
+						expected_len = 2;
+					}
+					else
+					{
+						expected_val = "off";
+						expected_len = 3;
+					}
 
 					val = PQgetvalue(res, 0, 0);
-					if (strncmp(val, "on", 2) == 0)
+					if (strncmp(val, expected_val, expected_len) == 0)
 					{
 						PQclear(res);
 						restoreErrorMessage(conn, &savedMessage);
 
-						/* Not writable; close connection. */
+						/* Not suitable; close connection. */
 						appendPQExpBuffer(&conn->errorMessage,
-								   libpq_gettext("could not make a writable "
+								   libpq_gettext("could not make a suitable "
 												 "connection to server "
 												 "\"%s:%s\"\n"),
 										conn->connhost[conn->whichhost].host,
@@ -3200,6 +3244,7 @@ makeEmptyPGconn(void)
 	conn->setenv_state = SETENV_STATE_IDLE;
 	conn->client_encoding = PG_SQL_ASCII;
 	conn->std_strings = false;	/* unless server says differently */
+	conn->session_read_only = false;	/* unless server says differently */
 	conn->verbosity = PQERRORS_DEFAULT;
 	conn->show_context = PQSHOW_CONTEXT_ERRORS;
 	conn->sock = PGINVALID_SOCKET;
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index 9decd53..9b034aa 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -956,8 +956,8 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
 	}
 
 	/*
-	 * Special hacks: remember client_encoding and
-	 * standard_conforming_strings, and convert server version to a numeric
+	 * Special hacks: remember client_encoding/
+	 * standard_conforming_strings/session_read_only, and convert server version to a numeric
 	 * form.  We keep the first two of these in static variables as well, so
 	 * that PQescapeString and PQescapeBytea can behave somewhat sanely (at
 	 * least in single-connection-using programs).
@@ -975,6 +975,8 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
 		conn->std_strings = (strcmp(value, "on") == 0);
 		static_std_strings = conn->std_strings;
 	}
+	else if (strcmp(name, "session_read_only") == 0)
+		conn->session_read_only = (strcmp(value, "on") == 0);
 	else if (strcmp(name, "server_version") == 0)
 	{
 		int			cnt;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 335568b..2430982 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -360,7 +360,7 @@ struct pg_conn
 	char	   *krbsrvname;		/* Kerberos service name */
 #endif
 
-	/* Type of connection to make.  Possible values: any, read-write. */
+	/* Type of connection to make.  Possible values: any, read-write, read-only. */
 	char	   *target_session_attrs;
 
 	/* Optional file to write trace info to */
@@ -422,6 +422,7 @@ struct pg_conn
 	pgParameterStatus *pstatus; /* ParameterStatus data */
 	int			client_encoding;	/* encoding id */
 	bool		std_strings;	/* standard_conforming_strings */
+	bool		session_read_only;	/* session_read_only */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
 	PGlobjfuncs *lobjfuncs;		/* private state for large-object access fns */
#26Robert Haas
robertmhaas@gmail.com
In reply to: Tsunakawa, Takayuki (#25)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, May 24, 2017 at 3:16 AM, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:

I confirmed that the attached patch successfully provides:

* target_session_attrs=read-only
* If the server is >= 10, avoid the round-trip for SHOW transaction_read_only.

For this, I added a GUC_REPORT variable session_read_only which indicates the session's default read-only status. The characteristics are:

* It cannot be changed directly by the user (postgresql.conf, SET, etc.)
* Its value is the same as default_transaction_read_only when not in recovery.
* Its value is false during recovery.

Could you include this in PG 10? I think these are necessary as the bottom line to meet the average expectation of users (please don't ask me what's the average; the main reasons are that PostgreSQL provides hot standby, PgJDBC enables connection to the standby (targetServerType=slave), and PostgreSQL emphasizes performance.) Ideally, I wanted to add other features of PgJDBC (e.g. targetServerType=preferSlave), but I thought this is the limit not to endanger the quality of the final release.

I've already stated my position on this, which is that:

* target_session_attrs=read-only is a perfectly good new feature, but
we're past feature freeze, so it's material for v11.

* I'm not opposed to adding a GUC_REPORT GUC of some kind, but I see
no urgency about that either. The feature works fine as it is. The
fact that it could possibly be made to work more efficiently is not a
critical bug.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#27Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Haas (#26)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

Robert Haas <robertmhaas@gmail.com> writes:

On Wed, May 24, 2017 at 3:16 AM, Tsunakawa, Takayuki
<tsunakawa.takay@jp.fujitsu.com> wrote:

For this, I added a GUC_REPORT variable session_read_only which indicates the session's default read-only status. The characteristics are:

* It cannot be changed directly by the user (postgresql.conf, SET, etc.)
* Its value is the same as default_transaction_read_only when not in recovery.

I didn't look at exactly how you tried to do that, but GUCs whose values
depend on other GUCs generally don't work well at all.

* Its value is false during recovery.

[ scratches head... ] Surely this should read as "true" during recovery?
Also, what happens if the standby server goes live mid-session?

Could you include this in PG 10?

I concur with Robert that this is too late for v10, and the argument to
shove it in anyway is not compelling.

regards, tom lane

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#28Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Robert Haas (#26)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

From: Robert Haas [mailto:robertmhaas@gmail.com]

I've already stated my position on this, which is that:

* target_session_attrs=read-only is a perfectly good new feature, but we're
past feature freeze, so it's material for v11.

* I'm not opposed to adding a GUC_REPORT GUC of some kind, but I see no
urgency about that either. The feature works fine as it is. The fact that
it could possibly be made to work more efficiently is not a critical bug.

I see. I'll add this in the next CF for PG 11. I'd be glad if you could review the patch in PG 11 development. Also, I'll update the PostgreSQL 10 Open Items page that way.

Regards
Takayuki Tsunakawa

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#29Tsunakawa, Takayuki
tsunakawa.takay@jp.fujitsu.com
In reply to: Tom Lane (#27)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

From: pgsql-hackers-owner@postgresql.org

[mailto:pgsql-hackers-owner@postgresql.org] On Behalf Of Tom Lane
I didn't look at exactly how you tried to do that, but GUCs whose values
depend on other GUCs generally don't work well at all.

transaction_read_only and transaction_isolation depends on default_transaction_read_only and default_transaction_isolation respectively. But I feel you are concerned about something I'm not aware of. Could you share your worries? I haven't found a problem so far.

* Its value is false during recovery.

[ scratches head... ] Surely this should read as "true" during recovery?

Ouch, you are right.

Also, what happens if the standby server goes live mid-session?

The clients will know the change of session_read_only when they do something that calls RecoveryInProgress(). Currently, RecoveryInProgress() seems to be the only place where the sessions notice the promotion, so I set session_read_only to the value of default_transaction_read_only there. I think that there is room for discussion here. It would be ideal for the sessions to notice the server promotion promptly and notify the clients of the change. I have no idea to do that well.

Regards
Takayuki Tsunakawa

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#30Michael Banck
michael.banck@credativ.de
In reply to: Tsunakawa, Takayuki (#25)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

Hi,

On Wed, May 24, 2017 at 07:16:06AM +0000, Tsunakawa, Takayuki wrote:

I confirmed that the attached patch successfully provides:

I was going to take a look at this, but the patch no longer applies
cleanly for me:

Hunk #1 succeeded at 1474 (offset 49 lines).
Hunk #2 succeeded at 1762 (offset 49 lines).
Hunk #3 succeeded at 1773 (offset 49 lines).
patching file doc/src/sgml/protocol.sgml
patching file src/backend/access/transam/xlog.c
Hunk #1 succeeded at 7909 (offset 5 lines).
patching file src/backend/tcop/postgres.c
Hunk #1 succeeded at 3737 (offset 15 lines).
patching file src/backend/utils/misc/check_guc
patching file src/backend/utils/misc/guc.c
Hunk #1 succeeded at 147 with fuzz 1.
Hunk #5 succeeded at 10062 (offset 11 lines).
patching file src/interfaces/libpq/fe-connect.c
Hunk #1 succeeded at 1178 (offset 112 lines).
Hunk #2 succeeded at 2973 (offset 124 lines).
Hunk #3 succeeded at 3003 (offset 124 lines).
Hunk #4 succeeded at 3067 (offset 124 lines).
Hunk #5 FAILED at 3022.
Hunk #6 succeeded at 3375 (offset 144 lines).
1 out of 6 hunks FAILED -- saving rejects to file
src/interfaces/libpq/fe-connect.c.rej
patching file src/interfaces/libpq/fe-exec.c
patching file src/interfaces/libpq/libpq-int.h
Hunk #1 succeeded at 361 (offset 1 line).
Hunk #2 succeeded at 421 (offset -1 lines).

Can you rebase it, please?

Best

Michael

--
Michael Banck
Projektleiter / Senior Berater
Tel.: +49 2166 9901-171
Fax: +49 2166 9901-100
Email: michael.banck@credativ.de

credativ GmbH, HRB M�nchengladbach 12080
USt-ID-Nummer: DE204566209
Trompeterallee 108, 41189 M�nchengladbach
Gesch�ftsf�hrung: Dr. Michael Meskes, J�rg Folz, Sascha Heuer

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#31Elvis Pranskevichus
elprans@gmail.com
In reply to: Tsunakawa, Takayuki (#29)
1 attachment(s)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wednesday, May 24, 2017 9:38:36 PM EDT Tsunakawa, Takayuki wrote:

The clients will know the change of session_read_only when they do
something that calls RecoveryInProgress(). Currently,
RecoveryInProgress() seems to be the only place where the sessions
notice the promotion, so I set session_read_only to the value of
default_transaction_read_only there. I think that there is room for
discussion here. It would be ideal for the sessions to notice the
server promotion promptly and notify the clients of the change. I
have no idea to do that well.

My original patch did that via the new SendSignalToAllBackends() helper,
which is called whenever the postmaster exits hot stanby.

I incorporated those bits into your patch and rebased in onto master.
Please see attached.

FWIW, I think that mixing the standby status and the default
transaction writability is suboptimal. They are related, yes, but not
the same thing. It is possible to have a master cluster in the
read-only mode, and with this patch it would be impossible to
distinguish from a hot-standby replica without also polling
pg_is_in_recovery(), which defeats the purpose of having to do no
database roundtrips.

Elvis

Attachments:

session-read-only.patchtext/x-patch; charset=UTF-8; name=session-read-only.patchDownload
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 096a8be605..4d74740699 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1474,10 +1474,14 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
        <para>
         If this parameter is set to <literal>read-write</literal>, only a
         connection in which read-write transactions are accepted by default
+        is considered acceptable.
+        If this parameter is set to <literal>read-only</literal>, only a
+        connection in which read-write transactions are rejected by default
         is considered acceptable.  The query
         <literal>SHOW transaction_read_only</literal> will be sent upon any
-        successful connection; if it returns <literal>on</>, the connection
-        will be closed.  If multiple hosts were specified in the connection
+        successful connection if the server is prior to version 10.
+        If the session attribute does not match the requested one, the connection will be closed.
+        If multiple hosts were specified in the connection
         string, any remaining servers will be tried just as if the connection
         attempt had failed.  The default value of this parameter,
         <literal>any</>, regards all connections as acceptable.
@@ -1758,6 +1762,7 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
        <varname>application_name</>,
        <varname>is_superuser</>,
        <varname>session_authorization</>,
+       <varname>session_read_only</>,
        <varname>DateStyle</>,
        <varname>IntervalStyle</>,
        <varname>TimeZone</>,
@@ -1768,7 +1773,8 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
        <varname>standard_conforming_strings</> was not reported by releases
        before 8.1;
        <varname>IntervalStyle</> was not reported by releases before 8.4;
-       <varname>application_name</> was not reported by releases before 9.0.)
+       <varname>application_name</> was not reported by releases before 9.0;
+       <varname>session_read_only</> was not reported by releases before 10.0.)
        Note that
        <varname>server_version</>,
        <varname>server_encoding</> and
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 76d1c13cc4..e2a1cd1c03 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1255,6 +1255,7 @@ SELCT 1/0;
     <varname>application_name</>,
     <varname>is_superuser</>,
     <varname>session_authorization</>,
+    <varname>session_read_only</>,
     <varname>DateStyle</>,
     <varname>IntervalStyle</>,
     <varname>TimeZone</>,
@@ -1265,7 +1266,8 @@ SELCT 1/0;
     <varname>standard_conforming_strings</> was not reported by releases
     before 8.1;
     <varname>IntervalStyle</> was not reported by releases before 8.4;
-    <varname>application_name</> was not reported by releases before 9.0.)
+    <varname>application_name</> was not reported by releases before 9.0;
+    <varname>session_read_only</> was not reported by releases before 10.0.)
     Note that
     <varname>server_version</>,
     <varname>server_encoding</> and
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 442341a707..e862d7e993 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7715,8 +7715,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)
@@ -7921,6 +7923,11 @@ RecoveryInProgress(void)
 			 */
 			pg_memory_barrier();
 			InitXLOGAccess();
+
+			/* Update session read-only status. */
+			SetConfigOption("session_read_only",
+							DefaultXactReadOnly ? "on" : "off",
+							PGC_INTERNAL, PGC_S_OVERRIDE);
 		}
 
 		/*
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index bacc08eb84..9b1646cf9b 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;
 
@@ -1733,6 +1735,53 @@ 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("session_read_only",
+					DefaultXactReadOnly ? "on" : "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
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index ffa6180eff..d4903b5528 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2953,6 +2953,36 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
 	return true;				/* timed out, still conflicts */
 }
 
+/*
+ * 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
  *
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index b9302ac630..9bc805fc7c 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -292,6 +292,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 d491ece60a..bd57fab328 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 4eb85720a7..590d42ffc4 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -526,9 +526,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)
 	{
@@ -3749,6 +3753,14 @@ PostgresMain(int argc, char *argv[],
 	 */
 	InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL);
 
+	/*
+	 * Update session read-only status if in recovery.
+	 */
+	if (IsUnderPostmaster && !DefaultXactReadOnly &&
+		RecoveryInProgress())
+		SetConfigOption("session_read_only", "on",
+						PGC_INTERNAL, PGC_S_OVERRIDE);
+
 	/*
 	 * If the PostmasterContext is still around, recycle the space; we don't
 	 * need it anymore after InitPostgres completes.  Note this does not trash
diff --git a/src/backend/utils/misc/check_guc b/src/backend/utils/misc/check_guc
index d228bbed68..da96df2298 100755
--- a/src/backend/utils/misc/check_guc
+++ b/src/backend/utils/misc/check_guc
@@ -21,7 +21,7 @@ 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"
+zero_damaged_pages session_read_only"
 
 ### 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 969e80f756..0ffa38f1ea 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -147,6 +147,8 @@ static bool call_string_check_hook(struct config_string *conf, char **newval,
 static bool call_enum_check_hook(struct config_enum *conf, int *newval,
 					 void **extra, GucSource source, int elevel);
 
+static void assign_default_transaction_read_only(bool newval, void *extra);
+
 static bool check_log_destination(char **newval, void **extra, GucSource source);
 static void assign_log_destination(const char *newval, void *extra);
 
@@ -493,6 +495,7 @@ int			huge_pages;
  */
 static char *syslog_ident_str;
 static bool session_auth_is_superuser;
+static bool session_read_only;
 static double phony_random_seed;
 static char *client_encoding_string;
 static char *datestyle_string;
@@ -932,6 +935,20 @@ static struct config_bool ConfigureNamesBool[] =
 		false,
 		NULL, NULL, NULL
 	},
+	{
+		/*
+		 * Not for general use --- used to indicate whether
+		 * the session is read-only by default.
+		 */
+		{"session_read_only", PGC_INTERNAL, UNGROUPED,
+			gettext_noop("Shows whether the session is read-only by default."),
+			NULL,
+			GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&session_read_only,
+		false,
+		NULL, NULL, NULL
+	},
 	{
 		{"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
 			gettext_noop("Enables advertising the server via Bonjour."),
@@ -1366,7 +1383,7 @@ static struct config_bool ConfigureNamesBool[] =
 		},
 		&DefaultXactReadOnly,
 		false,
-		NULL, NULL, NULL
+		NULL, assign_default_transaction_read_only, NULL
 	},
 	{
 		{"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -10049,6 +10066,30 @@ assign_wal_consistency_checking(const char *newval, void *extra)
 	wal_consistency_checking = (bool *) extra;
 }
 
+static void
+assign_default_transaction_read_only(bool newval, void *extra)
+{
+	if (newval == DefaultXactReadOnly)
+		return;
+
+	/*
+	 * We clamp manually-set values to at least 1MB.  Since
+	 * Also set the session read-only parameter.  We only need
+	 * to set the correct value in processes that have database
+	 * sessions, but there's no mechanism to know that there's
+	 * a session.  Instead, we use the shared memory segment
+	 * pointer because the processes with database sessions are
+	 * attached to the shared memory.  Without this check,
+	 * RecoveryInProgress() would crash the processes which
+	 * are not attached to the shared memory.
+	 */
+	if (IsUnderPostmaster && UsedShmemSegAddr != NULL &&
+		RecoveryInProgress())
+		newval = true;
+	SetConfigOption("session_read_only", newval ? "on" : "off",
+					PGC_INTERNAL, PGC_S_OVERRIDE);
+}
+
 static bool
 check_log_destination(char **newval, void **extra, GucSource source)
 {
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index 939711d8d9..7d62c59214 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 174c537be4..06ec4c7524 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -114,6 +114,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 20bb05b177..80d2af79dd 100644
--- a/src/include/storage/procsignal.h
+++ b/src/include/storage/procsignal.h
@@ -42,6 +42,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 f5404b4c1f..429eb61174 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);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index c580d91135..56c4482867 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1178,7 +1178,8 @@ connectOptions2(PGconn *conn)
 	if (conn->target_session_attrs)
 	{
 		if (strcmp(conn->target_session_attrs, "any") != 0
-			&& strcmp(conn->target_session_attrs, "read-write") != 0)
+			&& strcmp(conn->target_session_attrs, "read-write") != 0
+			&& strcmp(conn->target_session_attrs, "read-only") != 0)
 		{
 			conn->status = CONNECTION_BAD;
 			printfPQExpBuffer(&conn->errorMessage,
@@ -2972,10 +2973,12 @@ keep_going:						/* We will come back to here until there is
 				}
 
 				/*
-				 * If a read-write connection is required, see if we have one.
+				 * If a specific type of connection is required, see if we have one.
 				 */
-				if (conn->target_session_attrs != NULL &&
-					strcmp(conn->target_session_attrs, "read-write") == 0)
+				/* If the server version is before 10.0, issue an SQL query. */
+				if (conn->sversion < 100000 &&
+					conn->target_session_attrs != NULL &&
+					strcmp(conn->target_session_attrs, "any") != 0)
 				{
 					/*
 					 * We are yet to make a connection. Save all existing
@@ -3000,6 +3003,34 @@ keep_going:						/* We will come back to here until there is
 					return PGRES_POLLING_READING;
 				}
 
+				/* Otherwise, check parameter status sent by backend to avoid round-trip for a query. */
+				if (conn->target_session_attrs != NULL &&
+					((strcmp(conn->target_session_attrs, "read-write") == 0 && !conn->session_read_only) ||
+					 (strcmp(conn->target_session_attrs, "read-only") == 0 && conn->session_read_only)))
+				{
+					/* Not suitable; close connection. */
+					appendPQExpBuffer(&conn->errorMessage,
+									  libpq_gettext("could not make a suitable "
+													"connection to server "
+													"\"%s:%s\"\n"),
+									  conn->connhost[conn->whichhost].host,
+									  conn->connhost[conn->whichhost].port);
+					conn->status = CONNECTION_OK;
+					sendTerminateConn(conn);
+					pqDropConnection(conn, true);
+
+					/* Skip any remaining addresses for this host. */
+					conn->addr_cur = NULL;
+					if (conn->whichhost + 1 < conn->nconnhost)
+					{
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+
+					/* No more addresses to try. So we fail. */
+					goto error_return;
+				}
+
 				/* We can release the address lists now. */
 				release_all_addrinfo(conn);
 
@@ -3036,10 +3067,10 @@ keep_going:						/* We will come back to here until there is
 			}
 
 			/*
-			 * If a read-write connection is requested check for same.
+			 * If a specific type of connection is required, see if we have one.
 			 */
 			if (conn->target_session_attrs != NULL &&
-				strcmp(conn->target_session_attrs, "read-write") == 0)
+				strcmp(conn->target_session_attrs, "any") != 0)
 			{
 				if (!saveErrorMessage(conn, &savedMessage))
 					goto error_return;
@@ -3118,9 +3149,22 @@ keep_going:						/* We will come back to here until there is
 					PQntuples(res) == 1)
 				{
 					char	   *val;
+					char	   *expected_val;
+					int			expected_len;
+
+					if (strcmp(conn->target_session_attrs, "read-write") == 0)
+					{
+						expected_val = "on";
+						expected_len = 2;
+					}
+					else
+					{
+						expected_val = "off";
+						expected_len = 3;
+					}
 
 					val = PQgetvalue(res, 0, 0);
-					if (strncmp(val, "on", 2) == 0)
+					if (strncmp(val, expected_val, expected_len) == 0)
 					{
 						const char *displayed_host;
 						const char *displayed_port;
@@ -3136,9 +3180,9 @@ keep_going:						/* We will come back to here until there is
 						PQclear(res);
 						restoreErrorMessage(conn, &savedMessage);
 
-						/* Not writable; close connection. */
+						/* Not suitable; close connection. */
 						appendPQExpBuffer(&conn->errorMessage,
-										  libpq_gettext("could not make a writable "
+										  libpq_gettext("could not make a suiteable "
 														"connection to server "
 														"\"%s:%s\"\n"),
 										  displayed_host, displayed_port);
@@ -3344,6 +3388,7 @@ makeEmptyPGconn(void)
 	conn->setenv_state = SETENV_STATE_IDLE;
 	conn->client_encoding = PG_SQL_ASCII;
 	conn->std_strings = false;	/* unless server says differently */
+	conn->session_read_only = false;	/* unless server says differently */
 	conn->verbosity = PQERRORS_DEFAULT;
 	conn->show_context = PQSHOW_CONTEXT_ERRORS;
 	conn->sock = PGINVALID_SOCKET;
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index c24bce62dd..6d3e5705e5 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1007,8 +1007,8 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
 	}
 
 	/*
-	 * Special hacks: remember client_encoding and
-	 * standard_conforming_strings, and convert server version to a numeric
+	 * Special hacks: remember client_encoding/
+	 * standard_conforming_strings/session_read_only, and convert server version to a numeric
 	 * form.  We keep the first two of these in static variables as well, so
 	 * that PQescapeString and PQescapeBytea can behave somewhat sanely (at
 	 * least in single-connection-using programs).
@@ -1026,6 +1026,8 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
 		conn->std_strings = (strcmp(value, "on") == 0);
 		static_std_strings = conn->std_strings;
 	}
+	else if (strcmp(name, "session_read_only") == 0)
+		conn->session_read_only = (strcmp(value, "on") == 0);
 	else if (strcmp(name, "server_version") == 0)
 	{
 		int			cnt;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 42913604e3..b62cc9fab4 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -361,7 +361,7 @@ struct pg_conn
 	char	   *krbsrvname;		/* Kerberos service name */
 #endif
 
-	/* Type of connection to make.  Possible values: any, read-write. */
+	/* Type of connection to make.  Possible values: any, read-write, read-only. */
 	char	   *target_session_attrs;
 
 	/* Optional file to write trace info to */
@@ -421,6 +421,7 @@ struct pg_conn
 	pgParameterStatus *pstatus; /* ParameterStatus data */
 	int			client_encoding;	/* encoding id */
 	bool		std_strings;	/* standard_conforming_strings */
+	bool		session_read_only;	/* session_read_only */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
 	PGlobjfuncs *lobjfuncs;		/* private state for large-object access fns */
-- 
2.14.1

#32Thomas Munro
thomas.munro@enterprisedb.com
In reply to: Elvis Pranskevichus (#31)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Wed, Sep 13, 2017 at 3:48 AM, Elvis Pranskevichus <elprans@gmail.com> wrote:

I incorporated those bits into your patch and rebased in onto master.
Please see attached.

FWIW, I think that mixing the standby status and the default
transaction writability is suboptimal. They are related, yes, but not
the same thing. It is possible to have a master cluster in the
read-only mode, and with this patch it would be impossible to
distinguish from a hot-standby replica without also polling
pg_is_in_recovery(), which defeats the purpose of having to do no
database roundtrips.

Hi Elvis,

FYI the recovery test 001_stream_rep.pl fails with this patch applied.
You can see that if you configure with --enable-tap-tests, build and
then cd into src/test/recovery and "make check".

--
Thomas Munro
http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#33Melanie Plageman
melanieplageman@gmail.com
In reply to: Thomas Munro (#32)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Tue, Sep 12, 2017 at 6:11 PM, Thomas Munro <thomas.munro@enterprisedb.com

wrote:

On Wed, Sep 13, 2017 at 3:48 AM, Elvis Pranskevichus <elprans@gmail.com>
wrote:

I incorporated those bits into your patch and rebased in onto master.
Please see attached.

FWIW, I think that mixing the standby status and the default
transaction writability is suboptimal. They are related, yes, but not
the same thing. It is possible to have a master cluster in the
read-only mode, and with this patch it would be impossible to
distinguish from a hot-standby replica without also polling
pg_is_in_recovery(), which defeats the purpose of having to do no
database roundtrips.

Hi Elvis,

FYI the recovery test 001_stream_rep.pl fails with this patch applied.
You can see that if you configure with --enable-tap-tests, build and
then cd into src/test/recovery and "make check".

The latest patch applies cleanly and builds (I am also seeing the failing

TAP tests), however, I have a concern. With a single server set up, when I
attempt to make a connection with target_session_attrs=read-write, I get
the message
psql: could not make a suitable connection to server "localhost:5432"
Whereas, when I attempt to make a connection with
target_session_attrs=read-only, it is successful.

I might be missing something, but this seems somewhat counter-intuitive. I
would expect to specify read-write as target_session_attrs and successfully
connect to a server on which read and write operations are permitted. I see
this behavior implemented in src/interfaces/libpq/fe-connect.c
Is there a reason to reject a connection to a primary server when I specify
'read-write'? Is this intentional?

#34Melanie Plageman
melanieplageman@gmail.com
In reply to: Melanie Plageman (#33)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Tue, Sep 19, 2017 at 4:15 PM, Melanie Plageman <melanieplageman@gmail.com

wrote:

The latest patch applies cleanly and builds (I am also seeing the failing
TAP tests), however, I have a concern. With a single server set up, when I
attempt to make a connection with target_session_attrs=read-write, I get
the message
psql: could not make a suitable connection to server "localhost:5432"
Whereas, when I attempt to make a connection with
target_session_attrs=read-only, it is successful.

I might be missing something, but this seems somewhat counter-intuitive. I
would expect to specify read-write as target_session_attrs and successfully
connect to a server on which read and write operations are permitted. I see
this behavior implemented in src/interfaces/libpq/fe-connect.c
Is there a reason to reject a connection to a primary server when I
specify 'read-write'? Is this intentional?

Hi Elvis,

Making an assumption about the intended functionality mentioned above, I
swapped the 'not' to the following lines of
src/interfaces/libpq/fe-connect.c ~ line 3005

if (conn->target_session_attrs != NULL &&
((strcmp(conn->target_session_attrs, "read-write") == 0 &&
conn->session_read_only) ||
(strcmp(conn->target_session_attrs, "read-only") == 0 && *!*
conn->session_read_only)))

I rebased and built with this change locally.
The review below is based on the patch with that change.

Also, the following comment has what looks like a copy-paste error and the
first line should be deleted
in src/backend/utils/misc/guc.c ~ line 10078
assign_default_transaction_read_only

+assign_default_transaction_read_only(bool newval, void *extra)
...
+ /*
-  * We clamp manually-set values to at least 1MB.  Since
+  * Also set the session read-only parameter.  We only need
+  * to set the correct value in processes that have database
+  * sessions, but there's no mechanism to know that there's

patch applies cleanly: yes
installcheck: passed
installcheck-world: passed
feature works as expected: yes (details follow)

With two servers, one configured as the primary and one configured to run
in Hot Standby mode, I was able to observe that the value of
session_read_only changed after triggering failover once the standby server
exited recovery

When attempting to connect to a primary server with
target_session_attrs=read-write, I was successful and when attempting to
connect with target_session_attrs=read-only, the connection was closed and
the expected message was produced

Thanks!

#35Daniel Gustafsson
daniel@yesql.se
In reply to: Melanie Plageman (#34)
Re: [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 22 Sep 2017, at 18:57, Melanie Plageman <melanieplageman@gmail.com> wrote:

On Tue, Sep 19, 2017 at 4:15 PM, Melanie Plageman <melanieplageman@gmail.com <mailto:melanieplageman@gmail.com>> wrote:
The latest patch applies cleanly and builds (I am also seeing the failing TAP tests), however, I have a concern. With a single server set up, when I attempt to make a connection with target_session_attrs=read-write, I get the message
psql: could not make a suitable connection to server "localhost:5432"
Whereas, when I attempt to make a connection with target_session_attrs=read-only, it is successful.

I might be missing something, but this seems somewhat counter-intuitive. I would expect to specify read-write as target_session_attrs and successfully connect to a server on which read and write operations are permitted. I see this behavior implemented in src/interfaces/libpq/fe-connect.c
Is there a reason to reject a connection to a primary server when I specify 'read-write'? Is this intentional?

Hi Elvis,

Making an assumption about the intended functionality mentioned above, I swapped the 'not' to the following lines of src/interfaces/libpq/fe-connect.c ~ line 3005

if (conn->target_session_attrs != NULL &&
((strcmp(conn->target_session_attrs, "read-write") == 0 && conn->session_read_only) ||
(strcmp(conn->target_session_attrs, "read-only") == 0 && !conn->session_read_only)))

I rebased and built with this change locally.
The review below is based on the patch with that change.

Also, the following comment has what looks like a copy-paste error and the first line should be deleted
in src/backend/utils/misc/guc.c ~ line 10078
assign_default_transaction_read_only

+assign_default_transaction_read_only(bool newval, void *extra)
...
+	/*
-	 * We clamp manually-set values to at least 1MB.  Since
+	 * Also set the session read-only parameter.  We only need
+	 * to set the correct value in processes that have database
+	 * sessions, but there's no mechanism to know that there's

patch applies cleanly: yes
installcheck: passed
installcheck-world: passed
feature works as expected: yes (details follow)

With two servers, one configured as the primary and one configured to run in Hot Standby mode, I was able to observe that the value of session_read_only changed after triggering failover once the standby server exited recovery

When attempting to connect to a primary server with target_session_attrs=read-write, I was successful and when attempting to connect with target_session_attrs=read-only, the connection was closed and the expected message was produced

Based on the unaddressed questions raised in this thread, I’m marking this
patch Returned with Feedback. Please re-submit a new version of the patch to a
future commitfest.

cheers ./daniel

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#36Michael Paquier
michael.paquier@gmail.com
In reply to: Daniel Gustafsson (#35)
Re: [HACKERS] [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On Mon, Oct 2, 2017 at 4:16 PM, Daniel Gustafsson <daniel@yesql.se> wrote:

Based on the unaddressed questions raised in this thread, I’m marking this
patch Returned with Feedback. Please re-submit a new version of the patch to a
future commitfest.

For some reason this patch has been moved to CF 2017-11, but there has
been no real updates since the last version in
/messages/by-id/1572601.d6Y6hSXNBC@hammer.magicstack.net
was sent. The patch fails to apply as well now. I am marking it as
returned with feedback. I am not seeing any replies to the requests
done as well.
--
Michael

#37Andres Freund
andres@anarazel.de
In reply to: Michael Paquier (#36)
Re: [HACKERS] [PATCH v1] Add and report the new "in_hot_standby" GUC pseudo-variable.

On 2017-11-28 10:55:34 +0900, Michael Paquier wrote:

On Mon, Oct 2, 2017 at 4:16 PM, Daniel Gustafsson <daniel@yesql.se> wrote:

Based on the unaddressed questions raised in this thread, I’m marking this
patch Returned with Feedback. Please re-submit a new version of the patch to a
future commitfest.

For some reason this patch has been moved to CF 2017-11, but there has
been no real updates since the last version in
/messages/by-id/1572601.d6Y6hSXNBC@hammer.magicstack.net
was sent. The patch fails to apply as well now. I am marking it as
returned with feedback. I am not seeing any replies to the requests
done as well.

A CF entry for this patch has been created yesterday, without any
changes having happend since the above status update. Given that
there's been no progress for multiple commitfests, and this is the last
CF, this doesn't seem appropriate. Therefore marked as returned with
feedback.

Greetings,

Andres Freund

#38Elvis Pranskevichus
elprans@gmail.com
In reply to: Andres Freund (#37)
1 attachment(s)
Re: [HACKERS] [PATCH v2] Add and report the new "session_read_only" GUC pseudo-variable.

On Thursday, March 1, 2018 4:25:16 AM EDT Andres Freund wrote:

A CF entry for this patch has been created yesterday, without any
changes having happend since the above status update. Given that
there's been no progress for multiple commitfests, and this is the
last CF, this doesn't seem appropriate. Therefore marked as returned
with feedback.

Sorry for the long silence on this. I'm attaching a rebased and
cleaned-up patch with the earlier review issues addressed. I've checked
all relevant tests and verified manually.

Elvis

Attachments:

session-read-only-guc-v2.patchtext/x-patch; charset=UTF-8; name=session-read-only-guc-v2.patchDownload
From b4b23556552d1fddd3a58ec4db43cbcc62230a87 Mon Sep 17 00:00:00 2001
From: Elvis Pranskevichus <elvis@magic.io>
Date: Tue, 12 Sep 2017 11:15:01 -0400
Subject: [PATCH v2] Add and report the new "session_read_only" GUC
 pseudo-variable.

Currently, clients wishing to know whether the server is in hot standby
have to resort to polling, which is often suboptimal.

This adds the new "session_read_only" 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 is immediately useful for target_session_attrs=read-write, as
libpq will not need to make a `SHOW transaction_read_only` roundtrip.
It is also beneficial to various connection pooling systems
(pgpool, pgbouncer etc.)

This also adds support for "target_session_attrs=read-only".

Parts of the patch are based on the work by Tsunakawa Takayuki.
---
 doc/src/sgml/libpq.sgml              |  4 ++
 doc/src/sgml/protocol.sgml           |  3 +-
 src/backend/access/transam/xlog.c    |  9 +++-
 src/backend/commands/async.c         | 49 ++++++++++++++++++
 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          | 14 ++++-
 src/backend/utils/misc/check_guc     |  2 +-
 src/backend/utils/misc/guc.c         | 42 ++++++++++++++-
 src/include/commands/async.h         |  7 +++
 src/include/storage/procarray.h      |  2 +
 src/include/storage/procsignal.h     |  2 +
 src/include/storage/standby.h        |  1 +
 src/interfaces/libpq/fe-connect.c    | 76 ++++++++++++++++++++++++----
 src/interfaces/libpq/fe-exec.c       |  6 ++-
 src/interfaces/libpq/libpq-int.h     |  3 +-
 17 files changed, 243 insertions(+), 19 deletions(-)

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 06d909e804..0cd55bff97 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1579,6 +1579,9 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
        <para>
         If this parameter is set to <literal>read-write</literal>, only a
         connection in which read-write transactions are accepted by default
+        is considered acceptable.
+        If this parameter is set to <literal>read-only</literal>, only a
+        connection in which read-write transactions are rejected by default
         is considered acceptable.  The query
         <literal>SHOW transaction_read_only</literal> will be sent upon any
         successful connection; if it returns <literal>on</literal>, the connection
@@ -1929,6 +1932,7 @@ const char *PQparameterStatus(const PGconn *conn, const char *paramName);
        before 8.1;
        <varname>IntervalStyle</varname> was not reported by releases before 8.4;
        <varname>application_name</varname> was not reported by releases before 9.0.)
+       <varname>session_read_only</> was not reported by releases before 12.0.)
        Note that
        <varname>server_version</varname>,
        <varname>server_encoding</varname> and
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index f0b2145208..ab8db9dc89 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1291,6 +1291,7 @@ SELCT 1/0;
     before 8.1;
     <varname>IntervalStyle</varname> was not reported by releases before 8.4;
     <varname>application_name</varname> was not reported by releases before 9.0.)
+    <varname>session_read_only</> was not reported by releases before 12.0.)
     Note that
     <varname>server_version</varname>,
     <varname>server_encoding</varname> and
@@ -1586,7 +1587,7 @@ PostgreSQL is <literal>tls-server-end-point</literal>.
    user-supplied password in the transmitted password hash.  While this
    prevents the password hash from being successfully retransmitted in
    a later session, it does not prevent a fake server between the real
-   server and client from passing through the server's random value 
+   server and client from passing through the server's random value
    and successfully authenticating.
   </para>
 
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 4754e75436..8d29fd6aa1 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -7904,8 +7904,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)
@@ -8112,6 +8114,11 @@ RecoveryInProgress(void)
 			 */
 			pg_memory_barrier();
 			InitXLOGAccess();
+
+			/* Update session read-only status. */
+			SetConfigOption("session_read_only",
+							DefaultXactReadOnly ? "on" : "off",
+							PGC_INTERNAL, PGC_S_OVERRIDE);
 		}
 
 		/*
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index ee7c6d41b4..7635794040 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -357,6 +357,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;
 
@@ -1738,6 +1740,53 @@ 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("session_read_only",
+					DefaultXactReadOnly ? "on" : "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
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index bf2f4dbed2..cb27b598bd 100644
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -2955,6 +2955,36 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
 	return true;				/* timed out, still conflicts */
 }
 
+/*
+ * 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
  *
diff --git a/src/backend/storage/ipc/procsignal.c b/src/backend/storage/ipc/procsignal.c
index b0dd7d1b37..71b78ac462 100644
--- a/src/backend/storage/ipc/procsignal.c
+++ b/src/backend/storage/ipc/procsignal.c
@@ -292,6 +292,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 c9bb3e987d..e7f18058ab 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -138,6 +138,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 e4c6e3d406..e090349f25 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -539,9 +539,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)
 	{
@@ -3847,6 +3851,14 @@ PostgresMain(int argc, char *argv[],
 	 */
 	InitPostgres(dbname, InvalidOid, username, InvalidOid, NULL, false);
 
+	/*
+	 * Update session read-only status if in recovery.
+	 */
+	if (IsUnderPostmaster && !DefaultXactReadOnly &&
+		RecoveryInProgress())
+		SetConfigOption("session_read_only", "on",
+						PGC_INTERNAL, PGC_S_OVERRIDE);
+
 	/*
 	 * If the PostmasterContext is still around, recycle the space; we don't
 	 * need it anymore after InitPostgres completes.  Note this does not trash
diff --git a/src/backend/utils/misc/check_guc b/src/backend/utils/misc/check_guc
index d228bbed68..da96df2298 100755
--- a/src/backend/utils/misc/check_guc
+++ b/src/backend/utils/misc/check_guc
@@ -21,7 +21,7 @@ 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"
+zero_damaged_pages session_read_only"
 
 ### 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 e9f542cfed..973b246e51 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -149,6 +149,8 @@ static bool call_string_check_hook(struct config_string *conf, char **newval,
 static bool call_enum_check_hook(struct config_enum *conf, int *newval,
 					 void **extra, GucSource source, int elevel);
 
+static void assign_default_transaction_read_only(bool newval, void *extra);
+
 static bool check_log_destination(char **newval, void **extra, GucSource source);
 static void assign_log_destination(const char *newval, void *extra);
 
@@ -503,6 +505,7 @@ int			huge_pages;
  * and is kept in sync by assign_hooks.
  */
 static char *syslog_ident_str;
+static bool session_read_only;
 static double phony_random_seed;
 static char *client_encoding_string;
 static char *datestyle_string;
@@ -1001,6 +1004,20 @@ static struct config_bool ConfigureNamesBool[] =
 		false,
 		NULL, NULL, NULL
 	},
+	{
+		/*
+		 * Not for general use --- used to indicate whether
+		 * the session is read-only by default.
+		 */
+		{"session_read_only", PGC_INTERNAL, UNGROUPED,
+			gettext_noop("Shows whether the session is read-only by default."),
+			NULL,
+			GUC_REPORT | GUC_NO_SHOW_ALL | GUC_NO_RESET_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&session_read_only,
+		false,
+		NULL, NULL, NULL
+	},
 	{
 		{"bonjour", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
 			gettext_noop("Enables advertising the server via Bonjour."),
@@ -1444,7 +1461,7 @@ static struct config_bool ConfigureNamesBool[] =
 		},
 		&DefaultXactReadOnly,
 		false,
-		NULL, NULL, NULL
+		NULL, assign_default_transaction_read_only, NULL
 	},
 	{
 		{"transaction_read_only", PGC_USERSET, CLIENT_CONN_STATEMENT,
@@ -10344,6 +10361,29 @@ assign_wal_consistency_checking(const char *newval, void *extra)
 	wal_consistency_checking = (bool *) extra;
 }
 
+static void
+assign_default_transaction_read_only(bool newval, void *extra)
+{
+	if (newval == DefaultXactReadOnly)
+		return;
+
+	/*
+	 * Also set the session read-only parameter.  We only need
+	 * to set the correct value in processes that have database
+	 * sessions, but there's no mechanism to know that there's
+	 * a session.  Instead, we use the shared memory segment
+	 * pointer because the processes with database sessions are
+	 * attached to the shared memory.  Without this check,
+	 * RecoveryInProgress() would crash the processes which
+	 * are not attached to the shared memory.
+	 */
+	if (IsUnderPostmaster && UsedShmemSegAddr != NULL &&
+		RecoveryInProgress())
+		newval = true;
+	SetConfigOption("session_read_only", newval ? "on" : "off",
+					PGC_INTERNAL, PGC_S_OVERRIDE);
+}
+
 static bool
 check_log_destination(char **newval, void **extra, GucSource source)
 {
diff --git a/src/include/commands/async.h b/src/include/commands/async.h
index d5868c42a0..0d1565a3d9 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 75bab2985f..a996043f92 100644
--- a/src/include/storage/procarray.h
+++ b/src/include/storage/procarray.h
@@ -114,6 +114,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 6db0d69b71..6c1b07198f 100644
--- a/src/include/storage/procsignal.h
+++ b/src/include/storage/procsignal.h
@@ -42,6 +42,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 1fcd8cf1b5..22a40435b2 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);
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 45bc067921..a498e315ee 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -1240,7 +1240,8 @@ connectOptions2(PGconn *conn)
 	if (conn->target_session_attrs)
 	{
 		if (strcmp(conn->target_session_attrs, "any") != 0
-			&& strcmp(conn->target_session_attrs, "read-write") != 0)
+			&& strcmp(conn->target_session_attrs, "read-write") != 0
+			&& strcmp(conn->target_session_attrs, "read-only") != 0)
 		{
 			conn->status = CONNECTION_BAD;
 			printfPQExpBuffer(&conn->errorMessage,
@@ -3158,15 +3159,19 @@ keep_going:						/* We will come back to here until there is
 				}
 
 				/*
-				 * If a read-write connection is required, see if we have one.
+				 * If a read-write or a read-only connection is required,
+				 * see if we have one.
 				 *
 				 * Servers before 7.4 lack the transaction_read_only GUC, but
 				 * by the same token they don't have any read-only mode, so we
-				 * may just skip the test in that case.
+				 * may just skip the test in that case.  Servers starting
+				 * with 12.0 report the session_read_only value via a
+				 * parameter status message.
 				 */
-				if (conn->sversion >= 70400 &&
+				if (conn->sversion >= 70400 && conn->sversion < 120000 &&
 					conn->target_session_attrs != NULL &&
-					strcmp(conn->target_session_attrs, "read-write") == 0)
+					(strcmp(conn->target_session_attrs, "read-write") == 0 ||
+					 strcmp(conn->target_session_attrs, "read-only") == 0))
 				{
 					/*
 					 * Save existing error messages across the PQsendQuery
@@ -3190,6 +3195,36 @@ keep_going:						/* We will come back to here until there is
 					return PGRES_POLLING_READING;
 				}
 
+				if (conn->sversion >= 120000 &&
+					conn->target_session_attrs != NULL &&
+					((strcmp(conn->target_session_attrs, "read-write") == 0 &&
+					  conn->session_read_only) ||
+					 (strcmp(conn->target_session_attrs, "read-only") == 0 &&
+					  !conn->session_read_only)))
+				{
+					/* Not suitable; close connection. */
+					appendPQExpBuffer(&conn->errorMessage,
+									  libpq_gettext("could not make a suitable "
+													"connection to server "
+													"\"%s:%s\"\n"),
+									  conn->connhost[conn->whichhost].host,
+									  conn->connhost[conn->whichhost].port);
+					conn->status = CONNECTION_OK;
+					sendTerminateConn(conn);
+					pqDropConnection(conn, true);
+
+					/* Skip any remaining addresses for this host. */
+					conn->addr_cur = NULL;
+					if (conn->whichhost + 1 < conn->nconnhost)
+					{
+						conn->status = CONNECTION_NEEDED;
+						goto keep_going;
+					}
+
+					/* No more addresses to try. So we fail. */
+					goto error_return;
+				}
+
 				/* We can release the address list now. */
 				release_conn_addrinfo(conn);
 
@@ -3226,9 +3261,9 @@ keep_going:						/* We will come back to here until there is
 			}
 
 			/*
-			 * If a read-write connection is required, see if we have one.
-			 * (This should match the stanza in the CONNECTION_AUTH_OK case
-			 * above.)
+			 * If a read-write or a read-only connection is required,
+			 * see if we have one. (This should match the stanza in
+			 * the CONNECTION_AUTH_OK case above.)
 			 *
 			 * Servers before 7.4 lack the transaction_read_only GUC, but by
 			 * the same token they don't have any read-only mode, so we may
@@ -3236,7 +3271,8 @@ keep_going:						/* We will come back to here until there is
 			 */
 			if (conn->sversion >= 70400 &&
 				conn->target_session_attrs != NULL &&
-				strcmp(conn->target_session_attrs, "read-write") == 0)
+				(strcmp(conn->target_session_attrs, "read-write") == 0 ||
+				 strcmp(conn->target_session_attrs, "read-only") == 0))
 			{
 				if (!saveErrorMessage(conn, &savedMessage))
 					goto error_return;
@@ -3317,9 +3353,22 @@ keep_going:						/* We will come back to here until there is
 					PQntuples(res) == 1)
 				{
 					char	   *val;
+					char	   *expected_val;
+					int			expected_len;
+
+					if (strcmp(conn->target_session_attrs, "read-write") == 0)
+					{
+						expected_val = "on";
+						expected_len = 2;
+					}
+					else
+					{
+						expected_val = "off";
+						expected_len = 3;
+					}
 
 					val = PQgetvalue(res, 0, 0);
-					if (strncmp(val, "on", 2) == 0)
+					if (strncmp(val, expected_val, expected_len) == 0)
 					{
 						/* Not writable; fail this connection. */
 						const char *displayed_host;
@@ -3337,8 +3386,12 @@ keep_going:						/* We will come back to here until there is
 						if (displayed_port == NULL || displayed_port[0] == '\0')
 							displayed_port = DEF_PGPORT_STR;
 
+						PQclear(res);
+						restoreErrorMessage(conn, &savedMessage);
+
+						/* Not suitable; close connection. */
 						appendPQExpBuffer(&conn->errorMessage,
-										  libpq_gettext("could not make a writable "
+										  libpq_gettext("could not make a suiteable "
 														"connection to server "
 														"\"%s:%s\"\n"),
 										  displayed_host, displayed_port);
@@ -3533,6 +3586,7 @@ makeEmptyPGconn(void)
 	conn->setenv_state = SETENV_STATE_IDLE;
 	conn->client_encoding = PG_SQL_ASCII;
 	conn->std_strings = false;	/* unless server says differently */
+	conn->session_read_only = false;	/* unless server says differently */
 	conn->verbosity = PQERRORS_DEFAULT;
 	conn->show_context = PQSHOW_CONTEXT_ERRORS;
 	conn->sock = PGINVALID_SOCKET;
diff --git a/src/interfaces/libpq/fe-exec.c b/src/interfaces/libpq/fe-exec.c
index e8b28d9ccf..5e30c6b3fc 100644
--- a/src/interfaces/libpq/fe-exec.c
+++ b/src/interfaces/libpq/fe-exec.c
@@ -1033,8 +1033,8 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
 	}
 
 	/*
-	 * Special hacks: remember client_encoding and
-	 * standard_conforming_strings, and convert server version to a numeric
+	 * Special hacks: remember client_encoding/
+	 * standard_conforming_strings/session_read_only, and convert server version to a numeric
 	 * form.  We keep the first two of these in static variables as well, so
 	 * that PQescapeString and PQescapeBytea can behave somewhat sanely (at
 	 * least in single-connection-using programs).
@@ -1052,6 +1052,8 @@ pqSaveParameterStatus(PGconn *conn, const char *name, const char *value)
 		conn->std_strings = (strcmp(value, "on") == 0);
 		static_std_strings = conn->std_strings;
 	}
+	else if (strcmp(name, "session_read_only") == 0)
+		conn->session_read_only = (strcmp(value, "on") == 0);
 	else if (strcmp(name, "server_version") == 0)
 	{
 		int			cnt;
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index bdd8f9d9b2..891d6e3279 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -363,7 +363,7 @@ struct pg_conn
 	char	   *krbsrvname;		/* Kerberos service name */
 #endif
 
-	/* Type of connection to make.  Possible values: any, read-write. */
+	/* Type of connection to make.  Possible values: any, read-write, read-only. */
 	char	   *target_session_attrs;
 
 	/* Optional file to write trace info to */
@@ -426,6 +426,7 @@ struct pg_conn
 	pgParameterStatus *pstatus; /* ParameterStatus data */
 	int			client_encoding;	/* encoding id */
 	bool		std_strings;	/* standard_conforming_strings */
+	bool		session_read_only;	/* session_read_only */
 	PGVerbosity verbosity;		/* error/notice message verbosity */
 	PGContextVisibility show_context;	/* whether to show CONTEXT field */
 	PGlobjfuncs *lobjfuncs;		/* private state for large-object access fns */
-- 
2.19.0

#39Melanie Plageman
melanieplageman@gmail.com
In reply to: Elvis Pranskevichus (#38)
Re: [HACKERS] [PATCH v2] Add and report the new "session_read_only" GUC pseudo-variable.

On Mon, Sep 24, 2018 at 9:28 AM Elvis Pranskevichus <elprans@gmail.com>
wrote:

On Thursday, March 1, 2018 4:25:16 AM EDT Andres Freund wrote:

A CF entry for this patch has been created yesterday, without any
changes having happend since the above status update. Given that
there's been no progress for multiple commitfests, and this is the
last CF, this doesn't seem appropriate. Therefore marked as returned
with feedback.

Sorry for the long silence on this. I'm attaching a rebased and
cleaned-up patch with the earlier review issues addressed. I've checked
all relevant tests and verified manually.

Elvis

After taking a look at the updated patch, it appears to address the review
feedback which I provided. However, the patch didn't apply cleanly for me,
so
it likely needs a quick look along with a rebase.

After looking at the patch [1]https://commitfest.postgresql.org/20/1677/ to add a "prefer-read" option to
target-session-attrs which is also up for consideration this commitfest, I
was
wondering, assuming it is desirable to have both "prefer-read" and
"read-only"
modes, does it make sense for the "prefer-read" option to also be
implemented
with a ParameterStatus message instead of using polling?

[1]: https://commitfest.postgresql.org/20/1677/

#40Tom Lane
tgl@sss.pgh.pa.us
In reply to: Melanie Plageman (#39)
Re: [HACKERS] [PATCH v2] Add and report the new "session_read_only" GUC pseudo-variable.

Melanie Plageman <melanieplageman@gmail.com> writes:

On Mon, Sep 24, 2018 at 9:28 AM Elvis Pranskevichus <elprans@gmail.com>
wrote:

Sorry for the long silence on this. I'm attaching a rebased and
cleaned-up patch with the earlier review issues addressed. I've checked
all relevant tests and verified manually.

After taking a look at the updated patch, it appears to address the review
feedback which I provided. However, the patch didn't apply cleanly for me,
so it likely needs a quick look along with a rebase.

It looks like the one apply failure is due to the patch having corrected
a comment that somebody else already corrected. So no big deal there.

Looking through the thread, it seems like there's a pretty fundamental
design issue that hasn't been resolved, namely whether and how this ought
to interact with default_transaction_read_only. The patch as it stands
seems to be trying to implement the definition that the transmittable
variable session_read_only is equal to "!(DefaultXactReadOnly ||
RecoveryInProgress())". I doubt that that's a good idea. In the first
place, it's not at all clear that such a flag is sufficient for all
use-cases. In the second, it's somewhere between difficult and impossible
to correctly implement GUCs that are interdependent in that way; the
current patch certainly fails to do so. (It will not correctly track
intra-session changes to DefaultXactReadOnly, for instance.)

I think that we'd be better off maintaining a strict separation between
"in hot standby" and default_transaction_read_only. If there are use
cases in which people would like to reject connections based on either
one being true, let's handle that by marking them both GUC_REPORT, and
having libpq check both. (So there need to be two flavors of
target-session-attrs libpq parameter, depending on whether you want
"in hot standby" or "currently read only" to be checked.)

That puts us back to having to choose an appropriate GUC name, because
"session_read_only" isn't it :-(. Don't have any better ideas about
that than what's been discussed in the thread.

I'm also not terribly happy with the patch adding a whole new
cross-backend signaling mechanism for this; surely we don't really
need that. Perhaps it'd be sufficient to transmit SIGHUP and embed
the check for "just exited hot standby" in the handling for that?

regards, tom lane

#41Elvis Pranskevichus
elprans@gmail.com
In reply to: Tom Lane (#40)
Re: [HACKERS] [PATCH v2] Add and report the new "session_read_only" GUC pseudo-variable.

On Monday, November 12, 2018 1:08:37 PM EST Tom Lane wrote:

Looking through the thread, it seems like there's a pretty fundamental
design issue that hasn't been resolved, namely whether and how this
ought to interact with default_transaction_read_only. The patch as
it stands seems to be trying to implement the definition that the
transmittable variable session_read_only is equal to
"!(DefaultXactReadOnly || RecoveryInProgress())". I doubt that
that's a good idea. In the first place, it's not at all clear that
such a flag is sufficient for all use-cases. In the second, it's
somewhere between difficult and impossible to correctly implement
GUCs that are interdependent in that way; the current patch certainly
fails to do so. (It will not correctly track intra-session changes
to DefaultXactReadOnly, for instance.)

I think that we'd be better off maintaining a strict separation
between "in hot standby" and default_transaction_read_only. If there
are use cases in which people would like to reject connections based
on either one being true, let's handle that by marking them both
GUC_REPORT, and having libpq check both. (So there need to be two
flavors of target-session-attrs libpq parameter, depending on whether
you want "in hot standby" or "currently read only" to be checked.)

I agree that the original design with the separate "in_hot_standby" GUC
is better. Hot standby and read-only session are distinct modes, not
all commands that are OK in a read-only session will succeed on a hot-
standby backend.

I'm also not terribly happy with the patch adding a whole new
cross-backend signaling mechanism for this; surely we don't really
need that. Perhaps it'd be sufficient to transmit SIGHUP and embed
the check for "just exited hot standby" in the handling for that?

That seems doable. Is there an existing check that is a good candidate
for "just exited hot standby"?

Elvis

#42Dmitry Dolgov
9erthalion6@gmail.com
In reply to: Elvis Pranskevichus (#41)
Re: [HACKERS] [PATCH v2] Add and report the new "session_read_only" GUC pseudo-variable.

On Mon, Nov 12, 2018 at 8:30 PM Elvis Pranskevichus <elprans@gmail.com> wrote:

On Monday, November 12, 2018 1:08:37 PM EST Tom Lane wrote:

Looking through the thread, it seems like there's a pretty fundamental
design issue that hasn't been resolved, namely whether and how this
ought to interact with default_transaction_read_only. The patch as
it stands seems to be trying to implement the definition that the
transmittable variable session_read_only is equal to
"!(DefaultXactReadOnly || RecoveryInProgress())". I doubt that
that's a good idea. In the first place, it's not at all clear that
such a flag is sufficient for all use-cases. In the second, it's
somewhere between difficult and impossible to correctly implement
GUCs that are interdependent in that way; the current patch certainly
fails to do so. (It will not correctly track intra-session changes
to DefaultXactReadOnly, for instance.)

I think that we'd be better off maintaining a strict separation
between "in hot standby" and default_transaction_read_only. If there
are use cases in which people would like to reject connections based
on either one being true, let's handle that by marking them both
GUC_REPORT, and having libpq check both. (So there need to be two
flavors of target-session-attrs libpq parameter, depending on whether
you want "in hot standby" or "currently read only" to be checked.)

I agree that the original design with the separate "in_hot_standby" GUC
is better. Hot standby and read-only session are distinct modes, not
all commands that are OK in a read-only session will succeed on a hot-
standby backend.

I'm also not terribly happy with the patch adding a whole new
cross-backend signaling mechanism for this; surely we don't really
need that. Perhaps it'd be sufficient to transmit SIGHUP and embed
the check for "just exited hot standby" in the handling for that?

That seems doable. Is there an existing check that is a good candidate
for "just exited hot standby"?

Apparently due the minor conflict, mentioned above, the patch was in "Waiting
on author" state, which probably is not exactly correct. I'm moving it to the
next CF, but still, it would be nice if you post an updated version without
conflicts.

#43Michael Paquier
michael@paquier.xyz
In reply to: Dmitry Dolgov (#42)
Re: [HACKERS] [PATCH v2] Add and report the new "session_read_only" GUC pseudo-variable.

On Fri, Nov 30, 2018 at 05:35:21PM +0100, Dmitry Dolgov wrote:

Apparently due the minor conflict, mentioned above, the patch was in "Waiting
on author" state, which probably is not exactly correct. I'm moving it to the
next CF, but still, it would be nice if you post an updated version without
conflicts.

And nothing has happened since, so I have marked the entry as returned
with feedback.
--
Michael