pg_upgrade: Parallelize encoding conversion check.
authorNathan Bossart <[email protected]>
Mon, 16 Sep 2024 21:10:33 +0000 (16:10 -0500)
committerNathan Bossart <[email protected]>
Mon, 16 Sep 2024 21:10:33 +0000 (16:10 -0500)
This commit makes use of the new task framework in pg_upgrade to
parallelize the check for incompatible user-defined encoding
conversions, i.e., those defined on servers older than v14.  This
step will now process multiple databases concurrently when
pg_upgrade's --jobs option is provided a value greater than 1.

Reviewed-by: Daniel Gustafsson, Ilya Gladyshev
Discussion: https://postgr.es/m/20240516211638.GA1688936%40nathanxps13

src/bin/pg_upgrade/check.c

index f63d113619a164565a943c042bf0bfdf91772c9a..1c277ce17bbe8c38dc93a790c2def925427c9582 100644 (file)
@@ -1684,81 +1684,89 @@ check_for_pg_role_prefix(ClusterInfo *cluster)
 }
 
 /*
- * Verify that no user-defined encoding conversions exist.
+ * Callback function for processing results of query for
+ * check_for_user_defined_encoding_conversions()'s UpgradeTask.  If the query
+ * returned any rows (i.e., the check failed), write the details to the report
+ * file.
  */
 static void
-check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
+process_user_defined_encoding_conversions(DbInfo *dbinfo, PGresult *res, void *arg)
 {
-   int         dbnum;
-   FILE       *script = NULL;
-   char        output_path[MAXPGPATH];
+   UpgradeTaskReport *report = (UpgradeTaskReport *) arg;
+   bool        db_used = false;
+   int         ntups = PQntuples(res);
+   int         i_conoid = PQfnumber(res, "conoid");
+   int         i_conname = PQfnumber(res, "conname");
+   int         i_nspname = PQfnumber(res, "nspname");
 
-   prep_status("Checking for user-defined encoding conversions");
+   AssertVariableIsOfType(&process_user_defined_encoding_conversions,
+                          UpgradeTaskProcessCB);
 
-   snprintf(output_path, sizeof(output_path), "%s/%s",
-            log_opts.basedir,
-            "encoding_conversions.txt");
+   if (!ntups)
+       return;
 
-   /* Find any user defined encoding conversions */
-   for (dbnum = 0; dbnum < cluster->dbarr.ndbs; dbnum++)
+   for (int rowno = 0; rowno < ntups; rowno++)
    {
-       PGresult   *res;
-       bool        db_used = false;
-       int         ntups;
-       int         rowno;
-       int         i_conoid,
-                   i_conname,
-                   i_nspname;
-       DbInfo     *active_db = &cluster->dbarr.dbs[dbnum];
-       PGconn     *conn = connectToServer(cluster, active_db->db_name);
-
-       /*
-        * The query below hardcodes FirstNormalObjectId as 16384 rather than
-        * interpolating that C #define into the query because, if that
-        * #define is ever changed, the cutoff we want to use is the value
-        * used by pre-version 14 servers, not that of some future version.
-        */
-       res = executeQueryOrDie(conn,
-                               "SELECT c.oid as conoid, c.conname, n.nspname "
-                               "FROM pg_catalog.pg_conversion c, "
-                               "     pg_catalog.pg_namespace n "
-                               "WHERE c.connamespace = n.oid AND "
-                               "      c.oid >= 16384");
-       ntups = PQntuples(res);
-       i_conoid = PQfnumber(res, "conoid");
-       i_conname = PQfnumber(res, "conname");
-       i_nspname = PQfnumber(res, "nspname");
-       for (rowno = 0; rowno < ntups; rowno++)
+       if (report->file == NULL &&
+           (report->file = fopen_priv(report->path, "w")) == NULL)
+           pg_fatal("could not open file \"%s\": %m", report->path);
+       if (!db_used)
        {
-           if (script == NULL &&
-               (script = fopen_priv(output_path, "w")) == NULL)
-               pg_fatal("could not open file \"%s\": %m", output_path);
-           if (!db_used)
-           {
-               fprintf(script, "In database: %s\n", active_db->db_name);
-               db_used = true;
-           }
-           fprintf(script, "  (oid=%s) %s.%s\n",
-                   PQgetvalue(res, rowno, i_conoid),
-                   PQgetvalue(res, rowno, i_nspname),
-                   PQgetvalue(res, rowno, i_conname));
+           fprintf(report->file, "In database: %s\n", dbinfo->db_name);
+           db_used = true;
        }
+       fprintf(report->file, "  (oid=%s) %s.%s\n",
+               PQgetvalue(res, rowno, i_conoid),
+               PQgetvalue(res, rowno, i_nspname),
+               PQgetvalue(res, rowno, i_conname));
+   }
+}
 
-       PQclear(res);
+/*
+ * Verify that no user-defined encoding conversions exist.
+ */
+static void
+check_for_user_defined_encoding_conversions(ClusterInfo *cluster)
+{
+   UpgradeTaskReport report;
+   UpgradeTask *task = upgrade_task_create();
+   const char *query;
 
-       PQfinish(conn);
-   }
+   prep_status("Checking for user-defined encoding conversions");
 
-   if (script)
+   report.file = NULL;
+   snprintf(report.path, sizeof(report.path), "%s/%s",
+            log_opts.basedir,
+            "encoding_conversions.txt");
+
+   /*
+    * The query below hardcodes FirstNormalObjectId as 16384 rather than
+    * interpolating that C #define into the query because, if that #define is
+    * ever changed, the cutoff we want to use is the value used by
+    * pre-version 14 servers, not that of some future version.
+    */
+   query = "SELECT c.oid as conoid, c.conname, n.nspname "
+       "FROM pg_catalog.pg_conversion c, "
+       "     pg_catalog.pg_namespace n "
+       "WHERE c.connamespace = n.oid AND "
+       "      c.oid >= 16384";
+
+   upgrade_task_add_step(task, query,
+                         process_user_defined_encoding_conversions,
+                         true, &report);
+   upgrade_task_run(task, cluster);
+   upgrade_task_free(task);
+
+   if (report.file)
    {
-       fclose(script);
+       fclose(report.file);
        pg_log(PG_REPORT, "fatal");
        pg_fatal("Your installation contains user-defined encoding conversions.\n"
                 "The conversion function parameters changed in PostgreSQL version 14\n"
                 "so this cluster cannot currently be upgraded.  You can remove the\n"
                 "encoding conversions in the old cluster and restart the upgrade.\n"
                 "A list of user-defined encoding conversions is in the file:\n"
-                "    %s", output_path);
+                "    %s", report.path);
    }
    else
        check_ok();