1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-18 13:44:19 +03:00

postgres_fdw: Extend postgres_fdw_get_connections to return remote backend PID.

This commit adds a new "remote_backend_pid" output column to
the postgres_fdw_get_connections function. It returns the process ID of
the remote backend, on the foreign server, handling the connection.

This enhancement is useful for troubleshooting, monitoring, and reporting.
For example, if a connection is unexpectedly closed by the foreign server,
the remote backend's PID can help diagnose the cause.

No extension version bump is needed, as commit c297a47c5f already
handled it for v18~.

Author: Sagar Dilip Shedge <sagar.shedge92@gmail.com>
Reviewed-by: Fujii Masao <masao.fujii@gmail.com>
Discussion: https://postgr.es/m/CAPhYifF25q5xUQWXETfKwhc0YVa_6+tfG9Kw4bCvCjpCWxYs2A@mail.gmail.com
This commit is contained in:
Fujii Masao 2025-03-03 08:51:30 +09:00
parent 15a79c7311
commit fe186bda78
5 changed files with 76 additions and 32 deletions

View File

@ -2111,8 +2111,8 @@ pgfdw_finish_abort_cleanup(List *pending_entries, List *cancel_requested,
/* Number of output arguments (columns) for various API versions */
#define POSTGRES_FDW_GET_CONNECTIONS_COLS_V1_1 2
#define POSTGRES_FDW_GET_CONNECTIONS_COLS_V1_2 5
#define POSTGRES_FDW_GET_CONNECTIONS_COLS 5 /* maximum of above */
#define POSTGRES_FDW_GET_CONNECTIONS_COLS_V1_2 6
#define POSTGRES_FDW_GET_CONNECTIONS_COLS 6 /* maximum of above */
/*
* Internal function used by postgres_fdw_get_connections variants.
@ -2128,13 +2128,15 @@ pgfdw_finish_abort_cleanup(List *pending_entries, List *cancel_requested,
*
* For API version 1.2 and later, this function takes an input parameter
* to check a connection status and returns the following
* additional values along with the three values from version 1.1:
* additional values along with the four values from version 1.1:
*
* - user_name - the local user name of the active connection. In case the
* user mapping is dropped but the connection is still active, then the
* user name will be NULL in the output.
* - used_in_xact - true if the connection is used in the current transaction.
* - closed - true if the connection is closed.
* - remote_backend_pid - process ID of the remote backend, on the foreign
* server, handling the connection.
*
* No records are returned when there are no cached connections at all.
*/
@ -2273,6 +2275,9 @@ postgres_fdw_get_connections_internal(FunctionCallInfo fcinfo,
values[i++] = BoolGetDatum(pgfdw_conn_check(entry->conn) != 0);
else
nulls[i++] = true;
/* Return process ID of remote backend */
values[i++] = Int32GetDatum(PQbackendPID(entry->conn));
}
tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);

View File

@ -10589,13 +10589,18 @@ drop cascades to foreign table ft7
-- List all the existing cached connections. loopback and loopback3
-- should be output as invalid connections. Also the server name and user name
-- for loopback3 should be NULL because both server and user mapping were
-- dropped.
SELECT server_name, user_name = CURRENT_USER as "user_name = CURRENT_USER", valid, used_in_xact, closed
-- dropped. In this test, the PIDs of remote backends can be gathered from
-- pg_stat_activity, and remote_backend_pid should match one of those PIDs.
SELECT server_name, user_name = CURRENT_USER as "user_name = CURRENT_USER",
valid, used_in_xact, closed,
remote_backend_pid = ANY(SELECT pid FROM pg_stat_activity
WHERE backend_type = 'client backend' AND pid <> pg_backend_pid())
as remote_backend_pid
FROM postgres_fdw_get_connections() ORDER BY 1;
server_name | user_name = CURRENT_USER | valid | used_in_xact | closed
-------------+--------------------------+-------+--------------+--------
loopback | t | f | t |
| | f | t |
server_name | user_name = CURRENT_USER | valid | used_in_xact | closed | remote_backend_pid
-------------+--------------------------+-------+--------------+--------+--------------------
loopback | t | f | t | | t
| | f | t | | t
(2 rows)
-- The invalid connections get closed in pgfdw_xact_callback during commit.
@ -12436,25 +12441,34 @@ SELECT 1 FROM ft1 LIMIT 1;
-- Since the remote server is still connected, "closed" should be FALSE,
-- or NULL if the connection status check is not available.
SELECT CASE WHEN closed IS NOT true THEN 1 ELSE 0 END
-- In this test, the remote backend handling this connection should have
-- application_name set to "fdw_conn_check", so remote_backend_pid should
-- match the PID from the pg_stat_activity entry with that application_name.
SELECT server_name,
CASE WHEN closed IS NOT true THEN false ELSE true END AS closed,
remote_backend_pid = (SELECT pid FROM pg_stat_activity
WHERE application_name = 'fdw_conn_check') AS remote_backend_pid
FROM postgres_fdw_get_connections(true);
case
------
1
server_name | closed | remote_backend_pid
-------------+--------+--------------------
loopback | f | t
(1 row)
-- After terminating the remote backend, since the connection is closed,
-- "closed" should be TRUE, or NULL if the connection status check
-- is not available.
-- is not available. Despite the termination, remote_backend_pid should
-- still show the non-zero PID of the terminated remote backend.
DO $$ BEGIN
PERFORM pg_terminate_backend(pid, 180000) FROM pg_stat_activity
WHERE application_name = 'fdw_conn_check';
END $$;
SELECT CASE WHEN closed IS NOT false THEN 1 ELSE 0 END
SELECT server_name,
CASE WHEN closed IS NOT false THEN true ELSE false END AS closed,
remote_backend_pid <> 0 AS remote_backend_pid
FROM postgres_fdw_get_connections(true);
case
------
1
server_name | closed | remote_backend_pid
-------------+--------+--------------------
loopback | t | t
(1 row)
-- Clean up

View File

@ -12,7 +12,7 @@ DROP FUNCTION postgres_fdw_get_connections ();
CREATE FUNCTION postgres_fdw_get_connections (
IN check_conn boolean DEFAULT false, OUT server_name text,
OUT user_name text, OUT valid boolean, OUT used_in_xact boolean,
OUT closed boolean)
OUT closed boolean, OUT remote_backend_pid int4)
RETURNS SETOF record
AS 'MODULE_PATHNAME', 'postgres_fdw_get_connections_1_2'
LANGUAGE C STRICT PARALLEL RESTRICTED;

View File

@ -3410,8 +3410,13 @@ DROP SERVER loopback3 CASCADE;
-- List all the existing cached connections. loopback and loopback3
-- should be output as invalid connections. Also the server name and user name
-- for loopback3 should be NULL because both server and user mapping were
-- dropped.
SELECT server_name, user_name = CURRENT_USER as "user_name = CURRENT_USER", valid, used_in_xact, closed
-- dropped. In this test, the PIDs of remote backends can be gathered from
-- pg_stat_activity, and remote_backend_pid should match one of those PIDs.
SELECT server_name, user_name = CURRENT_USER as "user_name = CURRENT_USER",
valid, used_in_xact, closed,
remote_backend_pid = ANY(SELECT pid FROM pg_stat_activity
WHERE backend_type = 'client backend' AND pid <> pg_backend_pid())
as remote_backend_pid
FROM postgres_fdw_get_connections() ORDER BY 1;
-- The invalid connections get closed in pgfdw_xact_callback during commit.
COMMIT;
@ -4288,17 +4293,26 @@ SELECT 1 FROM ft1 LIMIT 1;
-- Since the remote server is still connected, "closed" should be FALSE,
-- or NULL if the connection status check is not available.
SELECT CASE WHEN closed IS NOT true THEN 1 ELSE 0 END
-- In this test, the remote backend handling this connection should have
-- application_name set to "fdw_conn_check", so remote_backend_pid should
-- match the PID from the pg_stat_activity entry with that application_name.
SELECT server_name,
CASE WHEN closed IS NOT true THEN false ELSE true END AS closed,
remote_backend_pid = (SELECT pid FROM pg_stat_activity
WHERE application_name = 'fdw_conn_check') AS remote_backend_pid
FROM postgres_fdw_get_connections(true);
-- After terminating the remote backend, since the connection is closed,
-- "closed" should be TRUE, or NULL if the connection status check
-- is not available.
-- is not available. Despite the termination, remote_backend_pid should
-- still show the non-zero PID of the terminated remote backend.
DO $$ BEGIN
PERFORM pg_terminate_backend(pid, 180000) FROM pg_stat_activity
WHERE application_name = 'fdw_conn_check';
END $$;
SELECT CASE WHEN closed IS NOT false THEN 1 ELSE 0 END
SELECT server_name,
CASE WHEN closed IS NOT false THEN true ELSE false END AS closed,
remote_backend_pid <> 0 AS remote_backend_pid
FROM postgres_fdw_get_connections(true);
-- Clean up

View File

@ -854,7 +854,7 @@ OPTIONS (ADD password_required 'false');
<term><function>postgres_fdw_get_connections(
IN check_conn boolean DEFAULT false, OUT server_name text,
OUT user_name text, OUT valid boolean, OUT used_in_xact boolean,
OUT closed boolean)
OUT closed boolean, OUT remote_backend_pid int4)
returns setof record</function></term>
<listitem>
<para>
@ -882,11 +882,11 @@ OPTIONS (ADD password_required 'false');
Example usage of the function:
<screen>
postgres=# SELECT * FROM postgres_fdw_get_connections(true);
server_name | user_name | valid | used_in_xact | closed
-------------+-----------+-------+--------------+--------
loopback1 | postgres | t | t | f
loopback2 | public | t | t | f
loopback3 | | f | t | f
server_name | user_name | valid | used_in_xact | closed | remote_backend_pid
-------------+-----------+-------+--------------+-----------------------------
loopback1 | postgres | t | t | f | 1353340
loopback2 | public | t | t | f | 1353120
loopback3 | | f | t | f | 1353156
</screen>
The output columns are described in
<xref linkend="postgres-fdw-get-connections-columns"/>.
@ -951,6 +951,17 @@ postgres=# SELECT * FROM postgres_fdw_get_connections(true);
is not available on this platform.
</entry>
</row>
<row>
<entry><structfield>remote_backend_pid</structfield></entry>
<entry><type>int4</type></entry>
<entry>
Process ID of the remote backend, on the foreign server,
handling the connection. If the remote backend is terminated and
the connection is closed (with <literal>closed</literal> set to
<literal>true</literal>), this still shows the process ID of
the terminated backend.
</entry>
</row>
</tbody>
</tgroup>
</table>