From 4b8d7165d58776f934e2680cc3c061f84057fb68 Mon Sep 17 00:00:00 2001 From: Masahiko Sawada Date: Thu, 9 May 2019 20:02:05 +0900 Subject: [PATCH v2 1/2] Add --index-cleanup option to vacuumdb. --- doc/src/sgml/ref/vacuumdb.sgml | 18 ++++++++++++ src/bin/scripts/t/100_vacuumdb.pl | 16 +++++++++- src/bin/scripts/vacuumdb.c | 62 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/doc/src/sgml/ref/vacuumdb.sgml b/doc/src/sgml/ref/vacuumdb.sgml index 47d9345..78e8c49 100644 --- a/doc/src/sgml/ref/vacuumdb.sgml +++ b/doc/src/sgml/ref/vacuumdb.sgml @@ -149,6 +149,24 @@ PostgreSQL documentation + + + + Specify that VACUUM should attempt to remove + index entries pointing to dead tuples. If not specify this option + the behavior depends on vacuum_index_cleanup option + for the table to be vacuumed. + + + + This option is only available for servers running + PostgreSQL 12 and later. + + + + + + diff --git a/src/bin/scripts/t/100_vacuumdb.pl b/src/bin/scripts/t/100_vacuumdb.pl index 7f3a9b1..b23e091 100644 --- a/src/bin/scripts/t/100_vacuumdb.pl +++ b/src/bin/scripts/t/100_vacuumdb.pl @@ -3,7 +3,7 @@ use warnings; use PostgresNode; use TestLib; -use Test::More tests => 44; +use Test::More tests => 50; program_help_ok('vacuumdb'); program_version_ok('vacuumdb'); @@ -45,9 +45,23 @@ $node->issues_sql_like( [ 'vacuumdb', '--skip-locked', '--analyze-only', 'postgres' ], qr/statement: ANALYZE \(SKIP_LOCKED\).*;/, 'vacuumdb --skip-locked --analyze-only'); +$node->issues_sql_like( + [ 'vacuumdb', '--index-cleanup=false', 'postgres' ], + qr/statement: VACUUM \(INDEX_CLEANUP FALSE\).*;/, + 'vacuumdb --index-cleanup=false'); +$node->issues_sql_like( + [ 'vacuumdb', '--index-cleanup=true', 'postgres' ], + qr/statement: VACUUM \(INDEX_CLEANUP TRUE\).*;/, + 'vacuumdb --index-cleanup=true'); $node->command_fails( [ 'vacuumdb', '--analyze-only', '--disable-page-skipping', 'postgres' ], '--analyze-only and --disable-page-skipping specified together'); +$node->command_fails( + [ 'vacuumdb', '--analyze-only', '--index-cleanup=true', 'postgres' ], + '--analyze-only and --index-cleanup specified together'); +$node->command_fails( + [ 'vacuumdb', '--index-cleanup=invalid', 'postgres' ], + '--index-cleanup with an invalid argument'); $node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)], 'vacuumdb with connection string'); diff --git a/src/bin/scripts/vacuumdb.c b/src/bin/scripts/vacuumdb.c index e9da74c..408b4de 100644 --- a/src/bin/scripts/vacuumdb.c +++ b/src/bin/scripts/vacuumdb.c @@ -46,6 +46,7 @@ typedef struct vacuumingOptions bool skip_locked; int min_xid_age; int min_mxid_age; + char *index_cleanup; } vacuumingOptions; @@ -87,6 +88,10 @@ static void init_slot(ParallelSlot *slot, PGconn *conn); static void help(const char *progname); +static void check_bool_str(const char *opt_name, char *opt_str); + +static bool get_bool_from_str(char *bool_str); + /* For analyze-in-stages mode */ #define ANALYZE_NO_STAGE -1 #define ANALYZE_NUM_STAGES 3 @@ -118,6 +123,7 @@ main(int argc, char *argv[]) {"skip-locked", no_argument, NULL, 5}, {"min-xid-age", required_argument, NULL, 6}, {"min-mxid-age", required_argument, NULL, 7}, + {"index-cleanup", required_argument, NULL, 8}, {NULL, 0, NULL, 0} }; @@ -242,6 +248,12 @@ main(int argc, char *argv[]) exit(1); } break; + case 8: + { + vacopts.index_cleanup = pg_strdup(optarg); + check_bool_str("index-cleanup", vacopts.index_cleanup); + } + break; default: fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname); exit(1); @@ -286,6 +298,13 @@ main(int argc, char *argv[]) "disable-page-skipping"); exit(1); } + if (vacopts.index_cleanup && + get_bool_from_str(vacopts.index_cleanup)) + { + pg_log_error("cannot use the \"%s\" option when performing only analyze", + "index-cleanup"); + exit(1); + } /* allow 'and_analyze' with 'analyze_only' */ } @@ -414,6 +433,14 @@ vacuum_one_database(const char *dbname, vacuumingOptions *vacopts, exit(1); } + if (vacopts->index_cleanup != NULL && PQserverVersion(conn) < 120000) + { + PQfinish(conn); + pg_log_error("cannot use the \"%s\" option on server versions older than PostgreSQL 12", + "index-cleanup"); + exit(1); + } + if (vacopts->skip_locked && PQserverVersion(conn) < 120000) { PQfinish(conn); @@ -874,6 +901,15 @@ prepare_vacuum_command(PQExpBuffer sql, int serverVersion, appendPQExpBuffer(sql, "%sSKIP_LOCKED", sep); sep = comma; } + if (vacopts->index_cleanup) + { + /* INDEX_CLEANUP is supported since 12 */ + Assert(serverVersion >= 120000); + appendPQExpBuffer(sql, "%sINDEX_CLEANUP %s", sep, + get_bool_from_str(vacopts->index_cleanup) + ? "TRUE" : "FALSE"); + sep = comma; + } if (vacopts->full) { appendPQExpBuffer(sql, "%sFULL", sep); @@ -1209,6 +1245,31 @@ init_slot(ParallelSlot *slot, PGconn *conn) slot->isFree = true; } +/* Check the given string is either "true" or "false" */ +static void +check_bool_str(const char *opt_name, char *opt_str) +{ + if (strncasecmp(opt_str, "true", 4) != 0 && + strncasecmp(opt_str, "false", 5) != 0) + { + pg_log_error("the \"%s\" option requires a boolean value", opt_name); + exit(1); + } +} + +/* + * Return a bool value according to the given boolean string. 'bool_str' + * must not be NULL and be either "true" or "false". + */ +static bool +get_bool_from_str(char *bool_str) +{ + if (strncasecmp(bool_str, "true", 4) == 0) + return true; + else + return false; +} + static void help(const char *progname) { @@ -1222,6 +1283,7 @@ help(const char *progname) printf(_(" -e, --echo show the commands being sent to the server\n")); printf(_(" -f, --full do full vacuuming\n")); printf(_(" -F, --freeze freeze row transaction information\n")); + printf(_(" --index-cleanup=BOOLEAN do or do not index vacuuming and index cleanup\n")); 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")); -- 2.10.5