On 2021/02/22 14:55, Bharath Rupireddy wrote:
On Thu, Feb 4, 2021 at 9:36 AM Bharath Rupireddy
<bharath.rupireddyforpostg...@gmail.com> wrote:

On Wed, Feb 3, 2021 at 4:22 PM Fujii Masao <masao.fu...@oss.nttdata.com> wrote:
Maybe my explanation in the previous email was unclear. What I think is; If the 
server-level option is explicitly specified, its setting is used whatever GUC 
is. On the other hand, if the server-level option is NOT specified, GUC setting 
is used. For example, if we define the server as follows, GUC setting is used 
because the server-level option is NOT specified.

      CREATE SERVER loopback FOREIGN DATA WRAPPER postgres;

If we define the server as follows, the server-level setting is used.

      CREATE SERVER loopback FOREIGN DATA WRAPPER postgres OPTIONS 
(keep_connections 'on');

Attaching v20 patch set. Now, server level option if provided
overrides the GUC.The GUC will be used only if server level option is
not provided. And also, both server level option and GUC are named the
same - "keep_connections".

Please have a look.

Attaching v21 patch set, rebased onto the latest master.

I agree to add the server-level option. But I'm still not sure if it's good 
idea to also expose that option as GUC. Isn't the server-level option enough 
for most cases?

Also it's strange to expose only this option as GUC while there are other many 
postgres_fdw options?

With v21-002 patch, even when keep_connections GUC is disabled, the existing 
open connections are not close immediately. Only connections used in the 
transaction are closed at the end of that transaction. That is, the existing 
connections that no transactions use will never be closed. I'm not sure if this 
behavior is intuitive for users.

Therefore for now I'm thinking to support the server-level option at first... 
Then if we find it's not enough for most cases in practice, I'd like to 
consider to expose postgres_fdw options including keep_connections as GUC.

Thought?

BTW these patches fail to be applied to the master because of commit 
27e1f14563. I updated and simplified the 003 patch. Patch attached.

Regards,

--
Fujii Masao
Advanced Computing Technology Center
Research and Development Headquarters
NTT DATA CORPORATION
diff --git a/contrib/postgres_fdw/connection.c 
b/contrib/postgres_fdw/connection.c
index 54ab8edfab..6a61d83862 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -59,6 +59,8 @@ typedef struct ConnCacheEntry
        bool            have_error;             /* have any subxacts aborted in 
this xact? */
        bool            changing_xact_state;    /* xact state change in process 
*/
        bool            invalidated;    /* true if reconnect is pending */
+       bool            keep_connections;       /* setting value of 
keep_connections
+                                                                        * 
server option */
        Oid                     serverid;               /* foreign server OID 
used to get server name */
        uint32          server_hashvalue;       /* hash value of foreign server 
OID */
        uint32          mapping_hashvalue;      /* hash value of user mapping 
OID */
@@ -286,6 +288,7 @@ static void
 make_new_connection(ConnCacheEntry *entry, UserMapping *user)
 {
        ForeignServer *server = GetForeignServer(user->serverid);
+       ListCell   *lc;
 
        Assert(entry->conn == NULL);
 
@@ -304,6 +307,26 @@ make_new_connection(ConnCacheEntry *entry, UserMapping 
*user)
                                                          
ObjectIdGetDatum(user->umid));
        memset(&entry->state, 0, sizeof(entry->state));
 
+       /*
+        * Determine whether to keep the connection that we're about to make 
here
+        * open even after the transaction using it ends, so that the subsequent
+        * transactions can re-use it.
+        *
+        * It's enough to determine this only when making new connection because
+        * all the connections to the foreign server whose keep_connections 
option
+        * is changed will be closed and re-made later.
+        *
+        * By default, all the connections to any foreign servers are kept open.
+        */
+       entry->keep_connections = true;
+       foreach(lc, server->options)
+       {
+               DefElem    *def = (DefElem *) lfirst(lc);
+
+               if (strcmp(def->defname, "keep_connections") == 0)
+                       entry->keep_connections = defGetBoolean(def);
+       }
+
        /* Now try to make the connection */
        entry->conn = connect_pg_server(server, user);
 
@@ -970,14 +993,16 @@ pgfdw_xact_callback(XactEvent event, void *arg)
                entry->xact_depth = 0;
 
                /*
-                * 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.
+                * If the connection isn't in a good idle state, it is marked as
+                * invalid or keep_connections option of its server is 
disabled, 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 ||
+                       !entry->keep_connections)
                {
                        elog(DEBUG3, "discarding connection %p", entry->conn);
                        disconnect_pg_server(entry);
diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out 
b/contrib/postgres_fdw/expected/postgres_fdw.out
index eff7b04f11..5da68415ed 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -8908,7 +8908,7 @@ DO $d$
     END;
 $d$;
 ERROR:  invalid option "password"
-HINT:  Valid options in this context are: service, passfile, channel_binding, 
connect_timeout, dbname, host, hostaddr, port, options, application_name, 
keepalives, keepalives_idle, keepalives_interval, keepalives_count, 
tcp_user_timeout, sslmode, sslcompression, sslcert, sslkey, sslrootcert, 
sslcrl, sslcrldir, requirepeer, ssl_min_protocol_version, 
ssl_max_protocol_version, gssencmode, krbsrvname, gsslib, target_session_attrs, 
use_remote_estimate, fdw_startup_cost, fdw_tuple_cost, extensions, updatable, 
fetch_size, batch_size, async_capable
+HINT:  Valid options in this context are: service, passfile, channel_binding, 
connect_timeout, dbname, host, hostaddr, port, options, application_name, 
keepalives, keepalives_idle, keepalives_interval, keepalives_count, 
tcp_user_timeout, sslmode, sslcompression, sslcert, sslkey, sslrootcert, 
sslcrl, sslcrldir, requirepeer, ssl_min_protocol_version, 
ssl_max_protocol_version, gssencmode, krbsrvname, gsslib, target_session_attrs, 
use_remote_estimate, fdw_startup_cost, fdw_tuple_cost, extensions, updatable, 
fetch_size, batch_size, async_capable, keep_connections
 CONTEXT:  SQL statement "ALTER SERVER loopback_nopw OPTIONS (ADD password 
'dummypw')"
 PL/pgSQL function inline_code_block line 3 at EXECUTE
 -- If we add a password for our user mapping instead, we should get a different
@@ -9244,6 +9244,27 @@ DROP USER MAPPING FOR regress_multi_conn_user2 SERVER 
loopback;
 DROP ROLE regress_multi_conn_user1;
 DROP ROLE regress_multi_conn_user2;
 -- ===================================================================
+-- Test foreign server level option keep_connections
+-- ===================================================================
+-- By default, the connections associated with foreign server are cached i.e.
+-- keep_connections option is on. Set it to off.
+ALTER SERVER loopback OPTIONS (keep_connections 'off');
+-- connection to loopback server is closed at the end of xact
+-- as keep_connections was set to off.
+SELECT 1 FROM ft1 LIMIT 1;
+ ?column? 
+----------
+        1
+(1 row)
+
+-- No cached connections, so no records should be output.
+SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
+ server_name 
+-------------
+(0 rows)
+
+ALTER SERVER loopback OPTIONS (SET keep_connections 'on');
+-- ===================================================================
 -- batch insert
 -- ===================================================================
 BEGIN;
diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index 530d7a66d4..f1d0c8bd41 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -108,7 +108,8 @@ postgres_fdw_validator(PG_FUNCTION_ARGS)
                 */
                if (strcmp(def->defname, "use_remote_estimate") == 0 ||
                        strcmp(def->defname, "updatable") == 0 ||
-                       strcmp(def->defname, "async_capable") == 0)
+                       strcmp(def->defname, "async_capable") == 0 ||
+                       strcmp(def->defname, "keep_connections") == 0)
                {
                        /* these accept only boolean values */
                        (void) defGetBoolean(def);
@@ -221,6 +222,7 @@ InitPgFdwOptions(void)
                /* async_capable is available on both server and table */
                {"async_capable", ForeignServerRelationId, false},
                {"async_capable", ForeignTableRelationId, false},
+               {"keep_connections", ForeignServerRelationId, false},
                {"password_required", UserMappingRelationId, false},
 
                /*
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql 
b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 806a5bca28..85a968f7f0 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2819,6 +2819,19 @@ DROP USER MAPPING FOR regress_multi_conn_user2 SERVER 
loopback;
 DROP ROLE regress_multi_conn_user1;
 DROP ROLE regress_multi_conn_user2;
 
+-- ===================================================================
+-- Test foreign server level option keep_connections
+-- ===================================================================
+-- By default, the connections associated with foreign server are cached i.e.
+-- keep_connections option is on. Set it to off.
+ALTER SERVER loopback OPTIONS (keep_connections 'off');
+-- connection to loopback server is closed at the end of xact
+-- as keep_connections was set to off.
+SELECT 1 FROM ft1 LIMIT 1;
+-- No cached connections, so no records should be output.
+SELECT server_name FROM postgres_fdw_get_connections() ORDER BY 1;
+ALTER SERVER loopback OPTIONS (SET keep_connections 'on');
+
 -- ===================================================================
 -- batch insert
 -- ===================================================================
diff --git a/doc/src/sgml/postgres-fdw.sgml b/doc/src/sgml/postgres-fdw.sgml
index c21e9be209..a0c6b8f0b1 100644
--- a/doc/src/sgml/postgres-fdw.sgml
+++ b/doc/src/sgml/postgres-fdw.sgml
@@ -518,6 +518,33 @@ OPTIONS (ADD password_required 'false');
    </para>
 
   </sect3>
+
+  <sect3>
+    <title>Connection Management Options</title>
+
+    <para>
+     By default all the open connections that <filename>postgres_fdw</filename>
+     established to the foreign servers are kept in local session for re-use.
+    </para>
+ 
+    <variablelist>
+ 
+     <varlistentry>
+      <term><literal>keep_connections</literal></term>
+      <listitem>
+       <para>
+        This option controls whether <filename>postgres_fdw</filename> keeps
+        the connections to the foreign server open so that the subsequent
+        queries can re-use them. It can only be specified for a foreign server.
+        The default is <literal>true</literal>. If set to 
<literal>off</literal>,
+        all connections to this foreign server will be discarded at the end of
+        transaction.
+      </para>
+      </listitem>
+     </varlistentry>
+ 
+    </variablelist>
+   </sect3>
  </sect2>
 
 <sect2>
@@ -605,8 +632,10 @@ postgres=# SELECT postgres_fdw_disconnect_all();
   <para>
    <filename>postgres_fdw</filename> establishes a connection to a
    foreign server during the first query that uses a foreign table
-   associated with the foreign server.  This connection is kept and
-   re-used for subsequent queries in the same session.  However, if
+   associated with the foreign server.  By default this connection
+   is kept and re-used for subsequent queries in the same session.
+   This behavior can be controlled using
+   <literal>keep_connections</literal> option for a foreign server. If
    multiple user identities (user mappings) are used to access the foreign
    server, a connection is established for each user mapping.
   </para>
@@ -622,8 +651,10 @@ postgres=# SELECT postgres_fdw_disconnect_all();
 
   <para>
    Once a connection to a foreign server has been established,
-   it's usually kept until the local or corresponding remote
+   it's by default kept until the local or corresponding remote
    session exits.  To disconnect a connection explicitly,
+   <literal>keep_connections</literal> option for a foreign server
+   may be disabled, or
    <function>postgres_fdw_disconnect</function> and
    <function>postgres_fdw_disconnect_all</function> functions
    may be used.  For example, these are useful to close

Reply via email to