mirror of
https://github.com/postgres/postgres.git
synced 2026-03-28 21:33:14 -04:00
aio: Refactor tests in preparation for more tests
In a future commit more AIO related tests are due to be introduced. However 001_aio.pl already is fairly large. This commit introduces a new TestAio package with helpers for writing AIO related tests. Then it uses the new helpers to simplify the existing 001_aio.pl by iterating over all supported io_methods. This will be particularly helpful because additional methods already have been submitted. Additionally this commit splits out testing of initdb using a non-default method into its own test. While that test is somewhat important, it's fairly slow and doesn't break that often. For development velocity it's helpful for 001_aio.pl to be faster. While particularly the latter could benefit from being its own commit, it seems to introduce more back-and-forth than it's worth. Author: Andres Freund <andres@anarazel.de> Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com> Reviewed-by: Melanie Plageman <melanieplageman@gmail.com> Discussion: https://postgr.es/m/zljergweqti7x67lg5ije2rzjusie37nslsnkjkkby4laqqbfw@3p3zu522yykv
This commit is contained in:
parent
47c110f77e
commit
906a046972
4 changed files with 209 additions and 104 deletions
|
|
@ -32,6 +32,7 @@ tests += {
|
|||
'tests': [
|
||||
't/001_aio.pl',
|
||||
't/002_io_workers.pl',
|
||||
't/003_initdb.pl',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,53 +7,48 @@ use PostgreSQL::Test::Cluster;
|
|||
use PostgreSQL::Test::Utils;
|
||||
use Test::More;
|
||||
|
||||
use FindBin;
|
||||
use lib $FindBin::RealBin;
|
||||
|
||||
use TestAio;
|
||||
|
||||
my @methods = TestAio::supported_io_methods();
|
||||
my %nodes;
|
||||
|
||||
|
||||
###
|
||||
# Test io_method=worker
|
||||
# Create and configure one instance for each io_method
|
||||
###
|
||||
my $node_worker = create_node('worker');
|
||||
$node_worker->start();
|
||||
|
||||
test_generic('worker', $node_worker);
|
||||
SKIP:
|
||||
foreach my $method (@methods)
|
||||
{
|
||||
skip 'Injection points not supported by this build', 1
|
||||
unless $ENV{enable_injection_points} eq 'yes';
|
||||
test_inject_worker('worker', $node_worker);
|
||||
my $node = PostgreSQL::Test::Cluster->new($method);
|
||||
|
||||
$nodes{$method} = $node;
|
||||
$node->init();
|
||||
$node->append_conf('postgresql.conf', "io_method=$method");
|
||||
TestAio::configure($node);
|
||||
}
|
||||
|
||||
$node_worker->stop();
|
||||
|
||||
|
||||
###
|
||||
# Test io_method=io_uring
|
||||
###
|
||||
|
||||
if (have_io_uring())
|
||||
{
|
||||
my $node_uring = create_node('io_uring');
|
||||
$node_uring->start();
|
||||
test_generic('io_uring', $node_uring);
|
||||
$node_uring->stop();
|
||||
}
|
||||
|
||||
|
||||
###
|
||||
# Test io_method=sync
|
||||
###
|
||||
|
||||
my $node_sync = create_node('sync');
|
||||
|
||||
# just to have one test not use the default auto-tuning
|
||||
|
||||
$node_sync->append_conf(
|
||||
# Just to have one test not use the default auto-tuning
|
||||
$nodes{'sync'}->append_conf(
|
||||
'postgresql.conf', qq(
|
||||
io_max_concurrency=4
|
||||
io_max_concurrency=4
|
||||
));
|
||||
|
||||
$node_sync->start();
|
||||
test_generic('sync', $node_sync);
|
||||
$node_sync->stop();
|
||||
|
||||
###
|
||||
# Execute the tests for each io_method
|
||||
###
|
||||
|
||||
foreach my $method (@methods)
|
||||
{
|
||||
my $node = $nodes{$method};
|
||||
|
||||
$node->start();
|
||||
test_io_method($method, $node);
|
||||
$node->stop();
|
||||
}
|
||||
|
||||
done_testing();
|
||||
|
||||
|
|
@ -62,71 +57,6 @@ done_testing();
|
|||
# Test Helpers
|
||||
###
|
||||
|
||||
sub create_node
|
||||
{
|
||||
local $Test::Builder::Level = $Test::Builder::Level + 1;
|
||||
|
||||
my $io_method = shift;
|
||||
|
||||
my $node = PostgreSQL::Test::Cluster->new($io_method);
|
||||
|
||||
# Want to test initdb for each IO method, otherwise we could just reuse
|
||||
# the cluster.
|
||||
#
|
||||
# Unfortunately Cluster::init() puts PG_TEST_INITDB_EXTRA_OPTS after the
|
||||
# options specified by ->extra, if somebody puts -c io_method=xyz in
|
||||
# PG_TEST_INITDB_EXTRA_OPTS it would break this test. Fix that up if we
|
||||
# detect it.
|
||||
local $ENV{PG_TEST_INITDB_EXTRA_OPTS} = $ENV{PG_TEST_INITDB_EXTRA_OPTS};
|
||||
if (defined $ENV{PG_TEST_INITDB_EXTRA_OPTS}
|
||||
&& $ENV{PG_TEST_INITDB_EXTRA_OPTS} =~ m/io_method=/)
|
||||
{
|
||||
$ENV{PG_TEST_INITDB_EXTRA_OPTS} .= " -c io_method=$io_method";
|
||||
}
|
||||
|
||||
$node->init(extra => [ '-c', "io_method=$io_method" ]);
|
||||
|
||||
$node->append_conf(
|
||||
'postgresql.conf', qq(
|
||||
shared_preload_libraries=test_aio
|
||||
log_min_messages = 'DEBUG3'
|
||||
log_statement=all
|
||||
log_error_verbosity=default
|
||||
restart_after_crash=false
|
||||
temp_buffers=100
|
||||
));
|
||||
|
||||
# Even though we used -c io_method=... above, if TEMP_CONFIG sets
|
||||
# io_method, it'd override the setting persisted at initdb time. While
|
||||
# using (and later verifying) the setting from initdb provides some
|
||||
# verification of having used the io_method during initdb, it's probably
|
||||
# not worth the complication of only appending if the variable is set in
|
||||
# in TEMP_CONFIG.
|
||||
$node->append_conf(
|
||||
'postgresql.conf', qq(
|
||||
io_method=$io_method
|
||||
));
|
||||
|
||||
ok(1, "$io_method: initdb");
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
sub have_io_uring
|
||||
{
|
||||
# To detect if io_uring is supported, we look at the error message for
|
||||
# assigning an invalid value to an enum GUC, which lists all the valid
|
||||
# options. We need to use -C to deal with running as administrator on
|
||||
# windows, the superuser check is omitted if -C is used.
|
||||
my ($stdout, $stderr) =
|
||||
run_command [qw(postgres -C invalid -c io_method=invalid)];
|
||||
die "can't determine supported io_method values"
|
||||
unless $stderr =~ m/Available values: ([^\.]+)\./;
|
||||
my $methods = $1;
|
||||
note "supported io_method values are: $methods";
|
||||
|
||||
return ($methods =~ m/io_uring/) ? 1 : 0;
|
||||
}
|
||||
|
||||
sub psql_like
|
||||
{
|
||||
|
|
@ -1490,8 +1420,8 @@ SELECT read_rel_block_ll('tbl_cs_fail', 3, nblocks=>1, zero_on_error=>true);),
|
|||
}
|
||||
|
||||
|
||||
# Run all tests that are supported for all io_methods
|
||||
sub test_generic
|
||||
# Run all tests that for the specified node / io_method
|
||||
sub test_io_method
|
||||
{
|
||||
my $io_method = shift;
|
||||
my $node = shift;
|
||||
|
|
@ -1526,10 +1456,23 @@ CHECKPOINT;
|
|||
test_ignore_checksum($io_method, $node);
|
||||
test_checksum_createdb($io_method, $node);
|
||||
|
||||
# generic injection tests
|
||||
SKIP:
|
||||
{
|
||||
skip 'Injection points not supported by this build', 1
|
||||
unless $ENV{enable_injection_points} eq 'yes';
|
||||
test_inject($io_method, $node);
|
||||
}
|
||||
|
||||
# worker specific injection tests
|
||||
if ($io_method eq 'worker')
|
||||
{
|
||||
SKIP:
|
||||
{
|
||||
skip 'Injection points not supported by this build', 1
|
||||
unless $ENV{enable_injection_points} eq 'yes';
|
||||
|
||||
test_inject_worker($io_method, $node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
71
src/test/modules/test_aio/t/003_initdb.pl
Normal file
71
src/test/modules/test_aio/t/003_initdb.pl
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Copyright (c) 2024-2025, PostgreSQL Global Development Group
|
||||
#
|
||||
# Test initdb for each IO method. This is done separately from 001_aio.pl, as
|
||||
# it isn't fast. This way the more commonly failing / hacked-on 001_aio.pl can
|
||||
# be iterated on more quickly.
|
||||
|
||||
use strict;
|
||||
use warnings FATAL => 'all';
|
||||
use PostgreSQL::Test::Cluster;
|
||||
use PostgreSQL::Test::Utils;
|
||||
use Test::More;
|
||||
|
||||
use FindBin;
|
||||
use lib $FindBin::RealBin;
|
||||
|
||||
use TestAio;
|
||||
|
||||
|
||||
foreach my $method (TestAio::supported_io_methods())
|
||||
{
|
||||
test_create_node($method);
|
||||
}
|
||||
|
||||
done_testing();
|
||||
|
||||
|
||||
sub test_create_node
|
||||
{
|
||||
local $Test::Builder::Level = $Test::Builder::Level + 1;
|
||||
|
||||
my $io_method = shift;
|
||||
|
||||
my $node = PostgreSQL::Test::Cluster->new($io_method);
|
||||
|
||||
# Want to test initdb for each IO method, otherwise we could just reuse
|
||||
# the cluster.
|
||||
#
|
||||
# Unfortunately Cluster::init() puts PG_TEST_INITDB_EXTRA_OPTS after the
|
||||
# options specified by ->extra, if somebody puts -c io_method=xyz in
|
||||
# PG_TEST_INITDB_EXTRA_OPTS it would break this test. Fix that up if we
|
||||
# detect it.
|
||||
local $ENV{PG_TEST_INITDB_EXTRA_OPTS} = $ENV{PG_TEST_INITDB_EXTRA_OPTS};
|
||||
if (defined $ENV{PG_TEST_INITDB_EXTRA_OPTS}
|
||||
&& $ENV{PG_TEST_INITDB_EXTRA_OPTS} =~ m/io_method=/)
|
||||
{
|
||||
$ENV{PG_TEST_INITDB_EXTRA_OPTS} .= " -c io_method=$io_method";
|
||||
}
|
||||
|
||||
$node->init(extra => [ '-c', "io_method=$io_method" ]);
|
||||
|
||||
TestAio::configure($node);
|
||||
|
||||
# Even though we used -c io_method=... above, if TEMP_CONFIG sets
|
||||
# io_method, it'd override the setting persisted at initdb time. While
|
||||
# using (and later verifying) the setting from initdb provides some
|
||||
# verification of having used the io_method during initdb, it's probably
|
||||
# not worth the complication of only appending if the variable is set in
|
||||
# in TEMP_CONFIG.
|
||||
$node->append_conf(
|
||||
'postgresql.conf', qq(
|
||||
io_method=$io_method
|
||||
));
|
||||
|
||||
ok(1, "$io_method: initdb");
|
||||
|
||||
$node->start();
|
||||
$node->stop();
|
||||
ok(1, "$io_method: start & stop");
|
||||
|
||||
return $node;
|
||||
}
|
||||
90
src/test/modules/test_aio/t/TestAio.pm
Normal file
90
src/test/modules/test_aio/t/TestAio.pm
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Copyright (c) 2024-2025, PostgreSQL Global Development Group
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
TestAio - helpers for writing AIO related tests
|
||||
|
||||
=cut
|
||||
|
||||
package TestAio;
|
||||
|
||||
use PostgreSQL::Test::Cluster;
|
||||
use PostgreSQL::Test::Utils;
|
||||
use Test::More;
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=over
|
||||
|
||||
=item TestAio::supported_io_methods()
|
||||
|
||||
Return an array of all the supported values for the io_method GUC
|
||||
|
||||
=cut
|
||||
|
||||
sub supported_io_methods()
|
||||
{
|
||||
my @io_methods = ('worker');
|
||||
|
||||
push(@io_methods, "io_uring") if have_io_uring();
|
||||
|
||||
# Return sync last, as it will least commonly fail
|
||||
push(@io_methods, "sync");
|
||||
|
||||
return @io_methods;
|
||||
}
|
||||
|
||||
|
||||
=item TestAio::configure()
|
||||
|
||||
Prepare a cluster for AIO test
|
||||
|
||||
=cut
|
||||
|
||||
sub configure
|
||||
{
|
||||
my $node = shift;
|
||||
|
||||
$node->append_conf(
|
||||
'postgresql.conf', qq(
|
||||
shared_preload_libraries=test_aio
|
||||
log_min_messages = 'DEBUG3'
|
||||
log_statement=all
|
||||
log_error_verbosity=default
|
||||
restart_after_crash=false
|
||||
temp_buffers=100
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
|
||||
=pod
|
||||
|
||||
=item TestAio::have_io_uring()
|
||||
|
||||
Return if io_uring is supported
|
||||
|
||||
=cut
|
||||
|
||||
sub have_io_uring
|
||||
{
|
||||
# To detect if io_uring is supported, we look at the error message for
|
||||
# assigning an invalid value to an enum GUC, which lists all the valid
|
||||
# options. We need to use -C to deal with running as administrator on
|
||||
# windows, the superuser check is omitted if -C is used.
|
||||
my ($stdout, $stderr) =
|
||||
run_command [qw(postgres -C invalid -c io_method=invalid)];
|
||||
die "can't determine supported io_method values"
|
||||
unless $stderr =~ m/Available values: ([^\.]+)\./;
|
||||
my $methods = $1;
|
||||
note "supported io_method values are: $methods";
|
||||
|
||||
return ($methods =~ m/io_uring/) ? 1 : 0;
|
||||
}
|
||||
|
||||
1;
|
||||
Loading…
Reference in a new issue