From 6a6877cd2fe28cc76bff9210cc5c33297ed57eeb Mon Sep 17 00:00:00 2001 From: David Precious Date: Wed, 25 May 2011 21:58:42 +0100 Subject: [PATCH] Be fork/thread-safe. 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. --- lib/Dancer/Plugin/Database.pm | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Dancer/Plugin/Database.pm b/lib/Dancer/Plugin/Database.pm index e7db2060..9854d9e7 100644 --- a/lib/Dancer/Plugin/Database.pm +++ b/lib/Dancer/Plugin/Database.pm @@ -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} && @@ -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;