From c78e267328c6828473e78f87e8c17326ea059e0e Mon Sep 17 00:00:00 2001
From: Amit Kapila <akapila@postgresql.org>
Date: Mon, 23 Dec 2019 15:37:09 +0530
Subject: [PATCH 3/3] Add FAST option to vacuum command.

---
 doc/src/sgml/ref/vacuum.sgml         | 13 +++++++++++
 src/backend/access/heap/vacuumlazy.c | 43 ++++++++++++++++++++++--------------
 src/backend/commands/vacuum.c        |  9 ++++++--
 src/include/commands/vacuum.h        |  3 ++-
 src/test/regress/expected/vacuum.out |  3 +++
 src/test/regress/sql/vacuum.sql      |  4 ++++
 6 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml
index 9fee083..b190cb0 100644
--- a/doc/src/sgml/ref/vacuum.sgml
+++ b/doc/src/sgml/ref/vacuum.sgml
@@ -35,6 +35,7 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="paramet
     INDEX_CLEANUP [ <replaceable class="parameter">boolean</replaceable> ]
     TRUNCATE [ <replaceable class="parameter">boolean</replaceable> ]
     PARALLEL [ <replaceable class="parameter">integer</replaceable> ]
+    FAST [ <replaceable class="parameter">boolean</replaceable> ]
 
 <phrase>and <replaceable class="parameter">table_and_columns</replaceable> is:</phrase>
 
@@ -251,6 +252,18 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="paramet
    </varlistentry>
 
    <varlistentry>
+    <term><literal>FAST</literal></term>
+    <listitem>
+     <para>
+      Perform vacuum while disabling cost-based vacuum delay feature.
+      Specifying <literal>FAST</literal> is equivalent to performing
+      <command>VACUUM</command> with the
+      <xref linkend="guc-vacuum-cost-delay"/> parameter set to zero.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><replaceable class="parameter">boolean</replaceable></term>
     <listitem>
      <para>
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 71dea2c..01e51ef 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -219,6 +219,13 @@ typedef struct LVShared
 	pg_atomic_uint32 active_nworkers;
 
 	/*
+	 * True if we forcibly disable cost-based vacuum delay during parallel
+	 * index vacuum. This can be true when use specified the FAST vacuum
+	 * option.
+	 */
+	bool		fast;
+
+	/*
 	 * Variables to control parallel index vacuuming.  We have a bitmap to
 	 * indicate which index has stats in shared memory.  The set bit in the
 	 * map indicates that the particular index supports a parallel vacuum.
@@ -352,7 +359,7 @@ static void update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stat
 									int nindexes);
 static LVParallelState *begin_parallel_vacuum(Oid relid, Relation *Irel,
 											  LVRelStats *vacrelstats, BlockNumber nblocks,
-											  int nindexes, int nrequested);
+											  int nindexes, VacuumParams *params);
 static void end_parallel_vacuum(Relation *Irel, IndexBulkDeleteResult **stats,
 								LVParallelState *lps, int nindexes);
 static LVSharedIndStats *get_indstats(LVShared *lvshared, int n);
@@ -755,7 +762,7 @@ lazy_scan_heap(Relation onerel, VacuumParams *params, LVRelStats *vacrelstats,
 	if (params->nworkers >= 0 && vacrelstats->useindex)
 		lps = begin_parallel_vacuum(RelationGetRelid(onerel), Irel,
 									vacrelstats, nblocks, nindexes,
-									params->nworkers);
+									params);
 
 	/*
 	 * Allocate the space for dead tuples in case the parallel vacuum is not
@@ -1992,16 +1999,19 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
 			ReinitializeParallelDSM(lps->pcxt);
 		}
 
-		/* Enable shared cost balance */
-		VacuumSharedCostBalance = &(lps->lvshared->cost_balance);
-		VacuumActiveNWorkers = &(lps->lvshared->active_nworkers);
+		if (!lps->lvshared->fast)
+		{
+			/* Enable shared cost balance */
+			VacuumSharedCostBalance = &(lps->lvshared->cost_balance);
+			VacuumActiveNWorkers = &(lps->lvshared->active_nworkers);
 
-		/*
-		 * Set up shared cost balance and the number of active workers for
-		 * vacuum delay.
-		 */
-		pg_atomic_write_u32(VacuumSharedCostBalance, VacuumCostBalance);
-		pg_atomic_write_u32(VacuumActiveNWorkers, 0);
+			/*
+			 * Set up shared cost balance and the number of active workers for
+			 * vacuum delay.
+			 */
+			pg_atomic_write_u32(VacuumSharedCostBalance, VacuumCostBalance);
+			pg_atomic_write_u32(VacuumActiveNWorkers, 0);
+		}
 
 		/*
 		 * The number of workers can vary between and bulkdelete and cleanup
@@ -2020,7 +2030,7 @@ lazy_parallel_vacuum_indexes(Relation *Irel, IndexBulkDeleteResult **stats,
 			VacuumCostBalance = 0;
 			VacuumCostBalanceLocal = 0;
 		}
-		else
+		else if (!lps->lvshared->fast)
 		{
 			/*
 			 * Disable shared cost balance if we are not able to launch
@@ -3070,7 +3080,7 @@ update_index_statistics(Relation *Irel, IndexBulkDeleteResult **stats,
  */
 static LVParallelState *
 begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
-					  BlockNumber nblocks, int nindexes, int nrequested)
+					  BlockNumber nblocks, int nindexes, VacuumParams *params)
 {
 	LVParallelState *lps = NULL;
 	ParallelContext *pcxt;
@@ -3090,7 +3100,7 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
 	 * a parallel vacuum must be requested and there must be indexes on the
 	 * relation
 	 */
-	Assert(nrequested >= 0);
+	Assert(params->nworkers >= 0);
 	Assert(nindexes > 0);
 
 	/*
@@ -3098,7 +3108,7 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
 	 */
 	can_parallel_vacuum = (bool *) palloc0(sizeof(bool) * nindexes);
 	parallel_workers = compute_parallel_vacuum_workers(Irel, nindexes,
-													   nrequested,
+													   params->nworkers,
 													   can_parallel_vacuum);
 
 	/* Can't perform vacuum in parallel */
@@ -3177,6 +3187,7 @@ begin_parallel_vacuum(Oid relid, Relation *Irel, LVRelStats *vacrelstats,
 		(nindexes_mwm > 0) ?
 		maintenance_work_mem / Min(parallel_workers, nindexes_mwm) :
 		maintenance_work_mem;
+	shared->fast = (params->options & VACOPT_FAST);
 
 	/*
 	 * We need to care about alignment because we estimate the shared memory
@@ -3367,7 +3378,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
 												  false);
 
 	/* Set cost-based vacuum delay */
-	VacuumCostActive = (VacuumCostDelay > 0);
+	VacuumCostActive = ((VacuumCostDelay > 0) && !(lvshared->fast));
 	VacuumCostBalance = 0;
 	VacuumPageHit = 0;
 	VacuumPageMiss = 0;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 0672be2..3019a72 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -101,6 +101,7 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
 	bool		verbose = false;
 	bool		skip_locked = false;
 	bool		analyze = false;
+	bool		fast = false;
 	bool		freeze = false;
 	bool		full = false;
 	bool		disable_page_skipping = false;
@@ -130,6 +131,8 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
 		/* Parse options available on VACUUM */
 		else if (strcmp(opt->defname, "analyze") == 0)
 			analyze = defGetBoolean(opt);
+		else if (strcmp(opt->defname, "fast") == 0)
+			fast = defGetBoolean(opt);
 		else if (strcmp(opt->defname, "freeze") == 0)
 			freeze = defGetBoolean(opt);
 		else if (strcmp(opt->defname, "full") == 0)
@@ -177,7 +180,8 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel)
 		(analyze ? VACOPT_ANALYZE : 0) |
 		(freeze ? VACOPT_FREEZE : 0) |
 		(full ? VACOPT_FULL : 0) |
-		(disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0);
+		(disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0) |
+		(fast ? VACOPT_FAST : 0);
 
 	/* sanity checks on options */
 	Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE));
@@ -416,7 +420,8 @@ vacuum(List *relations, VacuumParams *params,
 		ListCell   *cur;
 
 		in_vacuum = true;
-		VacuumCostActive = (VacuumCostDelay > 0);
+		VacuumCostActive = ((VacuumCostDelay > 0) &&
+							!(params->options & VACOPT_FAST));
 		VacuumCostBalance = 0;
 		VacuumPageHit = 0;
 		VacuumPageMiss = 0;
diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h
index 254a6bc..faed3f9 100644
--- a/src/include/commands/vacuum.h
+++ b/src/include/commands/vacuum.h
@@ -183,7 +183,8 @@ typedef enum VacuumOption
 	VACOPT_FULL = 1 << 4,		/* FULL (non-concurrent) vacuum */
 	VACOPT_SKIP_LOCKED = 1 << 5,	/* skip if cannot get lock */
 	VACOPT_SKIPTOAST = 1 << 6,	/* don't process the TOAST table, if any */
-	VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7	/* don't skip any pages */
+	VACOPT_DISABLE_PAGE_SKIPPING = 1 << 7,	/* don't skip any pages */
+	VACOPT_FAST = 1 << 8		/* disable vacuum delay */
 } VacuumOption;
 
 /*
diff --git a/src/test/regress/expected/vacuum.out b/src/test/regress/expected/vacuum.out
index 8571133..07c7b88 100644
--- a/src/test/regress/expected/vacuum.out
+++ b/src/test/regress/expected/vacuum.out
@@ -118,6 +118,9 @@ CREATE TEMPORARY TABLE tmp (a int PRIMARY KEY);
 CREATE INDEX tmp_idx1 ON tmp (a);
 VACUUM (PARALLEL 1) tmp; -- disables parallel vacuum option
 WARNING:  disabling parallel option of vacuum on "tmp" --- cannot vacuum temporary tables in parallel
+--test FAST option
+UPDATE pvactst SET i = i WHERE i < 1000;
+VACUUM (FAST) pvactst;
 RESET min_parallel_index_scan_size;
 DROP TABLE pvactst;
 -- INDEX_CLEANUP option
diff --git a/src/test/regress/sql/vacuum.sql b/src/test/regress/sql/vacuum.sql
index be4f556..6227ab9 100644
--- a/src/test/regress/sql/vacuum.sql
+++ b/src/test/regress/sql/vacuum.sql
@@ -99,6 +99,10 @@ VACUUM (PARALLEL 2, FULL TRUE) pvactst; -- error, cannot use both PARALLEL and F
 CREATE TEMPORARY TABLE tmp (a int PRIMARY KEY);
 CREATE INDEX tmp_idx1 ON tmp (a);
 VACUUM (PARALLEL 1) tmp; -- disables parallel vacuum option
+
+--test FAST option
+UPDATE pvactst SET i = i WHERE i < 1000;
+VACUUM (FAST) pvactst;
 RESET min_parallel_index_scan_size;
 DROP TABLE pvactst;
 
-- 
1.8.3.1

