Add --parallel option to vacuumdb command.
authorAmit Kapila <akapila@postgresql.org>
Wed, 29 Jan 2020 05:38:50 +0000 (11:08 +0530)
committerAmit Kapila <akapila@postgresql.org>
Wed, 29 Jan 2020 05:38:50 +0000 (11:08 +0530)
Commit 40d964ec99 allowed vacuum command to leverage multiple CPUs by
invoking parallel workers to process indexes.  This commit provides a
'--parallel' option to specify the parallel degree used by vacuum command.

Author: Masahiko Sawada, with few modifications by me
Reviewed-by: Mahendra Singh and Amit Kapila
Discussion: https://postgr.es/m/CAD21AoDTPMgzSkV4E3SFo1CH_x50bf5PqZFQf4jmqjk-C03BWg@mail.gmail.com

doc/src/sgml/ref/vacuumdb.sgml
src/bin/scripts/t/100_vacuumdb.pl
src/bin/scripts/vacuumdb.c

index 47d93456f862009cb3519d13c4d71e7c59c03a02..775c9ec651b419ee5f78b46900a4df8ee2f83d29 100644 (file)
@@ -226,6 +226,24 @@ PostgreSQL documentation
       </listitem>
      </varlistentry>
 
+     <varlistentry>
+      <term><option>-P <replaceable class="parameter">parallel_degree</replaceable></option></term>
+      <term><option>--parallel=<replaceable class="parameter">parallel_degree</replaceable></option></term>
+      <listitem>
+       <para>
+        Specify the parallel degree of <firstterm>parallel vacuum</firstterm>.
+        This allows the vacuum to leverage multiple CPUs to process indexes.
+        See <xref linkend="sql-vacuum"/>.
+       </para>
+       <note>
+        <para>
+         This option is only available for servers running
+         <productname>PostgreSQL</productname> 13 and later.
+        </para>
+       </note>
+      </listitem>
+     </varlistentry>
+
      <varlistentry>
       <term><option>-q</option></term>
       <term><option>--quiet</option></term>
index b685b3528287031a853e6334b18701fd45e44908..c2284c8195f6ef3626261160a8916f294f757b50 100644 (file)
@@ -3,7 +3,7 @@ use warnings;
 
 use PostgresNode;
 use TestLib;
-use Test::More tests => 44;
+use Test::More tests => 49;
 
 program_help_ok('vacuumdb');
 program_version_ok('vacuumdb');
@@ -48,6 +48,14 @@ $node->issues_sql_like(
 $node->command_fails(
        [ 'vacuumdb', '--analyze-only', '--disable-page-skipping', 'postgres' ],
        '--analyze-only and --disable-page-skipping specified together');
+$node->issues_sql_like(
+       [ 'vacuumdb', '-P', 2, 'postgres' ],
+       qr/statement: VACUUM \(PARALLEL 2\).*;/,
+       'vacuumdb -P 2');
+$node->issues_sql_like(
+       [ 'vacuumdb', '-P', 0, 'postgres' ],
+       qr/statement: VACUUM \(PARALLEL 0\).*;/,
+       'vacuumdb -P 0');
 $node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)],
        'vacuumdb with connection string');
 
@@ -81,6 +89,9 @@ $node->command_fails(
 $node->command_fails(
        [ 'vacuumdb', '--analyze', '--table', 'vactable(c)', 'postgres' ],
        'incorrect column name with ANALYZE');
+$node->command_fails(
+       [ 'vacuumdb', '-P', -1, 'postgres' ],
+       'negative parallel degree');
 $node->issues_sql_like(
        [ 'vacuumdb', '--analyze', '--table', 'vactable(a, b)', 'postgres' ],
        qr/statement: VACUUM \(ANALYZE\) public.vactable\(a, b\);/,
index bfa6ac63553e4e06d7c51961887aff076570ccdb..0560f6304fff4fdb61697ec9c4e170963fab6626 100644 (file)
@@ -35,6 +35,8 @@ typedef struct vacuumingOptions
        bool            skip_locked;
        int                     min_xid_age;
        int                     min_mxid_age;
+       int                     parallel_workers;       /* >= 0 indicates user specified the
+                                                                        * parallel degree, otherwise -1 */
 } vacuumingOptions;
 
 
@@ -87,6 +89,7 @@ main(int argc, char *argv[])
                {"full", no_argument, NULL, 'f'},
                {"verbose", no_argument, NULL, 'v'},
                {"jobs", required_argument, NULL, 'j'},
+               {"parallel", required_argument, NULL, 'P'},
                {"maintenance-db", required_argument, NULL, 2},
                {"analyze-in-stages", no_argument, NULL, 3},
                {"disable-page-skipping", no_argument, NULL, 4},
@@ -116,6 +119,7 @@ main(int argc, char *argv[])
 
        /* initialize options to all false */
        memset(&vacopts, 0, sizeof(vacopts));
+       vacopts.parallel_workers = -1;
 
        pg_logging_init(argv[0]);
        progname = get_progname(argv[0]);
@@ -123,7 +127,7 @@ main(int argc, char *argv[])
 
        handle_help_version_opts(argc, argv, "vacuumdb", help);
 
-       while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fvj:", long_options, &optindex)) != -1)
+       while ((c = getopt_long(argc, argv, "h:p:U:wWeqd:zZFat:fvj:P:", long_options, &optindex)) != -1)
        {
                switch (c)
                {
@@ -183,6 +187,14 @@ main(int argc, char *argv[])
                                        exit(1);
                                }
                                break;
+                       case 'P':
+                               vacopts.parallel_workers = atoi(optarg);
+                               if (vacopts.parallel_workers < 0)
+                               {
+                                       pg_log_error("parallel vacuum degree must be a non-negative integer");
+                                       exit(1);
+                               }
+                               break;
                        case 2:
                                maintenance_db = pg_strdup(optarg);
                                break;
@@ -258,6 +270,23 @@ main(int argc, char *argv[])
                /* allow 'and_analyze' with 'analyze_only' */
        }
 
+       /* Prohibit full and analyze_only options with parallel option */
+       if (vacopts.parallel_workers >= 0)
+       {
+               if (vacopts.analyze_only)
+               {
+                       pg_log_error("cannot use the \"%s\" option when performing only analyze",
+                                                "parallel");
+                       exit(1);
+               }
+               if (vacopts.full)
+               {
+                       pg_log_error("cannot use the \"%s\" option when performing full",
+                                                "parallel");
+                       exit(1);
+               }
+       }
+
        setup_cancel_handler(NULL);
 
        /* Avoid opening extra connections. */
@@ -405,6 +434,13 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts,
                exit(1);
        }
 
+       if (vacopts->parallel_workers >= 0 && PQserverVersion(conn) < 130000)
+       {
+               pg_log_error("cannot use the \"%s\" option on server versions older than PostgreSQL %s",
+                                        "--parallel", "13");
+               exit(1);
+       }
+
        if (!quiet)
        {
                if (stage != ANALYZE_NO_STAGE)
@@ -823,6 +859,14 @@ prepare_vacuum_command(PQExpBuffer sql, int serverVersion,
                                appendPQExpBuffer(sql, "%sANALYZE", sep);
                                sep = comma;
                        }
+                       if (vacopts->parallel_workers >= 0)
+                       {
+                               /* PARALLEL is supported since v13 */
+                               Assert(serverVersion >= 130000);
+                               appendPQExpBuffer(sql, "%sPARALLEL %d", sep,
+                                                                 vacopts->parallel_workers);
+                               sep = comma;
+                       }
                        if (sep != paren)
                                appendPQExpBufferChar(sql, ')');
                }
@@ -886,6 +930,7 @@ help(const char *progname)
        printf(_("  -j, --jobs=NUM                  use this many concurrent connections to vacuum\n"));
        printf(_("      --min-mxid-age=MXID_AGE     minimum multixact ID age of tables to vacuum\n"));
        printf(_("      --min-xid-age=XID_AGE       minimum transaction ID age of tables to vacuum\n"));
+       printf(_("  -P, --parallel=PARALLEL_DEGREE  use this many background workers for vacuum, if available\n"));
        printf(_("  -q, --quiet                     don't write any messages\n"));
        printf(_("      --skip-locked               skip relations that cannot be immediately locked\n"));
        printf(_("  -t, --table='TABLE[(COLUMNS)]'  vacuum specific table(s) only\n"));