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
......@@ -100,16 +100,18 @@ sub new {
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();
$$rcount++; # dereference and increment shared var
$self->ref_count($rcount);
$self->db_handle($dbconn->db_handle());
$self->driver($dbconn->driver());
$self->host($dbconn->host());
$self->port($dbconn->port());
$self->dbname($dbconn->dbname());
$self->username($dbconn->username());
$self->password($dbconn->password());
$self->port($dbconn->port());
$self->db_handle($dbconn->db_handle());
return Bio::EnsEMBL::Container->new($self);
}
......@@ -127,6 +129,7 @@ sub new {
$port = 3306;
}
=head1
my $dsn = "DBI:$driver:database=$db;host=$host;port=$port";
my $dbh;
......@@ -140,6 +143,7 @@ sub new {
my $ref_count = 1;
$self->ref_count(\$ref_count);
$self->db_handle($dbh);
=cut
$self->username( $user );
$self->host( $host );
......@@ -148,6 +152,8 @@ sub new {
$self->port($port);
$self->driver($driver);
$self->connect();
# be very sneaky and actually return a container object which is outside
# of the circular reference loops and will perform cleanup when all
# references to the container are gone.
......@@ -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
Arg [1] : (optional) string $arg
......@@ -420,12 +465,12 @@ sub db_handle {
if( defined $value) {
$self->{'_db_handle'} = $value;
}
return $self->{'_db_handle'};
}
else { $self->connect(); }
return $self->{'_db_handle'};
}
=head2 prepare
Arg [1] : string $string
......@@ -446,13 +491,13 @@ sub prepare {
if( ! $string ) {
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.");
}
#info("SQL(".$self->dbname."):$string");
return $self->{_db_handle}->prepare($string);
return $self->db_handle->prepare($string);
}
......@@ -612,23 +657,46 @@ sub DESTROY {
#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
# 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;
}
=head2 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;
......@@ -5,7 +5,7 @@ use warnings;
BEGIN { $| = 1;
use Test;
plan tests => 15;
plan tests => 19;
}
use MultiTestDB;
......@@ -91,6 +91,7 @@ ok(test_getter_setter($dbc, 'db_handle', $db->db_handle));
my $sth = $dbc->prepare('SELECT * from gene limit 1');
$sth->execute;
ok($sth->rows);
$sth->finish;
#
# 12 add_db_adaptor
......@@ -114,7 +115,31 @@ $dbc->remove_db_adaptor('core');
ok(!defined $dbc->get_db_adaptor('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