Hello,

I believe there is an issue with Apache::DBI under mod_perl 2.
Apache::DBI is supposed not to cache connections created in the parent
apache process, since using such a connection from multiple children
simultaneously causes problems. Under MP1 the condition to avoid caching
is
  $Apache::ServerStarting and $Apache::ServerStarting == 1
and under MP2 it is
  Apache2::ServerUtil::restart_count() == 1

restart_count is mentioned in the doc as an MP2 alternative to
$Apache::ServerStarting, but it is not. When apache starts under MP2 it
runs the config phase and at this time restart_count == 1. Then apache
restarts  and runs the config phase again (similarly to MP1), but in
contrast to MP1 this happens in a new process and PerlRequire'd files
are executed again. In this phase restart_count == 2 and it remains 2
until apache is restarted again, then it becomes 3 and so on.

So we can have restart_count > 1 and still be in the parent process, in
this case Apache::DBI will happily cache connections. Indeed, using the
simple startup.pl attached below, apache segfaults on a consistent
basis. (note that Apache::DBI 1.07 dies when opening connections in
startup.pl due to a known bug (CPAN #36346), so I tested 1.06).

So it looks like a bug. The fix would be to correct the
"are-we-on-parent" check. Btw, since MP2 has no equivalent to
Apache::ServerStarting, I know no easy way to tell whether we're on a
parent or child. The only way I know (suggested by Perrin) is to
register a PerlChildInitHandler and set a flag there, but this assumes
we have access to at least startup.pl, which is not ideal for modules.
IMHO, MP2 should provide an easier way to do that.

Kostas

PS. CPAN bug #37272 looks similar at first sight, but refers to mod_perl
1 so I doubt it's related.



# putting this in startup.pl causes segfaults under mod_perl 2.0.4
# apache 2.2.9, Apache::DBI 1.06, linux kernel 2.6.27
#
# if 'use Apache::DBI' is removed everything works
#
use Apache::DBI;
use DBI;

use Apache2::ServerUtil;
my $s = Apache2::ServerUtil->server;

my $dsn = '...';
my $username = '...';
my $password = '...';

warn "connect " . DBI->connect($dsn, $username, $password);

$s->push_handlers(PerlChildInitHandler => sub {
        my $db = DBI->connect($dsn, $username, $password);
        warn "-- connect (pid $$) " . $db;

        for(1..1000) {
                my $sth = $db->prepare("select 1");
                $sth->execute;
                $sth->fetchall_arrayref;
        }
        warn "done $$";
        return 0;
});

Reply via email to