Subject: | fork disrupts the database connection 2.9002 and 2.9003 |
Distribution names: DBD-MySQL-2.9002 and DBD-mysql-2.9003
Perl versions: 5.8.0 and 5.8.1
Operating systems:
Linux cartman.network1.net 2.4.22-1.2115.nptl #1 Wed Oct 29 15:20:17 EST 2003 i586 i586 i386 GNU/Linux
FreeBSD skipper.network1.net 4.8-RC FreeBSD 4.8-RC #0: Wed Mar 5 16:45:13 EST 2003 root@skipper.network1.net:/usr/obj/usr/src/sys/FNGi i386
After an initial select, and then a fork, the database connection still exists, but is unusable. That is as specific as I can be...
Here is some example code that does not work under the above mentioned dbd versions, but does work on dbd-mysql-2.1026:
#!/usr/bin/perl
my $db_host='localhost';
my $db='fngimon';
my $db_user='<hidden>';
my $db_pass='<hidden>';
use strict;
use DBI;
use POSIX ":sys_wait_h";
my $dbh=&db_connect($db_host,$db,$db_user,$db_pass);
while (1) {
my $sqlquery="select id from interfaces order by rand() limit 0, 5";
my $obj=&db_query($dbh,$sqlquery);
my $ntuples=$obj->rows();
my $debug=1;
while (my $ref = $obj->fetchrow_hashref()) {
my $interfaces_id=$ref->{'id'};
print "interfaces_id:$interfaces_id " if ($debug);
&safefork;
}
print "-----------------------------------------------------------------------------------------------------------------\n";
}
##############################################################
# This subroutine forks the recv() so the script doesnt hang!#
##############################################################
sub safefork {
my $pid_;
my $return;
my %SIG;
$SIG{CHLD} = \&REAPER;
# do something that forks...
FORK: {
if ($pid_ = fork) {
# parent here
# child process pid is available in $pid_
return ($pid_);
} elsif (defined $pid_) { # $pid_ is zero here if defined
# child here
# Child code goes here!
# parent process pid is available with getppid
exit;
} elsif ($! =~ /No more process/) {
# EAGAIN, supposedly recoverable fork error
#sleep 5;
#redo FORK;
# Just exit:
exit;
} else {
# weird fork error
print ("Can't fork: $!\n");
exit;
}
}
} # end safefork sub-routine
########################################################################
# This subroutine is REAPER that prevents Zombies with his shiny scythe#
# This is necessary on sysv due to the way it handles signals #
########################################################################
sub REAPER {
my $child;
my %Kid_Status;
my %SIG;
# If a second child dies while in the signal handler caused by the
# first death, we won't get another signal. So must loop here else
# we will leave the unreaped child as a zombie. And the next time
# two children die we get another zombie. And so on.
while (($child = waitpid(-1,WNOHANG)) > 0) {
$Kid_Status{$child} = $?;
}
$SIG{CHLD} = \&REAPER; # still loathe sysV
} # end REAPER sub-routine
sub db_connect {
my ($db_host,$db,$db_user,$db_pass) = @_;
my ($dbh);
my ($note_connect)=0;
while (!$dbh) {
$dbh = DBI->connect("DBI:mysql:$db:$db_host", "$db_user", "$db_pass", {PrintError => 0});
if (!$dbh) {
$note_connect=1;
sleep 2;
}
}
if ($note_connect==1) {
$note_connect=0;
}
return ($dbh);
}
sub db_query {
my ($dbh,$sqlquery) = @_;
my ($obj) = $dbh->prepare("$sqlquery");
if (!$obj) {
exit;
}
if (!$obj->execute) {
exit;
}
return ($obj);
} # end db_query sub-routine;