Optional::Dependencies::req_group_list (no known users in the wild)
- Protect tests and codebase from incomplete caller() overrides, like
e.g. RT#32640
+ - Work around rare test deadlock under heavy parallelism (RT#108390)
- Stop using bare $] throughout - protects the codebase from issues
similar (but likely not limited to) P5#72210
use strict;
use warnings;
-use DBICTest::Util qw( local_umask dbg DEBUG_TEST_CONCURRENCY_LOCKS );
+use DBICTest::Util qw( local_umask await_flock dbg DEBUG_TEST_CONCURRENCY_LOCKS );
use DBICTest::Schema;
use DBICTest::Util::LeakTracer qw/populate_weakregistry assert_empty_weakregistry/;
use DBIx::Class::_Util 'detected_reinvoked_destructor';
DEBUG_TEST_CONCURRENCY_LOCKS > 1
and dbg "Waiting for EXCLUSIVE global lock...";
- flock ($global_lock_fh, LOCK_EX) or die "Unable to lock $lockpath: $!";
+ await_flock ($global_lock_fh, LOCK_EX) or die "Unable to lock $lockpath: $!";
DEBUG_TEST_CONCURRENCY_LOCKS > 1
and dbg "Got EXCLUSIVE global lock";
DEBUG_TEST_CONCURRENCY_LOCKS > 1
and dbg "Waiting for SHARED global lock...";
- flock ($global_lock_fh, LOCK_SH) or die "Unable to lock $lockpath: $!";
+ await_flock ($global_lock_fh, LOCK_SH) or die "Unable to lock $lockpath: $!";
DEBUG_TEST_CONCURRENCY_LOCKS > 1
and dbg "Got SHARED global lock";
use Time::HiRes 'sleep';
use Scope::Guard ();
use DBICTest::Util::LeakTracer qw(populate_weakregistry assert_empty_weakregistry);
-use DBICTest::Util qw( local_umask dbg DEBUG_TEST_CONCURRENCY_LOCKS );
+use DBICTest::Util qw( local_umask await_flock dbg DEBUG_TEST_CONCURRENCY_LOCKS );
use namespace::clean;
sub capture_executed_sql_bind {
# an envvar, we can not detect when a user invokes prove -jN. Hence
# perform the locking at all times, it shouldn't hurt.
# the lock fh *should* inherit across forks/subprocesses
- #
- # File locking is hard. Really hard. By far the best lock implementation
- # I've seen is part of the guts of File::Temp. However it is sadly not
- # reusable. Since I am not aware of folks doing NFS parallel testing,
- # nor are we known to work on VMS, I am just going to punt this and
- # use the portable-ish flock() provided by perl itself. If this does
- # not work for you - patches more than welcome.
if (
! $DBICTest::global_exclusive_lock
and
sysopen ($lock_fh, $lockpath, O_RDWR|O_CREAT) or die "Unable to open $lockpath: $!";
}
- flock ($lock_fh, LOCK_EX) or die "Unable to lock $lockpath: $!";
+ await_flock ($lock_fh, LOCK_EX) or die "Unable to lock $lockpath: $!";
DEBUG_TEST_CONCURRENCY_LOCKS
and dbg "Got $locktype LOCK: $lockpath";
use Config;
use Carp 'confess';
+use Fcntl ':flock';
use Scalar::Util qw(blessed refaddr);
use DBIx::Class::_Util;
local_umask
visit_namespaces
check_customcond_args
- DEBUG_TEST_CONCURRENCY_LOCKS
+ await_flock DEBUG_TEST_CONCURRENCY_LOCKS
);
if (DEBUG_TEST_CONCURRENCY_LOCKS) {
;
}
+# File locking is hard. Really hard. By far the best lock implementation
+# I've seen is part of the guts of File::Temp. However it is sadly not
+# reusable. Since I am not aware of folks doing NFS parallel testing,
+# nor are we known to work on VMS, I am just going to punt this and
+# use the portable-ish flock() provided by perl itself. If this does
+# not work for you - patches more than welcome.
+#
+# This figure esentially means "how long can a single test hold a
+# resource before everyone else gives up waiting and aborts" or
+# in other words "how long does the longest test-group legitimally run?"
+my $lock_timeout_minutes = 15; # yes, that's long, I know
+my $wait_step_seconds = 0.25;
+
+sub await_flock ($$) {
+ my ($fh, $locktype) = @_;
+
+ my ($res, $tries);
+ while(
+ ! ( $res = flock( $fh, $locktype | LOCK_NB ) )
+ and
+ ++$tries <= $lock_timeout_minutes * 60 / $wait_step_seconds
+ ) {
+ select( undef, undef, undef, $wait_step_seconds );
+
+ # "say something" every 10 cycles to work around RT#108390
+ # jesus christ our tooling is such a crock of shit :(
+ print "#\n" if not $tries % 10;
+ }
+
+ return $res;
+}
+
sub local_umask {
return unless defined $Config{d_umask};