DBIx-Class
view release on metacpan or search on metacpan
t/52leaks.t view on Meta::CPAN
# dbh's are created in XS space, so pull them separately
for ( grep { defined } map { @{$_->{ChildHandles}} } values %{ {DBI->installed_drivers()} } ) {
$base_collection->{"DBI handle $_"} = $_;
}
populate_weakregistry ($weak_registry, $base_collection->{$_}, "basic $_")
for keys %$base_collection;
}
# check that "phantom-chaining" works - we never lose track of the original $schema
# and have access to the entire tree without leaking anything
{
my $phantom;
for (
sub { DBICTest->init_schema( sqlite_use_file => 0 ) },
sub { shift->source('Artist') },
sub { shift->resultset },
sub { shift->result_source },
sub { shift->schema },
sub { shift->resultset('Artist') },
sub { shift->find_or_create({ name => 'detachable' }) },
sub { shift->result_source },
sub { shift->schema },
sub { shift->clone },
sub { shift->resultset('CD') },
sub { shift->next },
sub { shift->artist },
sub { shift->search_related('cds') },
sub { shift->next },
sub { shift->search_related('artist') },
sub { shift->result_source },
sub { shift->resultset },
sub { shift->create({ name => 'detached' }) },
sub { shift->update({ name => 'reattached' }) },
sub { shift->discard_changes },
sub { shift->delete },
sub { shift->insert },
) {
$phantom = populate_weakregistry ( $weak_registry, scalar $_->($phantom) );
}
ok( $phantom->in_storage, 'Properly deleted/reinserted' );
is( $phantom->name, 'reattached', 'Still correct name' );
}
# Naturally we have some exceptions
my $cleared;
for my $addr (keys %$weak_registry) {
my $names = join "\n", keys %{$weak_registry->{$addr}{slot_names}};
if ($names =~ /^Test::Builder/m) {
# T::B 2.0 has result objects and other fancyness
delete $weak_registry->{$addr};
}
elsif ($names =~ /^Hash::Merge/m) {
# only clear one object of a specific behavior - more would indicate trouble
delete $weak_registry->{$addr}
unless $cleared->{hash_merge_singleton}{$weak_registry->{$addr}{weakref}{behavior}}++;
}
elsif ($names =~ /^B::Hooks::EndOfScope::PP::_TieHintHashFieldHash/m) {
# there is one tied lexical which stays alive until GC time
# https://metacpan.org/source/ETHER/B-Hooks-EndOfScope-0.15/lib/B/Hooks/EndOfScope/PP/FieldHash.pm#L24
# simply ignore it here, instead of teaching the leaktracer to examine ties
# the latter is possible yet terrible: https://metacpan.org/source/RIBASUSHI/DBIx-Class-0.082840/t/lib/DBICTest/Util/LeakTracer.pm#L113-117
delete $weak_registry->{$addr}
unless $cleared->{bheos_pptiehinthashfieldhash}++;
}
elsif ($names =~ /^B::Hooks::EndOfScope::PP::HintHash::__GraveyardTransport/m) {
# a workaround for perl-level double free: these "leak" by design
delete $weak_registry->{$addr};
}
elsif ($names =~ /^DateTime::TimeZone::UTC/m) {
# DT is going through a refactor it seems - let it leak zones for now
delete $weak_registry->{$addr};
}
elsif (
# # if we can look at closed over pieces - we will register it as a global
# !DBICTest::Util::LeakTracer::CV_TRACING
# and
$names =~ /^SQL::Translator::Generator::DDL::SQLite/m
) {
# SQLT::Producer::SQLite keeps global generators around for quoted
# and non-quoted DDL, allow one for each quoting style
delete $weak_registry->{$addr}
unless $cleared->{sqlt_ddl_sqlite}->{@{$weak_registry->{$addr}{weakref}->quote_chars}}++;
}
}
# FIXME !!!
# There is an actual strong circular reference taking place here, but because
# half of it is in XS, so it is a bit harder to track down (it stumps D::FR)
# (our tracker does not yet do it, but it'd be nice)
# The problem is:
#
# $cond_object --> result_source --> schema --> storage --> $dbh --> {CachedKids}
# ^ /
# \-------- bound value on prepared/cached STH <-----------/
#
{
my @circreffed;
for my $r (map
{ $_->{weakref} }
grep
{ $_->{slot_names}{'basic leaky_resultset_cond'} }
values %$weak_registry
) {
local $TODO = 'Needs Data::Entangled or somesuch - see RT#82942';
ok(! defined $r, 'Self-referential RS conditions no longer leak!')
or push @circreffed, $r;
}
if (@circreffed) {
is (scalar @circreffed, 1, 'One resultset expected to leak');
# this is useless on its own, it is to showcase the circref-diag
# and eventually test it when it is operational
local $TODO = 'Needs Data::Entangled or somesuch - see RT#82942';
while (@circreffed) {
weaken (my $r = shift @circreffed);
( run in 1.612 second using v1.01-cache-2.11-cpan-5735350b133 )