ensembl-hive  2.7.0
remove_mysqldb.pl
Go to the documentation of this file.
1 #!/usr/bin/env perl
2 # See the NOTICE file distributed with this work for additional information
3 # regarding copyright ownership.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 
17 
18 package Script;
19 
20 use strict;
21 use warnings;
22 
23 use Carp;
24 use DBI;
25 use Getopt::Long qw/:config no_ignore_case auto_version bundling_override/;
26 use Pod::Usage;
27 
28 sub args {
29  my ($self) = @_;
30  my $opts = { port => 3306, verbose => 0 };
31  GetOptions(
32  $opts, qw/
33  host|hostname|h=s
34  port|P=i
35  username|user|u=s
36  password|pass|p=s
37  databases|database|db=s@
38  verbose|v
39  log=s
40  help
41  man
42  /
43  ) or pod2usage(-verbose => 1, -exitval => 1);
44  pod2usage(-verbose => 1, -exitval => 0) if $opts->{help};
45  pod2usage(-verbose => 2, -exitval => 0) if $opts->{man};
46  $self->{opts} = $opts;
47  return;
48 }
49 
50 my $rcsid = '$Revision$';
51 our ($VERSION) = $rcsid =~ /(\d+\.\d+)/;
52 
53 sub run {
54  my ($class) = @_;
55  my $self = bless({}, $class);
56  $self->args();
57  $self->logging();
58  $self->process();
59 
60  if ($self->{oldfh}) {
61  select($self->{oldfh});
62  }
63 
64  return;
65 }
66 
67 sub defaults {
68  my ($self) = @_;
69  my $o = $self->opts();
70 
71  foreach my $required (qw/username databases host/) {
72  pod2usage(-msg => sprintf('No -%s specified', $required), -verbose => 2, -exitval => 1);
73  }
74  #Processing -opt 1 -opt 2,3 into opt => [1,2,3]
75  $self->_cmd_line_to_array('databases') if $o->{databases};
76 
77  $self->v(q{Working with %d database(s)}, scalar(@{$o->{databases}}));
78 
79  return;
80 }
81 
82 sub logging {
83  my ($self) = @_;
84  my $o = $self->opts();
85  if ($o->{log}) {
86  $o->{verbose} = 1;
87  my $file = $o->{log};
88  open my $fh, '>', $file or die "Cannot open log file '${file}' for writing: $!";
89  my $oldfh = select($fh);
90  $self->{oldfh} = $oldfh;
91  }
92  return;
93 }
94 
95 sub process {
96  my ($self) = @_;
97  my $databases = $self->opts()->{databases};
98  foreach my $db (@{$databases}) {
99  $self->v('Working with database %s', $db);
100  $self->dbh($db);
101  $self->delete_tables();
102  my $ddl = sprintf('drop database %s', $db);
103  $self->v(qq{\tRunning: '%s'}, $ddl);
104  $self->dbh()->do($ddl);
105  $self->clear_tables();
106  $self->clear_dbh();
107  }
108  return;
109 }
110 
111 sub delete_tables {
112  my ($self) = @_;
113  my @tables = keys %{ $self->tables() };
114  foreach my $table (@tables) {
115  $self->v(q{Processing '%s'}, $table);
116  my @sql;
117  if($self->is_view($table)) {
118  $self->v(q{'%s' is a view; just dropping}, $table);
119  push(@sql, 'drop view '.$table);
120  }
121  else {
122  $self->v(q{'%s' is being truncated and then dropped}, $table);
123  push(@sql,
124  'truncate table '.$table,
125  'drop table '.$table,
126  );
127  }
128 
129  foreach my $statement (@sql) {
130  $self->v(qq{\tRunning: '%s'}, $statement);
131  $self->dbh()->do($statement);
132  }
133  }
134  return;
135 }
136 
137 sub v {
138  my ($self, $msg, @args) = @_;
139  return unless $self->opts()->{verbose};
140  my $s_msg = sprintf($msg, @args);
141  my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
142  localtime(time());
143  print sprintf("[%02d-%02d-%04d %02d:%02d:%02d] %s\n",
144  $mday, $mon, $year + 1900,
145  $hour, $min, $sec, $s_msg);
146  return;
147 }
148 
149 sub dbh {
150  my ($self, $database) = @_;
151  if (!exists $self->{'dbh'}) {
152  my $o = $self->opts();
153  my %args = (host => $o->{host}, port => $o->{port});
154  $args{database} = $database if defined $database;
155 
156  my $dsn =
157  'DBI:mysql:' . join(q{;}, map { $_ . '=' . $args{$_} } keys %args);
158  $self->v('DBI connection URI %s', $dsn);
159  my $dbh =
160  DBI->connect($dsn, $o->{username}, $o->{password}, { RaiseError => 1 });
161 
162  $self->{dbh} = $dbh;
163  }
164  return $self->{'dbh'};
165 }
166 
167 sub clear_dbh {
168  my ($self) = @_;
169  if (exists $self->{dbh}) {
170  $self->{dbh}->disconnect();
171  delete $self->{dbh};
172  }
173  return;
174 }
175 
176 sub is_view {
177  my ($self, $table) = @_;
178  return ($self->tables()->{$table} eq 'VIEW') ? 1 : 0;
179 }
180 
181 sub tables {
182  my ($self) = @_;
183  if (!exists $self->{tables}) {
184  my $array =
185  $self->dbh()->selectcol_arrayref(
186 'select TABLE_NAME, TABLE_TYPE from information_schema.TABLES where TABLE_SCHEMA = DATABASE()',
187  { Columns => [ 1, 2 ] }
188  );
189  my %hits = @{$array};
190  $self->{tables} = \%hits;
191  }
192  return $self->{tables};
193 }
194 
195 sub clear_tables {
196  my ($self) = @_;
197  delete $self->{tables};
198  return;
199 }
200 
201 sub _cmd_line_to_array {
202  my ($self, $key) = @_;
203  my $array = $self->opts()->{$key};
204  $array = (ref($array) && ref($array) eq 'ARRAY') ? $array : [$array];
205  my $string = join(q{,}, @{$array});
206  my @new_array = split(/,/, $string);
207  $self->opts()->{$key} = \@new_array;
208  return;
209 }
210 
211 Script->run();
212 
213 1;
214 __END__
215 
216 =pod
217 
218 =head1 NAME
219 
220 remove_mysqldb.pl
221 
222 =head1 SYNOPSIS
223 
224  #Basic
225  ./remove_mysqldb.pl -username USER -password PASS -host HOST [-port PORT] -database DB [-verbose] [-help | -man]
226 
227  #Advanced
228  ./remove_mysqldb.pl -username USER -password PASS -host HOST -port PORT -database DB -database DBTWO -verbose
229 
230 =head1 DESCRIPTION
231 
232 A script which is used to drop a database in the most lock friendly way.
233 If you issue a C<drop database DB> command to MySQL it first aquires
234 a C<LOCK_open> which is a global mutex always applied for when you open
235 and close a file. Once the drop command has the lock no other process can
236 query the MySQL DB until the lock is relinquished once the DB has been dropped.
237 If your DB is very large or has a large number of tables this can take a long
238 time and has you performing a denile of service attack on your own DB server.
239 
240 =head1 OPTIONS
241 
242 =over 8
243 
244 =item B<--username | --user | -u>
245 
246 REQUIRED. Username of the connecting account. Must be able to perform
247 drop and truncate calls.
248 
249 =item B<--password | -pass | -p>
250 
251 Password of the connecting user.
252 
253 =item B<--host | --hostname | -h>
254 
255 REQUIRED. Host name of the database to connect to
256 
257 =item B<--port | -P>
258 
259 Optional integer of the database port. Defaults to 3306
260 
261 =item B<--databases | --database | --db>
262 
263 Allows database name specification and can be used more than once. Comma
264 separated values are supported.
265 
266 =item B<--verbose>
267 
268 Makes the program give more information about what is going on. Otherwise
269 the program is silent.
270 
271 =item B<--log>
272 
273 If given the script will write all logs to output. Switches on C<--verbose>
274 
275 =item B<--help>
276 
277 Help message
278 
279 =item B<--man>
280 
281 Man page
282 
283 =back
284 
285 =head1 REQUIREMENTS
286 
287 =over 8
288 
289 =item Perl 5.8+
290 
291 =item DBI
292 
293 =item DBD::mysql
294 
295 =back
296 
297 =cut
map
public map()
Script::run
public run()
Script::opts
public opts()
about
public about()
Script::v
public v()
Script
Definition: dump_mysql.pl:9
run
public run()
Script::args
public args()