008_poc_false_positive.pl
text/x-perl-script
Filename: 008_poc_false_positive.pl
Type: text/x-perl-script
Part: 0
# POC: indexallkeysmatch false positive under concurrent VACUUM
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
use IPC::Run ();
my $node = PostgreSQL::Test::Cluster->new('race');
$node->init;
$node->append_conf('postgresql.conf', q{
autovacuum = off
shared_buffers = 32MB
});
$node->start;
$node->safe_psql('postgres', 'CREATE EXTENSION amcheck');
my $port = $node->port;
my $host = $node->host;
# 1M rows x ~230 bytes => ~30K heap pages => VACUUM Phase 1 takes real time
$node->safe_psql('postgres', q{
CREATE TABLE race(id int, pad text);
INSERT INTO race SELECT i, repeat('x', 200)
FROM generate_series(1, 1000000) i;
CREATE INDEX race_idx ON race(id);
ANALYZE race;
});
my $false_positive = 0;
for my $attempt (1..8)
{
# Delete all rows. After commit, tuples are LP_NORMAL with xmax set.
$node->safe_psql('postgres', 'DELETE FROM race');
# Start both VACUUM and bt_index_check
my ($v_out, $v_err, $c_out, $c_err) = ('', '', '', '');
my $vacuum_h = IPC::Run::start(
['psql', '-X', '-h', $host, '-p', $port,
'-d', 'postgres', '-c', 'VACUUM race'],
\my $v_in, \$v_out, \$v_err);
my $check_h = IPC::Run::start(
['psql', '-X', '-h', $host, '-p', $port,
'-d', 'postgres', '-c',
"SELECT bt_index_check('race_idx', false, false, true)"],
\my $c_in, \$c_out, \$c_err);
$check_h->finish;
$vacuum_h->finish;
if ($c_err =~ /points to non-existent heap tuple/)
{
$false_positive = 1;
diag("Race triggered on attempt $attempt");
last;
}
diag("Attempt $attempt: no race (check_err='$c_err')");
# Restore data for next round
$node->safe_psql('postgres', q{
TRUNCATE race;
INSERT INTO race SELECT i, repeat('x', 200)
FROM generate_series(1, 1000000) i;
REINDEX INDEX race_idx;
});
}
ok($false_positive,
'FALSE POSITIVE: indexallkeysmatch reports corruption during concurrent VACUUM');
$node->stop;
done_testing();