Earlier, I was bitching about Postgres and it's "server closed the connection unexpectedly" message.
Here's a refresher. A fellow programmer wrote a few lines of code to exercize an OO-ification I had done, where logic got moved into an object. He made it use one of two subclasses and switch back and forth. Approximately 8,000 lines after the switch, the database would ... vanish. diff'ing traces turned up nothing, and the query that died was often the same but sometimes not. Stumped. The object that gets created forks and runs some code CPU bound code in the fork but doesn't touch the database. I decided to make it close all of the $dbh's it inherited from the parent process when it forked. Boom -- server starts barfing on queries immediately after the object switch happens and the $dbh is closed in the child. Aha!
Solution: destroy the DESTROY routine so the "tell the server to go away" logic never runs. This code in the child process made the server stop going away:
do { # destroy all $dbh's in the forked process, but do so in a way that doesn't # affect the parent's connection to the database use PadWalker; my $i; while(1) { $i++; my $sf = eval { PadWalker::peek_my($i) } or last; if(exists $sf->{'$dbh'}) { no strict 'refs'; my $package = ref ${ $sf->{'$dbh'} }; # DBI::db::DESTROY *{$package.'::DESTROY'} = sub { }; ${ $sf->{'$dbh'} } = undef; } } };
(that's off the top of my head, so probably won't work verbatim){
my ($pid, $dbh);
sub get_dbh {
if ($$ != $pid) {
$dbh = DBI->connect(...);
}
return $dbh;
}
}