Make pg_createsubscriber warn if publisher has two-phase commit enabled.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Jun 2024 18:24:14 +0000 (14:24 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 30 Jun 2024 18:24:14 +0000 (14:24 -0400)
pg_createsubscriber currently always sets up logical replication
with two-phase commit disabled.  Improving that is not going to
happen for v17.  In the meantime, document the deficiency, and
adjust pg_createsubscriber so that it will emit a warning if
the source installation has max_prepared_transactions > 0.

Hayato Kuroda (some mods by Amit Kapila and me), per complaint from
Noah Misch

Discussion: https://postgr.es/m/20240623062157.97.nmisch@google.com

doc/src/sgml/ref/pg_createsubscriber.sgml
src/bin/pg_basebackup/pg_createsubscriber.c

index 2ee6eee9e35f72a774f90ccdf347a2fc538291f5..87a9d3db28e5d6e017ec9b5eefa9690784ee1046 100644 (file)
@@ -353,6 +353,17 @@ PostgreSQL documentation
     <application>pg_createsubscriber</application>.
    </para>
 
+   <para>
+    <application>pg_createsubscriber</application> sets up logical
+    replication with two-phase commit disabled.  This means that any
+    prepared transactions will be replicated at the time
+    of <command>COMMIT PREPARED</command>, without advance preparation.
+    Once setup is complete, you can manually drop and re-create the
+    subscription(s) with
+    the <link linkend="sql-createsubscription-params-with-two-phase"><literal>two_phase</literal></link>
+    option enabled.
+   </para>
+
    <para>
     <application>pg_createsubscriber</application> changes the system
     identifier using <application>pg_resetwal</application>.  It would avoid
index 7c943317860c45b8b7ff6b0d35c56152af5ed86d..fecf5db3653940df663bd5e28a510064803c056c 100644 (file)
@@ -823,6 +823,7 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
        int                     cur_repslots;
        int                     max_walsenders;
        int                     cur_walsenders;
+       int                     max_prepared_transactions;
 
        pg_log_info("checking settings on publisher");
 
@@ -849,23 +850,12 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
         * -----------------------------------------------------------------------
         */
        res = PQexec(conn,
-                                "WITH wl AS "
-                                "(SELECT setting AS wallevel FROM pg_catalog.pg_settings "
-                                "WHERE name = 'wal_level'), "
-                                "total_mrs AS "
-                                "(SELECT setting AS tmrs FROM pg_catalog.pg_settings "
-                                "WHERE name = 'max_replication_slots'), "
-                                "cur_mrs AS "
-                                "(SELECT count(*) AS cmrs "
-                                "FROM pg_catalog.pg_replication_slots), "
-                                "total_mws AS "
-                                "(SELECT setting AS tmws FROM pg_catalog.pg_settings "
-                                "WHERE name = 'max_wal_senders'), "
-                                "cur_mws AS "
-                                "(SELECT count(*) AS cmws FROM pg_catalog.pg_stat_activity "
-                                "WHERE backend_type = 'walsender') "
-                                "SELECT wallevel, tmrs, cmrs, tmws, cmws "
-                                "FROM wl, total_mrs, cur_mrs, total_mws, cur_mws");
+                                "SELECT pg_catalog.current_setting('wal_level'),"
+                                " pg_catalog.current_setting('max_replication_slots'),"
+                                " (SELECT count(*) FROM pg_catalog.pg_replication_slots),"
+                                " pg_catalog.current_setting('max_wal_senders'),"
+                                " (SELECT count(*) FROM pg_catalog.pg_stat_activity WHERE backend_type = 'walsender'),"
+                                " pg_catalog.current_setting('max_prepared_transactions')");
 
        if (PQresultStatus(res) != PGRES_TUPLES_OK)
        {
@@ -879,6 +869,7 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
        cur_repslots = atoi(PQgetvalue(res, 0, 2));
        max_walsenders = atoi(PQgetvalue(res, 0, 3));
        cur_walsenders = atoi(PQgetvalue(res, 0, 4));
+       max_prepared_transactions = atoi(PQgetvalue(res, 0, 5));
 
        PQclear(res);
 
@@ -887,6 +878,8 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
        pg_log_debug("publisher: current replication slots: %d", cur_repslots);
        pg_log_debug("publisher: max_wal_senders: %d", max_walsenders);
        pg_log_debug("publisher: current wal senders: %d", cur_walsenders);
+       pg_log_debug("publisher: max_prepared_transactions: %d",
+                                max_prepared_transactions);
 
        disconnect_database(conn, false);
 
@@ -914,6 +907,13 @@ check_publisher(const struct LogicalRepInfo *dbinfo)
                failed = true;
        }
 
+       if (max_prepared_transactions != 0)
+       {
+               pg_log_warning("two_phase option will not be enabled for slots");
+               pg_log_warning_detail("Subscriptions will be created with the two_phase option disabled.  "
+                                                         "Prepared transactions will be replicated at COMMIT PREPARED.");
+       }
+
        pg_free(wal_level);
 
        if (failed)