Skip to content
Snippets Groups Projects
Commit 549e6b9a authored by Jessica Severin's avatar Jessica Severin
Browse files

added disconnect method. smart enough to deal with shared db_handles

'reconnect' is automatic when any access to the handle (db_handle, prepare)
is requested. Also added explicit connect method which returns if the
handle is already connected (shouldn't need to be called)
parent ac92724d
No related branches found
No related tags found
No related merge requests found
...@@ -100,16 +100,18 @@ sub new { ...@@ -100,16 +100,18 @@ sub new {
throw("Bio::EnsEMBL::DBSQL::DBConnection argument expected."); throw("Bio::EnsEMBL::DBSQL::DBConnection argument expected.");
} }
#share a common db_handle, use a shared scalar ref_count to track # connections
my $rcount = $dbconn->ref_count(); my $rcount = $dbconn->ref_count();
$$rcount++; # dereference and increment shared var $$rcount++; # dereference and increment shared var
$self->ref_count($rcount); $self->ref_count($rcount);
$self->db_handle($dbconn->db_handle());
$self->driver($dbconn->driver()); $self->driver($dbconn->driver());
$self->host($dbconn->host()); $self->host($dbconn->host());
$self->port($dbconn->port());
$self->dbname($dbconn->dbname());
$self->username($dbconn->username()); $self->username($dbconn->username());
$self->password($dbconn->password()); $self->password($dbconn->password());
$self->port($dbconn->port());
$self->db_handle($dbconn->db_handle());
return Bio::EnsEMBL::Container->new($self); return Bio::EnsEMBL::Container->new($self);
} }
...@@ -127,6 +129,7 @@ sub new { ...@@ -127,6 +129,7 @@ sub new {
$port = 3306; $port = 3306;
} }
=head1
my $dsn = "DBI:$driver:database=$db;host=$host;port=$port"; my $dsn = "DBI:$driver:database=$db;host=$host;port=$port";
my $dbh; my $dbh;
...@@ -140,6 +143,7 @@ sub new { ...@@ -140,6 +143,7 @@ sub new {
my $ref_count = 1; my $ref_count = 1;
$self->ref_count(\$ref_count); $self->ref_count(\$ref_count);
$self->db_handle($dbh); $self->db_handle($dbh);
=cut
$self->username( $user ); $self->username( $user );
$self->host( $host ); $self->host( $host );
...@@ -148,6 +152,8 @@ sub new { ...@@ -148,6 +152,8 @@ sub new {
$self->port($port); $self->port($port);
$self->driver($driver); $self->driver($driver);
$self->connect();
# be very sneaky and actually return a container object which is outside # be very sneaky and actually return a container object which is outside
# of the circular reference loops and will perform cleanup when all # of the circular reference loops and will perform cleanup when all
# references to the container are gone. # references to the container are gone.
...@@ -155,6 +161,45 @@ sub new { ...@@ -155,6 +161,45 @@ sub new {
} }
=head2 connect
Example : $db_connection->connect()
Description: Explicitely connect to database if not connected
Returntype : none
Exceptions : none
Caller : new, db_handle
=cut
sub connect {
my $self = shift;
if($self->{'_db_handle'}) { return; }
my $host = $self->host();
my $driver = $self->driver();
my $user = $self->username();
my $password = $self->password();
my $port = $self->port();
my $db = $self->dbname();
my $dsn = "DBI:$driver:database=$db;host=$host;port=$port";
my $dbh;
eval{
$dbh = DBI->connect("$dsn","$user",$password, {RaiseError => 1});
};
$dbh || throw("Could not connect to database $db user " .
"$user using [$dsn] as a locator\n" . $DBI::errstr);
#print STDERR "DBConnection : CONNECT\n";
my $ref_count = 1;
$self->ref_count(\$ref_count);
$self->{'_db_handle'} = $dbh;
}
=head2 driver =head2 driver
Arg [1] : (optional) string $arg Arg [1] : (optional) string $arg
...@@ -420,12 +465,12 @@ sub db_handle { ...@@ -420,12 +465,12 @@ sub db_handle {
if( defined $value) { if( defined $value) {
$self->{'_db_handle'} = $value; $self->{'_db_handle'} = $value;
} }
return $self->{'_db_handle'}; else { $self->connect(); }
return $self->{'_db_handle'};
} }
=head2 prepare =head2 prepare
Arg [1] : string $string Arg [1] : string $string
...@@ -446,13 +491,13 @@ sub prepare { ...@@ -446,13 +491,13 @@ sub prepare {
if( ! $string ) { if( ! $string ) {
throw("Attempting to prepare an empty SQL query."); throw("Attempting to prepare an empty SQL query.");
} }
if( !defined $self->{_db_handle} ) { if( !defined $self->db_handle ) {
throw("Database object has lost its database handle."); throw("Database object has lost its database handle.");
} }
#info("SQL(".$self->dbname."):$string"); #info("SQL(".$self->dbname."):$string");
return $self->{_db_handle}->prepare($string); return $self->db_handle->prepare($string);
} }
...@@ -612,23 +657,46 @@ sub DESTROY { ...@@ -612,23 +657,46 @@ sub DESTROY {
#print STDERR "DESTROYING DBConnection\n"; #print STDERR "DESTROYING DBConnection\n";
my $dbh = $obj->{'_db_handle'}; $obj->disconnect();
}
if( $dbh ) {
my $refcount = $obj->ref_count();
$$refcount--;
# Do not disconnect if the InactiveDestroy flag has been set =head2 disconnect
# this can really screw up forked processes.
# Also: do not disconnect if this database handle is shared by
# other DBConnections (as indicated by the refcount)
if(!$dbh->{'InactiveDestroy'} && $$refcount == 0) {
$dbh->disconnect;
}
$obj->{'_db_handle'} = undef; Example : $db_connection->disconnect()
} Description: Explicitely disconnect from database if connected
} Returntype : none
Exceptions : none
Caller : ?, DESTROY
=cut
sub disconnect {
my $self = shift;
my $dbh = $self->{'_db_handle'};
if( $dbh ) {
my $refcount = $self->ref_count();
$$refcount--;
#print STDERR "DBConnection : ref_count-- ";
# Do not disconnect if the InactiveDestroy flag has been set
# this can really screw up forked processes.
# Also: do not disconnect if this database handle is shared by
# other DBConnections (as indicated by the refcount)
if(!$dbh->{'InactiveDestroy'} && $$refcount == 0) {
$dbh->disconnect;
#print STDERR ": DISCONNECT ";
}
#print STDERR "\n";
$self->{'_db_handle'} = undef;
#unlink shared ref_count variable since no longer sharing db_handle
my $unlinked_refcount = 0;
$self->ref_count(\$unlinked_refcount);
}
}
1; 1;
...@@ -5,7 +5,7 @@ use warnings; ...@@ -5,7 +5,7 @@ use warnings;
BEGIN { $| = 1; BEGIN { $| = 1;
use Test; use Test;
plan tests => 15; plan tests => 19;
} }
use MultiTestDB; use MultiTestDB;
...@@ -91,6 +91,7 @@ ok(test_getter_setter($dbc, 'db_handle', $db->db_handle)); ...@@ -91,6 +91,7 @@ ok(test_getter_setter($dbc, 'db_handle', $db->db_handle));
my $sth = $dbc->prepare('SELECT * from gene limit 1'); my $sth = $dbc->prepare('SELECT * from gene limit 1');
$sth->execute; $sth->execute;
ok($sth->rows); ok($sth->rows);
$sth->finish;
# #
# 12 add_db_adaptor # 12 add_db_adaptor
...@@ -114,7 +115,31 @@ $dbc->remove_db_adaptor('core'); ...@@ -114,7 +115,31 @@ $dbc->remove_db_adaptor('core');
ok(!defined $dbc->get_db_adaptor('core')); ok(!defined $dbc->get_db_adaptor('core'));
ok(!defined $dbc->get_all_db_adaptors->{'core'}); ok(!defined $dbc->get_all_db_adaptors->{'core'});
#
# 16-17 disconnect and auto-reconnect via a prepare
#
ok($dbc->disconnect);
$sth = $dbc->prepare('SELECT * from gene limit 1');
$sth->execute;
ok($sth->rows);
$sth->finish;
#
# 18-19 make new connection with shared dbhandle,
# test copied/shared connection
# disconnect original,
# use copy with shared handle (that shouldn't have been disconnected)
#
my $dbc2 = Bio::EnsEMBL::DBSQL::DBConnection->new(-dbconn => $dbc);
$sth = $dbc2->prepare('SELECT * from gene limit 1');
$sth->execute;
ok($sth->rows);
$sth->finish;
$dbc->disconnect;
$sth = $dbc2->prepare('SELECT * from gene limit 1');
$sth->execute;
ok($sth->rows);
$sth->finish;
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment