regression_tests_for_parallel_vacuum.patch
application/octet-stream
Filename: regression_tests_for_parallel_vacuum.patch
Type: application/octet-stream
Part: 0
Message:
Re: parallel vacuum comments
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/access/heap/vacuumlazy.c | 100 | 0 |
| src/test/regress/expected/vacuum_parallel.out | 38 | 0 |
| src/test/regress/parallel_schedule | 1 | 0 |
| src/test/regress/sql/vacuum_parallel.sql | 42 | 0 |
diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c
index 05221cc1d6..1abfdf06b7 100644
--- a/src/backend/access/heap/vacuumlazy.c
+++ b/src/backend/access/heap/vacuumlazy.c
@@ -153,6 +153,7 @@
#define PARALLEL_VACUUM_KEY_QUERY_TEXT 3
#define PARALLEL_VACUUM_KEY_BUFFER_USAGE 4
#define PARALLEL_VACUUM_KEY_WAL_USAGE 5
+#define PARALLEL_VACUUM_KEY_INDVAC_CHECK 6 /* used only when USE_ASSERT_CHECKING */
/*
* Macro to check if we are in a parallel vacuum. If true, we are in the
@@ -193,6 +194,20 @@ typedef struct LVDeadTuples
#define MAXDEADTUPLES(max_size) \
(((max_size) - offsetof(LVDeadTuples, itemptrs)) / sizeof(ItemPointerData))
+/*
+ * LVIndexCheck stores an array of booleans that indicates whether or not
+ * N'th index is vacuumed (or cleaned up) or not. This is used to verify that
+ * all indexes are processed by parallel index vacuum. Therefore, this
+ * is used only when parallel vacuum and USE_ASSERT_CHECKING is defined.
+ */
+typedef struct LVIndVacCheck
+{
+ int nindexes;
+ bool processed[FLEXIBLE_ARRAY_MEMBER];
+} LVIndVacCheck;
+#define SizeOfLVIndVacCheck(nindexes) \
+ add_size(offsetof(LVIndVacCheck, processed), mul_size(sizeof(bool), (nindexes)))
+
/*
* Shared information among parallel workers. So this is allocated in the DSM
* segment.
@@ -369,6 +384,12 @@ typedef struct LVRelState
* table */
int64 num_tuples; /* total number of nonremovable tuples */
int64 live_tuples; /* live tuples (reltuples estimate) */
+
+ /*
+ * Information used to verify the result of parallel vacuum. This is
+ * always NULL if USE_ASSERT_CHECKING is undefined.
+ */
+ LVIndVacCheck *indvac_check;
} LVRelState;
/*
@@ -468,6 +489,11 @@ static void update_vacuum_error_info(LVRelState *vacrel,
static void restore_vacuum_error_info(LVRelState *vacrel,
const LVSavedErrInfo *saved_vacrel);
+#ifdef USE_ASSERT_CHECKING
+static void lazy_clear_indvac_check_info(LVIndVacCheck *indvac_check);
+static void lazy_mark_index_processed(LVIndVacCheck *indvac_check, int idx);
+static void lazy_verify_indvac_result(LVIndVacCheck *indvac_check);
+#endif
/*
* heap_vacuum_rel() -- perform VACUUM for one heap relation
@@ -2764,6 +2790,11 @@ do_parallel_vacuum_or_cleanup(LVRelState *vacrel, int nworkers)
lps->pcxt->nworkers_launched, nworkers)));
}
+#ifdef USE_ASSERT_CHECKING
+ /* Clear index vacuum check info before actual vacuum processing */
+ lazy_clear_indvac_check_info(vacrel->indvac_check);
+#endif
+
/* Process the indexes that can be processed by only leader process */
do_serial_processing_for_unsafe_indexes(vacrel, lps->lvshared);
@@ -2786,6 +2817,11 @@ do_parallel_vacuum_or_cleanup(LVRelState *vacrel, int nworkers)
InstrAccumParallelQuery(&lps->buffer_usage[i], &lps->wal_usage[i]);
}
+#ifdef USE_ASSERT_CHECKING
+ /* Check if all indexes have been processed */
+ lazy_verify_indvac_result(vacrel->indvac_check);
+#endif
+
/*
* Carry the shared balance value to heap scan and disable shared costing
*/
@@ -2847,6 +2883,10 @@ do_parallel_processing(LVRelState *vacrel, LVShared *lvshared)
lvshared,
shared_istat,
vacrel);
+#ifdef USE_ASSERT_CHECKING
+ /* Mark this index has been processed */
+ lazy_mark_index_processed(vacrel->indvac_check, idx);
+#endif
}
/*
@@ -2898,6 +2938,11 @@ do_serial_processing_for_unsafe_indexes(LVRelState *vacrel, LVShared *lvshared)
lvshared,
shared_istat,
vacrel);
+
+#ifdef USE_ASSERT_CHECKING
+ /* Mark this index has been processed */
+ lazy_mark_index_processed(vacrel->indvac_check, idx);
+#endif
}
/*
@@ -3837,6 +3882,7 @@ begin_parallel_vacuum(LVRelState *vacrel, BlockNumber nblocks,
ParallelContext *pcxt;
LVShared *shared;
LVDeadTuples *dead_tuples;
+ LVIndVacCheck *indvac_check = NULL;
BufferUsage *buffer_usage;
WalUsage *wal_usage;
bool *can_parallel_vacuum;
@@ -3936,6 +3982,15 @@ begin_parallel_vacuum(LVRelState *vacrel, BlockNumber nblocks,
mul_size(sizeof(WalUsage), pcxt->nworkers));
shm_toc_estimate_keys(&pcxt->estimator, 1);
+ /*
+ * Estimate size for index check information --
+ * PARALLEL_VACUUM_KEY_INDVAC_CHECK.
+ */
+#ifdef USE_ASSERT_CHECKING
+ shm_toc_estimate_chunk(&pcxt->estimator, SizeOfLVIndVacCheck(nindexes));
+ shm_toc_estimate_keys(&pcxt->estimator, 1);
+#endif
+
/* Finally, estimate PARALLEL_VACUUM_KEY_QUERY_TEXT space */
if (debug_query_string)
{
@@ -4013,6 +4068,16 @@ begin_parallel_vacuum(LVRelState *vacrel, BlockNumber nblocks,
PARALLEL_VACUUM_KEY_QUERY_TEXT, sharedquery);
}
+#ifdef USE_ASSERT_CHECKING
+ /* Allocate and initialize space for index vacuum check information */
+ indvac_check = shm_toc_allocate(pcxt->toc, SizeOfLVIndVacCheck(nindexes));
+ MemSet(indvac_check, 0, SizeOfLVIndVacCheck(nindexes));
+ indvac_check->nindexes = nindexes;
+ shm_toc_insert(pcxt->toc, PARALLEL_VACUUM_KEY_INDVAC_CHECK, indvac_check);
+#endif
+
+ vacrel->indvac_check = indvac_check;
+
pfree(can_parallel_vacuum);
return lps;
}
@@ -4140,6 +4205,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
Relation *indrels;
LVShared *lvshared;
LVDeadTuples *dead_tuples;
+ LVIndVacCheck *indvac_check = NULL;
BufferUsage *buffer_usage;
WalUsage *wal_usage;
int nindexes;
@@ -4201,6 +4267,10 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
if (lvshared->maintenance_work_mem_worker > 0)
maintenance_work_mem = lvshared->maintenance_work_mem_worker;
+#ifdef USE_ASSERT_CHECKING
+ indvac_check = shm_toc_lookup(toc, PARALLEL_VACUUM_KEY_INDVAC_CHECK, false);
+#endif
+
/*
* Initialize vacrel for use as error callback arg by parallel worker.
*/
@@ -4209,6 +4279,7 @@ parallel_vacuum_main(dsm_segment *seg, shm_toc *toc)
vacrel.indname = NULL;
vacrel.phase = VACUUM_ERRCB_PHASE_UNKNOWN; /* Not yet processing */
vacrel.dead_tuples = dead_tuples;
+ vacrel.indvac_check = indvac_check;
/* Setup error traceback support for ereport() */
errcallback.callback = vacuum_error_callback;
@@ -4331,3 +4402,32 @@ restore_vacuum_error_info(LVRelState *vacrel,
vacrel->offnum = saved_vacrel->offnum;
vacrel->phase = saved_vacrel->phase;
}
+
+#ifdef USE_ASSERT_CHECKING
+
+/* Clear information used by lazy_verify_indvac_result() later */
+static void
+lazy_clear_indvac_check_info(LVIndVacCheck *indvac_check)
+{
+ MemSet(indvac_check->processed, false, sizeof(bool) * indvac_check->nindexes);
+}
+
+/* Mark the idx'th index has been processed */
+static void
+lazy_mark_index_processed(LVIndVacCheck *indvac_check, int idx)
+{
+ /* The index must be processed only one process */
+ Assert(!indvac_check->processed[idx]);
+ indvac_check->processed[idx] = true;
+}
+
+/* Check if all indexes have been processed */
+static void
+lazy_verify_indvac_result(LVIndVacCheck *indvac_check)
+{
+ Assert(indvac_check->nindexes > 0);
+ for (int i = 0; i < indvac_check->nindexes; i++)
+ Assert(indvac_check->processed[i]);
+}
+
+#endif /* USE_ASSERT_CHECKING */
diff --git a/src/test/regress/expected/vacuum_parallel.out b/src/test/regress/expected/vacuum_parallel.out
new file mode 100644
index 0000000000..b2946a22eb
--- /dev/null
+++ b/src/test/regress/expected/vacuum_parallel.out
@@ -0,0 +1,38 @@
+--
+-- VACUUM_PARALLEL
+-- All parallel vacuum tests in this file check if any index is not
+-- vacuumed during parallel vacuum which causes an assertion failure.
+--
+SET max_parallel_maintenance_workers TO 4;
+SET min_parallel_index_scan_size TO '64kB';
+CREATE TABLE pvac_test1 (a int) WITH (autovacuum_enabled = off);
+INSERT INTO pvac_test1 SELECT generate_series(1, 100000);
+CREATE INDEX pvac_large_index_1 ON pvac_test1 (a);
+CREATE INDEX pvac_large_index_2 ON pvac_test1 (a);
+CREATE INDEX pvac_small_index_1 ON pvac_test1 (a) WHERE a < 10;
+CREATE INDEX pvac_small_index_2 ON pvac_test1 (a) WHERE a < 20;
+SELECT relname, pg_relation_size(oid) < pg_size_bytes(current_setting('min_parallel_index_scan_size')) as is_small FROM pg_class WHERE relname ~ 'pvac_' AND relkind = 'i' ORDER BY 1;
+ relname | is_small
+--------------------+----------
+ pvac_large_index_1 | f
+ pvac_large_index_2 | f
+ pvac_small_index_1 | t
+ pvac_small_index_2 | t
+(4 rows)
+
+DELETE FROM pvac_test1;
+-- Do parallel index vacuum.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
+-- Do parallel index cleanup.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
+CREATE TABLE pvac_test2 (a int, b int4[]) WITH (autovacuum_enabled = off);
+INSERT INTO pvac_test2 SELECT g, ARRAY[1, 2, g] FROM generate_series(1, 100000) g;
+CREATE INDEX pvac_btree_idx on pvac_test2 USING btree (a);
+CREATE INDEX pvac_gin_idx on pvac_test2 USING gin (b);
+CREATE INDEX pvac_brin_idx on pvac_test2 USING brin (a);
+CREATE INDEX pvac_hash_idx on pvac_test2 USING hash (a);
+DELETE FROM pvac_test2;
+-- Do parallel index vacuum for different kinds of indexes.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
+-- Do parallel index cleanup for different kinds of indexes.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 7be89178f0..017e962fed 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -96,6 +96,7 @@ test: rules psql psql_crosstab amutils stats_ext collate.linux.utf8
# run by itself so it can run parallel workers
test: select_parallel
test: write_parallel
+test: vacuum_parallel
# no relation related tests can be put in this group
test: publication subscription
diff --git a/src/test/regress/sql/vacuum_parallel.sql b/src/test/regress/sql/vacuum_parallel.sql
new file mode 100644
index 0000000000..78a8e3681f
--- /dev/null
+++ b/src/test/regress/sql/vacuum_parallel.sql
@@ -0,0 +1,42 @@
+--
+-- VACUUM_PARALLEL
+-- All parallel vacuum tests in this file check if any index is not
+-- vacuumed during parallel vacuum which causes an assertion failure.
+--
+
+SET max_parallel_maintenance_workers TO 4;
+SET min_parallel_index_scan_size TO '64kB';
+
+CREATE TABLE pvac_test1 (a int) WITH (autovacuum_enabled = off);
+INSERT INTO pvac_test1 SELECT generate_series(1, 100000);
+
+CREATE INDEX pvac_large_index_1 ON pvac_test1 (a);
+CREATE INDEX pvac_large_index_2 ON pvac_test1 (a);
+CREATE INDEX pvac_small_index_1 ON pvac_test1 (a) WHERE a < 10;
+CREATE INDEX pvac_small_index_2 ON pvac_test1 (a) WHERE a < 20;
+
+SELECT relname, pg_relation_size(oid) < pg_size_bytes(current_setting('min_parallel_index_scan_size')) as is_small FROM pg_class WHERE relname ~ 'pvac_' AND relkind = 'i' ORDER BY 1;
+
+DELETE FROM pvac_test1;
+
+-- Do parallel index vacuum.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
+
+-- Do parallel index cleanup.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
+
+CREATE TABLE pvac_test2 (a int, b int4[]) WITH (autovacuum_enabled = off);
+INSERT INTO pvac_test2 SELECT g, ARRAY[1, 2, g] FROM generate_series(1, 100000) g;
+
+CREATE INDEX pvac_btree_idx on pvac_test2 USING btree (a);
+CREATE INDEX pvac_gin_idx on pvac_test2 USING gin (b);
+CREATE INDEX pvac_brin_idx on pvac_test2 USING brin (a);
+CREATE INDEX pvac_hash_idx on pvac_test2 USING hash (a);
+
+DELETE FROM pvac_test2;
+
+-- Do parallel index vacuum for different kinds of indexes.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;
+
+-- Do parallel index cleanup for different kinds of indexes.
+VACUUM (PARALLEL 4, INDEX_CLEANUP ON) pvac_test1;