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