[cgiapp] cached DBI connections with cgiapp/fastcgi

Benjamin Hitz hitz at genome.stanford.edu
Thu Oct 23 16:03:25 EDT 2008


>
> On Oct 22, 2008, at 10:39 AM, Michael Peters wrote:
>>
>> It will probably reconnect if the handle isn't there. But not if it  
>> goes bad. I don't know for sure since I don't use that plugin. But  
>> it's a common problem when dealing with persistant DB connections.  
>> If you want to see how mod_perl folks handle, take a look at  
>> Apache::DBI. Look at it's connect() method and particularly how it  
>> uses ping().
>

I am sure are all dying for an update.
1) Unable to turn on DBI_TRACE within perl ($ENV{DBI_TRACE} = 2=/path/ 
to/file).  I have had this problem in the past with other scripts, I  
suppose I will have to fiddle around more with this.
2) The error is here: DBD::Oracle::st execute failed: ORA-01012: not  
logged on (DBD ERROR: OCIStmtExecute)  and it will occur after the  
IDLE time of the user is exceeded. This was tested with a special user  
with 10M idle time.

My review of cgiapp::Plugin::DBH and Apache::DBI
Turns up the following:

my code:

$self->dbh_config(sub { DBI->connect_cached(..) });

Plugin::DBH

(sub dbh)
     ...
     unless( defined($self->{__DBH}{$name}) && $self->{__DBH}{$name}- 
 >ping ) {
         # create DBH object
         if(my $config = $self->{__DBH_CONFIG}{$name} ) {
             # Use a callback
             if (ref $config eq 'CODE') {
                 $self->{__DBH}{$name} = $config->();
             }
             # use the parameters the user supplied
             else {
                 require DBI;
                 $self->{__DBH}{$name} = DBI->connect(@{ $self- 
 >{__DBH_CONFIG}{$name} });
             }
         } else {
         }
     }


sub connect_cached in DBI.pm:

	if ($dbh && $dbh->FETCH('Active') && eval { $dbh->ping }) {
             # If the caller has provided a callback then call it
             if ($cb and $cb = $cb->{"connect_cached.reused"}) {
		local $_ = "connect_cached.reused";
		$cb->($dbh, $dsn, $user, $auth, $attr);
             }
	    return $dbh;
	}

	# If the caller has provided a callback then call it
	# ... not using Callbacks so deleted for brevity

	$dbh = $drh->connect(@_);
	$cache->{$key} = $dbh;	# replace prev entry, even if connect failed
	return $dbh;


Apache::DBI essentially reimplements connect_cached with a ping only  
when necessary:

     # do we need to ping the database ?
     $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;
     print STDERR "$prefix need ping: ", $needping == 1 ? "yes" :  
"no", "\n" if $Apache::DBI::DEBUG > 1;
     $LastPingTime{$dsn} = $now;

     # check first if there is already a database-handle cached
     # if this is the case, possibly verify the database-handle
     # using the ping-method. Use eval for checking the connection
     # handle in order to avoid problems (dying inside ping) when
     # 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;
         return (bless $Connected{$Idx}, 'Apache::DBI::db');
     }

     # either there is no database handle-cached or it is not valid,
     # so get a new database-handle and store it in the cache
     delete $Connected{$Idx};
     $Connected{$Idx} = $drh->connect(@args);
     return undef if !$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');


I note that in the Plugin::DBH code there is no eval{} around the  
ping...  I will probably try that.

First I am going to try what I have with just connect() instead of  
connect_cached.. I am wondering if the dual layer of $dbh checking is  
causing system to get confused.  I agree oracle connections are  
slow... but the FastCGI version of this page takes 3 seconds WHEN  
CACHED... so I am not really worried about it (will profile it though)

Ben


--
Ben Hitz
Senior Scientific Programmer ** Saccharomyces Genome Database ** GO  
Consortium
Stanford University ** hitz at genome.stanford.edu





More information about the cgiapp mailing list