From c76ddc36ecb96d57f17e3ad2f8cb6a24cb61648e Mon Sep 17 00:00:00 2001 From: Bharath Rupireddy Date: Wed, 27 Jan 2021 06:33:55 +0530 Subject: [PATCH v19] postgres_fdw add keep_connections GUC to not cache connections This patch adds a new GUC postgres_fdw.keep_connections, default being on, when set to off no remote connections are cached by the local session. --- contrib/postgres_fdw/connection.c | 12 +++-- .../postgres_fdw/expected/postgres_fdw.out | 43 ++++++++++++++++++ contrib/postgres_fdw/postgres_fdw.c | 16 +++++++ contrib/postgres_fdw/postgres_fdw.h | 3 ++ contrib/postgres_fdw/sql/postgres_fdw.sql | 20 +++++++++ doc/src/sgml/postgres-fdw.sgml | 44 +++++++++++++++++++ 6 files changed, 135 insertions(+), 3 deletions(-) diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index ee0b4acf0b..3325ce00f2 100644 --- a/contrib/postgres_fdw/connection.c +++ b/contrib/postgres_fdw/connection.c @@ -809,6 +809,7 @@ pgfdw_xact_callback(XactEvent event, void *arg) while ((entry = (ConnCacheEntry *) hash_seq_search(&scan))) { PGresult *res; + bool used_in_current_xact = false; /* Ignore cache entry if no open connection right now */ if (entry->conn == NULL) @@ -819,6 +820,8 @@ pgfdw_xact_callback(XactEvent event, void *arg) { bool abort_cleanup_failure = false; + used_in_current_xact = true; + elog(DEBUG3, "closing remote transaction on connection %p", entry->conn); @@ -953,16 +956,19 @@ pgfdw_xact_callback(XactEvent event, void *arg) /* * If the connection isn't in a good idle state or it is marked as - * invalid, then discard it to recover. Next GetConnection will open a - * new connection. + * invalid or keep_connections GUC is false and this connection is used + * in current xact, then discard it to recover. Next GetConnection will + * open a new connection. */ if (PQstatus(entry->conn) != CONNECTION_OK || PQtransactionStatus(entry->conn) != PQTRANS_IDLE || entry->changing_xact_state || - entry->invalidated) + entry->invalidated || + (used_in_current_xact && !keep_connections)) { elog(DEBUG3, "discarding connection %p", entry->conn); disconnect_pg_server(entry); + used_in_current_xact = false; } } diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 07e06e5bf7..5bfb70d19e 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -9316,6 +9316,49 @@ DROP USER MAPPING FOR regress_multi_conn_user1 SERVER loopback; DROP USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; DROP ROLE regress_multi_conn_user1; DROP ROLE regress_multi_conn_user2; +-- =================================================================== +-- Test postgres_fdw.keep_connections GUC +-- =================================================================== +-- By default, keep_connections GUC is on i.e. local session caches all the +-- foreign server connections. +SHOW postgres_fdw.keep_connections; + postgres_fdw.keep_connections +------------------------------- + on +(1 row) + +-- Set it off i.e. the cached connections which are used after this setting are +-- disconnected at the end of respective xacts. +SET postgres_fdw.keep_connections TO off; +-- Make connection using loopback server, connection should not be cached as +-- the GUC is off. +SELECT 1 FROM ft1 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +-- Should output nothing. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- +(0 rows) + +-- Set it on i.e. connections are cached. +SET postgres_fdw.keep_connections TO on; +SELECT 1 FROM ft1 LIMIT 1; + ?column? +---------- + 1 +(1 row) + +-- Should output loopback. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + server_name | valid +-------------+------- + loopback | t +(1 row) + -- =================================================================== -- batch insert -- =================================================================== diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 2ce42ce3f1..c5a76b7ad0 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -312,6 +312,8 @@ typedef struct List *already_used; /* expressions already dealt with */ } ec_member_foreign_arg; +bool keep_connections = true; + /* * SQL functions */ @@ -527,6 +529,20 @@ static void merge_fdw_options(PgFdwRelationInfo *fpinfo, const PgFdwRelationInfo *fpinfo_i); static int get_batch_size_option(Relation rel); +void +_PG_init(void) +{ + DefineCustomBoolVariable("postgres_fdw.keep_connections", + "Enables postgres_fdw connection caching.", + "When off postgres_fdw will close connections at the end of transaction.", + &keep_connections, + true, + PGC_USERSET, + 0, + NULL, + NULL, + NULL); +} /* * Foreign-data wrapper handler function: return a struct with pointers diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h index 1f67b4d9fd..ceea46b304 100644 --- a/contrib/postgres_fdw/postgres_fdw.h +++ b/contrib/postgres_fdw/postgres_fdw.h @@ -124,9 +124,12 @@ typedef struct PgFdwRelationInfo int relation_index; } PgFdwRelationInfo; +extern bool keep_connections; + /* in postgres_fdw.c */ extern int set_transmission_modes(void); extern void reset_transmission_modes(int nestlevel); +extern void _PG_init(void); /* in connection.c */ extern PGconn *GetConnection(UserMapping *user, bool will_prep_stmt); diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 647192cf6a..37d36b0484 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -2832,6 +2832,26 @@ DROP USER MAPPING FOR regress_multi_conn_user2 SERVER loopback; DROP ROLE regress_multi_conn_user1; DROP ROLE regress_multi_conn_user2; +-- =================================================================== +-- Test postgres_fdw.keep_connections GUC +-- =================================================================== +-- By default, keep_connections GUC is on i.e. local session caches all the +-- foreign server connections. +SHOW postgres_fdw.keep_connections; +-- Set it off i.e. the cached connections which are used after this setting are +-- disconnected at the end of respective xacts. +SET postgres_fdw.keep_connections TO off; +-- Make connection using loopback server, connection should not be cached as +-- the GUC is off. +SELECT 1 FROM ft1 LIMIT 1; +-- Should output nothing. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; +-- Set it on i.e. connections are cached. +SET postgres_fdw.keep_connections TO on; +SELECT 1 FROM ft1 LIMIT 1; +-- Should output loopback. +SELECT * FROM postgres_fdw_get_connections() ORDER BY 1; + -- =================================================================== -- batch insert -- =================================================================== diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml index 8d6abd4c54..f23b77e847 100644 --- a/doc/src/sgml/postgres-fdw.sgml +++ b/doc/src/sgml/postgres-fdw.sgml @@ -571,6 +571,42 @@ postgres=# SELECT postgres_fdw_disconnect_all(); + + Configuration Parameters + + + + + + postgres_fdw.keep_connections (boolean) + + postgres_fdw.keep_connections configuration parameter + + + + + + + Allows postgres_fdw to keep or discard the + connection made to the foreign server by the local session. Default is + on. When set to off the local + session doesn't keep the connections made to the foreign servers. Each + connection is discarded at the end of transaction in which it is used. + + + + Note that setting postgres_fdw.keep_connections to + off does not discard any previously made and still open + connections immediately. They will be closed only at the end of future + transactions, which operated on them. To close all connections + immediately use postgres_fdw_disconnect function. + + + + + + + Connection Management @@ -602,6 +638,14 @@ postgres=# SELECT postgres_fdw_disconnect_all(); the connections that are no longer necessary and then preventing them from consuming the foreign server connections capacity too much. + + + Use configuration parameter postgres_fdw.keep_connections, + so that the local session doesn't keep any remote connections that are made + to the foreign servers within it. Default being on, when + set to off, each connection is discarded at the end of + local transaction in which it is used. + -- 2.25.1