Hi, On Wed, Apr 8, 2026 at 1:03 AM Sami Imseih <[email protected]> wrote: > > > I am afraid that this would be too rough a workaround for this problem.. > > Perhaps, but I don't see it being unreasonable for injection points. > > I guess we can also think about expanding InjectionPointCondition to > handle other types of conditions, maybe OID??, to filter when running > the point. >
Hm, sounds reasonable. I am thinking about how to make it less invasive. For example, we can write an extension for this test (like many other tests do). The extension could allow us to specify the oid of the table we are interested in. See attached patch that demonstrates my idea. What do you think? > > > We also have an "autovacuum_parallel_workers" reloption that can > > additionally > > limit the number of parallel workers for the table. Default value of the > > reloption is "-1" which means "use the GUC parameter's value". I.e. when we > > are > > setting the GUC parameter to N, then every table automatically allows N > > parallel a/v workers. If autovacuum_max_parallel_workers = 0 then no one can > > launch parallel workers for autovacuum, even if reloption is > 0. Thus, > > autovacuum_max_parallel_workers is the main limiter during the number of > > parallel workers calculation. > > autovacuum_max_parallel_workers being the limiter is a desirable > attribute, otherwise > it will allow users to disable the GUC and set whatever they want on a > per table level, > only guarded by max_parallel_workers. That to me sounds pretty easy to > misconfigure > and manage. Yes, this is the main argument against this idea. However, in the thread that I mentioned I tried to give arguments why this might be extremely convenient for users with large databases. -- Best regards, Daniil Davydov
From 68a164ff4c44ddac64f8a2c3a1fe7fb3f0f16da3 Mon Sep 17 00:00:00 2001 From: Daniil Davidov <[email protected]> Date: Wed, 8 Apr 2026 02:55:48 +0700 Subject: [PATCH] Improvements for parallel autovacuum testing --- src/backend/access/heap/vacuumlazy.c | 2 +- src/test/modules/test_autovacuum/Makefile | 8 + src/test/modules/test_autovacuum/meson.build | 21 +++ .../t/001_parallel_autovacuum.pl | 19 ++- .../test_autovacuum/test_autovacuum--1.0.sql | 19 +++ .../modules/test_autovacuum/test_autovacuum.c | 158 ++++++++++++++++++ .../test_autovacuum/test_autovacuum.control | 3 + 7 files changed, 222 insertions(+), 8 deletions(-) create mode 100644 src/test/modules/test_autovacuum/test_autovacuum--1.0.sql create mode 100644 src/test/modules/test_autovacuum/test_autovacuum.c create mode 100644 src/test/modules/test_autovacuum/test_autovacuum.control diff --git a/src/backend/access/heap/vacuumlazy.c b/src/backend/access/heap/vacuumlazy.c index 39395aed0d5..36558f19c7c 100644 --- a/src/backend/access/heap/vacuumlazy.c +++ b/src/backend/access/heap/vacuumlazy.c @@ -871,7 +871,7 @@ heap_vacuum_rel(Relation rel, const VacuumParams *params, * workers. */ if (AmAutoVacuumWorkerProcess() && ParallelVacuumIsActive(vacrel)) - INJECTION_POINT("autovacuum-start-parallel-vacuum", NULL); + INJECTION_POINT("autovacuum-start-parallel-vacuum", &rel->rd_id); #endif /* diff --git a/src/test/modules/test_autovacuum/Makefile b/src/test/modules/test_autovacuum/Makefile index 15e83010c1c..1cbe7125bae 100644 --- a/src/test/modules/test_autovacuum/Makefile +++ b/src/test/modules/test_autovacuum/Makefile @@ -2,6 +2,14 @@ PGFILEDESC = "test_autovacuum - test code for autovacuum" +MODULE_big = test_autovacuum +OBJS = \ + $(WIN32RES) \ + test_autovacuum.o + +EXTENSION = test_autovacuum +DATA = test_autovacuum--1.0.sql + TAP_TESTS = 1 EXTRA_INSTALL = src/test/modules/injection_points diff --git a/src/test/modules/test_autovacuum/meson.build b/src/test/modules/test_autovacuum/meson.build index 86e392bc0de..f9f31084b54 100644 --- a/src/test/modules/test_autovacuum/meson.build +++ b/src/test/modules/test_autovacuum/meson.build @@ -1,5 +1,26 @@ # Copyright (c) 2024-2026, PostgreSQL Global Development Group +test_autovacuum_sources = files( + 'test_autovacuum.c', +) + +if host_system == 'windows' + test_autovacuum_sources += rc_lib_gen.process(win32ver_rc, extra_args: [ + '--NAME', 'test_autovacuum', + '--FILEDESC', 'test_autovacuum - test code for autovacuum',]) +endif + +test_autovacuum = shared_module('test_autovacuum', + test_autovacuum_sources, + kwargs: pg_test_mod_args, +) +test_install_libs += test_autovacuum + +test_install_data += files( + 'test_autovacuum.control', + 'test_autovacuum--1.0.sql', +) + tests += { 'name': 'test_autovacuum', 'sd': meson.current_source_dir(), diff --git a/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl b/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl index c5a2e78246a..e5ce1a12cef 100644 --- a/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl +++ b/src/test/modules/test_autovacuum/t/001_parallel_autovacuum.pl @@ -63,6 +63,7 @@ log_min_messages = debug2 autovacuum_naptime = '1s' min_parallel_index_scan_size = 0 log_autovacuum_min_duration = -1 +shared_preload_libraries = 'test_autovacuum' }); $node->start; @@ -78,6 +79,7 @@ if (!$node->check_extension('injection_points')) $node->safe_psql( 'postgres', qq{ CREATE EXTENSION injection_points; + CREATE EXTENSION test_autovacuum; }); my $indexes_num = 3; @@ -141,16 +143,19 @@ ok( $node->log_contains( $av_count = prepare_for_next_test($node, 2); $log_offset = -s $node->logfile; +my $tableoid = $node->safe_psql( + 'postgres', + "SELECT 'test_autovac'::regclass::oid"); + $node->safe_psql( 'postgres', qq{ - SELECT injection_points_attach('autovacuum-start-parallel-vacuum', 'wait'); - + SELECT inj_start_parallel_vacuum_attach($tableoid); ALTER TABLE test_autovac SET (autovacuum_parallel_workers = 1, autovacuum_enabled = true); }); -# Wait until parallel autovacuum is inited -$node->wait_for_event('autovacuum worker', - 'autovacuum-start-parallel-vacuum'); +# !!Hardcoded badness!! +# Of cource, we need another mechanis to wait until parallel vacuum is started +sleep(5); # Update the shared cost-based delay parameters. $node->safe_psql( @@ -168,7 +173,7 @@ $node->safe_psql( # before vacuuming indexes due to the injection point. $node->safe_psql( 'postgres', qq{ - SELECT injection_points_wakeup('autovacuum-start-parallel-vacuum'); + SELECT inj_start_parallel_vacuum_wakeup(); }); # Check whether parallel worker successfully updated all parameters during @@ -182,7 +187,7 @@ wait_for_autovacuum_complete($node, $av_count); # Cleanup $node->safe_psql( 'postgres', qq{ - SELECT injection_points_detach('autovacuum-start-parallel-vacuum'); + SELECT inj_start_parallel_vacuum_detach(); }); $node->stop; diff --git a/src/test/modules/test_autovacuum/test_autovacuum--1.0.sql b/src/test/modules/test_autovacuum/test_autovacuum--1.0.sql new file mode 100644 index 00000000000..2d22e4ddc8c --- /dev/null +++ b/src/test/modules/test_autovacuum/test_autovacuum--1.0.sql @@ -0,0 +1,19 @@ +/* src/test/modules/test_autovacuum/test_autovacuum--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_autovacuum" to load this file. \quit + +/* + * Injection point related functions + */ +CREATE FUNCTION inj_start_parallel_vacuum_attach(table_oid oid) +RETURNS VOID STRICT +AS 'MODULE_PATHNAME' LANGUAGE C; + +CREATE FUNCTION inj_start_parallel_vacuum_wakeup() +RETURNS VOID STRICT +AS 'MODULE_PATHNAME' LANGUAGE C; + +CREATE FUNCTION inj_start_parallel_vacuum_detach() +RETURNS VOID STRICT +AS 'MODULE_PATHNAME' LANGUAGE C; diff --git a/src/test/modules/test_autovacuum/test_autovacuum.c b/src/test/modules/test_autovacuum/test_autovacuum.c new file mode 100644 index 00000000000..6a1d218d7e8 --- /dev/null +++ b/src/test/modules/test_autovacuum/test_autovacuum.c @@ -0,0 +1,158 @@ +/*------------------------------------------------------------------------- + * + * test_autovacuum.c + * Helpers to write tests for autovacuum + * + * Copyright (c) 2026, PostgreSQL Global Development Group + * + * IDENTIFICATION + * src/test/modules/test_autovacuum/test_autovacuum.c + * + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "fmgr.h" +#include "miscadmin.h" +#include "postmaster/autovacuum.h" +#include "storage/shmem.h" +#include "storage/ipc.h" +#include "storage/lwlock.h" +#include "storage/condition_variable.h" +#include "utils/builtins.h" +#include "utils/injection_point.h" +#include "utils/wait_event_types.h" + +PG_MODULE_MAGIC; + +typedef struct InjPointState +{ + ConditionVariable cv; + Oid target_oid; + bool enabled_start_parallel_vacuum; +} InjPointState; + +static InjPointState * inj_point_state; + +/* Shared memory init callbacks */ +static shmem_request_hook_type prev_shmem_request_hook = NULL; +static shmem_startup_hook_type prev_shmem_startup_hook = NULL; + +static void +test_autovacuum_shmem_request(void) +{ + if (prev_shmem_request_hook) + prev_shmem_request_hook(); + + RequestAddinShmemSpace(sizeof(InjPointState)); +} + +static void +test_autovacuum_shmem_startup(void) +{ + bool found; + + if (prev_shmem_startup_hook) + prev_shmem_startup_hook(); + + /* Create or attach to the shared memory state */ + LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE); + + inj_point_state = ShmemInitStruct("injection_points for autovacuum testing", + sizeof(InjPointState), + &found); + + if (!found) + { + /* First time through, initialize */ + inj_point_state->enabled_start_parallel_vacuum = false; + inj_point_state->target_oid = InvalidOid; + + ConditionVariableInit(&inj_point_state->cv); + + InjectionPointAttach("autovacuum-start-parallel-vacuum", + "test_autovacuum", + "inj_start_parallel_vacuum", + NULL, + 0); + } + + LWLockRelease(AddinShmemInitLock); +} + +void +_PG_init(void) +{ + if (!process_shared_preload_libraries_in_progress) + return; + + prev_shmem_request_hook = shmem_request_hook; + shmem_request_hook = test_autovacuum_shmem_request; + prev_shmem_startup_hook = shmem_startup_hook; + shmem_startup_hook = test_autovacuum_shmem_startup; +} + +extern PGDLLEXPORT void inj_start_parallel_vacuum(const char *name, + const void *private_data, + void *arg); + +/* + * Set number of currently available parallel a/v workers. This value may + * change after reserving or releasing such workers. + * + * Function called from parallel autovacuum leader. + */ +void +inj_start_parallel_vacuum(const char *name, const void *private_data, void *arg) +{ + if (!inj_point_state->enabled_start_parallel_vacuum) + return; + + Assert(arg != NULL); + + if (inj_point_state->target_oid != *(Oid *) arg) + return; + + ConditionVariablePrepareToSleep(&inj_point_state->cv); + ConditionVariableSleep(&inj_point_state->cv, + WAIT_EVENT_ARCHIVE_COMMAND); /* another wait event needed */ +} + +PG_FUNCTION_INFO_V1(inj_start_parallel_vacuum_attach); +Datum +inj_start_parallel_vacuum_attach(PG_FUNCTION_ARGS) +{ +#ifdef USE_INJECTION_POINTS + inj_point_state->enabled_start_parallel_vacuum = true; + inj_point_state->target_oid = PG_ARGISNULL(0) ? InvalidOid : PG_GETARG_OID(0); +#else + elog(ERROR, "injection points not supported"); +#endif + PG_RETURN_VOID(); +} + +PG_FUNCTION_INFO_V1(inj_start_parallel_vacuum_wakeup); +Datum +inj_start_parallel_vacuum_wakeup(PG_FUNCTION_ARGS) +{ +#ifdef USE_INJECTION_POINTS + ConditionVariableBroadcast(&inj_point_state->cv); +#else + elog(ERROR, "injection points not supported"); +#endif + PG_RETURN_VOID(); +} + +PG_FUNCTION_INFO_V1(inj_start_parallel_vacuum_detach); +Datum +inj_start_parallel_vacuum_detach(PG_FUNCTION_ARGS) +{ +#ifdef USE_INJECTION_POINTS + inj_point_state->enabled_start_parallel_vacuum = false; + inj_point_state->target_oid = InvalidOid; +#else + elog(ERROR, "injection points not supported"); +#endif + PG_RETURN_VOID(); +} diff --git a/src/test/modules/test_autovacuum/test_autovacuum.control b/src/test/modules/test_autovacuum/test_autovacuum.control new file mode 100644 index 00000000000..62bc6e53e29 --- /dev/null +++ b/src/test/modules/test_autovacuum/test_autovacuum.control @@ -0,0 +1,3 @@ +comment = 'Test code for autovacuum' +default_version = '1.0' +module_pathname = '$libdir/test_autovacuum' \ No newline at end of file -- 2.43.0
