Bill Moseley scribbled on 4/12/07 9:11 PM:
> Ok, I just have to ask.  What are people doing for dbh caching?
> I know this comes up often:
> 
>     
> http://thread.gmane.org/gmane.comp.lang.perl.modules.dbi.rose-db-object/1138/focus=1140
> 

here's my (admittedly buggy) code for doing this. It caches a single dbh for 
each unique RDB registry entry combination of domain.type.dsn. I know that it 
breaks under mod_perl -- anyone spot why? (the error I get is from Pg: 
"prepared 
statement 'dbdpg_1' already exists" after first request, because %cache seems 
to 
be shared across all apache child processes).

First the RDBO subclass:
------------------------------------------
package My::RDBO;

use My::DB;
use base qw( Rose::DB::Object );
use Rose::Class::MakeMethods::Generic (scalar => ['debug']);

our %cache;    # DBI object cache

sub init_db
{
     my $class = shift;
     my %o     = @_;

     unless (exists $o{debug})
     {
         $o{debug} = $class->debug || $ENV{PERL_DEBUG} || 0;
     }

     my $db = My::DB->new(%o);

     if ($db->cache_dbh)
     {
         my $i = $db->idx;
         if (    exists $cache{$i}
             and defined $cache{$i}->{dbh}
             and (time() - $cache{$i}->{age}) < $db->timeout
             and $db->ping($cache{$i}->{dbh}))
         {
             $cache{$i}->{cnt}++;
             $db->logger(
                  "using cached dbh for $class (called $cache{$i}->{cnt} 
times)")
               if $db->debug > 1;
             $db->dbh($cache{$i}->{dbh});
         }
         else
         {
             $db->logger("creating new dbh for $i") if $db->debug;
             if (exists $cache{$i}->{dbh})
             {
                 $cache{$i}->{dbh}
                   ->disconnect;    # explicitly disconnect old handle
             }
             my $dbh = $db->dbh;
             $cache{$i} = {
                           dbh => $dbh,
                           age => time(),
                           cnt => 1,
                           dbi => "$dbh"
                          };
         }
         if (exists $cache{$i})
         {
             $db->logger("dbh = $cache{$i}->{dbh}")
               if $db->debug > 1;
         }
     }

     return $db;
}

1;


and the RDB subclass:
------------------------------------
package My::DB;

use base qw( Rose::DB );
use Rose::Object::MakeMethods::Generic (
     'scalar --get_set_init' => [qw(timeout debug logfh cache_dbh)],
);

sub init_timeout   { '3600' }
sub init_logfh     { *STDERR{IO} }
sub init_debug     { 0 }
sub init_cache_dbh { 1 }

sub ping
{
     my $self       = shift;
     my $dbh        = shift || $self->dbh;
     my $ret        = 0;
     my $prev_alarm = 0;
     eval {
         local $SIG{__DIE__}  = sub { $self->logger("ping died: $@"); return 0 
};
         local $SIG{__WARN__} = sub { return (0); };
         local $SIG{ALRM}     = sub { return (0); };

         $self->logger('setting alarm') if $self->debug > 1;
         $prev_alarm = CORE::alarm(2);
         $self->logger("alarm = $prev_alarm") if $self->debug > 1;
         $ret = $dbh->do("select 1");
         $self->logger('ping ok') if $self->debug > 1;
     };
     $prev_alarm ? CORE::alarm($prev_alarm) : CORE::alarm(0);
     $self->logger('alarm reset to ' . $prev_alarm) if $self->debug > 1;

     return ($@) ? 0 : $ret;
}

# unique name for cache
sub idx
{
     my $self = shift;
     return join('::', $self->domain, $self->type, $self->dsn);
}

# overriden to prevent automatic DBI->disconnect
sub release_dbh
{
     my $self = shift;
     return 1                       if $self->cache_dbh;
     $self->logger("releasing dbh") if $self->debug;
     $self->SUPER::release_dbh(@_);
}

sub logger
{
     my $self = shift;
     my @msg  = @_;
     for my $m (@msg)
     {
         print {$self->logfh} join(' ', $self->loglabel, $m, "\n");
     }
}

sub loglabel
{
     my $self = shift;
     my $time = localtime();
     return '[' . $time . '] ' . '[' . $self->nick . '] ';
}

sub nick
{
     my $self = shift;
     return
       join('.', $self->domain, $self->type,
            $self->database . '@' . $self->host);
}

1;



-- 
Peter Karman  .  http://peknet.com/  .  [EMAIL PROTECTED]

-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys-and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
Rose-db-object mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/rose-db-object

Reply via email to