Skip to content

Commit

Permalink
Be fork/thread-safe.
Browse files Browse the repository at this point in the history
Store handles by PID (and TID, if running under threads), so that no two
processes/threads could receive the same handle.

I'd previously not thought this was a problem since if Dancer is going to fork,
it does so when a request starts, but if the database() keyword was used at
runtime as the app starts rather than in a route handler, dragons could lie
ahead.  Also, if running under mod_perl + mpm_worker, or on Windows, where
forking is imitated with threads.

Thanks to mst for hitting me with the cluebat on this one.

Considering overhauling to use DBIx::Connector, but I think that may be overkill
and require more effort and potential API changes than it may be worth.
More thought on that required; comments welcome.
  • Loading branch information
bigpresh committed May 25, 2011
1 parent e25f520 commit 6a6877c
Showing 1 changed file with 8 additions and 2 deletions.
10 changes: 8 additions & 2 deletions lib/Dancer/Plugin/Database.pm
Expand Up @@ -55,8 +55,14 @@ register database => sub {
}
}

# To be fork safe and thread safe, use a combination of the PID and TID (if
# running with use threads) to make sure no two processes/threads share
# handles. Implementation based on DBIx::Connector by David E. Wheeler.
my $pid_tid = $$;
$pid_tid .= '_' . threads->tid if $INC{'threads.pm'};

# OK, see if we have a matching handle
$handle = $handles{$handle_key} || {};
$handle = $handles{$pid_tid}{$handle_key} || {};

if ($handle->{dbh}) {
if ($conn_details->{connection_check_threshold} &&
Expand All @@ -81,7 +87,7 @@ register database => sub {
# Get a new connection
if ($handle->{dbh} = _get_connection($conn_details)) {
$handle->{last_connection_check} = time;
$handles{$handle_key} = $handle;
$handles{$pid_tid}{$handle_key} = $handle;
return $handle->{dbh};
} else {
return;
Expand Down

0 comments on commit 6a6877c

Please sign in to comment.