Enhance pg_stat_wal_receiver view to display connected host
Hi Hackers,
With the multi host connection string feature, it is possible to specify
multiple
hosts in primary_conninfo that is used in streaming replication to make sure
that WAL streaming is not affected.
Currently there is no information that is available in the standby node to
find out
to which primary currently it is connected. Need to find out from primary
node only.
I feel it may be better if we can enhance the pg_stat_wal_receiver to
display the
connected host information such as "hostname", "hostaddr" and "port". So
that
it is possible to find out the from standby node to which primary currently
it is
connected.
The current connected host details are already available in the PGconn
structure,
Exposing those details in the view will suffice this requirement. Currently
these
members are characters pointers, I used them as it is and displayed them in
the
view as character arrays except the port number.
Attached the draft patch. Any comments?
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-connected-host.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-connected-host.patchDownload
From 523f8cb1842053d1ef092da0e5ee2de32227ae64 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Thu, 21 Dec 2017 16:59:25 +1100
Subject: [PATCH] pg_stat_wal_receiver to display connected host
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of primary host information from which the replication is
streaming currently.
---
src/backend/catalog/system_views.sql | 3 ++
.../libpqwalreceiver/libpqwalreceiver.c | 18 +++++++++--
src/backend/replication/walreceiver.c | 37 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 12 +++++--
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 21 ++++++++++++
src/interfaces/libpq/libpq-fe.h | 8 +++++
8 files changed, 93 insertions(+), 9 deletions(-)
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 394aea8e0f..5d530d5134 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,9 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.primary_hostname,
+ s.primary_hostaddr,
+ s.primary_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 3957bd37fb..2a268e5d84 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -52,7 +52,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
bool logical, const char *appname,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
-static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -238,7 +239,8 @@ libpqrcv_check_conninfo(const char *conninfo)
* are obfuscated.
*/
static char *
-libpqrcv_get_conninfo(WalReceiverConn *conn)
+libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port)
{
PQconninfoOption *conn_opts;
PQconninfoOption *conn_opt;
@@ -277,6 +279,18 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
PQconninfoFree(conn_opts);
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_HOST_NAME);
+ if (retval)
+ *host = pstrdup(retval);
+
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_HOST_ADDRESS);
+ if (retval)
+ *hostaddr = pstrdup(retval);
+
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_PORT);
+ if (retval)
+ *port = atoi(retval);
+
retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
termPQExpBuffer(&buf);
return retval;
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index fe4e085938..3c3423e3ff 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -199,6 +199,9 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *host = NULL;
+ char *hostaddr = NULL;
+ int port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -310,11 +313,21 @@ WalReceiverMain(void)
* Save user-visible connection string. This clobbers the original
* conninfo, for security.
*/
- tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_conninfo = walrcv_get_conninfo(wrconn, &host, &hostaddr, &port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->host, 0, NAMEDATALEN);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NAMEDATALEN);
+
+ memset(walrcv->hostaddr, 0, NAMEDATALEN);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NAMEDATALEN);
+
+ walrcv->port = port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
@@ -1402,6 +1415,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char host[NAMEDATALEN];
+ char hostaddr[NAMEDATALEN];
+ int port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1435,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(host, (char *) WalRcv->host, sizeof(host));
+ strlcpy(hostaddr, (char *) WalRcv->hostaddr, sizeof(hostaddr));
+ port = WalRcv->port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1481,10 +1500,22 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(host);
+ if (*hostaddr == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(hostaddr);
+ if (port == 0)
+ nulls[13] = true;
+ else
+ values[13] = Int32GetDatum(port);
+ if (*conninfo == '\0')
+ nulls[14] = true;
+ else
+ values[14] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c969375981..3d68753bac 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,primary_hostname,primary_hostaddr,primary_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index e58fc49c68..5aa5b56dde 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,9 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char host[NAMEDATALEN];
+ char hostaddr[NAMEDATALEN];
+ int port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -196,7 +199,10 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
const char *appname,
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
-typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn,
+ char **host,
+ char **hostaddr,
+ int *port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -244,8 +250,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err)
#define walrcv_check_conninfo(conninfo) \
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
-#define walrcv_get_conninfo(conn) \
- WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_conninfo(conn, host, hostaddr, port) \
+ WalReceiverFunctions->walrcv_get_conninfo(conn, host, hostaddr, port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..97ad8c9594 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQconnectedhostinfo 173
\ No newline at end of file
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 68fb9a124a..95bc6dbfc6 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6032,6 +6032,27 @@ PQhost(const PGconn *conn)
}
}
+/* Provides connected host info details */
+char *
+PQconnectedhostinfo(const PGconn *conn, pg_connected_host_info type)
+{
+ if (!conn || !conn->connhost)
+ return NULL;
+
+ switch (type)
+ {
+ case PQ_HOST_NAME:
+ return conn->connhost[conn->whichhost].host;
+ case PQ_HOST_ADDRESS:
+ return conn->connhost[conn->whichhost].hostaddr;
+ case PQ_PORT:
+ return conn->connhost[conn->whichhost].port;
+ }
+
+ /* keep compiler silent */
+ return NULL;
+}
+
char *
PQport(const PGconn *conn)
{
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 1d915e7915..39f712efd7 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -134,6 +134,13 @@ typedef enum
PQPING_NO_ATTEMPT /* connection not attempted (bad params) */
} PGPing;
+typedef enum pg_connected_host_info
+{
+ PQ_HOST_NAME,
+ PQ_HOST_ADDRESS,
+ PQ_PORT
+} pg_connected_host_info;
+
/* PGconn encapsulates a connection to the backend.
* The contents of this struct are not supposed to be known to applications.
*/
@@ -312,6 +319,7 @@ extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
+extern char *PQconnectedhostinfo(const PGconn *conn, pg_connected_host_info type);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
--
2.15.0.windows.1
On Thu, Dec 21, 2017 at 8:16 PM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:
The current connected host details are already available in the PGconn
structure,
Exposing those details in the view will suffice this requirement. Currently
these
members are characters pointers, I used them as it is and displayed them in
the
view as character arrays except the port number.Attached the draft patch. Any comments?
I agree that it would be nice to have an equivalent to
pg_stat_replication's client_addr, client_hostname, client_port on the
receiver side, particularly because it is possible to list multiple
hosts and ports. Could you add that to the next commit fest?
Please note that you need to update rules.out and the documentation
because of the new fields.
--
Michael
On Thu, Dec 21, 2017 at 11:12 PM, Michael Paquier <michael.paquier@gmail.com
wrote:
On Thu, Dec 21, 2017 at 8:16 PM, Haribabu Kommi
<kommi.haribabu@gmail.com> wrote:The current connected host details are already available in the PGconn
structure,
Exposing those details in the view will suffice this requirement.Currently
these
members are characters pointers, I used them as it is and displayed themin
the
view as character arrays except the port number.Attached the draft patch. Any comments?
I agree that it would be nice to have an equivalent to
pg_stat_replication's client_addr, client_hostname, client_port on the
receiver side, particularly because it is possible to list multiple
hosts and ports. Could you add that to the next commit fest?
Added.
Please note that you need to update rules.out and the documentation
because of the new fields.
Updated patch attached with tests and doc changes.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-connected-host_v1.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-connected-host_v1.patchDownload
From e8ce5058b25a08a60c67ba0c435f721325ff5639 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Thu, 21 Dec 2017 16:59:25 +1100
Subject: [PATCH] pg_stat_wal_receiver to display connected host
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of primary host information from which the replication is
streaming currently.
---
doc/src/sgml/monitoring.sgml | 15 +++++++++
src/backend/catalog/system_views.sql | 3 ++
.../libpqwalreceiver/libpqwalreceiver.c | 18 +++++++++--
src/backend/replication/walreceiver.c | 37 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 12 +++++--
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 21 ++++++++++++
src/interfaces/libpq/libpq-fe.h | 8 +++++
src/test/regress/expected/rules.out | 5 ++-
10 files changed, 112 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..68739d9a1e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,6 +2022,21 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>primary_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host name of the primary connected by this WAL receiver</entry>
+ </row>
+ <row>
+ <entry><structfield>primary_hostaddr</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host address of the primary connected by this WAL receiver</entry>
+ </row>
+ <row>
+ <entry><structfield>primary_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>port number of the primary connected by this WAL receiver</entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 394aea8e0f..5d530d5134 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,9 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.primary_hostname,
+ s.primary_hostaddr,
+ s.primary_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 3957bd37fb..2a268e5d84 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -52,7 +52,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
bool logical, const char *appname,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
-static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -238,7 +239,8 @@ libpqrcv_check_conninfo(const char *conninfo)
* are obfuscated.
*/
static char *
-libpqrcv_get_conninfo(WalReceiverConn *conn)
+libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port)
{
PQconninfoOption *conn_opts;
PQconninfoOption *conn_opt;
@@ -277,6 +279,18 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
PQconninfoFree(conn_opts);
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_HOST_NAME);
+ if (retval)
+ *host = pstrdup(retval);
+
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_HOST_ADDRESS);
+ if (retval)
+ *hostaddr = pstrdup(retval);
+
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_PORT);
+ if (retval)
+ *port = atoi(retval);
+
retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
termPQExpBuffer(&buf);
return retval;
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index fe4e085938..3c3423e3ff 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -199,6 +199,9 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *host = NULL;
+ char *hostaddr = NULL;
+ int port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -310,11 +313,21 @@ WalReceiverMain(void)
* Save user-visible connection string. This clobbers the original
* conninfo, for security.
*/
- tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_conninfo = walrcv_get_conninfo(wrconn, &host, &hostaddr, &port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->host, 0, NAMEDATALEN);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NAMEDATALEN);
+
+ memset(walrcv->hostaddr, 0, NAMEDATALEN);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NAMEDATALEN);
+
+ walrcv->port = port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
@@ -1402,6 +1415,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char host[NAMEDATALEN];
+ char hostaddr[NAMEDATALEN];
+ int port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1435,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(host, (char *) WalRcv->host, sizeof(host));
+ strlcpy(hostaddr, (char *) WalRcv->hostaddr, sizeof(hostaddr));
+ port = WalRcv->port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1481,10 +1500,22 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(host);
+ if (*hostaddr == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(hostaddr);
+ if (port == 0)
+ nulls[13] = true;
+ else
+ values[13] = Int32GetDatum(port);
+ if (*conninfo == '\0')
+ nulls[14] = true;
+ else
+ values[14] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c969375981..3d68753bac 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,primary_hostname,primary_hostaddr,primary_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index e58fc49c68..5aa5b56dde 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,9 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char host[NAMEDATALEN];
+ char hostaddr[NAMEDATALEN];
+ int port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -196,7 +199,10 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
const char *appname,
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
-typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn,
+ char **host,
+ char **hostaddr,
+ int *port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -244,8 +250,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err)
#define walrcv_check_conninfo(conninfo) \
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
-#define walrcv_get_conninfo(conn) \
- WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_conninfo(conn, host, hostaddr, port) \
+ WalReceiverFunctions->walrcv_get_conninfo(conn, host, hostaddr, port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..97ad8c9594 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQconnectedhostinfo 173
\ No newline at end of file
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 68fb9a124a..95bc6dbfc6 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6032,6 +6032,27 @@ PQhost(const PGconn *conn)
}
}
+/* Provides connected host info details */
+char *
+PQconnectedhostinfo(const PGconn *conn, pg_connected_host_info type)
+{
+ if (!conn || !conn->connhost)
+ return NULL;
+
+ switch (type)
+ {
+ case PQ_HOST_NAME:
+ return conn->connhost[conn->whichhost].host;
+ case PQ_HOST_ADDRESS:
+ return conn->connhost[conn->whichhost].hostaddr;
+ case PQ_PORT:
+ return conn->connhost[conn->whichhost].port;
+ }
+
+ /* keep compiler silent */
+ return NULL;
+}
+
char *
PQport(const PGconn *conn)
{
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 1d915e7915..39f712efd7 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -134,6 +134,13 @@ typedef enum
PQPING_NO_ATTEMPT /* connection not attempted (bad params) */
} PGPing;
+typedef enum pg_connected_host_info
+{
+ PQ_HOST_NAME,
+ PQ_HOST_ADDRESS,
+ PQ_PORT
+} pg_connected_host_info;
+
/* PGconn encapsulates a connection to the backend.
* The contents of this struct are not supposed to be known to applications.
*/
@@ -312,6 +319,7 @@ extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
+extern char *PQconnectedhostinfo(const PGconn *conn, pg_connected_host_info type);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..8cbe485d77 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,11 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.primary_hostname,
+ s.primary_hostaddr,
+ s.primary_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, primary_hostname, primary_hostaddr, primary_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
On Fri, Dec 22, 2017 at 03:11:07PM +1100, Haribabu Kommi wrote:
Updated patch attached with tests and doc changes.
+ <row>
+ <entry><structfield>primary_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host name of the primary connected by this WAL receiver</entry>
+ </row>
+ <row>
+ <entry><structfield>primary_hostaddr</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host address of the primary connected by this WAL receiver</entry>
+ </row>
+ <row>
+ <entry><structfield>primary_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>port number of the primary connected by this WAL receiver</entry>
+ </row>
A WAL receiver could be connected to a standby as well with cascading
replication, so "primary" does not sound like a term adapted to me.
Why not just saying "XXX of the PostgreSQL instance this WAL receiver is
connected to"? Similarly the field names don't seem adapted to me. Would
"remote" be more adapted? Other ideas are of course welcome.
+ char host[NAMEDATALEN];
+ char hostaddr[NAMEDATALEN];
Those two should use NI_MAXHOST as maximum length. getaddrinfo() relies on
that.
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_HOST_ADDRESS);
+ if (retval)
+ *hostaddr = pstrdup(retval);
Yes, going through PQconnectedhostinfo() is a good idea at the end of
the day, as well as keeping one API with libpqrcv_get_conninfo().
--
Michael
On Fri, Dec 22, 2017 at 4:55 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Fri, Dec 22, 2017 at 03:11:07PM +1100, Haribabu Kommi wrote:
Updated patch attached with tests and doc changes.
Thanks for the review.
+ <row> + <entry><structfield>primary_hostname</structfield></entry> + <entry><type>text</type></entry> + <entry>Host name of the primary connected by this WAL receiver</entry> + </row> + <row> + <entry><structfield>primary_hostaddr</structfield></entry> + <entry><type>text</type></entry> + <entry>Host address of the primary connected by this WAL receiver</entry> + </row> + <row> + <entry><structfield>primary_port</structfield></entry> + <entry><type>integer</type></entry> + <entry>port number of the primary connected by this WAL receiver</entry> + </row> A WAL receiver could be connected to a standby as well with cascading replication, so "primary" does not sound like a term adapted to me. Why not just saying "XXX of the PostgreSQL instance this WAL receiver is connected to"? Similarly the field names don't seem adapted to me. Would "remote" be more adapted? Other ideas are of course welcome.
changed the description and field names also to remote instead of primary.
+ char host[NAMEDATALEN]; + char hostaddr[NAMEDATALEN]; Those two should use NI_MAXHOST as maximum length. getaddrinfo() relies on that.
Corrected.
+ retval = PQconnectedhostinfo(conn->streamConn, PQ_HOST_ADDRESS); + if (retval) + *hostaddr = pstrdup(retval); Yes, going through PQconnectedhostinfo() is a good idea at the end of the day, as well as keeping one API with libpqrcv_get_conninfo().
Changed as one API call.
update patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-connected-host_v2.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-connected-host_v2.patchDownload
From 7cd875d4b35ec7c7503c194b01a7d15e52fe0b8b Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Thu, 21 Dec 2017 16:59:25 +1100
Subject: [PATCH] pg_stat_wal_receiver to display connected host
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of remote host information from which the replication is
streaming currently.
---
doc/src/sgml/monitoring.sgml | 15 +++++++++
src/backend/catalog/system_views.sql | 3 ++
.../libpqwalreceiver/libpqwalreceiver.c | 8 +++--
src/backend/replication/walreceiver.c | 38 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 12 +++++--
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 17 ++++++++++
src/interfaces/libpq/libpq-fe.h | 1 +
src/test/regress/expected/rules.out | 5 ++-
10 files changed, 92 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..fbdecdaff3 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,6 +2022,21 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host name of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
+ <row>
+ <entry><structfield>remote_hostaddr</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host address of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
+ <row>
+ <entry><structfield>remote_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>port number of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 394aea8e0f..6f658801ea 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,9 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index 3957bd37fb..c43d815fea 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -52,7 +52,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
bool logical, const char *appname,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
-static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -238,7 +239,8 @@ libpqrcv_check_conninfo(const char *conninfo)
* are obfuscated.
*/
static char *
-libpqrcv_get_conninfo(WalReceiverConn *conn)
+libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port)
{
PQconninfoOption *conn_opts;
PQconninfoOption *conn_opt;
@@ -277,6 +279,8 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
PQconninfoFree(conn_opts);
+ PQconnectedhostinfo(conn->streamConn, host, hostaddr, port);
+
retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
termPQExpBuffer(&buf);
return retval;
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index fe4e085938..c2ce4e4f09 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,9 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *host = NULL;
+ char *hostaddr = NULL;
+ int port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -310,11 +314,21 @@ WalReceiverMain(void)
* Save user-visible connection string. This clobbers the original
* conninfo, for security.
*/
- tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_conninfo = walrcv_get_conninfo(wrconn, &host, &hostaddr, &port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->host, 0, NAMEDATALEN);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NAMEDATALEN);
+
+ memset(walrcv->hostaddr, 0, NAMEDATALEN);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NAMEDATALEN);
+
+ walrcv->port = port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
@@ -1402,6 +1416,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1436,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(host, (char *) WalRcv->host, sizeof(host));
+ strlcpy(hostaddr, (char *) WalRcv->hostaddr, sizeof(hostaddr));
+ port = WalRcv->port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1481,10 +1501,22 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(host);
+ if (*hostaddr == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(hostaddr);
+ if (port == 0)
+ nulls[13] = true;
+ else
+ values[13] = Int32GetDatum(port);
+ if (*conninfo == '\0')
+ nulls[14] = true;
+ else
+ values[14] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 830bab37ea..4d6b842f89 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_hostname,remote_hostaddr,remote_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index e58fc49c68..74ae054468 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,9 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -196,7 +199,10 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
const char *appname,
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
-typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn,
+ char **host,
+ char **hostaddr,
+ int *port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -244,8 +250,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err)
#define walrcv_check_conninfo(conninfo) \
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
-#define walrcv_get_conninfo(conn) \
- WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_conninfo(conn, host, hostaddr, port) \
+ WalReceiverFunctions->walrcv_get_conninfo(conn, host, hostaddr, port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..97ad8c9594 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQconnectedhostinfo 173
\ No newline at end of file
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 68fb9a124a..58fcc7067c 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6032,6 +6032,23 @@ PQhost(const PGconn *conn)
}
}
+/* Provides connected host info details */
+void
+PQconnectedhostinfo(const PGconn *conn, char **host, char **hostaddr, int *port)
+{
+ if (!conn || !conn->connhost)
+ return;
+
+ if (conn->connhost[conn->whichhost].host)
+ *host = pstrdup(conn->connhost[conn->whichhost].host);
+
+ if (conn->connhost[conn->whichhost].hostaddr)
+ *hostaddr = pstrdup(conn->connhost[conn->whichhost].hostaddr);
+
+ if (conn->connhost[conn->whichhost].port)
+ *port = atoi(conn->connhost[conn->whichhost].port);
+}
+
char *
PQport(const PGconn *conn)
{
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index 1d915e7915..c85ffc6a7e 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -312,6 +312,7 @@ extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
+extern void PQconnectedhostinfo(const PGconn *conn, char **host, char **hostaddr, int *port);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..f216bd33de 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,11 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_hostname, remote_hostaddr, remote_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
On Wed, Jan 3, 2018 at 12:25 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:
update patch attached.
Last patch has undefined symbol, corrected patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-connected-host_v3.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-connected-host_v3.patchDownload
From 361d879ba5a5bda78fe61b92b49963234c283db9 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Thu, 21 Dec 2017 16:59:25 +1100
Subject: [PATCH] pg_stat_wal_receiver to display connected host
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of remote host information from which the replication is
streaming currently.
---
doc/src/sgml/monitoring.sgml | 15 +++++++++
src/backend/catalog/system_views.sql | 3 ++
.../libpqwalreceiver/libpqwalreceiver.c | 8 +++--
src/backend/replication/walreceiver.c | 38 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 12 +++++--
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 17 ++++++++++
src/interfaces/libpq/libpq-fe.h | 1 +
src/test/regress/expected/rules.out | 5 ++-
10 files changed, 92 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..fbdecdaff3 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,6 +2022,21 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host name of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
+ <row>
+ <entry><structfield>remote_hostaddr</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host address of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
+ <row>
+ <entry><structfield>remote_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>port number of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d..57d1f90e21 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,9 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..d1ff2fd035 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -52,7 +52,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
bool logical, const char *appname,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
-static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -238,7 +239,8 @@ libpqrcv_check_conninfo(const char *conninfo)
* are obfuscated.
*/
static char *
-libpqrcv_get_conninfo(WalReceiverConn *conn)
+libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port)
{
PQconninfoOption *conn_opts;
PQconninfoOption *conn_opt;
@@ -277,6 +279,8 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
PQconninfoFree(conn_opts);
+ PQconnectedhostinfo(conn->streamConn, host, hostaddr, port);
+
retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
termPQExpBuffer(&buf);
return retval;
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a7fc67153a..287cb1de89 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,9 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *host = NULL;
+ char *hostaddr = NULL;
+ int port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -310,11 +314,21 @@ WalReceiverMain(void)
* Save user-visible connection string. This clobbers the original
* conninfo, for security.
*/
- tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_conninfo = walrcv_get_conninfo(wrconn, &host, &hostaddr, &port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->host, 0, NAMEDATALEN);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NAMEDATALEN);
+
+ memset(walrcv->hostaddr, 0, NAMEDATALEN);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NAMEDATALEN);
+
+ walrcv->port = port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
@@ -1402,6 +1416,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1436,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(host, (char *) WalRcv->host, sizeof(host));
+ strlcpy(hostaddr, (char *) WalRcv->hostaddr, sizeof(hostaddr));
+ port = WalRcv->port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1481,10 +1501,22 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(host);
+ if (*hostaddr == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(hostaddr);
+ if (port == 0)
+ nulls[13] = true;
+ else
+ values[13] = Int32GetDatum(port);
+ if (*conninfo == '\0')
+ nulls[14] = true;
+ else
+ values[14] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 298e0ae2f0..59c45d8adc 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_hostname,remote_hostaddr,remote_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..07b9604760 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,9 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -196,7 +199,10 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
const char *appname,
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
-typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn,
+ char **host,
+ char **hostaddr,
+ int *port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -244,8 +250,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err)
#define walrcv_check_conninfo(conninfo) \
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
-#define walrcv_get_conninfo(conn) \
- WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_conninfo(conn, host, hostaddr, port) \
+ WalReceiverFunctions->walrcv_get_conninfo(conn, host, hostaddr, port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..97ad8c9594 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQconnectedhostinfo 173
\ No newline at end of file
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..5152dbbd16 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6032,6 +6032,23 @@ PQhost(const PGconn *conn)
}
}
+/* Provides connected host info details */
+void
+PQconnectedhostinfo(const PGconn *conn, char **host, char **hostaddr, int *port)
+{
+ if (!conn || !conn->connhost)
+ return;
+
+ if (conn->connhost[conn->whichhost].host)
+ *host = conn->connhost[conn->whichhost].host;
+
+ if (conn->connhost[conn->whichhost].hostaddr)
+ *hostaddr = conn->connhost[conn->whichhost].hostaddr;
+
+ if (conn->connhost[conn->whichhost].port)
+ *port = atoi(conn->connhost[conn->whichhost].port);
+}
+
char *
PQport(const PGconn *conn)
{
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..c196b04baa 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -312,6 +312,7 @@ extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
+extern void PQconnectedhostinfo(const PGconn *conn, char **host, char **hostaddr, int *port);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..f216bd33de 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,11 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_hostname, remote_hostaddr, remote_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
On Wed, Jan 03, 2018 at 06:48:07PM +1100, Haribabu Kommi wrote:
On Wed, Jan 3, 2018 at 12:25 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
Last patch has undefined symbol, corrected patch attached.
+ memset(walrcv->host, 0, NAMEDATALEN);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NAMEDATALEN);
+
+ memset(walrcv->hostaddr, 0, NAMEDATALEN);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NAMEDATALEN);
You need to use NI_MAXHOST for both things here.
+ <row>
+ <entry><structfield>remote_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>Host name of the PostgreSQL instance this WAL receiver is connected to</entry>
+ </row>
PostgreSQL is usualy referred to with the <productname> markup. Those
should be split on multiple lines. The doc changes are nits though.
I have done some testing with this patch with primary_conninfo using
multiple values of host and port, and the correct values are being
reported, which is a nice feature.
--
Michael
On Thu, Jan 4, 2018 at 11:53 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Wed, Jan 03, 2018 at 06:48:07PM +1100, Haribabu Kommi wrote:
On Wed, Jan 3, 2018 at 12:25 PM, Haribabu Kommi <
kommi.haribabu@gmail.com>
Last patch has undefined symbol, corrected patch attached.
Thanks for the review.
+ memset(walrcv->host, 0, NAMEDATALEN);
+ if (host) + strlcpy((char *) walrcv->host, host, NAMEDATALEN); + + memset(walrcv->hostaddr, 0, NAMEDATALEN); + if (hostaddr) + strlcpy((char *) walrcv->hostaddr, hostaddr, NAMEDATALEN); You need to use NI_MAXHOST for both things here.
Corrected.
+ <row> + <entry><structfield>remote_hostname</structfield></entry> + <entry><type>text</type></entry> + <entry>Host name of the PostgreSQL instance this WAL receiver is connected to</entry> + </row> PostgreSQL is usualy referred to with the <productname> markup. Those should be split on multiple lines. The doc changes are nits though.
updated the documentation with markups.
I have done some testing with this patch with primary_conninfo using
multiple values of host and port, and the correct values are being
reported, which is a nice feature.
Thanks for testing. updated patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-connected-host_v4.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-connected-host_v4.patchDownload
From 8afe279c9bcbebaa85ac18298fb9ef852f3decd7 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Thu, 21 Dec 2017 16:59:25 +1100
Subject: [PATCH] pg_stat_wal_receiver to display connected host
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of remote host information from which the replication is
streaming currently.
---
doc/src/sgml/monitoring.sgml | 24 ++++++++++++++
src/backend/catalog/system_views.sql | 3 ++
.../libpqwalreceiver/libpqwalreceiver.c | 8 +++--
src/backend/replication/walreceiver.c | 38 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 12 +++++--
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 17 ++++++++++
src/interfaces/libpq/libpq-fe.h | 1 +
src/test/regress/expected/rules.out | 5 ++-
10 files changed, 101 insertions(+), 10 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..3e37b800f6 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,6 +2022,30 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host name of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>remote_hostaddr</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host address of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>remote_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>
+ port number of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d..57d1f90e21 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,9 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..d1ff2fd035 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -52,7 +52,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
bool logical, const char *appname,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
-static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -238,7 +239,8 @@ libpqrcv_check_conninfo(const char *conninfo)
* are obfuscated.
*/
static char *
-libpqrcv_get_conninfo(WalReceiverConn *conn)
+libpqrcv_get_conninfo(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port)
{
PQconninfoOption *conn_opts;
PQconninfoOption *conn_opt;
@@ -277,6 +279,8 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
PQconninfoFree(conn_opts);
+ PQconnectedhostinfo(conn->streamConn, host, hostaddr, port);
+
retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
termPQExpBuffer(&buf);
return retval;
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a7fc67153a..d03aac6211 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,9 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *host = NULL;
+ char *hostaddr = NULL;
+ int port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -310,11 +314,21 @@ WalReceiverMain(void)
* Save user-visible connection string. This clobbers the original
* conninfo, for security.
*/
- tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_conninfo = walrcv_get_conninfo(wrconn, &host, &hostaddr, &port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->host, 0, NI_MAXHOST);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NI_MAXHOST);
+
+ memset(walrcv->hostaddr, 0, NI_MAXHOST);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NI_MAXHOST);
+
+ walrcv->port = port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
@@ -1402,6 +1416,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1436,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(host, (char *) WalRcv->host, sizeof(host));
+ strlcpy(hostaddr, (char *) WalRcv->hostaddr, sizeof(hostaddr));
+ port = WalRcv->port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1481,10 +1501,22 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(host);
+ if (*hostaddr == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(hostaddr);
+ if (port == 0)
+ nulls[13] = true;
+ else
+ values[13] = Int32GetDatum(port);
+ if (*conninfo == '\0')
+ nulls[14] = true;
+ else
+ values[14] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 298e0ae2f0..59c45d8adc 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_hostname,remote_hostaddr,remote_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..07b9604760 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,9 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -196,7 +199,10 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
const char *appname,
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
-typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn,
+ char **host,
+ char **hostaddr,
+ int *port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -244,8 +250,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_connect(conninfo, logical, appname, err)
#define walrcv_check_conninfo(conninfo) \
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
-#define walrcv_get_conninfo(conn) \
- WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_conninfo(conn, host, hostaddr, port) \
+ WalReceiverFunctions->walrcv_get_conninfo(conn, host, hostaddr, port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..97ad8c9594 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQconnectedhostinfo 173
\ No newline at end of file
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..5152dbbd16 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6032,6 +6032,23 @@ PQhost(const PGconn *conn)
}
}
+/* Provides connected host info details */
+void
+PQconnectedhostinfo(const PGconn *conn, char **host, char **hostaddr, int *port)
+{
+ if (!conn || !conn->connhost)
+ return;
+
+ if (conn->connhost[conn->whichhost].host)
+ *host = conn->connhost[conn->whichhost].host;
+
+ if (conn->connhost[conn->whichhost].hostaddr)
+ *hostaddr = conn->connhost[conn->whichhost].hostaddr;
+
+ if (conn->connhost[conn->whichhost].port)
+ *port = atoi(conn->connhost[conn->whichhost].port);
+}
+
char *
PQport(const PGconn *conn)
{
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..c196b04baa 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -312,6 +312,7 @@ extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
+extern void PQconnectedhostinfo(const PGconn *conn, char **host, char **hostaddr, int *port);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..f216bd33de 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,11 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_hostname, remote_hostaddr, remote_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
I think more attention should be given to the libpq side of this patch;
maybe have a 0001 with only the new libpq function, to easily verify
that it does all it needs to do. It needs docs for the new function in
libpq.sgml; also I wonder if checking conn->status before reporting
values is necessary; finally, has the application any good way to check
that the values can be safely read after calling the new function?
Nit: the new libpq function name is not great with all those lowercase
letters. Better to make it camelCase like the rest of the libpq API?
Thanks for the patch,
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Thu, Jan 04, 2018 at 05:21:02PM +1100, Haribabu Kommi wrote:
On Thu, Jan 4, 2018 at 11:53 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:On Wed, Jan 03, 2018 at 06:48:07PM +1100, Haribabu Kommi wrote:
On Wed, Jan 3, 2018 at 12:25 PM, Haribabu Kommi <
kommi.haribabu@gmail.com>
Last patch has undefined symbol, corrected patch attached.
Thanks for the review.
Almost there.
Sorry, I have just noticed that the comment on top of
libpqrcv_get_conninfo() needs a refresh. With your patch more
information than a siple connection string are returned to the caller.
Some initialization of the return values should happen directly inside
walrcv_get_conninfo(), or get the feeling that we'll be trapped in the
future if this gets called somewhere else.
[nit]
+ <entry>
+ port number of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
Missing an upper case at the beginning of the sentence here.
[/nit]
--
Michael
On Thu, Jan 04, 2018 at 08:54:37AM -0300, Alvaro Herrera wrote:
I think more attention should be given to the libpq side of this patch;
maybe have a 0001 with only the new libpq function, to easily verify
that it does all it needs to do. It needs docs for the new function in
libpq.sgml; also I wonder if checking conn->status before reporting
values is necessary; finally, has the application any good way to check
that the values can be safely read after calling the new function?
Or instead of reinventing again the wheel, why not removing
remote_hostaddr, and fetch the wanted values from PQhost() and PQport()
after making sure that the connection status is good? There is no need
for a new API this way. And as bonus points, we can also rely on
defaults.
--
Michael
On Fri, Jan 5, 2018 at 12:05 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Thu, Jan 04, 2018 at 08:54:37AM -0300, Alvaro Herrera wrote:
I think more attention should be given to the libpq side of this patch;
maybe have a 0001 with only the new libpq function, to easily verify
that it does all it needs to do. It needs docs for the new function in
libpq.sgml; also I wonder if checking conn->status before reporting
values is necessary; finally, has the application any good way to check
that the values can be safely read after calling the new function?Or instead of reinventing again the wheel, why not removing
remote_hostaddr, and fetch the wanted values from PQhost() and PQport()
after making sure that the connection status is good? There is no need
for a new API this way. And as bonus points, we can also rely on
defaults.
PQhost() doesn't provide the proper details even if we remove the
remote_hostaddr. For example with the following conninfo,
host=host1,host2 hostaddr=127.0.0.1,127.0.0.1 port=5434,5432
The connection type for both address of the above conninfo is
CHT_HOST_ADDRESS. so the PQhost() returns the conn->pghost
value i.e "host1,host2". That returned value doesn't give the clarity to
which host it is exactly connected. Because of this reason only, I came
up with a new function.
How about changing the PQhost() function behavior? Instead of checking
the connection type, checking whether there exists any host name or not?
And also not returning "default host" details, because for the conninfo
without any host details, the return value must be NULL. But this change
may break the backward compatibility of the function.
or
write two new functions PQconnhost() and PQconnhostaddr() to return the
connected host and hostaddr and reuse the PQport() function.
Regards,
Hari Babu
Fujitsu Australia
Haribabu Kommi wrote:
And also not returning "default host" details, because for the conninfo
without any host details, the return value must be NULL. But this change
may break the backward compatibility of the function.
I wouldn't want to have to fight that battle.
or
write two new functions PQconnhost() and PQconnhostaddr() to return the
connected host and hostaddr and reuse the PQport() function.
How about using an API similar to PQconninfo, where we return an array
of connection options used? Say, PQeffectiveConninfo(). This seems to
me to reduce ugliness in the API, and be more generally useful.
walrecvr could display as an array or just flatten to a string -- not
sure what's the better option there.
--
�lvaro Herrera https://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
On Fri, Jan 5, 2018 at 11:15 PM, Alvaro Herrera <alvherre@alvh.no-ip.org>
wrote:
Haribabu Kommi wrote:
or
write two new functions PQconnhost() and PQconnhostaddr() to return the
connected host and hostaddr and reuse the PQport() function.How about using an API similar to PQconninfo, where we return an array
of connection options used? Say, PQeffectiveConninfo(). This seems to
me to reduce ugliness in the API, and be more generally useful.
OK. Added the new API PQeffectiveConninfo() that returns all the connection
options that are actively used. Currently the connection options host,
hostaddr
and port may change based on the active connection and rest of the options
may be same.
walrecvr could display as an array or just flatten to a string -- not
sure what's the better option there.
Currently I went with a string model to display all the effective_conninfo
options. I feel if we go with string approach, adding a new option that gets
updated in future is simple.
postgres=# select conninfo, effective_conninfo from pg_stat_wal_receiver;
-[ RECORD 1 ]------+----------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
-------------------------------------------------
conninfo | user=kommih passfile=/home/kommih/.pgpass
dbname=replication hostaddr=127.0.0.1,127.0.0.1 port=5434,5432
application_name=s2 fallback_application_name=walreceiver sslmode=disable
sslcompression=1 target_session_attrs=any
effective_conninfo | user=kommih passfile=/home/kommih/.pgpass
dbname=replication hostaddr=127.0.0.1 port=5432 application_name=s2
fallback_application_name=walreceiver sslmode=disable sslcompression=1
target_session_attrs=any
Majority of the options are same in both conninfo and effective_conninfo
columns.
Instead of "effective_conninfo" column, how about something like
"remote_server"
as string that displays only the host, hostaddr and port options that
differs with
each connection?
Current set of patches are attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
0002-Effective-conninfo-column-addtion-to-pg_stat_wal_rec.patchapplication/octet-stream; name=0002-Effective-conninfo-column-addtion-to-pg_stat_wal_rec.patchDownload
From 18860d4352c50fc6beb96757145456ceeab80c74 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 8 Jan 2018 14:20:50 +1100
Subject: [PATCH 2/2] Effective conninfo column addtion to pg_stat_wal_receiver
This column provides the connection string that is
currently effective in connecting to the server from
the list of provided connection string details.
---
doc/src/sgml/monitoring.sgml | 10 +++++++-
src/backend/catalog/system_views.sql | 3 ++-
.../libpqwalreceiver/libpqwalreceiver.c | 29 ++++++++++++++++++++--
src/backend/replication/walreceiver.c | 14 +++++++++++
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 10 ++++++++
src/test/regress/expected/rules.out | 5 ++--
7 files changed, 66 insertions(+), 7 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..a1c2d5b6d3 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2026,7 +2026,15 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
<entry>
- Connection string used by this WAL receiver,
+ Initial connection string used by this WAL receiver,
+ with security-sensitive fields obfuscated.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>effective_conninfo</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Effective connection string used by this WAL receiver,
with security-sensitive fields obfuscated.
</entry>
</row>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d..6644f6cc73 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,7 +750,8 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
- s.conninfo
+ s.conninfo,
+ s.effective_conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..31c5d77659 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,7 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_effective_conninfo(WalReceiverConn *conn);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -82,6 +83,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
libpqrcv_connect,
libpqrcv_check_conninfo,
libpqrcv_get_conninfo,
+ libpqrcv_get_effective_conninfo,
libpqrcv_identify_system,
libpqrcv_readtimelinehistoryfile,
libpqrcv_startstreaming,
@@ -238,7 +240,7 @@ libpqrcv_check_conninfo(const char *conninfo)
* are obfuscated.
*/
static char *
-libpqrcv_get_conninfo(WalReceiverConn *conn)
+libpqrcv_get_conninfo_internal(WalReceiverConn *conn, bool initial)
{
PQconninfoOption *conn_opts;
PQconninfoOption *conn_opt;
@@ -248,7 +250,10 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
Assert(conn->streamConn != NULL);
initPQExpBuffer(&buf);
- conn_opts = PQconninfo(conn->streamConn);
+ if (initial)
+ conn_opts = PQconninfo(conn->streamConn);
+ else
+ conn_opts = PQeffectiveConninfo(conn->streamConn);
if (conn_opts == NULL)
ereport(ERROR,
@@ -282,6 +287,26 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
return retval;
}
+/*
+ * Return a user-displayable conninfo string. Any security-sensitive fields
+ * are obfuscated.
+ */
+static char *
+libpqrcv_get_conninfo(WalReceiverConn *conn)
+{
+ return libpqrcv_get_conninfo_internal(conn, true);
+}
+
+/*
+ * Return a user-displayable effective conninfo string.
+ * Any security-sensitive fields are obfuscated.
+ */
+static char *
+libpqrcv_get_effective_conninfo(WalReceiverConn *conn)
+{
+ return libpqrcv_get_conninfo_internal(conn, false);
+}
+
/*
* Check that primary's system identifier matches ours, and fetch the current
* timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..0f6d5ea3e0 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -189,6 +189,7 @@ WalReceiverMain(void)
{
char conninfo[MAXCONNINFO];
char *tmp_conninfo;
+ char *tmp_effective_conninfo;
char slotname[NAMEDATALEN];
XLogRecPtr startpoint;
TimeLineID startpointTLI;
@@ -311,10 +312,17 @@ WalReceiverMain(void)
* conninfo, for security.
*/
tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_effective_conninfo = walrcv_get_effective_conninfo(wrconn);
+
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->effective_conninfo, 0, MAXCONNINFO);
+ if (tmp_effective_conninfo)
+ strlcpy((char *) walrcv->effective_conninfo, tmp_effective_conninfo, MAXCONNINFO);
+
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
@@ -1404,6 +1412,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz latest_end_time;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
+ char effective_conninfo[MAXCONNINFO];
/* Take a lock to ensure value consistency */
SpinLockAcquire(&WalRcv->mutex);
@@ -1420,6 +1429,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
+ strlcpy(effective_conninfo, (char *) WalRcv->effective_conninfo, sizeof(effective_conninfo));
SpinLockRelease(&WalRcv->mutex);
/*
@@ -1486,6 +1496,10 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[11] = true;
else
values[11] = CStringGetTextDatum(conninfo);
+ if (*effective_conninfo == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(effective_conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 298e0ae2f0..c883bfda17 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo,effective_conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..92f56b6834 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -108,6 +108,12 @@ typedef struct
*/
char conninfo[MAXCONNINFO];
+ /*
+ * connection string; effectively used to connect to the primary, and later
+ * clobbered to hide security-sensitive fields.
+ */
+ char effective_conninfo[MAXCONNINFO];
+
/*
* replication slot name; is also used for walreceiver to connect with the
* primary
@@ -197,6 +203,7 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_effective_conninfo_fn) (WalReceiverConn *conn);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -227,6 +234,7 @@ typedef struct WalReceiverFunctionsType
walrcv_connect_fn walrcv_connect;
walrcv_check_conninfo_fn walrcv_check_conninfo;
walrcv_get_conninfo_fn walrcv_get_conninfo;
+ walrcv_get_effective_conninfo_fn walrcv_get_effective_conninfo;
walrcv_identify_system_fn walrcv_identify_system;
walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +254,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_effective_conninfo(conn) \
+ WalReceiverFunctions->walrcv_get_effective_conninfo(conn)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..3712a0d62f 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,9 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
- s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ s.conninfo,
+ s.effective_conninfo
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo, effective_conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
0001-Addition-of-new-libpq-API-PQeffectiveconninfo.patchapplication/octet-stream; name=0001-Addition-of-new-libpq-API-PQeffectiveconninfo.patchDownload
From e47b3a7d9aa6198a85a6322727b17f083bb25499 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 8 Jan 2018 12:03:46 +1100
Subject: [PATCH 1/2] Addition of new libpq API PQeffectiveconninfo
PQeffectiveConninfo is a new API which is similar like
PQconninfo, but it provides the effectively used connection
options in the current connection. As of now the connection
options host, hostaddr and port number can change according
to the connection and rest of the parameters are same.
---
doc/src/sgml/libpq.sgml | 25 +++++++++++++++++
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 56 +++++++++++++++++++++++++++++++++++++++
src/interfaces/libpq/libpq-fe.h | 3 +++
4 files changed, 85 insertions(+)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 4e4645136c..c85094fa98 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -541,6 +541,31 @@ PQconninfoOption *PQconninfo(PGconn *conn);
</listitem>
</varlistentry>
+ <varlistentry id="libpq-pqeffectiveconninfo">
+ <term><function>PQeffectiveConninfo</function><indexterm><primary>PQeffectiveConninfo</primary></indexterm></term>
+ <listitem>
+ <para>
+ Returns the effective connection options used by a live connection.
+<synopsis>
+PQconninfoOption *PQeffectiveConninfo(PGconn *conn);
+</synopsis>
+ </para>
+
+ <para>
+ Returns a connection options array similar like <function>PQconninfo</function>.
+ But this function returns the effective connection options and the
+ values that were used to connect to the server. As of now the connection
+ options host name, host IP address and port numbers can change according
+ to the effective connection to the server. The return value points to an
+ array of <structname>PQconninfoOption</structname> structures, which ends
+ with an entry having a null <structfield>keyword</structfield> pointer.
+ All notes above for <function>PQconndefaults</function> also apply to the
+ result of <function>PQeffectiveConninfo</function>.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-pqconninfoparse">
<term><function>PQconninfoParse</function><indexterm><primary>PQconninfoParse</primary></indexterm></term>
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..1ca9029bdd 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQeffectiveConninfo 173
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..a1dd8040d2 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -5960,6 +5960,62 @@ PQconninfo(PGconn *conn)
return connOptions;
}
+/*
+ * Return the effective connection options used for the connection
+ *
+ * This function is similar like PQconninfo, but it provides the
+ * effectively used connection options in the current connection.
+ *
+ * As of now the connection options host, hostaddr and port number
+ * can change according to the connection and rest of the parameters
+ * are same.
+ */
+PQconninfoOption *
+PQeffectiveConninfo(PGconn *conn)
+{
+ PQExpBufferData errorBuf;
+ PQconninfoOption *connOptions;
+
+ if (conn == NULL)
+ return NULL;
+
+ /* We don't actually report any errors here, but callees want a buffer */
+ initPQExpBuffer(&errorBuf);
+ if (PQExpBufferDataBroken(errorBuf))
+ return NULL; /* out of memory already :-( */
+
+ connOptions = conninfo_init(&errorBuf);
+
+ if (connOptions != NULL)
+ {
+ const internalPQconninfoOption *option;
+
+ for (option = PQconninfoOptions; option->keyword; option++)
+ {
+ char **connmember;
+
+ if (option->connofs < 0)
+ continue;
+
+ if (strcmp(option->keyword, "host") == 0)
+ connmember = &conn->connhost[conn->whichhost].host;
+ else if (strcmp(option->keyword, "hostaddr") == 0)
+ connmember = &conn->connhost[conn->whichhost].hostaddr;
+ else if (strcmp(option->keyword, "port") == 0)
+ connmember = &conn->connhost[conn->whichhost].port;
+ else
+ connmember = (char **) ((char *) conn + option->connofs);
+
+ if (*connmember)
+ conninfo_storeval(connOptions, option->keyword, *connmember,
+ &errorBuf, true, false);
+ }
+ }
+
+ termPQExpBuffer(&errorBuf);
+
+ return connOptions;
+}
void
PQconninfoFree(PQconninfoOption *connOptions)
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..1a500dc2a3 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -281,6 +281,9 @@ extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);
/* return the connection options used by a live connection */
extern PQconninfoOption *PQconninfo(PGconn *conn);
+/* return the effective connection options used by a live connection */
+extern PQconninfoOption *PQeffectiveConninfo(PGconn *conn);
+
/* free the data structure returned by PQconndefaults() or PQconninfoParse() */
extern void PQconninfoFree(PQconninfoOption *connOptions);
--
2.15.0.windows.1
On Fri, Jan 05, 2018 at 09:15:36AM -0300, Alvaro Herrera wrote:
Haribabu Kommi wrote:
And also not returning "default host" details, because for the conninfo
without any host details, the return value must be NULL. But this change
may break the backward compatibility of the function.I wouldn't want to have to fight that battle.
Hm. Any users of psql's PROMPT would be equally confused, and this can
actually lead to more confusion from the user prospective I think than
just pg_stat_wal_receiver. If you take the case of Haribabu from
upthread with say this bit in psqlrc:
\set PROMPT1 '[host=%M;port=%>]=%# '
Then you get on HEAD the following set of results using different
connection strings:
1) host=localhost,localhost hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=localhost,localhost;port=5432]=#
2) host=localhost,localhost port=5432,5433
[host=localhost;port=5432]=#
3) hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=[local];port=5432]=#
4) host=/tmp,tmp hostaddr=127.0.0.1,127.0.0.1
[host=[local:/tmp,tmp];port=5432]=#
So for cases 2) and 4), mixing both hostaddr and host is hurting the
experience. The documentation in [1]https://www.postgresql.org/docs/current/static/libpq-connect.html -- Michael also specifies that if both host
and hostaddrs are specified then host is ignored. The same rule applies
for multiple values so for 2) and 4) the correct values ought to be
"local" for both of them. This would be more consistent with the pre-9.6
behavior as well.
[1]: https://www.postgresql.org/docs/current/static/libpq-connect.html -- Michael
--
Michael
On Tue, Jan 9, 2018 at 12:15 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Fri, Jan 05, 2018 at 09:15:36AM -0300, Alvaro Herrera wrote:
Haribabu Kommi wrote:
And also not returning "default host" details, because for the conninfo
without any host details, the return value must be NULL. But thischange
may break the backward compatibility of the function.
I wouldn't want to have to fight that battle.
Hm. Any users of psql's PROMPT would be equally confused, and this can
actually lead to more confusion from the user prospective I think than
just pg_stat_wal_receiver. If you take the case of Haribabu from
upthread with say this bit in psqlrc:
\set PROMPT1 '[host=%M;port=%>]=%# 'Then you get on HEAD the following set of results using different
connection strings:
1) host=localhost,localhost hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=localhost,localhost;port=5432]=#2) host=localhost,localhost port=5432,5433
[host=localhost;port=5432]=#3) hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=[local];port=5432]=#4) host=/tmp,tmp hostaddr=127.0.0.1,127.0.0.1
[host=[local:/tmp,tmp];port=5432]=#So for cases 2) and 4), mixing both hostaddr and host is hurting the
experience. The documentation in [1] also specifies that if both host
and hostaddrs are specified then host is ignored. The same rule applies
for multiple values so for 2) and 4) the correct values ought to be
"local" for both of them. This would be more consistent with the pre-9.6
behavior as well.
I think you mean to say for the cases 1) and 4)? because those are the
cases where it differs with pre-9.6 behavior. With the attached patch
of changing PQhost() to return the host if exists, irrespective of the
connection type will bring back the pre-9.6 behavior.
1) host=localhost,localhost hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=localhost;port=5432]=#
4) host=/tmp,tmp hostaddr=127.0.0.1,127.0.0.1
[host=[local];port=5432]=#
Even for default unix domain socket connection,
conn->connhost[conn->whichhost].host
is filled with the details, but not the global member. So no need of
checking global member and returning the same in PQhost() function.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
PQhost-update-to-return-proper-host-details.patchapplication/octet-stream; name=PQhost-update-to-return-proper-host-details.patchDownload
From e91c1c0da6cbb987ef57abf01d420ea863a041a6 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Wed, 10 Jan 2018 15:33:25 +1100
Subject: [PATCH] PQhost update to return proper host details
Earlier PQhost doesn't return the connected host details
when the connection type is CHT_HOST_ADDRESS instead it
returns the provided connection host parameter or the default
host details.
Providing specified connection host parameter or default host
leads to use confusion, it is better to provide the host details
of the connected host irrespective of the connection type
if exists.
---
src/interfaces/libpq/fe-connect.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..886d042f91 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6018,10 +6018,9 @@ PQhost(const PGconn *conn)
if (!conn)
return NULL;
if (conn->connhost != NULL &&
- conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS)
+ conn->connhost[conn->whichhost].host != NULL &&
+ conn->connhost[conn->whichhost].host[0] != '\0')
return conn->connhost[conn->whichhost].host;
- else if (conn->pghost != NULL && conn->pghost[0] != '\0')
- return conn->pghost;
else
{
#ifdef HAVE_UNIX_SOCKETS
--
2.15.0.windows.1
On Wed, Jan 10, 2018 at 04:10:35PM +1100, Haribabu Kommi wrote:
On Tue, Jan 9, 2018 at 12:15 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:Hm. Any users of psql's PROMPT would be equally confused, and this can
actually lead to more confusion from the user prospective I think than
just pg_stat_wal_receiver. If you take the case of Haribabu from
upthread with say this bit in psqlrc:
\set PROMPT1 '[host=%M;port=%>]=%# 'Then you get on HEAD the following set of results using different
connection strings:
1) host=localhost,localhost hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=localhost,localhost;port=5432]=#2) host=localhost,localhost port=5432,5433
[host=localhost;port=5432]=#3) hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=[local];port=5432]=#4) host=/tmp,tmp hostaddr=127.0.0.1,127.0.0.1
[host=[local:/tmp,tmp];port=5432]=#So for cases 2) and 4), mixing both hostaddr and host is hurting the
experience. The documentation in [1] also specifies that if both host
and hostaddrs are specified then host is ignored. The same rule applies
for multiple values so for 2) and 4) the correct values ought to be
"local" for both of them. This would be more consistent with the pre-9.6
behavior as well.I think you mean to say for the cases 1) and 4)? because those are the
cases where it differs with pre-9.6 behavior.
Sure, sorry for the mistake. That's indeed what I meant.
With the attached patch of changing PQhost() to return the host if
exists, irrespective of the connection type will bring back the
pre-9.6 behavior.1) host=localhost,localhost hostaddr=127.0.0.1,127.0.0.1 port=5432,5433
[host=localhost;port=5432]=#4) host=/tmp,tmp hostaddr=127.0.0.1,127.0.0.1
[host=[local];port=5432]=#Even for default unix domain socket connection,
conn->connhost[conn->whichhost].host
is filled with the details, but not the global member. So no need of
checking global member and returning the same in PQhost() function.
Thanks for the patch and the investigation, this visibly points out to
the fact that 11003eb5 did not get it completely right either. I am
adding Robert in CC for some input on the matter. To me, this looks like
a bug that should be applied down to v10. I think that it would be better
to spawn a new thread as well to raise awareness on the matter. This is
quite different than the patch you are presenting here. What do you
think?
I have redone my set of previous tests and can confirm that PQhost is
behaving as I would expect it should, and those results are the same as
yours.
With your patch, please note also that the SSL test suite does not
complain, which is an excellent thing!
--
Michael
On Fri, Jan 12, 2018 at 11:37:22AM +0900, Michael Paquier wrote:
I have redone my set of previous tests and can confirm that PQhost is
behaving as I would expect it should, and those results are the same as
yours.
if (conn->connhost != NULL &&
- conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS)
+ conn->connhost[conn->whichhost].host != NULL &&
+ conn->connhost[conn->whichhost].host[0] != '\0')
return conn->connhost[conn->whichhost].host;
- else if (conn->pghost != NULL && conn->pghost[0] != '\0')
- return conn->pghost;
Upon further review, the second bit of the patch is making me itching. I
think that you should not remove the second check which returns
conn->pghost if a value is found in it.
--
Michael
On Fri, Jan 12, 2018 at 3:26 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Fri, Jan 12, 2018 at 11:37:22AM +0900, Michael Paquier wrote:
I have redone my set of previous tests and can confirm that PQhost is
behaving as I would expect it should, and those results are the same as
yours.if (conn->connhost != NULL && - conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS) + conn->connhost[conn->whichhost].host != NULL && + conn->connhost[conn->whichhost].host[0] != '\0') return conn->connhost[conn->whichhost].host; - else if (conn->pghost != NULL && conn->pghost[0] != '\0') - return conn->pghost;Upon further review, the second bit of the patch is making me itching. I
think that you should not remove the second check which returns
conn->pghost if a value is found in it.
Thanks for the review.
Before posting the patch, first I did the same, upon further study
I didn't find any scenario where the value is not present in
conn->connhost[conn->whichhost].host and present in conn->pghost.
If user provides "host" as connection option, the value is present
in both the variables. Even if the connection is unix domain socket,
there is a value in conn->connhost[conn->whichhost].host.
In case if user provides only hostaddr and host connection option,
then in that case, both the members are NULL. So even if we add
that case, it will be dead code.
I agree with your opinion of creating a new thread of this discussion.
Regards,
Hari Babu
Fujitsu Australia
On Fri, Jan 12, 2018 at 03:55:04PM +1100, Haribabu Kommi wrote:
Before posting the patch, first I did the same, upon further study
I didn't find any scenario where the value is not present in
conn->connhost[conn->whichhost].host and present in conn->pghost.If user provides "host" as connection option, the value is present
in both the variables. Even if the connection is unix domain socket,
there is a value in conn->connhost[conn->whichhost].host.In case if user provides only hostaddr and host connection option,
then in that case, both the members are NULL. So even if we add
that case, it will be dead code.
Hm. Wouldn't it matter for cases where caller has not yet established a
connection to the server but still calls PQhost to get the host string?
--
Michael
On Fri, Jan 12, 2018 at 4:06 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Fri, Jan 12, 2018 at 03:55:04PM +1100, Haribabu Kommi wrote:
Before posting the patch, first I did the same, upon further study
I didn't find any scenario where the value is not present in
conn->connhost[conn->whichhost].host and present in conn->pghost.If user provides "host" as connection option, the value is present
in both the variables. Even if the connection is unix domain socket,
there is a value in conn->connhost[conn->whichhost].host.In case if user provides only hostaddr and host connection option,
then in that case, both the members are NULL. So even if we add
that case, it will be dead code.Hm. Wouldn't it matter for cases where caller has not yet established a
connection to the server but still calls PQhost to get the host string?
Yes I agree that the above scenario leads to a wrong result with the
earlier patch,
Updated patch attached by including the conn->pghost. Thanks for the review.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
PQhost-update-to-return-proper-host-details_v2.patchapplication/octet-stream; name=PQhost-update-to-return-proper-host-details_v2.patchDownload
From 7c5e76f0b00fde298563a694268333129658bc02 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Fri, 12 Jan 2018 16:29:14 +1100
Subject: [PATCH] PQhost update to return proper host details
Earlier PQhost doesn't return the connected host details
when the connection type is CHT_HOST_ADDRESS instead it
returns the provided connection host parameter or the default
host details.
Providing specified connection host parameter or default host
leads to use confusion, it is better to provide the host details
of the connected host irrespective of the connection type
if exists.
---
src/interfaces/libpq/fe-connect.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..bad7769fe0 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6018,7 +6018,8 @@ PQhost(const PGconn *conn)
if (!conn)
return NULL;
if (conn->connhost != NULL &&
- conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS)
+ conn->connhost[conn->whichhost].host != NULL &&
+ conn->connhost[conn->whichhost].host[0] != '\0')
return conn->connhost[conn->whichhost].host;
else if (conn->pghost != NULL && conn->pghost[0] != '\0')
return conn->pghost;
--
2.15.0.windows.1
On Fri, Jan 12, 2018 at 04:32:54PM +1100, Haribabu Kommi wrote:
On Fri, Jan 12, 2018 at 4:06 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:On Fri, Jan 12, 2018 at 03:55:04PM +1100, Haribabu Kommi wrote:
Before posting the patch, first I did the same, upon further study
I didn't find any scenario where the value is not present in
conn->connhost[conn->whichhost].host and present in conn->pghost.If user provides "host" as connection option, the value is present
in both the variables. Even if the connection is unix domain socket,
there is a value in conn->connhost[conn->whichhost].host.In case if user provides only hostaddr and host connection option,
then in that case, both the members are NULL. So even if we add
that case, it will be dead code.Hm. Wouldn't it matter for cases where caller has not yet established a
connection to the server but still calls PQhost to get the host string?Yes I agree that the above scenario leads to a wrong result with the
earlier patch,
Updated patch attached by including the conn->pghost. Thanks for the review.
Could you begin a new thread by the way? As you are the one who
discovered the inconsistency and the one who wrote a patch this looks
adapted to me. Or perhaps I should?
--
Michael
On Mon, Jan 8, 2018 at 3:32 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:
On Fri, Jan 5, 2018 at 11:15 PM, Alvaro Herrera <alvherre@alvh.no-ip.org>
wrote:Haribabu Kommi wrote:
or
write two new functions PQconnhost() and PQconnhostaddr() to return the
connected host and hostaddr and reuse the PQport() function.How about using an API similar to PQconninfo, where we return an array
of connection options used? Say, PQeffectiveConninfo(). This seems to
me to reduce ugliness in the API, and be more generally useful.OK. Added the new API PQeffectiveConninfo() that returns all the connection
options that are actively used. Currently the connection options host,
hostaddr
and port may change based on the active connection and rest of the options
may be same.walrecvr could display as an array or just flatten to a string -- not
sure what's the better option there.
Currently I went with a string model to display all the effective_conninfo
options. I feel if we go with string approach, adding a new option that
gets
updated in future is simple.postgres=# select conninfo, effective_conninfo from pg_stat_wal_receiver;
-[ RECORD 1 ]------+----------------------------------------------------
------------------------------------------------------------
------------------------------------------------------------
-------------------------------------------------
conninfo | user=kommih passfile=/home/kommih/.pgpass
dbname=replication hostaddr=127.0.0.1,127.0.0.1 port=5434,5432
application_name=s2 fallback_application_name=walreceiver sslmode=disable
sslcompression=1 target_session_attrs=any
effective_conninfo | user=kommih passfile=/home/kommih/.pgpass
dbname=replication hostaddr=127.0.0.1 port=5432 application_name=s2
fallback_application_name=walreceiver sslmode=disable sslcompression=1
target_session_attrs=anyMajority of the options are same in both conninfo and effective_conninfo
columns.
Instead of "effective_conninfo" column, how about something like
"remote_server"
as string that displays only the host, hostaddr and port options that
differs with
each connection?
Instead of effective_conninfo, I changed the column name as
remote_serve_info and
display only the host, hostaddr and port details. These are the only values
that differs
with each remote connection.
patches attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
0001-Addition-of-new-libpq-API-PQeffectiveconninfo.patchapplication/octet-stream; name=0001-Addition-of-new-libpq-API-PQeffectiveconninfo.patchDownload
From 78f4a84f095b623bb238f3595d24b4a0fe366b7c Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 8 Jan 2018 12:03:46 +1100
Subject: [PATCH 1/2] Addition of new libpq API PQeffectiveconninfo
PQeffectiveConninfo is a new API which is similar like
PQconninfo, but it provides the effectively used connection
options in the current connection. As of now the connection
options host, hostaddr and port number can change according
to the connection and rest of the parameters are same.
---
doc/src/sgml/libpq.sgml | 25 +++++++++++++++++
src/interfaces/libpq/exports.txt | 1 +
src/interfaces/libpq/fe-connect.c | 56 +++++++++++++++++++++++++++++++++++++++
src/interfaces/libpq/libpq-fe.h | 3 +++
4 files changed, 85 insertions(+)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 4e4645136c..c85094fa98 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -541,6 +541,31 @@ PQconninfoOption *PQconninfo(PGconn *conn);
</listitem>
</varlistentry>
+ <varlistentry id="libpq-pqeffectiveconninfo">
+ <term><function>PQeffectiveConninfo</function><indexterm><primary>PQeffectiveConninfo</primary></indexterm></term>
+ <listitem>
+ <para>
+ Returns the effective connection options used by a live connection.
+<synopsis>
+PQconninfoOption *PQeffectiveConninfo(PGconn *conn);
+</synopsis>
+ </para>
+
+ <para>
+ Returns a connection options array similar like <function>PQconninfo</function>.
+ But this function returns the effective connection options and the
+ values that were used to connect to the server. As of now the connection
+ options host name, host IP address and port numbers can change according
+ to the effective connection to the server. The return value points to an
+ array of <structname>PQconninfoOption</structname> structures, which ends
+ with an entry having a null <structfield>keyword</structfield> pointer.
+ All notes above for <function>PQconndefaults</function> also apply to the
+ result of <function>PQeffectiveConninfo</function>.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-pqconninfoparse">
<term><function>PQconninfoParse</function><indexterm><primary>PQconninfoParse</primary></indexterm></term>
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..1ca9029bdd 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,4 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQeffectiveConninfo 173
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8d543334ae..a1dd8040d2 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -5960,6 +5960,62 @@ PQconninfo(PGconn *conn)
return connOptions;
}
+/*
+ * Return the effective connection options used for the connection
+ *
+ * This function is similar like PQconninfo, but it provides the
+ * effectively used connection options in the current connection.
+ *
+ * As of now the connection options host, hostaddr and port number
+ * can change according to the connection and rest of the parameters
+ * are same.
+ */
+PQconninfoOption *
+PQeffectiveConninfo(PGconn *conn)
+{
+ PQExpBufferData errorBuf;
+ PQconninfoOption *connOptions;
+
+ if (conn == NULL)
+ return NULL;
+
+ /* We don't actually report any errors here, but callees want a buffer */
+ initPQExpBuffer(&errorBuf);
+ if (PQExpBufferDataBroken(errorBuf))
+ return NULL; /* out of memory already :-( */
+
+ connOptions = conninfo_init(&errorBuf);
+
+ if (connOptions != NULL)
+ {
+ const internalPQconninfoOption *option;
+
+ for (option = PQconninfoOptions; option->keyword; option++)
+ {
+ char **connmember;
+
+ if (option->connofs < 0)
+ continue;
+
+ if (strcmp(option->keyword, "host") == 0)
+ connmember = &conn->connhost[conn->whichhost].host;
+ else if (strcmp(option->keyword, "hostaddr") == 0)
+ connmember = &conn->connhost[conn->whichhost].hostaddr;
+ else if (strcmp(option->keyword, "port") == 0)
+ connmember = &conn->connhost[conn->whichhost].port;
+ else
+ connmember = (char **) ((char *) conn + option->connofs);
+
+ if (*connmember)
+ conninfo_storeval(connOptions, option->keyword, *connmember,
+ &errorBuf, true, false);
+ }
+ }
+
+ termPQExpBuffer(&errorBuf);
+
+ return connOptions;
+}
void
PQconninfoFree(PQconninfoOption *connOptions)
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..1a500dc2a3 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -281,6 +281,9 @@ extern PQconninfoOption *PQconninfoParse(const char *conninfo, char **errmsg);
/* return the connection options used by a live connection */
extern PQconninfoOption *PQconninfo(PGconn *conn);
+/* return the effective connection options used by a live connection */
+extern PQconninfoOption *PQeffectiveConninfo(PGconn *conn);
+
/* free the data structure returned by PQconndefaults() or PQconninfoParse() */
extern void PQconninfoFree(PQconninfoOption *connOptions);
--
2.15.0.windows.1
0002-remote_server_info-column-addtion-to-pg_stat_wal_rec.patchapplication/octet-stream; name=0002-remote_server_info-column-addtion-to-pg_stat_wal_rec.patchDownload
From f32c4a3edbc49440305cc4edf775121147e6e259 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 8 Jan 2018 14:20:50 +1100
Subject: [PATCH 2/2] remote_server_info column addtion to pg_stat_wal_receiver
This column provides the remote server information of
the WAL receiver connection to the remote host.
---
doc/src/sgml/monitoring.sgml | 9 ++++-
src/backend/catalog/system_views.sql | 1 +
.../libpqwalreceiver/libpqwalreceiver.c | 44 ++++++++++++++++++++++
src/backend/replication/walreceiver.c | 21 ++++++++++-
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 10 +++++
src/test/regress/expected/rules.out | 3 +-
7 files changed, 85 insertions(+), 5 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..9a6aac45f5 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,11 +2022,18 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_server_info</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Effective remote server connection info string used by this WAL receiver.
+ </entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
<entry>
- Connection string used by this WAL receiver,
+ Initial connection string used by this WAL receiver,
with security-sensitive fields obfuscated.
</entry>
</row>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d..b0f74ed9bc 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,7 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_server_info,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..488c1c2dde 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,7 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static char *libpqrcv_get_remote_server_info(WalReceiverConn *conn);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -82,6 +83,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
libpqrcv_connect,
libpqrcv_check_conninfo,
libpqrcv_get_conninfo,
+ libpqrcv_get_remote_server_info,
libpqrcv_identify_system,
libpqrcv_readtimelinehistoryfile,
libpqrcv_startstreaming,
@@ -282,6 +284,47 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
return retval;
}
+/*
+ * Return a user-displayable remote server information.
+ */
+static char *
+libpqrcv_get_remote_server_info(WalReceiverConn *conn)
+{
+ PQconninfoOption *conn_opts;
+ PQconninfoOption *conn_opt;
+ PQExpBufferData buf;
+ char *retval;
+
+ Assert(conn->streamConn != NULL);
+
+ initPQExpBuffer(&buf);
+ conn_opts = PQeffectiveConninfo(conn->streamConn);
+
+ if (conn_opts == NULL)
+ ereport(ERROR,
+ (errmsg("could not parse connection string: %s",
+ _("out of memory"))));
+
+ /* build a clean connection string from pieces */
+ for (conn_opt = conn_opts; conn_opt->keyword != NULL; conn_opt++)
+ {
+ if ((strcmp(conn_opt->keyword, "host") == 0) ||
+ (strcmp(conn_opt->keyword, "hostaddr") == 0) ||
+ (strcmp(conn_opt->keyword, "port") == 0))
+ {
+ appendPQExpBuffer(&buf, "%s%s=%s",
+ buf.len == 0 ? "" : " ",
+ conn_opt->keyword, conn_opt->val);
+ }
+ }
+
+ PQconninfoFree(conn_opts);
+
+ retval = PQExpBufferDataBroken(buf) ? NULL : pstrdup(buf.data);
+ termPQExpBuffer(&buf);
+ return retval;
+}
+
/*
* Check that primary's system identifier matches ours, and fetch the current
* timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..b93b843b2d 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -189,6 +190,7 @@ WalReceiverMain(void)
{
char conninfo[MAXCONNINFO];
char *tmp_conninfo;
+ char *tmp_remote_server_info;
char slotname[NAMEDATALEN];
XLogRecPtr startpoint;
TimeLineID startpointTLI;
@@ -311,16 +313,25 @@ WalReceiverMain(void)
* conninfo, for security.
*/
tmp_conninfo = walrcv_get_conninfo(wrconn);
+ tmp_remote_server_info = walrcv_get_remote_server_info(wrconn);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->remote_server_info, 0, MAXCONNINFO);
+ if (tmp_remote_server_info)
+ strlcpy((char *) walrcv->remote_server_info, tmp_remote_server_info, MAXCONNINFO);
+
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
if (tmp_conninfo)
pfree(tmp_conninfo);
+ if (tmp_remote_server_info)
+ pfree(tmp_remote_server_info);
+
first_stream = true;
for (;;)
{
@@ -1404,6 +1415,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz latest_end_time;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
+ char remote_server_info[MAXCONNINFO];
/* Take a lock to ensure value consistency */
SpinLockAcquire(&WalRcv->mutex);
@@ -1419,6 +1431,7 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(remote_server_info, (char *) WalRcv->remote_server_info, sizeof(remote_server_info));
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1482,10 +1495,14 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*remote_server_info == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(remote_server_info);
+ if (*conninfo == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 298e0ae2f0..f043d88797 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_server_info,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..2f0f33ad03 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -108,6 +108,12 @@ typedef struct
*/
char conninfo[MAXCONNINFO];
+ /*
+ * connection string; effectively used to connect to the primary, and later
+ * clobbered to hide security-sensitive fields.
+ */
+ char remote_server_info[MAXCONNINFO];
+
/*
* replication slot name; is also used for walreceiver to connect with the
* primary
@@ -197,6 +203,7 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef char *(*walrcv_get_remote_server_info_fn) (WalReceiverConn *conn);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -227,6 +234,7 @@ typedef struct WalReceiverFunctionsType
walrcv_connect_fn walrcv_connect;
walrcv_check_conninfo_fn walrcv_check_conninfo;
walrcv_get_conninfo_fn walrcv_get_conninfo;
+ walrcv_get_remote_server_info_fn walrcv_get_remote_server_info;
walrcv_identify_system_fn walrcv_identify_system;
walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +254,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_remote_server_info(conn) \
+ WalReceiverFunctions->walrcv_get_remote_server_info(conn)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index f1c1b44d6f..5d757c141e 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,9 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_server_info,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_server_info, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
[ Including Hackers as earlier mail mistakenly removed it ]
On Tue, Jan 16, 2018 at 2:55 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Mon, Jan 15, 2018 at 05:51:58PM +1100, Haribabu Kommi wrote:
Instead of effective_conninfo, I changed the column name as
remote_serve_info and
display only the host, hostaddr and port details. These are the onlyvalues
that differs
with each remote connection.I agree that it is pointless to show duplication between both
strings. The differences would be made harder to catch.+PQconninfoOption * +PQeffectiveConninfo(PGconn *conn) +{ + PQExpBufferData errorBuf; + PQconninfoOption *connOptions; + + if (conn == NULL) + return NULL;Shouldn't this check for CONNECTION_BAD as well and return NULL?
OK. I will update it.
If I use something like "port=5432 host=/tmp" as connection string, then
PQeffectiveConninfo gives me the following with hostaddr being weird:
host=/tmp hostaddr=(null) port=5432
This should show an empty hostaddr value.
I will correct it.
+ <entry><structfield>remote_server_info</structfield></entry> + <entry><type>text</type></entry> + <entry> + Effective remote server connection info string used by this WAL receiver. + </entry> "Effective" is not a precise term. What about just telling that this is the set of parameters used for hte active connection, and that this value should be the one used when using multiple host, hostaddr, and ports.
OK. I will update it.
Note that I still find this API confusing, it seems to me that just
sorting out the confusion problems with PQhost and then use it would be
more simple.
OK, Understood. Even if the confusion problems with PQhost that are
discussed in [1] are solved, we need two new API's that are required to\
display the proper remote server details.
PQhostNoDefault - Similar like PQhost but doesn't return default host
details.
Displaying default value always some confuse even if the user doesn't
provide
the host details, so to avoid that confusion, we need this function.
PQhostaddr - Return hostaddr used in the connection.
Without PQhostaddr() function, for the connections where the host is not
specified, it will be difficult to find out to remote server.
With the above two new API's we can display either string or individual
columns
representation of remote server.
comments?
Regards,
Hari Babu
Fujitsu Australia
Import Notes
Reply to msg id not found: 20180116035529.GA2212@paquier.xyz
On Tue, Jan 16, 2018 at 5:56 PM, Haribabu Kommi <kommi.haribabu@gmail.com>
wrote:
On Tue, Jan 16, 2018 at 2:55 PM, Michael Paquier <
michael.paquier@gmail.com> wrote:Note that I still find this API confusing, it seems to me that just
sorting out the confusion problems with PQhost and then use it would be
more simple.OK, Understood. Even if the confusion problems with PQhost that are
discussed in [1] are solved, we need two new API's that are required to\
display the proper remote server details.PQhostNoDefault - Similar like PQhost but doesn't return default host
details.Displaying default value always some confuse even if the user doesn't
provide
the host details, so to avoid that confusion, we need this function.PQhostaddr - Return hostaddr used in the connection.
Without PQhostaddr() function, for the connections where the host is not
specified, it will be difficult to find out to remote server.With the above two new API's we can display either string or individual
columns
representation of remote server.
As I didn't hear objections, I changed the patch as per the above
description
with two new libpq API's and also with three additional columns
"remote_hostname",
"remote_hostaddr" and "remote_port" to the pg_stat_wal_receiver view.
I didn't explicitly add the CONNECTION_BAD, because the added libpq
functions
must return the value even the connection is not established.
Updated patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
0002-pg_stat_wal_receiver-to-display-connected-host.patchapplication/octet-stream; name=0002-pg_stat_wal_receiver-to-display-connected-host.patchDownload
From da30175c5c40925f229fd058052709f0b07afc47 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 15 Jan 2018 15:28:57 +1100
Subject: [PATCH 2/2] pg_stat_wal_receiver to display connected host
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of remote host information from which the replication is
streaming currently with three additional columns remote_hostname,
remote_hostaddr and remote_port.
---
doc/src/sgml/monitoring.sgml | 24 ++++++++++++
src/backend/catalog/system_views.sql | 3 ++
.../libpqwalreceiver/libpqwalreceiver.c | 27 ++++++++++++++
src/backend/replication/walreceiver.c | 43 +++++++++++++++++++++-
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 10 +++++
src/test/regress/expected/rules.out | 5 ++-
7 files changed, 110 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 8a9793644f..d8fe7c446b 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2022,6 +2022,30 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_hostname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host name of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>remote_hostaddr</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host address of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>remote_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>
+ Port number of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9ee6d..57d1f90e21 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -750,6 +750,9 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..a01e84dece 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static void libpqrcv_get_remoteserver_info(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -82,6 +84,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
libpqrcv_connect,
libpqrcv_check_conninfo,
libpqrcv_get_conninfo,
+ libpqrcv_get_remoteserver_info,
libpqrcv_identify_system,
libpqrcv_readtimelinehistoryfile,
libpqrcv_startstreaming,
@@ -282,6 +285,30 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
return retval;
}
+/*
+ * Provides effective connected remote sever connection details.
+ */
+static void
+libpqrcv_get_remoteserver_info(WalReceiverConn *conn, char **host,
+ char **hostaddr, int *port)
+{
+ char *ret = NULL;
+
+ Assert(conn->streamConn != NULL);
+
+ ret = PQhostNoDefault(conn->streamConn);
+ if (ret)
+ *host = pstrdup(ret);
+
+ ret = PQhostaddr(conn->streamConn);
+ if (ret)
+ *hostaddr = pstrdup(ret);
+
+ ret = PQport(conn->streamConn);
+ if (ret)
+ *port = atoi(ret);
+}
+
/*
* Check that primary's system identifier matches ours, and fetch the current
* timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..a5079fc6bf 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,9 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *host = NULL;
+ char *hostaddr = NULL;
+ int port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -311,16 +315,33 @@ WalReceiverMain(void)
* conninfo, for security.
*/
tmp_conninfo = walrcv_get_conninfo(wrconn);
+ walrcv_get_remoteserver_info(wrconn, &host, &hostaddr, &port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->host, 0, NI_MAXHOST);
+ if (host)
+ strlcpy((char *) walrcv->host, host, NI_MAXHOST);
+
+ memset(walrcv->hostaddr, 0, NI_MAXHOST);
+ if (hostaddr)
+ strlcpy((char *) walrcv->hostaddr, hostaddr, NI_MAXHOST);
+
+ walrcv->port = port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
if (tmp_conninfo)
pfree(tmp_conninfo);
+ if (host)
+ pfree(host);
+
+ if (hostaddr)
+ pfree(hostaddr);
+
first_stream = true;
for (;;)
{
@@ -1402,6 +1423,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1443,9 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(host, (char *) WalRcv->host, sizeof(host));
+ strlcpy(hostaddr, (char *) WalRcv->hostaddr, sizeof(hostaddr));
+ port = WalRcv->port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1482,10 +1509,22 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(host);
+ if (*hostaddr == '\0')
+ nulls[12] = true;
+ else
+ values[12] = CStringGetTextDatum(hostaddr);
+ if (port == 0)
+ nulls[13] = true;
+ else
+ values[13] = Int32GetDatum(port);
+ if (*conninfo == '\0')
+ nulls[14] = true;
+ else
+ values[14] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index f01648c961..b6c2e474ad 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2883,7 +2883,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_hostname,remote_hostaddr,remote_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..35783be820 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,9 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char host[NI_MAXHOST];
+ char hostaddr[NI_MAXHOST];
+ int port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -197,6 +200,10 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef void (*walrcv_get_remoteserver_info_fn) (WalReceiverConn *conn,
+ char **host,
+ char **hostaddr,
+ int *port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -227,6 +234,7 @@ typedef struct WalReceiverFunctionsType
walrcv_connect_fn walrcv_connect;
walrcv_check_conninfo_fn walrcv_check_conninfo;
walrcv_get_conninfo_fn walrcv_get_conninfo;
+ walrcv_get_remoteserver_info_fn walrcv_get_remoteserver_info;
walrcv_identify_system_fn walrcv_identify_system;
walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +254,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_remoteserver_info(conn, host, hostaddr, port) \
+ WalReceiverFunctions->walrcv_get_remoteserver_info(conn, host, hostaddr, port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5433944c6a..2ddf8c7674 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1970,8 +1970,11 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_hostname,
+ s.remote_hostaddr,
+ s.remote_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_hostname, remote_hostaddr, remote_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.15.0.windows.1
0001-Addition-of-two-new-libpq-API-s.patchapplication/octet-stream; name=0001-Addition-of-two-new-libpq-API-s.patchDownload
From 6557b564a1597883a074540bddecdc159678e372 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Sun, 14 Jan 2018 15:59:03 +1100
Subject: [PATCH 1/2] Addition of two new libpq API's
PQhostNoDefault is a new API which is similar like PQhost,
but it doesn't return the default host name.
PQhostaddr is a new API which is similar like PQhost,
but it returns the server host address of the connection or
NULL
---
doc/src/sgml/libpq.sgml | 41 ++++++++++++++++++++++++++++++++++++
src/interfaces/libpq/exports.txt | 2 ++
src/interfaces/libpq/fe-connect.c | 44 ++++++++++++++++++++++++++++++++++-----
src/interfaces/libpq/libpq-fe.h | 2 ++
4 files changed, 84 insertions(+), 5 deletions(-)
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 02884bae1f..ae6250640a 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1621,6 +1621,47 @@ char *PQhost(const PGconn *conn);
</listitem>
</varlistentry>
+ <varlistentry id="libpq-pqhostnodefault">
+ <term>
+ <function>PQhostNoDefault</function>
+ <indexterm>
+ <primary>PQhostNoDefault</primary>
+ </indexterm>
+ </term>
+
+ <listitem>
+ <para>
+ Returns the server host name of the connection or NULL if there is
+ no host name associated with the connection. This can be a host name,
+ an IP address, or a directory path if the connection is via Unix socket.
+ (The path case can be distinguished because it will always be an
+ absolute path, beginning with <literal>/</literal>.)
+<synopsis>
+char *PQhostNoDefault(const PGconn *conn);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry id="libpq-pqhostaddr">
+ <term>
+ <function>PQhostaddr</function>
+ <indexterm>
+ <primary>PQhostaddr</primary>
+ </indexterm>
+ </term>
+
+ <listitem>
+ <para>
+ Returns the server host address of the connection.
+
+<synopsis>
+char *PQhostaddr(const PGconn *conn);
+</synopsis>
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry id="libpq-pqport">
<term>
<function>PQport</function>
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index d6a38d0df8..94581e73b4 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -172,3 +172,5 @@ PQsslAttribute 169
PQsetErrorContextVisibility 170
PQresultVerboseErrorMessage 171
PQencryptPasswordConn 172
+PQhostNoDefault 173
+PQhostaddr 174
\ No newline at end of file
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 77eebb0ba1..174c8f98db 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -6015,13 +6015,15 @@ PQpass(const PGconn *conn)
char *
PQhost(const PGconn *conn)
{
+ char *host;
+
if (!conn)
return NULL;
- if (conn->connhost != NULL &&
- conn->connhost[conn->whichhost].type != CHT_HOST_ADDRESS)
- return conn->connhost[conn->whichhost].host;
- else if (conn->pghost != NULL && conn->pghost[0] != '\0')
- return conn->pghost;
+
+ host = PQhostNoDefault(conn);
+
+ if (host)
+ return host;
else
{
#ifdef HAVE_UNIX_SOCKETS
@@ -6032,6 +6034,38 @@ PQhost(const PGconn *conn)
}
}
+char *
+PQhostNoDefault(const PGconn *conn)
+{
+ if (!conn)
+ return NULL;
+ if (conn->connhost != NULL &&
+ conn->connhost[conn->whichhost].host != NULL &&
+ conn->connhost[conn->whichhost].host[0] != '\0')
+ return conn->connhost[conn->whichhost].host;
+ else if (conn->pghost != NULL && conn->pghost[0] != '\0')
+ return conn->pghost;
+ else
+ return NULL;
+}
+
+char *
+PQhostaddr(const PGconn *conn)
+{
+ if (!conn)
+ return NULL;
+ if (conn->connhost != NULL &&
+ conn->connhost[conn->whichhost].hostaddr != NULL &&
+ conn->connhost[conn->whichhost].hostaddr[0] != '\0')
+ return conn->connhost[conn->whichhost].hostaddr;
+ else if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
+ return conn->pghostaddr;
+ else
+ {
+ return NULL;
+ }
+}
+
char *
PQport(const PGconn *conn)
{
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index ed9c806861..551bcc41c0 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -312,6 +312,8 @@ extern char *PQdb(const PGconn *conn);
extern char *PQuser(const PGconn *conn);
extern char *PQpass(const PGconn *conn);
extern char *PQhost(const PGconn *conn);
+extern char *PQhostNoDefault(const PGconn *conn);
+extern char *PQhostaddr(const PGconn *conn);
extern char *PQport(const PGconn *conn);
extern char *PQtty(const PGconn *conn);
extern char *PQoptions(const PGconn *conn);
--
2.15.0.windows.1
On Tue, Jan 16, 2018 at 05:56:22PM +1100, Haribabu Kommi wrote:
Without PQhostaddr() function, for the connections where the host is not
specified, it will be difficult to find out to remote server.
That's true as well, but hostaddr should be used with host only to save
IP lookups... There are recent threads on the matter, like this one:
/messages/by-id/15728.1493654814@sss.pgh.pa.us
See particularly the commits cited in this message. PQhostaddr has been
already introduced, and reverted in the tree.
This may lead to some confusion as well. Take for example this
connection string:
'port=6666,5432 hostaddr=127.0.0.1,127.0.0.1 host=/tmp,/tmp'
=# select remote_hostname, remote_hostaddr, remote_port from
pg_stat_wal_receiver;
remote_hostname | remote_hostaddr | remote_port
-----------------+-----------------+-------------
/tmp | 127.0.0.1 | 5432
(1 row)
The documentation states that in this case the IP connection is used,
though this can be confusing for users to show both. I'll bet that we
would get complains about that, without at least proper documentation.
So my take would be to really just use PQhost and PQport, as this does
not remove any usefulness of this feature. If you want to use IP
addresses, there is nothing preventing you to use them in host as well,
and those would show up properly. The commit fest is coming to an end,
so my recommendation would be to move it on the next CF and get feedback
on /messages/by-id/CAJrrPGdrC4JTJQ4d7PT1Bi7K8nW91XPMPQ5kJ3GWK3ts+W-35g@mail.gmail.com
before concluding on this feature. The problem with PQhost and multiple
hosts is quite different than the 1st thread I am referring in this
email, so let's wait and see for Robert's input.
With the above two new API's we can display either string or individual
columns representation of remote server.
I like the naming "remote_*" by the way.
--
Michael
On Mon, Jan 29, 2018 at 7:06 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Tue, Jan 16, 2018 at 05:56:22PM +1100, Haribabu Kommi wrote:
Without PQhostaddr() function, for the connections where the host is not
specified, it will be difficult to find out to remote server.That's true as well, but hostaddr should be used with host only to save
IP lookups... There are recent threads on the matter, like this one:
/messages/by-id/15728.1493654814@sss.pgh.pa.us
See particularly the commits cited in this message. PQhostaddr has been
already introduced, and reverted in the tree.
Thanks for the link, I checked it. The main reason for the revert was
because
of using host to return the hostaddr even though the host is not specified.
But it may be fine to return the hostaddr with a different function.
Following
are sequence of commits that has changed the behavior.
commit 274bb2b3 introduced the support of returning PQhost() function to
return the connected host. (internally hostaddr also)
commit 11003eb5 added a check in the PQhost() function not to return the
host if the connection type is CHT_HOST_ADDRESS.
This is because an earlier change in connectOptions2() function that changes
the host with hostaddr, because of this reason, PQhost() function returns
the hostaddr and it is not expected from PQhost() function when the host is
not specified.
if (conn->pghostaddr != NULL && conn->pghostaddr[0] != '\0')
{
conn->connhost[0].host = strdup(conn->pghostaddr);
if (conn->connhost[0].host == NULL)
goto oom_error;
conn->connhost[0].type = CHT_HOST_ADDRESS;
}
But the above part of the code is changed in commit 7b02ba62
to support "Allow multiple hostaddrs to go with multiple hostnames"
With this commit, the commit 11003eb5 that blocks the host names
that are of CHT_HOST_ADDRESS connection type is not be required.
This may lead to some confusion as well. Take for example this
connection string:
'port=6666,5432 hostaddr=127.0.0.1,127.0.0.1 host=/tmp,/tmp'
=# select remote_hostname, remote_hostaddr, remote_port from
pg_stat_wal_receiver;
remote_hostname | remote_hostaddr | remote_port
-----------------+-----------------+-------------
/tmp | 127.0.0.1 | 5432
(1 row)
The documentation states that in this case the IP connection is used,
though this can be confusing for users to show both. I'll bet that we
would get complains about that, without at least proper documentation.
Ok, understood. As the libpq gives preference to hostaddr connection
parameter than host while connecting. How about going with one column
"remote_host" that displays either hostaddr(if exists) or hostname. So that
one column that displays the actual remote host to where it connected?
Note : The one column approach for both host and hostaddr will depend on
how we go with PQhostaddr() function.
So my take would be to really just use PQhost and PQport, as this does
not remove any usefulness of this feature. If you want to use IP
addresses, there is nothing preventing you to use them in host as well,
and those would show up properly. The commit fest is coming to an end,
so my recommendation would be to move it on the next CF and get feedback
on /messages/by-id/CAJrrPGdrC4JTJQ4d7PT1B
i7K8nW91XPMPQ5kJ3GWK3ts%2BW-35g%40mail.gmail.com
before concluding on this feature. The problem with PQhost and multiple
hosts is quite different than the 1st thread I am referring in this
email, so let's wait and see for Robert's input.
OK. I will move the patch to next commitfest.
Regards,
Hari Babu
Fujitsu Australia
On Tue, Jan 30, 2018 at 03:10:12PM +1100, Haribabu Kommi wrote:
Ok, understood. As the libpq gives preference to hostaddr connection
parameter than host while connecting. How about going with one column
"remote_host" that displays either hostaddr(if exists) or hostname. So that
one column that displays the actual remote host to where it connected?Note : The one column approach for both host and hostaddr will depend on
how we go with PQhostaddr() function.
Yeah, we don't want to begin a open battle for that. Using one column as
a first step would still be useful anyway. If the discussion about
PQhostaddr() comes to a result at some point, then it could make sense
to integrate that with pg_stat_wal_receiver. The problem with PQhost
handling strangely multiple host values is inconsistent though.
OK. I will move the patch to next commitfest.
Thanks. Let's see what others think on all those threads.
--
Michael
On Tue, Jan 30, 2018 at 4:02 PM, Michael Paquier <michael.paquier@gmail.com>
wrote:
On Tue, Jan 30, 2018 at 03:10:12PM +1100, Haribabu Kommi wrote:
Ok, understood. As the libpq gives preference to hostaddr connection
parameter than host while connecting. How about going with one column
"remote_host" that displays either hostaddr(if exists) or hostname. Sothat
one column that displays the actual remote host to where it connected?
Note : The one column approach for both host and hostaddr will depend on
how we go with PQhostaddr() function.Yeah, we don't want to begin a open battle for that. Using one column as
a first step would still be useful anyway. If the discussion about
PQhostaddr() comes to a result at some point, then it could make sense
to integrate that with pg_stat_wal_receiver. The problem with PQhost
handling strangely multiple host values is inconsistent though.
I updated the pg_stat_wal_receiver patch with the new PQhost() function
behavior
and updated the view with two columns, (remote_server and remote_port)
instead
of three as earlier.
Updated patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-remote-server-info_v2.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-remote-server-info_v2.patchDownload
From 4570ebf065c92b996eb799d6267dd3c9541b01e5 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 15 Jan 2018 15:28:57 +1100
Subject: [PATCH] pg_stat_wal_receiver to display remote server info
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of remote server information from which the replication is
streaming currently with two additional columns remote_server
and remote_port.
---
doc/src/sgml/monitoring.sgml | 19 ++++++++++++++
src/backend/catalog/system_views.sql | 2 ++
.../libpqwalreceiver/libpqwalreceiver.c | 23 +++++++++++++++++
src/backend/replication/walreceiver.c | 29 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 8 ++++++
src/test/regress/expected/rules.out | 4 ++-
7 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3bc4de57d5..1488789be1 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2031,6 +2031,25 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_server</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to. This can be a host name,
+ an IP address, or a directory path if the connection is via
+ Unix socket. (The path case can be distinguished because it
+ will always be an absolute path, beginning with <literal>/</literal>.)
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>remote_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>
+ Port number of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5e6e8a64f6..cdcf3972e8 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -752,6 +752,8 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_server,
+ s.remote_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..d6c2d891a9 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static void libpqrcv_get_remoteserver_info(WalReceiverConn *conn,
+ char **remote_server, int *remote_port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -82,6 +84,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
libpqrcv_connect,
libpqrcv_check_conninfo,
libpqrcv_get_conninfo,
+ libpqrcv_get_remoteserver_info,
libpqrcv_identify_system,
libpqrcv_readtimelinehistoryfile,
libpqrcv_startstreaming,
@@ -282,6 +285,26 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
return retval;
}
+/*
+ * Provides remote sever info.
+ */
+static void
+libpqrcv_get_remoteserver_info(WalReceiverConn *conn, char **remote_server,
+ int *remote_port)
+{
+ char *ret = NULL;
+
+ Assert(conn->streamConn != NULL);
+
+ ret = PQhost(conn->streamConn);
+ if (ret)
+ *remote_server = pstrdup(ret);
+
+ ret = PQport(conn->streamConn);
+ if (ret)
+ *remote_port = atoi(ret);
+}
+
/*
* Check that primary's system identifier matches ours, and fetch the current
* timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..df774a47f0 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,8 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *remote_server = NULL;
+ int remote_port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -311,16 +314,26 @@ WalReceiverMain(void)
* conninfo, for security.
*/
tmp_conninfo = walrcv_get_conninfo(wrconn);
+ walrcv_get_remoteserver_info(wrconn, &remote_server, &remote_port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->remote_server, 0, NI_MAXHOST);
+ if (remote_server)
+ strlcpy((char *) walrcv->remote_server, remote_server, NI_MAXHOST);
+
+ walrcv->remote_port = remote_port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
if (tmp_conninfo)
pfree(tmp_conninfo);
+ if (remote_server)
+ pfree(remote_server);
+
first_stream = true;
for (;;)
{
@@ -1402,6 +1415,8 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char remote_server[NI_MAXHOST];
+ int remote_port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1434,8 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(remote_server, (char *) WalRcv->remote_server, sizeof(remote_server));
+ remote_port = WalRcv->remote_port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1482,10 +1499,18 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*remote_server == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(remote_server);
+ if (remote_port == 0)
+ nulls[12] = true;
+ else
+ values[12] = Int32GetDatum(remote_port);
+ if (*conninfo == '\0')
+ nulls[13] = true;
+ else
+ values[13] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index bfc90098f8..634eca1b95 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2903,7 +2903,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_server,remote_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..c13ce9413a 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,8 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char remote_server[NI_MAXHOST];
+ int remote_port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -197,6 +199,9 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef void (*walrcv_get_remoteserver_info_fn) (WalReceiverConn *conn,
+ char **remote_server,
+ int *remote_port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -227,6 +232,7 @@ typedef struct WalReceiverFunctionsType
walrcv_connect_fn walrcv_connect;
walrcv_check_conninfo_fn walrcv_check_conninfo;
walrcv_get_conninfo_fn walrcv_get_conninfo;
+ walrcv_get_remoteserver_info_fn walrcv_get_remoteserver_info;
walrcv_identify_system_fn walrcv_identify_system;
walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +252,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_remoteserver_info(conn, remote_host, remote_port) \
+ WalReceiverFunctions->walrcv_get_remoteserver_info(conn, remote_host, remote_port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5149b72fe9..e138569f6c 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1972,8 +1972,10 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_server,
+ s.remote_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_server, remote_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.16.1.windows.4
On Wed, Mar 28, 2018 at 11:28:32AM +1100, Haribabu Kommi wrote:
I updated the pg_stat_wal_receiver patch with the new PQhost() function
behavior and updated the view with two columns, (remote_server and
remote_port) instead of three as earlier.Updated patch attached.
Thanks Hari for the updated patch. I was looking forward to seeing a
ner version.
+/*
+ * Provides remote sever info.
+ */
Typo here. This could be more precise, like "Provides information of
remote server this WAL receiver is connected to".
+libpqrcv_get_remoteserver_info(WalReceiverConn *conn, char
**remote_server,
+ int *remote_port)
+{
+ char *ret = NULL;
+
+ Assert(conn->streamConn != NULL);
Okay. The connection should be established so normally the results from
PQport and PQhost should not be NULL. Still I agree that this feels
safer for the long term.
Except for the small typo outlined, the rest of the patch lokks fine to
me. Most of the work has really happened for PQhost..
--
Michael
On Wed, Mar 28, 2018 at 12:54 PM, Michael Paquier <michael@paquier.xyz>
wrote:
On Wed, Mar 28, 2018 at 11:28:32AM +1100, Haribabu Kommi wrote:
I updated the pg_stat_wal_receiver patch with the new PQhost() function
behavior and updated the view with two columns, (remote_server and
remote_port) instead of three as earlier.Updated patch attached.
Thanks Hari for the updated patch. I was looking forward to seeing a
ner version.
Thanks for the review.
+/* + * Provides remote sever info. + */ Typo here. This could be more precise, like "Provides information of remote server this WAL receiver is connected to".
updated as above.
+libpqrcv_get_remoteserver_info(WalReceiverConn *conn, char
**remote_server, + int *remote_port) +{ + char *ret = NULL; + + Assert(conn->streamConn != NULL);Okay. The connection should be established so normally the results from
PQport and PQhost should not be NULL. Still I agree that this feels
safer for the long term.
OK.
Updated patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-remote-server-info_v3.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-remote-server-info_v3.patchDownload
From 81a9615ce6a76463360ea0afca7a3a834e0c3bfc Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Mon, 15 Jan 2018 15:28:57 +1100
Subject: [PATCH] pg_stat_wal_receiver to display remote server info
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of remote server information from which the replication is
streaming currently with two additional columns remote_server
and remote_port.
---
doc/src/sgml/monitoring.sgml | 19 ++++++++++++++
src/backend/catalog/system_views.sql | 2 ++
.../libpqwalreceiver/libpqwalreceiver.c | 23 +++++++++++++++++
src/backend/replication/walreceiver.c | 29 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 8 ++++++
src/test/regress/expected/rules.out | 4 ++-
7 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3bc4de57d5..1488789be1 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2031,6 +2031,25 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>remote_server</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to. This can be a host name,
+ an IP address, or a directory path if the connection is via
+ Unix socket. (The path case can be distinguished because it
+ will always be an absolute path, beginning with <literal>/</literal>.)
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>remote_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>
+ Port number of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5e6e8a64f6..cdcf3972e8 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -752,6 +752,8 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_server,
+ s.remote_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..ebe22a7fc1 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static void libpqrcv_get_remoteserver_info(WalReceiverConn *conn,
+ char **remote_server, int *remote_port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -82,6 +84,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
libpqrcv_connect,
libpqrcv_check_conninfo,
libpqrcv_get_conninfo,
+ libpqrcv_get_remoteserver_info,
libpqrcv_identify_system,
libpqrcv_readtimelinehistoryfile,
libpqrcv_startstreaming,
@@ -282,6 +285,26 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
return retval;
}
+/*
+ * Provides information of remote server this WAL receiver is connected to.
+ */
+static void
+libpqrcv_get_remoteserver_info(WalReceiverConn *conn, char **remote_server,
+ int *remote_port)
+{
+ char *ret = NULL;
+
+ Assert(conn->streamConn != NULL);
+
+ ret = PQhost(conn->streamConn);
+ if (ret)
+ *remote_server = pstrdup(ret);
+
+ ret = PQport(conn->streamConn);
+ if (ret)
+ *remote_port = atoi(ret);
+}
+
/*
* Check that primary's system identifier matches ours, and fetch the current
* timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..df774a47f0 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,8 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *remote_server = NULL;
+ int remote_port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -311,16 +314,26 @@ WalReceiverMain(void)
* conninfo, for security.
*/
tmp_conninfo = walrcv_get_conninfo(wrconn);
+ walrcv_get_remoteserver_info(wrconn, &remote_server, &remote_port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->remote_server, 0, NI_MAXHOST);
+ if (remote_server)
+ strlcpy((char *) walrcv->remote_server, remote_server, NI_MAXHOST);
+
+ walrcv->remote_port = remote_port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
if (tmp_conninfo)
pfree(tmp_conninfo);
+ if (remote_server)
+ pfree(remote_server);
+
first_stream = true;
for (;;)
{
@@ -1402,6 +1415,8 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char remote_server[NI_MAXHOST];
+ int remote_port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1434,8 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(remote_server, (char *) WalRcv->remote_server, sizeof(remote_server));
+ remote_port = WalRcv->remote_port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1482,10 +1499,18 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*remote_server == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(remote_server);
+ if (remote_port == 0)
+ nulls[12] = true;
+ else
+ values[12] = Int32GetDatum(remote_port);
+ if (*conninfo == '\0')
+ nulls[13] = true;
+ else
+ values[13] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index bfc90098f8..634eca1b95 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2903,7 +2903,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,remote_server,remote_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..c13ce9413a 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,8 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char remote_server[NI_MAXHOST];
+ int remote_port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -197,6 +199,9 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef void (*walrcv_get_remoteserver_info_fn) (WalReceiverConn *conn,
+ char **remote_server,
+ int *remote_port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -227,6 +232,7 @@ typedef struct WalReceiverFunctionsType
walrcv_connect_fn walrcv_connect;
walrcv_check_conninfo_fn walrcv_check_conninfo;
walrcv_get_conninfo_fn walrcv_get_conninfo;
+ walrcv_get_remoteserver_info_fn walrcv_get_remoteserver_info;
walrcv_identify_system_fn walrcv_identify_system;
walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +252,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_remoteserver_info(conn, remote_host, remote_port) \
+ WalReceiverFunctions->walrcv_get_remoteserver_info(conn, remote_host, remote_port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5149b72fe9..e138569f6c 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1972,8 +1972,10 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.remote_server,
+ s.remote_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, remote_server, remote_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.16.1.windows.4
On Wed, Mar 28, 2018 at 03:41:33PM +1100, Haribabu Kommi wrote:
On Wed, Mar 28, 2018 at 12:54 PM, Michael Paquier <michael@paquier.xyz>
wrote:
Updated patch attached.
Thanks, switched as ready for committer.
--
Michael
On Wed, Mar 28, 2018 at 3:09 PM, Michael Paquier <michael@paquier.xyz> wrote:
On Wed, Mar 28, 2018 at 03:41:33PM +1100, Haribabu Kommi wrote:
On Wed, Mar 28, 2018 at 12:54 PM, Michael Paquier <michael@paquier.xyz>
wrote:
Updated patch attached.
Thanks for the patch! I'd like to commit this feature for v11.
@@ -753,4 +753,6 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_time,
s.slot_name,
+ s.remote_server,
+ s.remote_port,
As the column names, aren't sender_host and sender_port more intuitive
rather than remote_server and remote_port?
+ ret = PQhost(conn->streamConn);
+ if (ret)
+ *remote_server = pstrdup(ret);
When the connection has an error, PQhost() and PQport() return an empty string.
In this case, pg_stat_wal_receiver reports an empty string in remote_server and
NULL in remote_port. Which looks inconsistent to me. In that case, both of them
should be reported NULL, I think. So I think that the above "if (ret)" condition
should be "if (ret & strcmp(ret, "") == 0)". Thought?
Of course, currently it's basically impossible that PQhost() and PQport() return
an empty string in libpqrcv_get_remoteserver_info() because it's called just
after the replication connection is successfully established. But it's better to
handle also that case for robustness of the code.
Regards,
--
Fujii Masao
On Fri, Mar 30, 2018 at 7:26 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
On Wed, Mar 28, 2018 at 3:09 PM, Michael Paquier <michael@paquier.xyz>
wrote:On Wed, Mar 28, 2018 at 03:41:33PM +1100, Haribabu Kommi wrote:
On Wed, Mar 28, 2018 at 12:54 PM, Michael Paquier <michael@paquier.xyz>
wrote:
Updated patch attached.Thanks for the patch! I'd like to commit this feature for v11.
Thanks for the review.
@@ -753,4 +753,6 @@ CREATE VIEW pg_stat_wal_receiver AS s.latest_end_time, s.slot_name, + s.remote_server, + s.remote_port,As the column names, aren't sender_host and sender_port more intuitive
rather than remote_server and remote_port?
OK. Changed accordingly.
+ ret = PQhost(conn->streamConn); + if (ret) + *remote_server = pstrdup(ret);When the connection has an error, PQhost() and PQport() return an empty
string.
In this case, pg_stat_wal_receiver reports an empty string in
remote_server and
NULL in remote_port. Which looks inconsistent to me. In that case, both of
them
should be reported NULL, I think. So I think that the above "if (ret)"
condition
should be "if (ret & strcmp(ret, "") == 0)". Thought?
OK. Added a check to verify the returned host value.
Of course, currently it's basically impossible that PQhost() and PQport()
return
an empty string in libpqrcv_get_remoteserver_info() because it's called
just
after the replication connection is successfully established. But it's
better to
handle also that case for robustness of the code.
OK.
Updated patch attached.
Regards,
Hari Babu
Fujitsu Australia
Attachments:
pg_stat_wal_receiver-to-display-sender-host-info_v4.patchapplication/octet-stream; name=pg_stat_wal_receiver-to-display-sender-host-info_v4.patchDownload
From 4db29a990bfc95cd3e6cf8aee88f8c4e1d739fb4 Mon Sep 17 00:00:00 2001
From: Hari Babu <kommi.haribabu@gmail.com>
Date: Fri, 30 Mar 2018 10:28:57 +1100
Subject: [PATCH] pg_stat_wal_receiver to display sender host info
With the support of multi host connection string support
in PostgreSQL, it is possible for the user to specify the
multi host connection string in recovery.conf to avoid
breakdown of streaming replication.
The pg_stat_wal_receiver view is enhanced to support display
of sender host information from where the replication is
streaming currently with two additional columns sender_host
and sender_port.
---
doc/src/sgml/monitoring.sgml | 19 ++++++++++++++
src/backend/catalog/system_views.sql | 2 ++
.../libpqwalreceiver/libpqwalreceiver.c | 23 +++++++++++++++++
src/backend/replication/walreceiver.c | 29 ++++++++++++++++++++--
src/include/catalog/pg_proc.h | 2 +-
src/include/replication/walreceiver.h | 8 ++++++
src/test/regress/expected/rules.out | 4 ++-
7 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3bc4de57d5..c278076e68 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2031,6 +2031,25 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
<entry><type>text</type></entry>
<entry>Replication slot name used by this WAL receiver</entry>
</row>
+ <row>
+ <entry><structfield>sender_host</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry>
+ Host of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to. This can be a host name,
+ an IP address, or a directory path if the connection is via
+ Unix socket. (The path case can be distinguished because it
+ will always be an absolute path, beginning with <literal>/</literal>.)
+ </entry>
+ </row>
+ <row>
+ <entry><structfield>sender_port</structfield></entry>
+ <entry><type>integer</type></entry>
+ <entry>
+ Port number of the <productname>PostgreSQL</productname> instance
+ this WAL receiver is connected to.
+ </entry>
+ </row>
<row>
<entry><structfield>conninfo</structfield></entry>
<entry><type>text</type></entry>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5e6e8a64f6..e9e188682f 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -752,6 +752,8 @@ CREATE VIEW pg_stat_wal_receiver AS
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.sender_host,
+ s.sender_port,
s.conninfo
FROM pg_stat_get_wal_receiver() s
WHERE s.pid IS NOT NULL;
diff --git a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
index f9aec0531a..466e04204b 100644
--- a/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
+++ b/src/backend/replication/libpqwalreceiver/libpqwalreceiver.c
@@ -53,6 +53,8 @@ static WalReceiverConn *libpqrcv_connect(const char *conninfo,
char **err);
static void libpqrcv_check_conninfo(const char *conninfo);
static char *libpqrcv_get_conninfo(WalReceiverConn *conn);
+static void libpqrcv_get_senderhost_info(WalReceiverConn *conn,
+ char **sender_host, int *sender_port);
static char *libpqrcv_identify_system(WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -82,6 +84,7 @@ static WalReceiverFunctionsType PQWalReceiverFunctions = {
libpqrcv_connect,
libpqrcv_check_conninfo,
libpqrcv_get_conninfo,
+ libpqrcv_get_senderhost_info,
libpqrcv_identify_system,
libpqrcv_readtimelinehistoryfile,
libpqrcv_startstreaming,
@@ -282,6 +285,26 @@ libpqrcv_get_conninfo(WalReceiverConn *conn)
return retval;
}
+/*
+ * Provides information of sender host this WAL receiver is connected to.
+ */
+static void
+libpqrcv_get_senderhost_info(WalReceiverConn *conn, char **sender_host,
+ int *sender_port)
+{
+ char *ret = NULL;
+
+ Assert(conn->streamConn != NULL);
+
+ ret = PQhost(conn->streamConn);
+ if (ret && (strcmp(ret,"") != 0))
+ *sender_host = pstrdup(ret);
+
+ ret = PQport(conn->streamConn);
+ if (ret)
+ *sender_port = atoi(ret);
+}
+
/*
* Check that primary's system identifier matches ours, and fetch the current
* timeline ID of the primary.
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a39a98ff18..15fbf129fc 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -52,6 +52,7 @@
#include "access/xlog_internal.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_type.h"
+#include "common/ip.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
@@ -199,6 +200,8 @@ WalReceiverMain(void)
TimestampTz now;
bool ping_sent;
char *err;
+ char *sender_host = NULL;
+ int sender_port = 0;
/*
* WalRcv should be set up already (if we are a backend, we inherit this
@@ -311,16 +314,26 @@ WalReceiverMain(void)
* conninfo, for security.
*/
tmp_conninfo = walrcv_get_conninfo(wrconn);
+ walrcv_get_senderhost_info(wrconn, &sender_host, &sender_port);
SpinLockAcquire(&walrcv->mutex);
memset(walrcv->conninfo, 0, MAXCONNINFO);
if (tmp_conninfo)
strlcpy((char *) walrcv->conninfo, tmp_conninfo, MAXCONNINFO);
+
+ memset(walrcv->sender_host, 0, NI_MAXHOST);
+ if (sender_host)
+ strlcpy((char *) walrcv->sender_host, sender_host, NI_MAXHOST);
+
+ walrcv->sender_port = sender_port;
walrcv->ready_to_display = true;
SpinLockRelease(&walrcv->mutex);
if (tmp_conninfo)
pfree(tmp_conninfo);
+ if (sender_host)
+ pfree(sender_host);
+
first_stream = true;
for (;;)
{
@@ -1402,6 +1415,8 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
TimestampTz last_receipt_time;
XLogRecPtr latest_end_lsn;
TimestampTz latest_end_time;
+ char sender_host[NI_MAXHOST];
+ int sender_port = 0;
char slotname[NAMEDATALEN];
char conninfo[MAXCONNINFO];
@@ -1419,6 +1434,8 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
latest_end_lsn = WalRcv->latestWalEnd;
latest_end_time = WalRcv->latestWalEndTime;
strlcpy(slotname, (char *) WalRcv->slotname, sizeof(slotname));
+ strlcpy(sender_host, (char *) WalRcv->sender_host, sizeof(sender_host));
+ sender_port = WalRcv->sender_port;
strlcpy(conninfo, (char *) WalRcv->conninfo, sizeof(conninfo));
SpinLockRelease(&WalRcv->mutex);
@@ -1482,10 +1499,18 @@ pg_stat_get_wal_receiver(PG_FUNCTION_ARGS)
nulls[10] = true;
else
values[10] = CStringGetTextDatum(slotname);
- if (*conninfo == '\0')
+ if (*sender_host == '\0')
nulls[11] = true;
else
- values[11] = CStringGetTextDatum(conninfo);
+ values[11] = CStringGetTextDatum(sender_host);
+ if (sender_port == 0)
+ nulls[12] = true;
+ else
+ values[12] = Int32GetDatum(sender_port);
+ if (*conninfo == '\0')
+ nulls[13] = true;
+ else
+ values[13] = CStringGetTextDatum(conninfo);
}
/* Returns the record as Datum */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index ec50afcdf0..ec046fcbde 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2919,7 +2919,7 @@ DATA(insert OID = 3318 ( pg_stat_get_progress_info PGNSP PGUID 12 1 100 0 0
DESCR("statistics: information about progress of backends running maintenance command");
DATA(insert OID = 3099 ( pg_stat_get_wal_senders PGNSP PGUID 12 1 10 0 0 f f f f t s r 0 0 2249 "" "{23,25,3220,3220,3220,3220,1186,1186,1186,23,25}" "{o,o,o,o,o,o,o,o,o,o,o}" "{pid,state,sent_lsn,write_lsn,flush_lsn,replay_lsn,write_lag,flush_lag,replay_lag,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
DESCR("statistics: information about currently active replication");
-DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25}" "{o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
+DATA(insert OID = 3317 ( pg_stat_get_wal_receiver PGNSP PGUID 12 1 0 0 0 f f f f f s r 0 0 2249 "" "{23,25,3220,23,3220,23,1184,1184,3220,1184,25,25,23,25}" "{o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,status,receive_start_lsn,receive_start_tli,received_lsn,received_tli,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time,slot_name,sender_host,sender_port,conninfo}" _null_ _null_ pg_stat_get_wal_receiver _null_ _null_ _null_ ));
DESCR("statistics: information about WAL receiver");
DATA(insert OID = 6118 ( pg_stat_get_subscription PGNSP PGUID 12 1 0 0 0 f f f f f s r 1 0 2249 "26" "{26,26,26,23,3220,1184,1184,3220,1184}" "{i,o,o,o,o,o,o,o,o}" "{subid,subid,relid,pid,received_lsn,last_msg_send_time,last_msg_receipt_time,latest_end_lsn,latest_end_time}" _null_ _null_ pg_stat_get_subscription _null_ _null_ _null_ ));
DESCR("statistics: information about subscription");
diff --git a/src/include/replication/walreceiver.h b/src/include/replication/walreceiver.h
index ea7967f6fc..d2572a23a9 100644
--- a/src/include/replication/walreceiver.h
+++ b/src/include/replication/walreceiver.h
@@ -107,6 +107,8 @@ typedef struct
* clobbered to hide security-sensitive fields.
*/
char conninfo[MAXCONNINFO];
+ char sender_host[NI_MAXHOST];
+ int sender_port;
/*
* replication slot name; is also used for walreceiver to connect with the
@@ -197,6 +199,9 @@ typedef WalReceiverConn *(*walrcv_connect_fn) (const char *conninfo, bool logica
char **err);
typedef void (*walrcv_check_conninfo_fn) (const char *conninfo);
typedef char *(*walrcv_get_conninfo_fn) (WalReceiverConn *conn);
+typedef void (*walrcv_get_senderhost_info_fn) (WalReceiverConn *conn,
+ char **sender_host,
+ int *sender_port);
typedef char *(*walrcv_identify_system_fn) (WalReceiverConn *conn,
TimeLineID *primary_tli,
int *server_version);
@@ -227,6 +232,7 @@ typedef struct WalReceiverFunctionsType
walrcv_connect_fn walrcv_connect;
walrcv_check_conninfo_fn walrcv_check_conninfo;
walrcv_get_conninfo_fn walrcv_get_conninfo;
+ walrcv_get_senderhost_info_fn walrcv_get_senderhost_info;
walrcv_identify_system_fn walrcv_identify_system;
walrcv_readtimelinehistoryfile_fn walrcv_readtimelinehistoryfile;
walrcv_startstreaming_fn walrcv_startstreaming;
@@ -246,6 +252,8 @@ extern PGDLLIMPORT WalReceiverFunctionsType *WalReceiverFunctions;
WalReceiverFunctions->walrcv_check_conninfo(conninfo)
#define walrcv_get_conninfo(conn) \
WalReceiverFunctions->walrcv_get_conninfo(conn)
+#define walrcv_get_senderhost_info(conn, sender_host, sender_port) \
+ WalReceiverFunctions->walrcv_get_senderhost_info(conn, sender_host, sender_port)
#define walrcv_identify_system(conn, primary_tli, server_version) \
WalReceiverFunctions->walrcv_identify_system(conn, primary_tli, server_version)
#define walrcv_readtimelinehistoryfile(conn, tli, filename, content, size) \
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5149b72fe9..ae0cd253d5 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1972,8 +1972,10 @@ pg_stat_wal_receiver| SELECT s.pid,
s.latest_end_lsn,
s.latest_end_time,
s.slot_name,
+ s.sender_host,
+ s.sender_port,
s.conninfo
- FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, conninfo)
+ FROM pg_stat_get_wal_receiver() s(pid, status, receive_start_lsn, receive_start_tli, received_lsn, received_tli, last_msg_send_time, last_msg_receipt_time, latest_end_lsn, latest_end_time, slot_name, sender_host, sender_port, conninfo)
WHERE (s.pid IS NOT NULL);
pg_stat_xact_all_tables| SELECT c.oid AS relid,
n.nspname AS schemaname,
--
2.16.1.windows.4
On Fri, Mar 30, 2018 at 10:52:02AM +1100, Haribabu Kommi wrote:
On Fri, Mar 30, 2018 at 7:26 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
@@ -753,4 +753,6 @@ CREATE VIEW pg_stat_wal_receiver AS s.latest_end_time, s.slot_name, + s.remote_server, + s.remote_port,As the column names, aren't sender_host and sender_port more intuitive
rather than remote_server and remote_port?OK. Changed accordingly.
No problems with those names.
+ ret = PQhost(conn->streamConn);
+ if (ret && (strcmp(ret,"") != 0))
+ *sender_host = pstrdup(ret);
The code tends to use more strlen to check for empty strings,
particularly libpq. A small nit it is.
--
Michael
On Fri, Mar 30, 2018 at 9:34 AM, Michael Paquier <michael@paquier.xyz> wrote:
On Fri, Mar 30, 2018 at 10:52:02AM +1100, Haribabu Kommi wrote:
On Fri, Mar 30, 2018 at 7:26 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
@@ -753,4 +753,6 @@ CREATE VIEW pg_stat_wal_receiver AS s.latest_end_time, s.slot_name, + s.remote_server, + s.remote_port,As the column names, aren't sender_host and sender_port more intuitive
rather than remote_server and remote_port?OK. Changed accordingly.
No problems with those names.
+ ret = PQhost(conn->streamConn); + if (ret && (strcmp(ret,"") != 0)) + *sender_host = pstrdup(ret); The code tends to use more strlen to check for empty strings, particularly libpq. A small nit it is.
Ok, updated the patch so strlen is used.
I pushed the patch. Many thanks to Haribabu and Michael!
Regards,
--
Fujii Masao
On Sat, Mar 31, 2018 at 10:08 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
On Fri, Mar 30, 2018 at 9:34 AM, Michael Paquier <michael@paquier.xyz>
wrote:On Fri, Mar 30, 2018 at 10:52:02AM +1100, Haribabu Kommi wrote:
On Fri, Mar 30, 2018 at 7:26 AM, Fujii Masao <masao.fujii@gmail.com>
wrote:
@@ -753,4 +753,6 @@ CREATE VIEW pg_stat_wal_receiver AS s.latest_end_time, s.slot_name, + s.remote_server, + s.remote_port,As the column names, aren't sender_host and sender_port more intuitive
rather than remote_server and remote_port?OK. Changed accordingly.
No problems with those names.
+ ret = PQhost(conn->streamConn); + if (ret && (strcmp(ret,"") != 0)) + *sender_host = pstrdup(ret); The code tends to use more strlen to check for empty strings, particularly libpq. A small nit it is.Ok, updated the patch so strlen is used.
I pushed the patch. Many thanks to Haribabu and Michael!
Thanks for the changes and commit and thanks Michael for the review.
Regards,
Hari Babu
Fujitsu Australia