Hi, Over the past few months I have posted a couple of fixes in relation to how Apache::DBI handles are cleaned up. This however is the most complete fix in that it covers the following issues :-
TimeOut = 0 : Should always ping even when multiple requests are made in the same secondi Setting Attributes post connection : $dbh->{AutoCommit}=0 will convert an AutoCommit handle to non AutoCommit so when it is next retunred it behaves incorrectly. Other settings can be effected in the same way. Using begin_work : This is a tempory version of the above. The next commit resets the handle to the default value. I have tested this under mp1 but do not have any active setups for testing under mp2. I have not found that this fix degrades performance but I have not done exhautive benchmarking on multiple platforms. I would be grateful for all feedback in relation to this patch both good and bad.. The patch is against the current CVS version. Thank you all Paddy
--- Changes 2003-07-20 09:03:15.000000000 +0000 +++ Changes 2003-07-21 09:02:11.000000000 +0000 @@ -1,5 +1,11 @@ Revision history for ApacheDBI. +patch July 21, 2003 + - Fixed issues relating to chanding handle state post connection. + Handles now returned in same state as original and incomplete + transactions rolled back before re-issuing handle so begin_work + should now be safe. "Patrick Mulvany" <[EMAIL PROTECTED]> + 0.92-dev - Avoid use of uninitialized value warning under mod_perl 2. --- DBI.pm 2003-06-10 12:20:06.000000000 +0000 +++ DBI.cleanup.pm 2003-07-21 09:22:34.000000000 +0000 @@ -23,6 +23,8 @@ my %LastPingTime; # keeps track of last ping per data_source my $Idx; # key of %Connected and %Rollback. +# Check to see if we need to reset TaintIn and TaintOut +my $TaintInOut = ($DBI::VERSION>=1.31)?1:0; # supposed to be called in a startup script. # stores the data_source of all connections, which are supposed to be created upon @@ -87,11 +89,13 @@ } # this PerlCleanupHandler is supposed to initiate a rollback after the script has finished if AutoCommit is off. - my $needCleanup = ($Idx =~ /AutoCommit[^\d]+0/) ? 1 : 0; + # however cleanup can only be determined at end of handle life as begin_work may have been called to temporarily turn off AutoCommit. + # # TODO - Fix mod_perl 2.0 here - if(!$Rollback{$Idx} and $needCleanup and Apache->can('push_handlers')) { + if(!$Rollback{$Idx} and Apache->can('push_handlers')) { print STDERR "$prefix push PerlCleanupHandler \n" if $Apache::DBI::DEBUG > 1; Apache->push_handlers("PerlCleanupHandler", \&cleanup); + # make sure, that the rollback is called only once for every # request, even if the script calls connect more than once $Rollback{$Idx} = 1; @@ -101,7 +105,8 @@ $PingTimeOut{$dsn} = 0 unless $PingTimeOut{$dsn}; $LastPingTime{$dsn} = 0 unless $LastPingTime{$dsn}; my $now = time; - my $needping = (($PingTimeOut{$dsn} == 0 or $PingTimeOut{$dsn} > 0) and $now - $LastPingTime{$dsn} > $PingTimeOut{$dsn}) ? 1 : 0; + # Must ping if TimeOut = 0 else base on time + my $needping = ($PingTimeOut{$dsn} == 0 or ($PingTimeOut{$dsn} > 0 and $now - $LastPingTime{$dsn} > $PingTimeOut{$dsn})) ? 1 : 0; print STDERR "$prefix need ping: ", $needping == 1 ? "yes" : "no", "\n" if $Apache::DBI::DEBUG > 1; $LastPingTime{$dsn} = $now; @@ -112,6 +117,10 @@ # RaiseError being on and the handle is invalid. if ($Connected{$Idx} and (!$needping or eval{$Connected{$Idx}->ping})) { print STDERR "$prefix already connected to '$Idx'\n" if $Apache::DBI::DEBUG > 1; + + # Force clean up of handle in case previous transaction failed to clean up the handle + &reset_startup_state(); + return (bless $Connected{$Idx}, 'Apache::DBI::db'); } @@ -121,6 +130,9 @@ $Connected{$Idx} = $drh->connect(@args); return undef if !$Connected{$Idx}; + # store the parameters of the initial connection in the handle + set_startup_state($Connected{$Idx}); + # return the new database handle print STDERR "$prefix new connect to '$Idx'\n" if $Apache::DBI::DEBUG; return (bless $Connected{$Idx}, 'Apache::DBI::db'); @@ -158,6 +170,47 @@ 1; } +# Store the default start state of each dbh in the handle +# Note: This uses private_Apache_DBI hash ref to store it in the handle itself + +sub set_startup_state { + foreach my $key qw{ AutoCommit Warn CompatMode InactiveDestroy + PrintError RaiseError HandleError + ShowErrorStatement TraceLevel FetchHashKeyName + ChopBlanks LongReadLen LongTruncOk + Taint Profile} { + $Connected{$Idx}->{private_Apache_DBI}{$key} = $Connected{$Idx}->{$key}; + } + if ($TaintInOut) { + foreach my $key qw{ TaintIn TaintOut } { + $Connected{$Idx}->{private_Apache_DBI}{$key} = $Connected{$Idx}->{$key}; + } + } + 1; +} + + +# Restore the default start state of each dbh + +sub reset_startup_state { + # Rollback current transaction if currently in one + $Connected{$Idx}->{Active} and !$Connected{$Idx}->{AutoCommit} and eval {$Connected{$Idx}->rollback}; + + foreach my $key qw{ AutoCommit Warn CompatMode InactiveDestroy + PrintError RaiseError HandleError + ShowErrorStatement TraceLevel FetchHashKeyName + ChopBlanks LongReadLen LongTruncOk + Taint Profile } { + $Connected{$Idx}->{$key} = $Connected{$Idx}->{private_Apache_DBI}{$key}; + } + if ($TaintInOut) { + foreach my $key qw{ TaintIn TaintOut } { + $Connected{$Idx}->{$key} = $Connected{$Idx}->{private_Apache_DBI}{$key}; + } + } + 1; +} + # This function can be called from other handlers to perform tasks on all cached database handles. @@ -301,8 +354,10 @@ AutoCommit is off and the script finishes without an explicit rollback, the Apache::DBI module uses a PerlCleanupHandler to issue a rollback at the end of every request. Note, that this CleanupHandler will only be used, if -the initial data_source sets AutoCommit = 0. It will not be used, if AutoCommit -will be turned off, after the connect has been done. +the initial data_source sets AutoCommit = 0 or AutoCommit is turned off, after +the connect has been done (ie begin_work). However, because a connection may have +set other parameters, the handle is reset to its initial connection state before +it is returned for a second time. This module plugs in a menu item for Apache::Status. The menu lists the current database connections. It should be considered incomplete because of
pgp00000.pgp
Description: PGP signature