From f362b542c11975d288ac57bc24d894d3e7950ab6 Mon Sep 17 00:00:00 2001 From: Sami Imseih Date: Mon, 10 Aug 2026 21:51:31 +0000 Subject: [PATCH v2 2/2] test autovacuum toast reloptions --- src/backend/commands/vacuum.c | 26 ++++-- src/test/modules/test_misc/meson.build | 1 + .../t/015_autovacuum_toast_reloptions.pl | 82 +++++++++++++++++++ 3 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 src/test/modules/test_misc/t/015_autovacuum_toast_reloptions.pl diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 31f9824899c..f535488631c 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -2228,12 +2228,22 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, } #ifdef USE_INJECTION_POINTS + + /* + * An autovacuum worker processes many relations, so it passes the + * relation name for a test to match with a condition string. A manual + * VACUUM is tested with a local injection point, so it does not need to + * deal with other relations. + */ if (params.index_cleanup == VACOPTVALUE_AUTO) - INJECTION_POINT("vacuum-index-cleanup-auto", NULL); + INJECTION_POINT("vacuum-index-cleanup-auto", + AmAutoVacuumWorkerProcess() ? RelationGetRelationName(rel) : NULL); else if (params.index_cleanup == VACOPTVALUE_DISABLED) - INJECTION_POINT("vacuum-index-cleanup-disabled", NULL); + INJECTION_POINT("vacuum-index-cleanup-disabled", + AmAutoVacuumWorkerProcess() ? RelationGetRelationName(rel) : NULL); else if (params.index_cleanup == VACOPTVALUE_ENABLED) - INJECTION_POINT("vacuum-index-cleanup-enabled", NULL); + INJECTION_POINT("vacuum-index-cleanup-enabled", + AmAutoVacuumWorkerProcess() ? RelationGetRelationName(rel) : NULL); #endif /* @@ -2267,12 +2277,16 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams params, } #ifdef USE_INJECTION_POINTS + /* See the comment for the index_cleanup injection points above. */ if (params.truncate == VACOPTVALUE_AUTO) - INJECTION_POINT("vacuum-truncate-auto", NULL); + INJECTION_POINT("vacuum-truncate-auto", + AmAutoVacuumWorkerProcess() ? RelationGetRelationName(rel) : NULL); else if (params.truncate == VACOPTVALUE_DISABLED) - INJECTION_POINT("vacuum-truncate-disabled", NULL); + INJECTION_POINT("vacuum-truncate-disabled", + AmAutoVacuumWorkerProcess() ? RelationGetRelationName(rel) : NULL); else if (params.truncate == VACOPTVALUE_ENABLED) - INJECTION_POINT("vacuum-truncate-enabled", NULL); + INJECTION_POINT("vacuum-truncate-enabled", + AmAutoVacuumWorkerProcess() ? RelationGetRelationName(rel) : NULL); #endif /* diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build index ee290698b31..f03c8d09c76 100644 --- a/src/test/modules/test_misc/meson.build +++ b/src/test/modules/test_misc/meson.build @@ -23,6 +23,7 @@ tests += { 't/012_ddlutils.pl', 't/013_temp_obj_multisession.pl', 't/014_log_statement_max_length.pl', + 't/015_autovacuum_toast_reloptions.pl', ], # The injection points are cluster-wide, so disable installcheck 'runningcheck': false, diff --git a/src/test/modules/test_misc/t/015_autovacuum_toast_reloptions.pl b/src/test/modules/test_misc/t/015_autovacuum_toast_reloptions.pl new file mode 100644 index 00000000000..2fa18466045 --- /dev/null +++ b/src/test/modules/test_misc/t/015_autovacuum_toast_reloptions.pl @@ -0,0 +1,82 @@ +# Copyright (c) 2024-2026, PostgreSQL Global Development Group + +# A TOAST relation inherits vacuum reloptions from its main table when it has +# no toast.* value of its own. Condition strings key each wait to the TOAST +# relation, so its resolution is observed on its own. + +use strict; +use warnings FATAL => 'all'; +use PostgreSQL::Test::Cluster; +use Test::More; + +if ($ENV{enable_injection_points} ne 'yes') +{ + plan skip_all => 'Injection points not supported by this build'; +} + +my $node = PostgreSQL::Test::Cluster->new('node'); +$node->init; + +# Run autovacuum quickly and eagerly. +$node->append_conf( + 'postgresql.conf', qq( +autovacuum_naptime = 1 +autovacuum_vacuum_threshold = 1 +autovacuum_vacuum_scale_factor = 0 +)); +$node->start; + +if (!$node->check_extension('injection_points')) +{ + plan skip_all => 'Extension injection_points not installed'; +} + +$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;'); + +# Set non-default options on the main table, none on the TOAST relation, so it +# inherits them. +$node->safe_psql( + 'postgres', qq( + CREATE TABLE tab (i int, j text) WITH ( + autovacuum_enabled=false, + vacuum_index_cleanup=false, + vacuum_truncate=false); + ALTER TABLE tab ALTER COLUMN j SET STORAGE EXTERNAL; + INSERT INTO tab SELECT g, repeat('x', 3000) FROM generate_series(1, 1000) g; + DELETE FROM tab; +)); + +my $toast_rel = $node->safe_psql( + 'postgres', qq( + SELECT relname FROM pg_class + WHERE oid = (SELECT reltoastrelid FROM pg_class WHERE oid = 'tab'::regclass); +)); + +$node->safe_psql( + 'postgres', qq( + SELECT injection_points_attach('vacuum-index-cleanup-disabled', 'wait', '$toast_rel'); + SELECT injection_points_attach('vacuum-truncate-disabled', 'wait', '$toast_rel'); +)); + +# Let autovacuum take the table. +$node->safe_psql('postgres', 'ALTER TABLE tab SET (autovacuum_enabled=true);'); +$node->reload(); + +$node->wait_for_event('autovacuum worker', 'vacuum-index-cleanup-disabled'); +pass('TOAST relation inherited vacuum_index_cleanup=false'); + +$node->safe_psql('postgres', + "SELECT injection_points_wakeup('vacuum-index-cleanup-disabled');"); + +$node->wait_for_event('autovacuum worker', 'vacuum-truncate-disabled'); +pass('TOAST relation inherited vacuum_truncate=false'); + +# Release and clean up. +$node->safe_psql( + 'postgres', qq( + SELECT injection_points_wakeup('vacuum-truncate-disabled'); + SELECT injection_points_detach('vacuum-index-cleanup-disabled'); + SELECT injection_points_detach('vacuum-truncate-disabled'); +)); + +done_testing(); -- 2.47.3