Fix test_misc/010_index_concurrently_upsert for cache-clobbering builds

The test script added by commit e1c971945d failed to handle the case
of cache-clobbering builds (CLOBBER_CACHE_ALWAYS and
CATCACHE_FORCE_RELEASE) properly -- it would only exit a loop on
timeout, which is slow, and unfortunate because I (Álvaro) increased the
timeout for that loop to the complete default TAP test timeout, causing
the buildfarm to report the whole test run as a timeout failure.  We can
be much quicker: exit the loop as soon as the backend is seen as waiting
on the injection point.

In this commit we still reduce the timeout (of that loop and a nearby
one just to be safe) to half of the default.

I (Álvaro) had also changed Mihail's "sleep(1)" to "sleep(0.1)", which
apparently turns a 1s sleep into a 0s sleep, because Perl -- probably
making this a busy loop.  Use Time::HiRes::usleep instead, like we do in
other tests.

Author: Mihail Nikalayeu <mihailnikalayeu@gmail.com>
Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de>
Discussion: https://postgr.es/m/CADzfLwWOVyJygX6BFuyuhTKkJ7uw2e8OcVCDnf6iqnOFhMPE%2BA%40mail.gmail.com
This commit is contained in:
Álvaro Herrera
2026-01-13 10:03:33 +01:00
parent 94a24b4ee5
commit 8a47d9ee7f

View File

@ -1,5 +1,5 @@
# Copyright (c) 2025, PostgreSQL Global Development Group
# Copyright (c) 2026, PostgreSQL Global Development Group
# Test INSERT ON CONFLICT DO UPDATE behavior concurrent with
# CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY.
@ -15,6 +15,7 @@ use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;
use Time::HiRes qw(usleep);
plan skip_all => 'Injection points not supported by this build'
unless $ENV{enable_injection_points} eq 'yes';
@ -624,14 +625,16 @@ $s1->query_until(
\echo attaching_injection_point
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait');
]);
# In case of CLOBBER_CACHE_ALWAYS - s1 may hit the injection point during attach.
# Wait for s1 to become idle (attach completed) or wakeup if stuck on injection point.
# In cases of cache clobbering, s1 may hit the injection point during attach.
# Wait for that session to become idle (attach completed), or wake it up if
# it becomes stuck on injection point.
if (!wait_for_idle($node, $s1_pid))
{
ok_injection_point(
$node,
'invalidate-catalog-snapshot-end',
's1 hit injection point during attach (CLOBBER_CACHE_ALWAYS)');
's1 hit injection point during attach (cache clobbering mode)');
$node->safe_psql(
'postgres', q[
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end');
@ -715,13 +718,16 @@ $s1->query_until(
\echo attaching_injection_point
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait');
]);
# In case of CLOBBER_CACHE_ALWAYS - s1 may hit the injection point during attach.
# Wait for s1 to become idle (attach completed) or wakeup if stuck on injection point.
# In cases of cache clobbering, s1 may hit the injection point during attach.
# Wait for that session to become idle (attach completed), or wake it up if
# it becomes stuck on injection point.
if (!wait_for_idle($node, $s1_pid))
{
ok_injection_point($node, 'invalidate-catalog-snapshot-end',
'Test 8: s1 hit injection point during attach (CLOBBER_CACHE_ALWAYS)'
);
ok_injection_point(
$node,
'invalidate-catalog-snapshot-end',
's1 hit injection point during attach (cache clobbering mode)');
$node->safe_psql(
'postgres', q[
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end');
@ -793,7 +799,7 @@ done_testing();
sub wait_for_injection_point
{
my ($node, $point_name, $timeout) = @_;
$timeout //= $PostgreSQL::Test::Utils::timeout_default;
$timeout //= $PostgreSQL::Test::Utils::timeout_default / 2;
for (my $elapsed = 0; $elapsed < $timeout * 10; $elapsed++)
{
@ -805,7 +811,7 @@ sub wait_for_injection_point
LIMIT 1;
]);
return 1 if $pid ne '';
sleep(0.1);
usleep(100_000);
}
# Timeout - report diagnostic information
@ -833,20 +839,25 @@ sub ok_injection_point
}
# Helper: Wait for a specific backend to become idle.
# Returns true if idle, false if timeout.
# Returns true if idle, false if waiting for injection point or timeout.
sub wait_for_idle
{
my ($node, $pid, $timeout) = @_;
$timeout //= $PostgreSQL::Test::Utils::timeout_default;
$timeout //= $PostgreSQL::Test::Utils::timeout_default / 2;
for (my $elapsed = 0; $elapsed < $timeout * 10; $elapsed++)
{
my $state = $node->safe_psql(
my $result = $node->safe_psql(
'postgres', qq[
SELECT state FROM pg_stat_activity WHERE pid = $pid;
SELECT state, wait_event_type FROM pg_stat_activity WHERE pid = $pid;
]);
my ($state, $wait_event_type) = split(/\|/, $result, 2);
$state //= '';
$wait_event_type //= '';
return 1 if $state eq 'idle';
sleep(0.1);
return 0 if $wait_event_type eq 'InjectionPoint';
usleep(100_000);
}
return 0;
}