Mercurial > repos > mahtabm > ensembl
comparison variant_effect_predictor/Bio/EnsEMBL/DBSQL/ProxyDBConnection.pm @ 0:1f6dce3d34e0
Uploaded
author | mahtabm |
---|---|
date | Thu, 11 Apr 2013 02:01:53 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1f6dce3d34e0 |
---|---|
1 =head1 LICENSE | |
2 | |
3 Copyright (c) 1999-2012 The European Bioinformatics Institute and | |
4 Genome Research Limited. All rights reserved. | |
5 | |
6 This software is distributed under a modified Apache license. | |
7 For license details, please see | |
8 | |
9 http://www.ensembl.org/info/about/code_licence.html | |
10 | |
11 =head1 CONTACT | |
12 | |
13 Please email comments or questions to the public Ensembl | |
14 developers list at <dev@ensembl.org>. | |
15 | |
16 Questions may also be sent to the Ensembl help desk at | |
17 <helpdesk@ensembl.org>. | |
18 | |
19 =cut | |
20 | |
21 =head1 NAME | |
22 | |
23 Bio::EnsEMBL::DBSQL::ProxyDBConnection - Database connection wrapper allowing | |
24 for one backing connection to be used for multiple DBs | |
25 | |
26 =head1 SYNOPSIS | |
27 | |
28 my $dbc = Bio::EnsEMBL::DBSQL::DBConnection->new(-HOST => 'host', -PORT => 3306, -USER => 'user'); | |
29 my $p_h_dbc = Bio::EnsEMBL::DBSQL::ProxyDBConnection->new(-DBC => $dbc, -DBNAME => 'human'); | |
30 my $p_m_dbc = Bio::EnsEMBL::DBSQL::ProxyDBConnection->new(-DBC => $dbc, -DBNAME => 'mouse'); | |
31 | |
32 # With a 10 minute timeout reconnection in milliseconds | |
33 my $p_h_rc_dbc = Bio::EnsEMBL::DBSQL::ProxyDBConnection->new(-DBC => $dbc, -DBNAME => 'human', -RECONNECT_INTERVAL => (10*60*1000)); | |
34 | |
35 =head1 DESCRIPTION | |
36 | |
37 This class is used to maintain one active connection to a database whilst it | |
38 appears to be working against multiple schemas. It does this by checking the | |
39 currently connected database before performing any query which could require | |
40 a database change such as prepare. | |
41 | |
42 This class is only intended for internal use so please do not use unless | |
43 you are aware of what it will do and what the consequences of its usage are. | |
44 | |
45 =head1 METHODS | |
46 | |
47 =cut | |
48 | |
49 package Bio::EnsEMBL::DBSQL::ProxyDBConnection; | |
50 | |
51 use strict; | |
52 use warnings; | |
53 | |
54 use base qw/Bio::EnsEMBL::Utils::Proxy/; | |
55 | |
56 use Bio::EnsEMBL::Utils::Argument qw/rearrange/; | |
57 use Bio::EnsEMBL::Utils::Exception qw/warning throw/; | |
58 use Bio::EnsEMBL::Utils::SqlHelper; | |
59 | |
60 use Time::HiRes qw/time/; | |
61 | |
62 sub new { | |
63 my ($class, @args) = @_; | |
64 my ($dbc, $dbname, $reconnect_interval) = rearrange([qw/DBC DBNAME RECONNECT_INTERVAL/], @args); | |
65 throw "No DBConnection -DBC given" unless $dbc; | |
66 throw "No database name -DBNAME given" unless $dbname; | |
67 my $self = $class->SUPER::new($dbc); | |
68 $self->dbname($dbname); | |
69 if($reconnect_interval) { | |
70 $self->reconnect_interval($reconnect_interval); | |
71 $self->_last_used(); | |
72 } | |
73 return $self; | |
74 } | |
75 | |
76 =head2 switch_database | |
77 | |
78 Description : Performs a switch of the backing DBConnection if the currently | |
79 connected database is not the same as the database this proxy | |
80 wants to connect to. It currently supports MySQL, Oracle and | |
81 Postges switches is untested with all bar MySQL. If it | |
82 cannot do a live DB/schema switch then it will disconnect | |
83 the connection and then wait for the next process to | |
84 connect therefore switching the DB. | |
85 Exceptions : None but will warn if you attempt to switch a DB with | |
86 active kids attached to the proxied database handle. | |
87 | |
88 =cut | |
89 | |
90 sub switch_database { | |
91 my ($self) = @_; | |
92 my $proxy = $self->__proxy(); | |
93 my $backing_dbname = $proxy->dbname(); | |
94 my $dbname = $self->dbname(); | |
95 | |
96 my $switch = 0; | |
97 if(defined $dbname) { | |
98 if(defined $backing_dbname) { | |
99 $switch = ($dbname ne $backing_dbname) ? 1 : 0; | |
100 } | |
101 else { | |
102 $switch = 1; | |
103 } | |
104 } | |
105 else { | |
106 $switch = 1 if defined $backing_dbname; | |
107 } | |
108 | |
109 if($switch) { | |
110 $proxy->dbname($dbname); | |
111 if($proxy->connected()) { | |
112 my $kids = $proxy->db_handle()->{Kids}; | |
113 my $driver = lc($proxy->driver()); | |
114 #Edit to add other DB switching strategies on a per driver basis | |
115 if($driver eq 'mysql') { | |
116 $proxy->do('use '.$dbname); | |
117 } | |
118 elsif($driver eq 'oracle') { | |
119 $proxy->do('ALTER SESSION SET CURRENT_SCHEMA = '.$dbname); | |
120 } | |
121 elsif($driver eq 'pg') { | |
122 $proxy->do('set search_path to '.$dbname); | |
123 } | |
124 else { | |
125 if($kids > 0) { | |
126 warning "Attempting a database switch from '$backing_dbname' to '$dbname' with $kids active handle(s). Check your logic or do not use a ProxyDBConnection"; | |
127 } | |
128 $proxy->disconnect_if_idle(); | |
129 } | |
130 } | |
131 } | |
132 | |
133 return $switch; | |
134 } | |
135 | |
136 =head2 check_reconnection | |
137 | |
138 Description : Looks to see if the last time we used the backing DBI | |
139 connection was greater than the reconnect_interval() | |
140 provided at construction or runtime. If enought time has | |
141 elapsed then a reconnection is attempted. We do not | |
142 attempt a reconnection if: | |
143 | |
144 - No reconnect_interval was set | |
145 - The connection was not active | |
146 | |
147 Exceptions : None apart from those raised from the reconnect() method | |
148 from DBConnection | |
149 =cut | |
150 | |
151 sub check_reconnection { | |
152 my ($self) = @_; | |
153 #Return early if we had no reconnection interval | |
154 return unless $self->{reconnect_interval}; | |
155 | |
156 my $proxy = $self->__proxy(); | |
157 | |
158 #Only attempt it if we were connected; otherwise we can just skip | |
159 if($proxy->connected()) { | |
160 if($self->_require_reconnect()) { | |
161 $proxy->reconnect(); | |
162 } | |
163 $self->_last_used(); | |
164 } | |
165 return; | |
166 } | |
167 | |
168 # Each time this is called we record the current time in seconds | |
169 # to be used by the _require_reconnect() method | |
170 sub _last_used { | |
171 my ($self) = @_; | |
172 $self->{_last_used} = int(time()*1000); | |
173 return; | |
174 } | |
175 | |
176 # Uses the _last_used() time and the current reconnect_interval() to decide | |
177 # if the connection has been unused for long enough that we should attempt | |
178 # a reconnect | |
179 sub _require_reconnect { | |
180 my ($self) = @_; | |
181 my $interval = $self->reconnect_interval(); | |
182 return unless $interval; | |
183 my $last_used = $self->{_last_used}; | |
184 my $time_elapsed = int(time()*1000) - $last_used; | |
185 return $time_elapsed > $interval ? 1 : 0; | |
186 } | |
187 | |
188 =head2 reconnect_interval | |
189 | |
190 Arg[1] : Integer reconnection interval in milliseconds | |
191 Description : Accessor for the reconnection interval expressed in milliseconds | |
192 Returntype : Int miliseconds for a reconnection interval | |
193 | |
194 =cut | |
195 | |
196 sub reconnect_interval { | |
197 my ($self, $reconnect_interval) = @_; | |
198 $self->{'reconnect_interval'} = $reconnect_interval if defined $reconnect_interval; | |
199 return $self->{'reconnect_interval'}; | |
200 } | |
201 | |
202 =head2 dbname | |
203 | |
204 Arg[1] : String DB name | |
205 Description : Accessor for the name of the database we should use whenever | |
206 a DBConnection request is made via this class | |
207 Returntype : String the name of the database which we should use | |
208 Exceptions : None | |
209 | |
210 =cut | |
211 | |
212 sub dbname { | |
213 my ($self, $dbname) = @_; | |
214 $self->{'dbname'} = $dbname if defined $dbname; | |
215 return $self->{'dbname'}; | |
216 } | |
217 | |
218 my %SWITCH_METHODS = map { $_ => 1 } qw/ | |
219 connect | |
220 db_handle | |
221 do | |
222 prepare | |
223 reconnect | |
224 work_with_db_handle | |
225 /; | |
226 | |
227 | |
228 # Manual override of the SqlHelper accessor to ensure it always gets the Proxy | |
229 sub sql_helper { | |
230 my ($self) = @_; | |
231 if(! exists $self->{_sql_helper}) { | |
232 my $helper = Bio::EnsEMBL::Utils::SqlHelper->new(-DB_CONNECTION => $self); | |
233 $self->{_sql_helper} = $helper; | |
234 } | |
235 return $self->{_sql_helper}; | |
236 } | |
237 | |
238 sub __resolver { | |
239 my ($self, $package, $method) = @_; | |
240 if($self->__proxy()->can($method)) { | |
241 if($SWITCH_METHODS{$method}) { | |
242 return sub { | |
243 my ($local_self, @args) = @_; | |
244 $local_self->check_reconnection(); | |
245 $local_self->switch_database(); | |
246 $local_self->_last_used(); | |
247 return $local_self->__proxy()->$method(@args); | |
248 }; | |
249 } | |
250 else { | |
251 return sub { | |
252 my ($local_self, @args) = @_; | |
253 return $local_self->__proxy()->$method(@args); | |
254 }; | |
255 } | |
256 } | |
257 return; | |
258 } | |
259 | |
260 1; |