Skip to content

Commit 527d7d0

Browse files
Daniil DavidovCommitfest Bot
authored andcommitted
Tests for parallel autovacuum
1 parent fddb5cd commit 527d7d0

File tree

11 files changed

+545
-0
lines changed

11 files changed

+545
-0
lines changed

src/backend/commands/vacuumparallel.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "postmaster/autovacuum.h"
4040
#include "storage/bufmgr.h"
4141
#include "tcop/tcopprot.h"
42+
#include "utils/injection_point.h"
4243
#include "utils/lsyscache.h"
4344
#include "utils/rel.h"
4445

@@ -752,6 +753,13 @@ parallel_vacuum_process_all_indexes(ParallelVacuumState *pvs, int num_index_scan
752753
}
753754
}
754755

756+
/*
757+
* To be able to exercise whether all reserved parallel workers are being
758+
* released anyway, allow injection points to trigger a failure at this
759+
* point.
760+
*/
761+
INJECTION_POINT("autovacuum-trigger-leader-failure", NULL);
762+
755763
/* Vacuum the indexes that can be processed by only leader process */
756764
parallel_vacuum_process_unsafe_indexes(pvs);
757765

src/backend/postmaster/autovacuum.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3437,6 +3437,13 @@ AutoVacuumReserveParallelWorkers(int nworkers)
34373437
/* Remember how many workers we have reserved. */
34383438
av_nworkers_reserved += nworkers;
34393439

3440+
/*
3441+
* Injection point to help exercising number of available parallel
3442+
* autovacuum workers.
3443+
*/
3444+
INJECTION_POINT("autovacuum-set-free-parallel-workers-num",
3445+
&AutoVacuumShmem->av_freeParallelWorkers);
3446+
34403447
LWLockRelease(AutovacuumLock);
34413448
return nreserved;
34423449
}
@@ -3467,6 +3474,13 @@ AutoVacuumReleaseParallelWorkers(int nworkers)
34673474
/* Don't have to remember these workers anymore. */
34683475
av_nworkers_reserved -= nworkers;
34693476

3477+
/*
3478+
* Injection point to help exercising number of available parallel
3479+
* autovacuum workers.
3480+
*/
3481+
INJECTION_POINT("autovacuum-set-free-parallel-workers-num",
3482+
&AutoVacuumShmem->av_freeParallelWorkers);
3483+
34703484
LWLockRelease(AutovacuumLock);
34713485
}
34723486

src/test/modules/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ SUBDIRS = \
1515
plsample \
1616
spgist_name_ops \
1717
test_aio \
18+
test_autovacuum \
1819
test_binaryheap \
1920
test_bitmapset \
2021
test_bloomfilter \

src/test/modules/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ subdir('plsample')
1414
subdir('spgist_name_ops')
1515
subdir('ssl_passphrase_callback')
1616
subdir('test_aio')
17+
subdir('test_autovacuum')
1718
subdir('test_binaryheap')
1819
subdir('test_bitmapset')
1920
subdir('test_bloomfilter')
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Generated subdirectories
2+
/tmp_check/
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# src/test/modules/test_autovacuum/Makefile
2+
3+
PGFILEDESC = "test_autovacuum - test code for parallel autovacuum"
4+
5+
MODULE_big = test_autovacuum
6+
OBJS = \
7+
$(WIN32RES) \
8+
test_autovacuum.o
9+
10+
EXTENSION = test_autovacuum
11+
DATA = test_autovacuum--1.0.sql
12+
13+
TAP_TESTS = 1
14+
15+
export enable_injection_points
16+
17+
ifdef USE_PGXS
18+
PG_CONFIG = pg_config
19+
PGXS := $(shell $(PG_CONFIG) --pgxs)
20+
include $(PGXS)
21+
else
22+
subdir = src/test/modules/test_autovacuum
23+
top_builddir = ../../../..
24+
include $(top_builddir)/src/Makefile.global
25+
include $(top_srcdir)/contrib/contrib-global.mk
26+
endif
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Copyright (c) 2024-2025, PostgreSQL Global Development Group
2+
3+
test_autovacuum_sources = files(
4+
'test_autovacuum.c',
5+
)
6+
7+
if host_system == 'windows'
8+
test_autovacuum_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
9+
'--NAME', 'test_autovacuum',
10+
'--FILEDESC', 'test_autovacuum - test code for parallel autovacuum',])
11+
endif
12+
13+
test_autovacuum = shared_module('test_autovacuum',
14+
test_autovacuum_sources,
15+
kwargs: pg_test_mod_args,
16+
)
17+
test_install_libs += test_autovacuum
18+
19+
test_install_data += files(
20+
'test_autovacuum.control',
21+
'test_autovacuum--1.0.sql',
22+
)
23+
24+
tests += {
25+
'name': 'test_autovacuum',
26+
'sd': meson.current_source_dir(),
27+
'bd': meson.current_build_dir(),
28+
'tap': {
29+
'env': {
30+
'enable_injection_points': get_option('injection_points') ? 'yes' : 'no',
31+
},
32+
'tests': [
33+
't/001_basic.pl',
34+
],
35+
},
36+
}
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
use warnings FATAL => 'all';
2+
use PostgreSQL::Test::Cluster;
3+
use PostgreSQL::Test::Utils;
4+
use Test::More;
5+
6+
my $psql_out;
7+
8+
my $node = PostgreSQL::Test::Cluster->new('node1');
9+
$node->init;
10+
11+
# Configure postgres, so it can launch parallel autovacuum workers, log all
12+
# information we are interested in and autovacuum works frequently
13+
$node->append_conf('postgresql.conf', qq{
14+
max_worker_processes = 20
15+
max_parallel_workers = 20
16+
max_parallel_maintenance_workers = 20
17+
autovacuum_max_parallel_workers = 10
18+
log_min_messages = debug2
19+
log_autovacuum_min_duration = 0
20+
autovacuum_naptime = '1s'
21+
min_parallel_index_scan_size = 0
22+
shared_preload_libraries=test_autovacuum
23+
});
24+
$node->start;
25+
26+
my $indexes_num = 4;
27+
my $initial_rows_num = 10_000;
28+
my $autovacuum_parallel_workers = 2;
29+
30+
# Create table with specified number of b-tree indexes on it
31+
$node->safe_psql('postgres', qq{
32+
CREATE TABLE test_autovac (
33+
id SERIAL PRIMARY KEY,
34+
col_1 INTEGER, col_2 INTEGER, col_3 INTEGER, col_4 INTEGER
35+
) WITH (autovacuum_parallel_workers = $autovacuum_parallel_workers,
36+
autovacuum_enabled = false);
37+
38+
DO \$\$
39+
DECLARE
40+
i INTEGER;
41+
BEGIN
42+
FOR i IN 1..$indexes_num LOOP
43+
EXECUTE format('CREATE INDEX idx_col_\%s ON test_autovac (col_\%s);', i, i);
44+
END LOOP;
45+
END \$\$;
46+
});
47+
48+
# Insert specified tuples num into the table
49+
$node->safe_psql('postgres', qq{
50+
DO \$\$
51+
DECLARE
52+
i INTEGER;
53+
BEGIN
54+
FOR i IN 1..$initial_rows_num LOOP
55+
INSERT INTO test_autovac VALUES (i, i + 1, i + 2, i + 3);
56+
END LOOP;
57+
END \$\$;
58+
});
59+
60+
# Now, create some dead tuples and refresh table statistics
61+
$node->safe_psql('postgres', qq{
62+
UPDATE test_autovac SET col_1 = 0 WHERE (col_1 % 3) = 0;
63+
ANALYZE test_autovac;
64+
});
65+
66+
# Create all functions needed for testing
67+
$node->safe_psql('postgres', qq{
68+
CREATE EXTENSION test_autovacuum;
69+
SELECT inj_set_free_workers_attach();
70+
SELECT inj_leader_failure_attach();
71+
});
72+
73+
# Test 1 :
74+
# Our table has enough indexes and appropriate reloptions, so autovacuum must
75+
# be able to process it in parallel mode. Just check if it can.
76+
# Also check whether all requested workers:
77+
# 1) launched
78+
# 2) correctly released
79+
80+
$node->safe_psql('postgres', qq{
81+
ALTER TABLE test_autovac SET (autovacuum_enabled = true);
82+
});
83+
84+
# Wait until the parallel autovacuum on table is completed. At the same time,
85+
# we check that the required number of parallel workers has been started.
86+
$node->wait_for_log(qr/workers usage statistics for all of index scans : / .
87+
qr/launched in total = 2, planned in total = 2/);
88+
89+
$node->psql('postgres',
90+
"SELECT get_parallel_autovacuum_free_workers();",
91+
stdout => \$psql_out,
92+
);
93+
is($psql_out, 10, 'All parallel workers has been released by the leader');
94+
95+
# Disable autovacuum on table during preparation for the next test
96+
$node->append_conf('postgresql.conf', qq{
97+
ALTER TABLE test_autovac SET (autovacuum_enabled = false);
98+
});
99+
100+
# Create more dead tuples
101+
$node->safe_psql('postgres', qq{
102+
UPDATE test_autovac SET col_2 = 0 WHERE (col_2 % 3) = 0;
103+
ANALYZE test_autovac;
104+
});
105+
106+
# Test 2:
107+
# We want parallel autovacuum workers to be released even if leader gets an
108+
# error. At first, simulate situation, when leader exites due to an ERROR.
109+
110+
$node->safe_psql('postgres', qq(
111+
SELECT trigger_leader_failure('ERROR');
112+
));
113+
114+
$node->safe_psql('postgres', qq{
115+
ALTER TABLE test_autovac SET (autovacuum_enabled = true);
116+
});
117+
118+
$node->wait_for_log(qr/error, triggered by injection point/);
119+
120+
$node->psql('postgres',
121+
"SELECT get_parallel_autovacuum_free_workers();",
122+
stdout => \$psql_out,
123+
);
124+
is($psql_out, 10,
125+
'All parallel workers has been released by the leader after ERROR');
126+
127+
# Disable autovacuum on table during preparation for the next test
128+
$node->append_conf('postgresql.conf', qq{
129+
ALTER TABLE test_autovac SET (autovacuum_enabled = false);
130+
});
131+
132+
# Create more dead tuples
133+
$node->safe_psql('postgres', qq{
134+
UPDATE test_autovac SET col_3 = 0 WHERE (col_3 % 3) = 0;
135+
ANALYZE test_autovac;
136+
});
137+
138+
# Test 3:
139+
# Same as Test 2, but simulate situation, when leader exites due to FATAL.
140+
141+
$node->safe_psql('postgres', qq(
142+
SELECT trigger_leader_failure('FATAL');
143+
));
144+
145+
$node->safe_psql('postgres', qq{
146+
ALTER TABLE test_autovac SET (autovacuum_enabled = true);
147+
});
148+
149+
$node->wait_for_log(qr/fatal, triggered by injection point/);
150+
151+
$node->psql('postgres',
152+
"SELECT get_parallel_autovacuum_free_workers();",
153+
stdout => \$psql_out,
154+
);
155+
is($psql_out, 10,
156+
'All parallel workers has been released by the leader after FATAL');
157+
158+
# Cleanup
159+
$node->safe_psql('postgres', qq{
160+
SELECT inj_set_free_workers_detach();
161+
SELECT inj_leader_failure_detach();
162+
});
163+
164+
$node->stop;
165+
done_testing();
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/* src/test/modules/test_autovacuum/test_autovacuum--1.0.sql */
2+
3+
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
4+
\echo Use "CREATE EXTENSION test_autovacuum" to load this file. \quit
5+
6+
/*
7+
* Functions for expecting or to interfere autovacuum state
8+
*/
9+
CREATE FUNCTION get_parallel_autovacuum_free_workers()
10+
RETURNS INTEGER STRICT
11+
AS 'MODULE_PATHNAME' LANGUAGE C;
12+
13+
CREATE FUNCTION trigger_leader_failure(failure_type text)
14+
RETURNS VOID STRICT
15+
AS 'MODULE_PATHNAME' LANGUAGE C;
16+
17+
/*
18+
* Injection point related functions
19+
*/
20+
CREATE FUNCTION inj_set_free_workers_attach()
21+
RETURNS VOID STRICT
22+
AS 'MODULE_PATHNAME' LANGUAGE C;
23+
24+
CREATE FUNCTION inj_set_free_workers_detach()
25+
RETURNS VOID STRICT
26+
AS 'MODULE_PATHNAME' LANGUAGE C;
27+
28+
CREATE FUNCTION inj_leader_failure_attach()
29+
RETURNS VOID STRICT
30+
AS 'MODULE_PATHNAME' LANGUAGE C;
31+
32+
CREATE FUNCTION inj_leader_failure_detach()
33+
RETURNS VOID STRICT
34+
AS 'MODULE_PATHNAME' LANGUAGE C;

0 commit comments

Comments
 (0)