diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/postmaster/autovacuum.c | 7 | ||||
-rw-r--r-- | src/test/modules/test_misc/meson.build | 3 | ||||
-rw-r--r-- | src/test/modules/test_misc/t/006_signal_autovacuum.pl | 95 |
3 files changed, 104 insertions, 1 deletions
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 928754b51c4..4e4a0ccbefb 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -100,6 +100,7 @@ #include "utils/fmgroids.h" #include "utils/fmgrprotos.h" #include "utils/guc_hooks.h" +#include "utils/injection_point.h" #include "utils/lsyscache.h" #include "utils/memutils.h" #include "utils/ps_status.h" @@ -1903,6 +1904,12 @@ do_autovacuum(void) StartTransactionCommand(); /* + * This injection point is put in a transaction block to work with a wait + * that uses a condition variable. + */ + INJECTION_POINT("autovacuum-worker-start"); + + /* * Compute the multixact age for which freezing is urgent. This is * normally autovacuum_multixact_freeze_max_age, but may be less if we are * short of multixact member space. diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build index df2913e8938..283ffa751aa 100644 --- a/src/test/modules/test_misc/meson.build +++ b/src/test/modules/test_misc/meson.build @@ -13,7 +13,8 @@ tests += { 't/002_tablespace.pl', 't/003_check_guc.pl', 't/004_io_direct.pl', - 't/005_timeouts.pl' + 't/005_timeouts.pl', + 't/006_signal_autovacuum.pl', ], }, } diff --git a/src/test/modules/test_misc/t/006_signal_autovacuum.pl b/src/test/modules/test_misc/t/006_signal_autovacuum.pl new file mode 100644 index 00000000000..f37f8ff776d --- /dev/null +++ b/src/test/modules/test_misc/t/006_signal_autovacuum.pl @@ -0,0 +1,95 @@ +# Copyright (c) 2024, PostgreSQL Global Development Group + +# Test signaling autovacuum worker with pg_signal_autovacuum_worker. +# +# Only roles with privileges of pg_signal_autovacuum_worker are allowed to +# signal autovacuum workers. This test uses an injection point located +# at the beginning of the autovacuum worker startup. + +use strict; +use warnings; +use PostgreSQL::Test::Cluster; +use Test::More; + +if ($ENV{enable_injection_points} ne 'yes') +{ + plan skip_all => 'Injection points not supported by this build'; +} + +# Initialize postgres +my $psql_err = ''; +my $psql_out = ''; +my $node = PostgreSQL::Test::Cluster->new('node'); +$node->init; + +# This ensures a quick worker spawn. +$node->append_conf('postgresql.conf', 'autovacuum_naptime = 1'); +$node->start; +$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;'); + +$node->safe_psql( + 'postgres', qq( + CREATE ROLE regress_regular_role; + CREATE ROLE regress_worker_role; + GRANT pg_signal_autovacuum_worker TO regress_worker_role; +)); + +# From this point, autovacuum worker will wait at startup. +$node->safe_psql('postgres', + "SELECT injection_points_attach('autovacuum-worker-start', 'wait');"); + +# Accelerate worker creation in case we reach this point before the naptime +# ends. +$node->reload(); + +# Wait until an autovacuum worker starts. +$node->wait_for_event('autovacuum worker', 'autovacuum-worker-start'); + +# And grab one of them. +my $av_pid = $node->safe_psql( + 'postgres', qq( + SELECT pid FROM pg_stat_activity WHERE backend_type = 'autovacuum worker' AND wait_event = 'autovacuum-worker-start' LIMIT 1; +)); + +# Regular role cannot terminate autovacuum worker. +my $terminate_with_no_pg_signal_av = $node->psql( + 'postgres', qq( + SET ROLE regress_regular_role; + SELECT pg_terminate_backend('$av_pid'); +), + stdout => \$psql_out, + stderr => \$psql_err); + +like( + $psql_err, + qr/ERROR: permission denied to terminate process\nDETAIL: Only roles with privileges of the "pg_signal_autovacuum_worker" role may terminate autovacuum workers./, + "autovacuum worker not signaled with regular role"); + +my $offset = -s $node->logfile; + +# Role with pg_signal_autovacuum can terminate autovacuum worker. +my $terminate_with_pg_signal_av = $node->psql( + 'postgres', qq( + SET ROLE regress_worker_role; + SELECT pg_terminate_backend('$av_pid'); +), + stdout => \$psql_out, + stderr => \$psql_err); + +# Wait for the autovacuum worker to exit before scanning the logs. +$node->poll_query_until('postgres', + "SELECT count(*) = 0 FROM pg_stat_activity " + . "WHERE pid = '$av_pid' AND backend_type = 'autovacuum worker';"); + +# Check that the primary server logs a FATAL indicating that autovacuum +# is terminated. +ok( $node->log_contains( + qr/FATAL: terminating autovacuum process due to administrator command/, + $offset), + "autovacuum worker signaled with pg_signal_autovacuum_worker granted"); + +# Release injection point. +$node->safe_psql('postgres', + "SELECT injection_points_detach('autovacuum-worker-start');"); + +done_testing(); |