[CDBI] Class::DBI and forking
Carlos Vicente <cvicente-zZ82ZiX1S8l+u43qRgrggVnYRNhDb3e+9nwVQlTi/[email protected]>
| Newsgroups | gmane.comp.lang.perl.modules.class-dbi |
|---|---|
| Message-ID | <[email protected]> |
Hi Perrin and others,
I've come across an already discussed problem regarding forking in CDBI
and its problems with shared db handles. I found the following thread:
http://lists.digitalcraftsmen.net/pipermail/classdbi/2006-March/000995.html
which refers to the use of the InactiveDestroy flag, overriding db_Main,
etc...
The problem is that the link in that particular thread is broken and I
cannot tell which changes exactly need to happen in the db_Main
subclass, Ima::DBI, etc...
I tried to make it work with the information I had. I modified the code
to have the child process set InactiveDestroy and call db_Main to open a
new db connection. However, it still throws db errors such as:
DBD::mysql::st fetchrow_array failed: fetch() without execute() [for
Statement "..."
So, obviously I'm still missing something.
Can anyone give me some more hints?
Any help would be much appreciated.
cv
Here's a snippet of the method that calls fork():
-------------------------------------------------
sub arp_update_all {
my ($class, %args) = @_;
$class->isa_class_method('arp_update_all');
$openkids = 0;
my $wait = 2;
my %caches;
my $dbh = $class->db_Main;
my $start = time;
my $device_count;
my $alldevs = Device->retrieve_all();
while ( my $dev = $alldevs->next ){
my $cache;
my $pid;
FORK: {
if ( $pid = fork ){
# parent here
$SIG{CHLD} = \&_reaper;
}elsif ( defined $pid ) { # $pid is zero here if defined
# child here
if ( !($dbh->{InactiveDestroy} = 1) ) {
$class->throw_fatal("Cannot set InactiveDestroy: ", $dbh->errstr);
}
$dbh = undef;
$dbh = $class->db_Main;
$cache = $dev->_get_snmp_arp();
$caches{$dev->id}{dev} = $dev;
$caches{$dev->id}{cache} = $cache;
exit;
}elsif ( $! =~ /No more process/ ) {
# EAGAIN, supposedly recoverable fork error
$logger->warn("Problem while forking: $!. Waiting for $wait
seconds");
sleep($wait);
redo FORK;
}else {
# weird fork error
$class->throw_fatal("Cannot fork: $!") unless defined $pid;
}
}
-------------------------------------------------
And my db_Main looks like:
sub db_Main {
my $self = shift;
my $dbh;
if ( $ENV{'MOD_PERL'} and !$Apache::ServerStarting ) {
$dbh = Apache->request()->pnotes('dbh');
}else{
$dbh = $self->SUPER::db_Main();
}
if ( !$dbh ) {
$dbh = DBI->connect_cached($defaults{dsn}, $defaults{user},
$defaults{password}, $defaults{dbi_options});
if ( $ENV{'MOD_PERL'} and !$Apache::ServerStarting ) {
Apache->request()->pnotes( 'dbh', $dbh );
}
}
return $dbh;
}
------------------------------------------------------