3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1 |
#!/usr/bin/env perl
|
2 |
||
12
by Daniel Nichter
Remove duplicate copyright notices. Add POD and copyright for Aspersa tools. Fix checking for "pt-pmp" instead of "pmp", etc. |
3 |
# This program is part of Percona Toolkit: http://www.percona.com/software/
|
4 |
# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
|
|
5 |
# notices and disclaimers.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
6 |
|
7 |
use strict; |
|
8 |
use warnings FATAL => 'all'; |
|
350.1.15
by Daniel Nichter
Remove _d from Percona::Toolkit because I can't get it to export correctly. Put Percona::Toolkit in most tools. |
9 |
|
10 |
# This tool is "fat-packed": most of its dependent modules are embedded
|
|
11 |
# in this file. Setting %INC to this file for each module makes Perl aware
|
|
12 |
# of this so it will not try to load the module from @INC. See the tool's
|
|
13 |
# documentation for a full list of dependencies.
|
|
14 |
BEGIN { |
|
15 |
$INC{$_} = __FILE__ for map { (my $pkg = "$_.pm") =~ s!::!/!g; $pkg } (qw( |
|
16 |
Percona::Toolkit
|
|
17 |
DSNParser
|
|
18 |
OptionParser
|
|
19 |
Quoter
|
|
20 |
TableParser
|
|
21 |
Daemon
|
|
350.1.18
by fraserb at gmail
Fix several test failures by doing s/HTTP::Micro/HTTPMicro/ |
22 |
HTTPMicro
|
522
by Daniel Nichter
Rename Pingback.pm to VersionCheck.pm. |
23 |
VersionCheck
|
350.1.15
by Daniel Nichter
Remove _d from Percona::Toolkit because I can't get it to export correctly. Put Percona::Toolkit in most tools. |
24 |
)); |
25 |
}
|
|
26 |
||
27 |
# ###########################################################################
|
|
28 |
# Percona::Toolkit package
|
|
29 |
# This package is a copy without comments from the original. The original
|
|
30 |
# with comments and its test file can be found in the Bazaar repository at,
|
|
31 |
# lib/Percona/Toolkit.pm
|
|
32 |
# t/lib/Percona/Toolkit.t
|
|
33 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
34 |
# ###########################################################################
|
|
35 |
{
|
|
36 |
package Percona::Toolkit; |
|
580.1.3
by Brian Fraser
Build percona-toolkit-2.2.2 |
37 |
our $VERSION = '2.2.2'; |
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
38 |
|
350.1.15
by Daniel Nichter
Remove _d from Percona::Toolkit because I can't get it to export correctly. Put Percona::Toolkit in most tools. |
39 |
1; |
40 |
}
|
|
41 |
# ###########################################################################
|
|
42 |
# End Percona::Toolkit package
|
|
43 |
# ###########################################################################
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
44 |
|
45 |
# ###########################################################################
|
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
46 |
# DSNParser package
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
47 |
# This package is a copy without comments from the original. The original
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
48 |
# with comments and its test file can be found in the Bazaar repository at,
|
49 |
# lib/DSNParser.pm
|
|
50 |
# t/lib/DSNParser.t
|
|
51 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
52 |
# ###########################################################################
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
53 |
{
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
54 |
package DSNParser; |
55 |
||
56 |
use strict; |
|
57 |
use warnings FATAL => 'all'; |
|
58 |
use English qw(-no_match_vars); |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
59 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
60 |
|
61 |
use Data::Dumper; |
|
62 |
$Data::Dumper::Indent = 0; |
|
63 |
$Data::Dumper::Quotekeys = 0; |
|
64 |
||
262.1.4
by Daniel Nichter
Update DSNParser in all tools. |
65 |
my $dsn_sep = qr/(?<!\\),/; |
66 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
67 |
eval { |
68 |
require DBI; |
|
69 |
};
|
|
70 |
my $have_dbi = $EVAL_ERROR ? 0 : 1; |
|
71 |
||
72 |
sub new { |
|
73 |
my ( $class, %args ) = @_; |
|
74 |
foreach my $arg ( qw(opts) ) { |
|
75 |
die "I need a $arg argument" unless $args{$arg}; |
|
76 |
}
|
|
77 |
my $self = { |
|
78 |
opts => {} # h, P, u, etc. Should come from DSN OPTIONS section in POD. |
|
79 |
};
|
|
80 |
foreach my $opt ( @{$args{opts}} ) { |
|
81 |
if ( !$opt->{key} || !$opt->{desc} ) { |
|
82 |
die "Invalid DSN option: ", Dumper($opt); |
|
83 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
84 |
PTDEBUG && _d('DSN option:', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
85 |
join(', ', |
86 |
map { "$_=" . (defined $opt->{$_} ? ($opt->{$_} || '') : 'undef') } |
|
87 |
keys %$opt |
|
88 |
)
|
|
89 |
);
|
|
90 |
$self->{opts}->{$opt->{key}} = { |
|
91 |
dsn => $opt->{dsn}, |
|
92 |
desc => $opt->{desc}, |
|
93 |
copy => $opt->{copy} || 0, |
|
94 |
};
|
|
95 |
}
|
|
96 |
return bless $self, $class; |
|
97 |
}
|
|
98 |
||
99 |
sub prop { |
|
100 |
my ( $self, $prop, $value ) = @_; |
|
101 |
if ( @_ > 2 ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
102 |
PTDEBUG && _d('Setting', $prop, 'property'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
103 |
$self->{$prop} = $value; |
104 |
}
|
|
105 |
return $self->{$prop}; |
|
106 |
}
|
|
107 |
||
108 |
sub parse { |
|
109 |
my ( $self, $dsn, $prev, $defaults ) = @_; |
|
110 |
if ( !$dsn ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
111 |
PTDEBUG && _d('No DSN to parse'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
112 |
return; |
113 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
114 |
PTDEBUG && _d('Parsing', $dsn); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
115 |
$prev ||= {}; |
116 |
$defaults ||= {}; |
|
117 |
my %given_props; |
|
118 |
my %final_props; |
|
119 |
my $opts = $self->{opts}; |
|
120 |
||
262.1.4
by Daniel Nichter
Update DSNParser in all tools. |
121 |
foreach my $dsn_part ( split($dsn_sep, $dsn) ) { |
122 |
$dsn_part =~ s/\\,/,/g; |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
123 |
if ( my ($prop_key, $prop_val) = $dsn_part =~ m/^(.)=(.*)$/ ) { |
124 |
$given_props{$prop_key} = $prop_val; |
|
125 |
}
|
|
126 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
127 |
PTDEBUG && _d('Interpreting', $dsn_part, 'as h=', $dsn_part); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
128 |
$given_props{h} = $dsn_part; |
129 |
}
|
|
130 |
}
|
|
131 |
||
132 |
foreach my $key ( keys %$opts ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
133 |
PTDEBUG && _d('Finding value for', $key); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
134 |
$final_props{$key} = $given_props{$key}; |
135 |
if ( !defined $final_props{$key} |
|
136 |
&& defined $prev->{$key} && $opts->{$key}->{copy} ) |
|
137 |
{
|
|
138 |
$final_props{$key} = $prev->{$key}; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
139 |
PTDEBUG && _d('Copying value for', $key, 'from previous DSN'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
140 |
}
|
141 |
if ( !defined $final_props{$key} ) { |
|
142 |
$final_props{$key} = $defaults->{$key}; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
143 |
PTDEBUG && _d('Copying value for', $key, 'from defaults'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
144 |
}
|
145 |
}
|
|
146 |
||
147 |
foreach my $key ( keys %given_props ) { |
|
148 |
die "Unknown DSN option '$key' in '$dsn'. For more details, " |
|
149 |
. "please use the --help option, or try 'perldoc $PROGRAM_NAME' " |
|
150 |
. "for complete documentation." |
|
151 |
unless exists $opts->{$key}; |
|
152 |
}
|
|
153 |
if ( (my $required = $self->prop('required')) ) { |
|
154 |
foreach my $key ( keys %$required ) { |
|
155 |
die "Missing required DSN option '$key' in '$dsn'. For more details, " |
|
156 |
. "please use the --help option, or try 'perldoc $PROGRAM_NAME' " |
|
157 |
. "for complete documentation." |
|
158 |
unless $final_props{$key}; |
|
159 |
}
|
|
160 |
}
|
|
161 |
||
162 |
return \%final_props; |
|
163 |
}
|
|
164 |
||
165 |
sub parse_options { |
|
166 |
my ( $self, $o ) = @_; |
|
167 |
die 'I need an OptionParser object' unless ref $o eq 'OptionParser'; |
|
168 |
my $dsn_string |
|
169 |
= join(',', |
|
170 |
map { "$_=".$o->get($_); } |
|
171 |
grep { $o->has($_) && $o->get($_) } |
|
172 |
keys %{$self->{opts}} |
|
173 |
);
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
174 |
PTDEBUG && _d('DSN string made from options:', $dsn_string); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
175 |
return $self->parse($dsn_string); |
176 |
}
|
|
177 |
||
178 |
sub as_string { |
|
179 |
my ( $self, $dsn, $props ) = @_; |
|
180 |
return $dsn unless ref $dsn; |
|
262.1.4
by Daniel Nichter
Update DSNParser in all tools. |
181 |
my @keys = $props ? @$props : sort keys %$dsn; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
182 |
return join(',', |
262.1.4
by Daniel Nichter
Update DSNParser in all tools. |
183 |
map { "$_=" . ($_ eq 'p' ? '...' : $dsn->{$_}) } |
184 |
grep { |
|
185 |
exists $self->{opts}->{$_} |
|
186 |
&& exists $dsn->{$_} |
|
187 |
&& defined $dsn->{$_} |
|
188 |
} @keys); |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
189 |
}
|
190 |
||
191 |
sub usage { |
|
192 |
my ( $self ) = @_; |
|
193 |
my $usage |
|
194 |
= "DSN syntax is key=value[,key=value...] Allowable DSN keys:\n\n" |
|
195 |
. " KEY COPY MEANING\n" |
|
196 |
. " === ==== =============================================\n"; |
|
197 |
my %opts = %{$self->{opts}}; |
|
198 |
foreach my $key ( sort keys %opts ) { |
|
199 |
$usage .= " $key " |
|
200 |
. ($opts{$key}->{copy} ? 'yes ' : 'no ') |
|
201 |
. ($opts{$key}->{desc} || '[No description]') |
|
202 |
. "\n"; |
|
203 |
}
|
|
204 |
$usage .= "\n If the DSN is a bareword, the word is treated as the 'h' key.\n"; |
|
205 |
return $usage; |
|
206 |
}
|
|
207 |
||
208 |
sub get_cxn_params { |
|
209 |
my ( $self, $info ) = @_; |
|
210 |
my $dsn; |
|
211 |
my %opts = %{$self->{opts}}; |
|
212 |
my $driver = $self->prop('dbidriver') || ''; |
|
213 |
if ( $driver eq 'Pg' ) { |
|
214 |
$dsn = 'DBI:Pg:dbname=' . ( $info->{D} || '' ) . ';' |
|
215 |
. join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } |
|
216 |
grep { defined $info->{$_} } |
|
217 |
qw(h P)); |
|
218 |
}
|
|
219 |
else { |
|
220 |
$dsn = 'DBI:mysql:' . ( $info->{D} || '' ) . ';' |
|
221 |
. join(';', map { "$opts{$_}->{dsn}=$info->{$_}" } |
|
222 |
grep { defined $info->{$_} } |
|
223 |
qw(F h P S A)) |
|
440
by Brian Fraser
Updated modules in all tools |
224 |
. ';mysql_read_default_group=client' |
225 |
. ($info->{L} ? ';mysql_local_infile=1' : ''); |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
226 |
}
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
227 |
PTDEBUG && _d($dsn); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
228 |
return ($dsn, $info->{u}, $info->{p}); |
229 |
}
|
|
230 |
||
231 |
sub fill_in_dsn { |
|
232 |
my ( $self, $dbh, $dsn ) = @_; |
|
233 |
my $vars = $dbh->selectall_hashref('SHOW VARIABLES', 'Variable_name'); |
|
234 |
my ($user, $db) = $dbh->selectrow_array('SELECT USER(), DATABASE()'); |
|
235 |
$user =~ s/@.*//; |
|
236 |
$dsn->{h} ||= $vars->{hostname}->{Value}; |
|
237 |
$dsn->{S} ||= $vars->{'socket'}->{Value}; |
|
238 |
$dsn->{P} ||= $vars->{port}->{Value}; |
|
239 |
$dsn->{u} ||= $user; |
|
240 |
$dsn->{D} ||= $db; |
|
241 |
}
|
|
242 |
||
243 |
sub get_dbh { |
|
244 |
my ( $self, $cxn_string, $user, $pass, $opts ) = @_; |
|
245 |
$opts ||= {}; |
|
246 |
my $defaults = { |
|
247 |
AutoCommit => 0, |
|
248 |
RaiseError => 1, |
|
249 |
PrintError => 0, |
|
250 |
ShowErrorStatement => 1, |
|
251 |
mysql_enable_utf8 => ($cxn_string =~ m/charset=utf8/i ? 1 : 0), |
|
252 |
};
|
|
253 |
@{$defaults}{ keys %$opts } = values %$opts; |
|
440
by Brian Fraser
Updated modules in all tools |
254 |
if (delete $defaults->{L}) { # L for LOAD DATA LOCAL INFILE, our own extension |
255 |
$defaults->{mysql_local_infile} = 1; |
|
256 |
}
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
257 |
|
258 |
if ( $opts->{mysql_use_result} ) { |
|
259 |
$defaults->{mysql_use_result} = 1; |
|
260 |
}
|
|
261 |
||
262 |
if ( !$have_dbi ) { |
|
263 |
die "Cannot connect to MySQL because the Perl DBI module is not " |
|
264 |
. "installed or not found. Run 'perl -MDBI' to see the directories " |
|
265 |
. "that Perl searches for DBI. If DBI is not installed, try:\n" |
|
266 |
. " Debian/Ubuntu apt-get install libdbi-perl\n" |
|
267 |
. " RHEL/CentOS yum install perl-DBI\n" |
|
344.1.2
by Brian Fraser
Updated modules for all tools |
268 |
. " OpenSolaris pkg install pkg:/SUNWpmdbi\n"; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
269 |
|
270 |
}
|
|
271 |
||
272 |
my $dbh; |
|
273 |
my $tries = 2; |
|
274 |
while ( !$dbh && $tries-- ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
275 |
PTDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, |
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
276 |
join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults )); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
277 |
|
290.1.2
by fraserb at gmail
Update all the modules |
278 |
$dbh = eval { DBI->connect($cxn_string, $user, $pass, $defaults) }; |
279 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
280 |
if ( !$dbh && $EVAL_ERROR ) { |
290.1.2
by fraserb at gmail
Update all the modules |
281 |
if ( $EVAL_ERROR =~ m/locate DBD\/mysql/i ) { |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
282 |
die "Cannot connect to MySQL because the Perl DBD::mysql module is " |
283 |
. "not installed or not found. Run 'perl -MDBD::mysql' to see " |
|
284 |
. "the directories that Perl searches for DBD::mysql. If " |
|
285 |
. "DBD::mysql is not installed, try:\n" |
|
286 |
. " Debian/Ubuntu apt-get install libdbd-mysql-perl\n" |
|
287 |
. " RHEL/CentOS yum install perl-DBD-MySQL\n" |
|
288 |
. " OpenSolaris pgk install pkg:/SUNWapu13dbd-mysql\n"; |
|
289 |
}
|
|
290.1.2
by fraserb at gmail
Update all the modules |
290 |
elsif ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) { |
291 |
PTDEBUG && _d('Going to try again without utf8 support'); |
|
292 |
delete $defaults->{mysql_enable_utf8}; |
|
293 |
}
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
294 |
if ( !$tries ) { |
295 |
die $EVAL_ERROR; |
|
296 |
}
|
|
297 |
}
|
|
298 |
}
|
|
299 |
||
290.1.2
by fraserb at gmail
Update all the modules |
300 |
if ( $cxn_string =~ m/mysql/i ) { |
301 |
my $sql; |
|
302 |
||
303 |
$sql = 'SELECT @@SQL_MODE'; |
|
304 |
PTDEBUG && _d($dbh, $sql); |
|
305 |
my ($sql_mode) = eval { $dbh->selectrow_array($sql) }; |
|
306 |
if ( $EVAL_ERROR ) { |
|
344.1.2
by Brian Fraser
Updated modules for all tools |
307 |
die "Error getting the current SQL_MODE: $EVAL_ERROR"; |
290.1.2
by fraserb at gmail
Update all the modules |
308 |
}
|
309 |
||
344.1.2
by Brian Fraser
Updated modules for all tools |
310 |
if ( my ($charset) = $cxn_string =~ m/charset=([\w]+)/ ) { |
311 |
$sql = qq{/*!40101 SET NAMES "$charset"*/}; |
|
531.2.2
by Daniel Nichter
Update OptionParser and DSNParser in all tools. |
312 |
PTDEBUG && _d($dbh, $sql); |
290.1.2
by fraserb at gmail
Update all the modules |
313 |
eval { $dbh->do($sql) }; |
314 |
if ( $EVAL_ERROR ) { |
|
344.1.2
by Brian Fraser
Updated modules for all tools |
315 |
die "Error setting NAMES to $charset: $EVAL_ERROR"; |
290.1.2
by fraserb at gmail
Update all the modules |
316 |
}
|
317 |
PTDEBUG && _d('Enabling charset for STDOUT'); |
|
318 |
if ( $charset eq 'utf8' ) { |
|
319 |
binmode(STDOUT, ':utf8') |
|
320 |
or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR"; |
|
321 |
}
|
|
322 |
else { |
|
323 |
binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR"; |
|
324 |
}
|
|
325 |
}
|
|
326 |
||
531.2.2
by Daniel Nichter
Update OptionParser and DSNParser in all tools. |
327 |
if ( my $vars = $self->prop('set-vars') ) { |
328 |
$self->set_vars($dbh, $vars); |
|
290.1.2
by fraserb at gmail
Update all the modules |
329 |
}
|
472.1.2
by Brian Fraser
Update modules for all tools using DSNParser |
330 |
|
331 |
$sql = 'SET @@SQL_QUOTE_SHOW_CREATE = 1' |
|
332 |
. '/*!40101, @@SQL_MODE=\'NO_AUTO_VALUE_ON_ZERO' |
|
333 |
. ($sql_mode ? ",$sql_mode" : '') |
|
334 |
. '\'*/'; |
|
335 |
PTDEBUG && _d($dbh, $sql); |
|
336 |
eval { $dbh->do($sql) }; |
|
337 |
if ( $EVAL_ERROR ) { |
|
338 |
die "Error setting SQL_QUOTE_SHOW_CREATE, SQL_MODE" |
|
339 |
. ($sql_mode ? " and $sql_mode" : '') |
|
340 |
. ": $EVAL_ERROR"; |
|
341 |
}
|
|
290.1.2
by fraserb at gmail
Update all the modules |
342 |
}
|
343 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
344 |
PTDEBUG && _d('DBH info: ', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
345 |
$dbh, |
346 |
Dumper($dbh->selectrow_hashref( |
|
347 |
'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')), |
|
348 |
'Connection info:', $dbh->{mysql_hostinfo}, |
|
349 |
'Character set info:', Dumper($dbh->selectall_arrayref( |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
350 |
"SHOW VARIABLES LIKE 'character_set%'", { Slice => {}})), |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
351 |
'$DBD::mysql::VERSION:', $DBD::mysql::VERSION, |
352 |
'$DBI::VERSION:', $DBI::VERSION, |
|
353 |
);
|
|
354 |
||
355 |
return $dbh; |
|
356 |
}
|
|
357 |
||
358 |
sub get_hostname { |
|
359 |
my ( $self, $dbh ) = @_; |
|
360 |
if ( my ($host) = ($dbh->{mysql_hostinfo} || '') =~ m/^(\w+) via/ ) { |
|
361 |
return $host; |
|
362 |
}
|
|
363 |
my ( $hostname, $one ) = $dbh->selectrow_array( |
|
364 |
'SELECT /*!50038 @@hostname, */ 1'); |
|
365 |
return $hostname; |
|
366 |
}
|
|
367 |
||
368 |
sub disconnect { |
|
369 |
my ( $self, $dbh ) = @_; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
370 |
PTDEBUG && $self->print_active_handles($dbh); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
371 |
$dbh->disconnect; |
372 |
}
|
|
373 |
||
374 |
sub print_active_handles { |
|
375 |
my ( $self, $thing, $level ) = @_; |
|
376 |
$level ||= 0; |
|
377 |
printf("# Active %sh: %s %s %s\n", ($thing->{Type} || 'undef'), "\t" x $level, |
|
378 |
$thing, (($thing->{Type} || '') eq 'st' ? $thing->{Statement} || '' : '')) |
|
379 |
or die "Cannot print: $OS_ERROR"; |
|
380 |
foreach my $handle ( grep {defined} @{ $thing->{ChildHandles} } ) { |
|
381 |
$self->print_active_handles( $handle, $level + 1 ); |
|
382 |
}
|
|
383 |
}
|
|
384 |
||
385 |
sub copy { |
|
386 |
my ( $self, $dsn_1, $dsn_2, %args ) = @_; |
|
387 |
die 'I need a dsn_1 argument' unless $dsn_1; |
|
388 |
die 'I need a dsn_2 argument' unless $dsn_2; |
|
389 |
my %new_dsn = map { |
|
390 |
my $key = $_; |
|
391 |
my $val; |
|
392 |
if ( $args{overwrite} ) { |
|
393 |
$val = defined $dsn_1->{$key} ? $dsn_1->{$key} : $dsn_2->{$key}; |
|
394 |
}
|
|
395 |
else { |
|
396 |
$val = defined $dsn_2->{$key} ? $dsn_2->{$key} : $dsn_1->{$key}; |
|
397 |
}
|
|
398 |
$key => $val; |
|
399 |
} keys %{$self->{opts}}; |
|
400 |
return \%new_dsn; |
|
401 |
}
|
|
402 |
||
531.2.2
by Daniel Nichter
Update OptionParser and DSNParser in all tools. |
403 |
sub set_vars { |
404 |
my ($self, $dbh, $vars) = @_; |
|
405 |
||
531.1.12
by Daniel Nichter
Update DSNParser in all tools. |
406 |
return unless $vars; |
407 |
||
531.2.2
by Daniel Nichter
Update OptionParser and DSNParser in all tools. |
408 |
foreach my $var ( sort keys %$vars ) { |
409 |
my $val = $vars->{$var}->{val}; |
|
410 |
||
411 |
(my $quoted_var = $var) =~ s/_/\\_/; |
|
412 |
my ($var_exists, $current_val); |
|
413 |
eval { |
|
414 |
($var_exists, $current_val) = $dbh->selectrow_array( |
|
415 |
"SHOW VARIABLES LIKE '$quoted_var'"); |
|
416 |
};
|
|
417 |
my $e = $EVAL_ERROR; |
|
418 |
if ( $e ) { |
|
419 |
PTDEBUG && _d($e); |
|
420 |
}
|
|
421 |
||
422 |
if ( $vars->{$var}->{default} && !$var_exists ) { |
|
423 |
PTDEBUG && _d('Not setting default var', $var, |
|
424 |
'because it does not exist'); |
|
425 |
next; |
|
426 |
}
|
|
427 |
||
428 |
if ( $current_val && $current_val eq $val ) { |
|
429 |
PTDEBUG && _d('Not setting var', $var, 'because its value', |
|
430 |
'is already', $val); |
|
431 |
next; |
|
432 |
}
|
|
433 |
||
434 |
my $sql = "SET SESSION $var=$val"; |
|
435 |
PTDEBUG && _d($dbh, $sql); |
|
436 |
eval { $dbh->do($sql) }; |
|
437 |
if ( my $set_error = $EVAL_ERROR ) { |
|
438 |
chomp($set_error); |
|
439 |
$set_error =~ s/ at \S+ line \d+//; |
|
440 |
my $msg = "Error setting $var: $set_error"; |
|
441 |
if ( $current_val ) { |
|
442 |
$msg .= " The current value for $var is $current_val. " |
|
443 |
. "If the variable is read only (not dynamic), specify " |
|
444 |
. "--set-vars $var=$current_val to avoid this warning, " |
|
445 |
. "else manually set the variable and restart MySQL."; |
|
446 |
}
|
|
447 |
warn $msg . "\n\n"; |
|
448 |
}
|
|
449 |
}
|
|
450 |
||
451 |
return; |
|
452 |
}
|
|
453 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
454 |
sub _d { |
455 |
my ($package, undef, $line) = caller 0; |
|
456 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
457 |
map { defined $_ ? $_ : 'undef' } |
|
458 |
@_; |
|
459 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
460 |
}
|
|
461 |
||
462 |
1; |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
463 |
}
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
464 |
# ###########################################################################
|
465 |
# End DSNParser package
|
|
466 |
# ###########################################################################
|
|
467 |
||
468 |
# ###########################################################################
|
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
469 |
# OptionParser package
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
470 |
# This package is a copy without comments from the original. The original
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
471 |
# with comments and its test file can be found in the Bazaar repository at,
|
472 |
# lib/OptionParser.pm
|
|
473 |
# t/lib/OptionParser.t
|
|
474 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
475 |
# ###########################################################################
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
476 |
{
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
477 |
package OptionParser; |
478 |
||
479 |
use strict; |
|
480 |
use warnings FATAL => 'all'; |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
481 |
use English qw(-no_match_vars); |
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
482 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
483 |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
484 |
use List::Util qw(max); |
485 |
use Getopt::Long; |
|
531.2.2
by Daniel Nichter
Update OptionParser and DSNParser in all tools. |
486 |
use Data::Dumper; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
487 |
|
488 |
my $POD_link_re = '[LC]<"?([^">]+)"?>'; |
|
489 |
||
490 |
sub new { |
|
491 |
my ( $class, %args ) = @_; |
|
492 |
my @required_args = qw(); |
|
493 |
foreach my $arg ( @required_args ) { |
|
494 |
die "I need a $arg argument" unless $args{$arg}; |
|
495 |
}
|
|
496 |
||
497 |
my ($program_name) = $PROGRAM_NAME =~ m/([.A-Za-z-]+)$/; |
|
498 |
$program_name ||= $PROGRAM_NAME; |
|
499 |
my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; |
|
500 |
||
501 |
my %attributes = ( |
|
502 |
'type' => 1, |
|
503 |
'short form' => 1, |
|
504 |
'group' => 1, |
|
505 |
'default' => 1, |
|
506 |
'cumulative' => 1, |
|
507 |
'negatable' => 1, |
|
508 |
);
|
|
509 |
||
510 |
my $self = { |
|
511 |
head1 => 'OPTIONS', # These args are used internally |
|
512 |
skip_rules => 0, # to instantiate another Option- |
|
513 |
item => '--(.*)', # Parser obj that parses the |
|
514 |
attributes => \%attributes, # DSN OPTIONS section. Tools |
|
515 |
parse_attributes => \&_parse_attribs, # don't tinker with these args. |
|
516 |
||
517 |
%args, |
|
518 |
||
519 |
strict => 1, # disabled by a special rule |
|
520 |
program_name => $program_name, |
|
521 |
opts => {}, |
|
522 |
got_opts => 0, |
|
523 |
short_opts => {}, |
|
524 |
defaults => {}, |
|
525 |
groups => {}, |
|
526 |
allowed_groups => {}, |
|
527 |
errors => [], |
|
528 |
rules => [], # desc of rules for --help |
|
529 |
mutex => [], # rule: opts are mutually exclusive |
|
530 |
atleast1 => [], # rule: at least one opt is required |
|
531 |
disables => {}, # rule: opt disables other opts |
|
532 |
defaults_to => {}, # rule: opt defaults to value of other opt |
|
533 |
DSNParser => undef, |
|
534 |
default_files => [ |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
535 |
"/etc/percona-toolkit/percona-toolkit.conf", |
536 |
"/etc/percona-toolkit/$program_name.conf", |
|
537 |
"$home/.percona-toolkit.conf", |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
538 |
"$home/.$program_name.conf", |
539 |
],
|
|
540 |
types => { |
|
541 |
string => 's', # standard Getopt type |
|
542 |
int => 'i', # standard Getopt type |
|
543 |
float => 'f', # standard Getopt type |
|
544 |
Hash => 'H', # hash, formed from a comma-separated list |
|
545 |
hash => 'h', # hash as above, but only if a value is given |
|
546 |
Array => 'A', # array, similar to Hash |
|
547 |
array => 'a', # array, similar to hash |
|
548 |
DSN => 'd', # DSN |
|
549 |
size => 'z', # size with kMG suffix (powers of 2^10) |
|
550 |
time => 'm', # time, with an optional suffix of s/h/m/d |
|
551 |
},
|
|
552 |
};
|
|
553 |
||
554 |
return bless $self, $class; |
|
555 |
}
|
|
556 |
||
557 |
sub get_specs { |
|
558 |
my ( $self, $file ) = @_; |
|
559 |
$file ||= $self->{file} || __FILE__; |
|
560 |
my @specs = $self->_pod_to_specs($file); |
|
561 |
$self->_parse_specs(@specs); |
|
562 |
||
563 |
open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; |
|
564 |
my $contents = do { local $/ = undef; <$fh> }; |
|
565 |
close $fh; |
|
566 |
if ( $contents =~ m/^=head1 DSN OPTIONS/m ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
567 |
PTDEBUG && _d('Parsing DSN OPTIONS'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
568 |
my $dsn_attribs = { |
569 |
dsn => 1, |
|
570 |
copy => 1, |
|
571 |
};
|
|
572 |
my $parse_dsn_attribs = sub { |
|
573 |
my ( $self, $option, $attribs ) = @_; |
|
574 |
map { |
|
575 |
my $val = $attribs->{$_}; |
|
576 |
if ( $val ) { |
|
577 |
$val = $val eq 'yes' ? 1 |
|
578 |
: $val eq 'no' ? 0 |
|
579 |
: $val; |
|
580 |
$attribs->{$_} = $val; |
|
581 |
}
|
|
582 |
} keys %$attribs; |
|
583 |
return { |
|
584 |
key => $option, |
|
585 |
%$attribs, |
|
586 |
};
|
|
587 |
};
|
|
588 |
my $dsn_o = new OptionParser( |
|
589 |
description => 'DSN OPTIONS', |
|
590 |
head1 => 'DSN OPTIONS', |
|
591 |
dsn => 0, # XXX don't infinitely recurse! |
|
592 |
item => '\* (.)', # key opts are a single character |
|
593 |
skip_rules => 1, # no rules before opts |
|
594 |
attributes => $dsn_attribs, |
|
595 |
parse_attributes => $parse_dsn_attribs, |
|
596 |
);
|
|
597 |
my @dsn_opts = map { |
|
598 |
my $opts = { |
|
599 |
key => $_->{spec}->{key}, |
|
600 |
dsn => $_->{spec}->{dsn}, |
|
601 |
copy => $_->{spec}->{copy}, |
|
602 |
desc => $_->{desc}, |
|
603 |
};
|
|
604 |
$opts; |
|
605 |
} $dsn_o->_pod_to_specs($file); |
|
606 |
$self->{DSNParser} = DSNParser->new(opts => \@dsn_opts); |
|
607 |
}
|
|
608 |
||
105
by Daniel
Update OptionParser in all tools. |
609 |
if ( $contents =~ m/^=head1 VERSION\n\n^(.+)$/m ) { |
76.1.2
by Daniel Nichter
Update OptionParser in all tools. |
610 |
$self->{version} = $1; |
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
611 |
PTDEBUG && _d($self->{version}); |
76.1.2
by Daniel Nichter
Update OptionParser in all tools. |
612 |
}
|
613 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
614 |
return; |
615 |
}
|
|
616 |
||
617 |
sub DSNParser { |
|
618 |
my ( $self ) = @_; |
|
619 |
return $self->{DSNParser}; |
|
620 |
};
|
|
621 |
||
622 |
sub get_defaults_files { |
|
623 |
my ( $self ) = @_; |
|
624 |
return @{$self->{default_files}}; |
|
625 |
}
|
|
626 |
||
627 |
sub _pod_to_specs { |
|
628 |
my ( $self, $file ) = @_; |
|
629 |
$file ||= $self->{file} || __FILE__; |
|
630 |
open my $fh, '<', $file or die "Cannot open $file: $OS_ERROR"; |
|
631 |
||
632 |
my @specs = (); |
|
633 |
my @rules = (); |
|
634 |
my $para; |
|
635 |
||
636 |
local $INPUT_RECORD_SEPARATOR = ''; |
|
637 |
while ( $para = <$fh> ) { |
|
638 |
next unless $para =~ m/^=head1 $self->{head1}/; |
|
639 |
last; |
|
640 |
}
|
|
641 |
||
642 |
while ( $para = <$fh> ) { |
|
643 |
last if $para =~ m/^=over/; |
|
644 |
next if $self->{skip_rules}; |
|
645 |
chomp $para; |
|
646 |
$para =~ s/\s+/ /g; |
|
647 |
$para =~ s/$POD_link_re/$1/go; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
648 |
PTDEBUG && _d('Option rule:', $para); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
649 |
push @rules, $para; |
650 |
}
|
|
651 |
||
652 |
die "POD has no $self->{head1} section" unless $para; |
|
653 |
||
654 |
do { |
|
655 |
if ( my ($option) = $para =~ m/^=item $self->{item}/ ) { |
|
656 |
chomp $para; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
657 |
PTDEBUG && _d($para); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
658 |
my %attribs; |
659 |
||
660 |
$para = <$fh>; # read next paragraph, possibly attributes |
|
661 |
||
662 |
if ( $para =~ m/: / ) { # attributes |
|
663 |
$para =~ s/\s+\Z//g; |
|
664 |
%attribs = map { |
|
665 |
my ( $attrib, $val) = split(/: /, $_); |
|
666 |
die "Unrecognized attribute for --$option: $attrib" |
|
667 |
unless $self->{attributes}->{$attrib}; |
|
668 |
($attrib, $val); |
|
669 |
} split(/; /, $para); |
|
670 |
if ( $attribs{'short form'} ) { |
|
671 |
$attribs{'short form'} =~ s/-//; |
|
672 |
}
|
|
673 |
$para = <$fh>; # read next paragraph, probably short help desc |
|
674 |
}
|
|
675 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
676 |
PTDEBUG && _d('Option has no attributes'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
677 |
}
|
678 |
||
679 |
$para =~ s/\s+\Z//g; |
|
680 |
$para =~ s/\s+/ /g; |
|
681 |
$para =~ s/$POD_link_re/$1/go; |
|
682 |
||
683 |
$para =~ s/\.(?:\n.*| [A-Z].*|\Z)//s; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
684 |
PTDEBUG && _d('Short help:', $para); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
685 |
|
686 |
die "No description after option spec $option" if $para =~ m/^=item/; |
|
687 |
||
688 |
if ( my ($base_option) = $option =~ m/^\[no\](.*)/ ) { |
|
689 |
$option = $base_option; |
|
690 |
$attribs{'negatable'} = 1; |
|
691 |
}
|
|
692 |
||
693 |
push @specs, { |
|
694 |
spec => $self->{parse_attributes}->($self, $option, \%attribs), |
|
695 |
desc => $para |
|
696 |
. (defined $attribs{default} ? " (default $attribs{default})" : ''), |
|
697 |
group => ($attribs{'group'} ? $attribs{'group'} : 'default'), |
|
698 |
};
|
|
699 |
}
|
|
700 |
while ( $para = <$fh> ) { |
|
701 |
last unless $para; |
|
702 |
if ( $para =~ m/^=head1/ ) { |
|
703 |
$para = undef; # Can't 'last' out of a do {} block. |
|
704 |
last; |
|
705 |
}
|
|
706 |
last if $para =~ m/^=item /; |
|
707 |
}
|
|
708 |
} while ( $para ); |
|
709 |
||
710 |
die "No valid specs in $self->{head1}" unless @specs; |
|
711 |
||
712 |
close $fh; |
|
713 |
return @specs, @rules; |
|
714 |
}
|
|
715 |
||
716 |
sub _parse_specs { |
|
717 |
my ( $self, @specs ) = @_; |
|
718 |
my %disables; # special rule that requires deferred checking |
|
719 |
||
720 |
foreach my $opt ( @specs ) { |
|
721 |
if ( ref $opt ) { # It's an option spec, not a rule. |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
722 |
PTDEBUG && _d('Parsing opt spec:', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
723 |
map { ($_, '=>', $opt->{$_}) } keys %$opt); |
724 |
||
725 |
my ( $long, $short ) = $opt->{spec} =~ m/^([\w-]+)(?:\|([^!+=]*))?/; |
|
726 |
if ( !$long ) { |
|
727 |
die "Cannot parse long option from spec $opt->{spec}"; |
|
728 |
}
|
|
729 |
$opt->{long} = $long; |
|
730 |
||
731 |
die "Duplicate long option --$long" if exists $self->{opts}->{$long}; |
|
732 |
$self->{opts}->{$long} = $opt; |
|
733 |
||
734 |
if ( length $long == 1 ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
735 |
PTDEBUG && _d('Long opt', $long, 'looks like short opt'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
736 |
$self->{short_opts}->{$long} = $long; |
737 |
}
|
|
738 |
||
739 |
if ( $short ) { |
|
740 |
die "Duplicate short option -$short" |
|
741 |
if exists $self->{short_opts}->{$short}; |
|
742 |
$self->{short_opts}->{$short} = $long; |
|
743 |
$opt->{short} = $short; |
|
744 |
}
|
|
745 |
else { |
|
746 |
$opt->{short} = undef; |
|
747 |
}
|
|
748 |
||
435.5.1
by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm |
749 |
$opt->{is_negatable} = $opt->{spec} =~ m/!/ ? 1 : 0; |
750 |
$opt->{is_cumulative} = $opt->{spec} =~ m/\+/ ? 1 : 0; |
|
751 |
$opt->{is_required} = $opt->{desc} =~ m/required/ ? 1 : 0; |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
752 |
|
753 |
$opt->{group} ||= 'default'; |
|
754 |
$self->{groups}->{ $opt->{group} }->{$long} = 1; |
|
755 |
||
756 |
$opt->{value} = undef; |
|
757 |
$opt->{got} = 0; |
|
758 |
||
759 |
my ( $type ) = $opt->{spec} =~ m/=(.)/; |
|
760 |
$opt->{type} = $type; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
761 |
PTDEBUG && _d($long, 'type:', $type); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
762 |
|
763 |
||
764 |
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ ); |
|
765 |
||
766 |
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) { |
|
767 |
$self->{defaults}->{$long} = defined $def ? $def : 1; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
768 |
PTDEBUG && _d($long, 'default:', $def); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
769 |
}
|
770 |
||
771 |
if ( $long eq 'config' ) { |
|
772 |
$self->{defaults}->{$long} = join(',', $self->get_defaults_files()); |
|
773 |
}
|
|
774 |
||
775 |
if ( (my ($dis) = $opt->{desc} =~ m/(disables .*)/) ) { |
|
776 |
$disables{$long} = $dis; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
777 |
PTDEBUG && _d('Deferring check of disables rule for', $opt, $dis); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
778 |
}
|
779 |
||
780 |
$self->{opts}->{$long} = $opt; |
|
781 |
}
|
|
782 |
else { # It's an option rule, not a spec. |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
783 |
PTDEBUG && _d('Parsing rule:', $opt); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
784 |
push @{$self->{rules}}, $opt; |
785 |
my @participants = $self->_get_participants($opt); |
|
786 |
my $rule_ok = 0; |
|
787 |
||
788 |
if ( $opt =~ m/mutually exclusive|one and only one/ ) { |
|
789 |
$rule_ok = 1; |
|
790 |
push @{$self->{mutex}}, \@participants; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
791 |
PTDEBUG && _d(@participants, 'are mutually exclusive'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
792 |
}
|
793 |
if ( $opt =~ m/at least one|one and only one/ ) { |
|
794 |
$rule_ok = 1; |
|
795 |
push @{$self->{atleast1}}, \@participants; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
796 |
PTDEBUG && _d(@participants, 'require at least one'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
797 |
}
|
798 |
if ( $opt =~ m/default to/ ) { |
|
799 |
$rule_ok = 1; |
|
800 |
$self->{defaults_to}->{$participants[0]} = $participants[1]; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
801 |
PTDEBUG && _d($participants[0], 'defaults to', $participants[1]); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
802 |
}
|
803 |
if ( $opt =~ m/restricted to option groups/ ) { |
|
804 |
$rule_ok = 1; |
|
805 |
my ($groups) = $opt =~ m/groups ([\w\s\,]+)/; |
|
806 |
my @groups = split(',', $groups); |
|
807 |
%{$self->{allowed_groups}->{$participants[0]}} = map { |
|
808 |
s/\s+//; |
|
809 |
$_ => 1; |
|
810 |
} @groups; |
|
811 |
}
|
|
812 |
if( $opt =~ m/accepts additional command-line arguments/ ) { |
|
813 |
$rule_ok = 1; |
|
814 |
$self->{strict} = 0; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
815 |
PTDEBUG && _d("Strict mode disabled by rule"); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
816 |
}
|
817 |
||
818 |
die "Unrecognized option rule: $opt" unless $rule_ok; |
|
819 |
}
|
|
820 |
}
|
|
821 |
||
822 |
foreach my $long ( keys %disables ) { |
|
823 |
my @participants = $self->_get_participants($disables{$long}); |
|
824 |
$self->{disables}->{$long} = \@participants; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
825 |
PTDEBUG && _d('Option', $long, 'disables', @participants); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
826 |
}
|
827 |
||
828 |
return; |
|
829 |
}
|
|
830 |
||
831 |
sub _get_participants { |
|
832 |
my ( $self, $str ) = @_; |
|
833 |
my @participants; |
|
834 |
foreach my $long ( $str =~ m/--(?:\[no\])?([\w-]+)/g ) { |
|
835 |
die "Option --$long does not exist while processing rule $str" |
|
836 |
unless exists $self->{opts}->{$long}; |
|
837 |
push @participants, $long; |
|
838 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
839 |
PTDEBUG && _d('Participants for', $str, ':', @participants); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
840 |
return @participants; |
841 |
}
|
|
842 |
||
843 |
sub opts { |
|
844 |
my ( $self ) = @_; |
|
845 |
my %opts = %{$self->{opts}}; |
|
846 |
return %opts; |
|
847 |
}
|
|
848 |
||
849 |
sub short_opts { |
|
850 |
my ( $self ) = @_; |
|
851 |
my %short_opts = %{$self->{short_opts}}; |
|
852 |
return %short_opts; |
|
853 |
}
|
|
854 |
||
855 |
sub set_defaults { |
|
856 |
my ( $self, %defaults ) = @_; |
|
857 |
$self->{defaults} = {}; |
|
858 |
foreach my $long ( keys %defaults ) { |
|
859 |
die "Cannot set default for nonexistent option $long" |
|
860 |
unless exists $self->{opts}->{$long}; |
|
861 |
$self->{defaults}->{$long} = $defaults{$long}; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
862 |
PTDEBUG && _d('Default val for', $long, ':', $defaults{$long}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
863 |
}
|
864 |
return; |
|
865 |
}
|
|
866 |
||
867 |
sub get_defaults { |
|
868 |
my ( $self ) = @_; |
|
869 |
return $self->{defaults}; |
|
870 |
}
|
|
871 |
||
872 |
sub get_groups { |
|
873 |
my ( $self ) = @_; |
|
874 |
return $self->{groups}; |
|
875 |
}
|
|
876 |
||
877 |
sub _set_option { |
|
878 |
my ( $self, $opt, $val ) = @_; |
|
879 |
my $long = exists $self->{opts}->{$opt} ? $opt |
|
880 |
: exists $self->{short_opts}->{$opt} ? $self->{short_opts}->{$opt} |
|
881 |
: die "Getopt::Long gave a nonexistent option: $opt"; |
|
882 |
||
883 |
$opt = $self->{opts}->{$long}; |
|
884 |
if ( $opt->{is_cumulative} ) { |
|
885 |
$opt->{value}++; |
|
886 |
}
|
|
435.5.1
by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm |
887 |
else { |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
888 |
$opt->{value} = $val; |
889 |
}
|
|
890 |
$opt->{got} = 1; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
891 |
PTDEBUG && _d('Got option', $long, '=', $val); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
892 |
}
|
893 |
||
894 |
sub get_opts { |
|
895 |
my ( $self ) = @_; |
|
896 |
||
897 |
foreach my $long ( keys %{$self->{opts}} ) { |
|
898 |
$self->{opts}->{$long}->{got} = 0; |
|
899 |
$self->{opts}->{$long}->{value} |
|
900 |
= exists $self->{defaults}->{$long} ? $self->{defaults}->{$long} |
|
901 |
: $self->{opts}->{$long}->{is_cumulative} ? 0 |
|
902 |
: undef; |
|
903 |
}
|
|
904 |
$self->{got_opts} = 0; |
|
905 |
||
906 |
$self->{errors} = []; |
|
907 |
||
908 |
if ( @ARGV && $ARGV[0] eq "--config" ) { |
|
909 |
shift @ARGV; |
|
910 |
$self->_set_option('config', shift @ARGV); |
|
911 |
}
|
|
912 |
if ( $self->has('config') ) { |
|
913 |
my @extra_args; |
|
914 |
foreach my $filename ( split(',', $self->get('config')) ) { |
|
915 |
eval { |
|
916 |
push @extra_args, $self->_read_config_file($filename); |
|
917 |
};
|
|
918 |
if ( $EVAL_ERROR ) { |
|
919 |
if ( $self->got('config') ) { |
|
920 |
die $EVAL_ERROR; |
|
921 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
922 |
elsif ( PTDEBUG ) { |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
923 |
_d($EVAL_ERROR); |
924 |
}
|
|
925 |
}
|
|
926 |
}
|
|
927 |
unshift @ARGV, @extra_args; |
|
928 |
}
|
|
929 |
||
930 |
Getopt::Long::Configure('no_ignore_case', 'bundling'); |
|
931 |
GetOptions( |
|
932 |
map { $_->{spec} => sub { $self->_set_option(@_); } } |
|
933 |
grep { $_->{long} ne 'config' } # --config is handled specially above. |
|
934 |
values %{$self->{opts}} |
|
935 |
) or $self->save_error('Error parsing options'); |
|
936 |
||
937 |
if ( exists $self->{opts}->{version} && $self->{opts}->{version}->{got} ) { |
|
76.1.2
by Daniel Nichter
Update OptionParser in all tools. |
938 |
if ( $self->{version} ) { |
939 |
print $self->{version}, "\n"; |
|
940 |
}
|
|
941 |
else { |
|
942 |
print "Error parsing version. See the VERSION section of the tool's documentation.\n"; |
|
943 |
}
|
|
424.1.3
by Daniel Nichter
Update OptionParser in all tools. |
944 |
exit 1; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
945 |
}
|
946 |
||
947 |
if ( @ARGV && $self->{strict} ) { |
|
948 |
$self->save_error("Unrecognized command-line options @ARGV"); |
|
949 |
}
|
|
950 |
||
951 |
foreach my $mutex ( @{$self->{mutex}} ) { |
|
952 |
my @set = grep { $self->{opts}->{$_}->{got} } @$mutex; |
|
953 |
if ( @set > 1 ) { |
|
954 |
my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } |
|
955 |
@{$mutex}[ 0 .. scalar(@$mutex) - 2] ) |
|
956 |
. ' and --'.$self->{opts}->{$mutex->[-1]}->{long} |
|
957 |
. ' are mutually exclusive.'; |
|
958 |
$self->save_error($err); |
|
959 |
}
|
|
960 |
}
|
|
961 |
||
962 |
foreach my $required ( @{$self->{atleast1}} ) { |
|
963 |
my @set = grep { $self->{opts}->{$_}->{got} } @$required; |
|
964 |
if ( @set == 0 ) { |
|
965 |
my $err = join(', ', map { "--$self->{opts}->{$_}->{long}" } |
|
966 |
@{$required}[ 0 .. scalar(@$required) - 2] ) |
|
967 |
.' or --'.$self->{opts}->{$required->[-1]}->{long}; |
|
968 |
$self->save_error("Specify at least one of $err"); |
|
969 |
}
|
|
970 |
}
|
|
971 |
||
972 |
$self->_check_opts( keys %{$self->{opts}} ); |
|
973 |
$self->{got_opts} = 1; |
|
974 |
return; |
|
975 |
}
|
|
976 |
||
977 |
sub _check_opts { |
|
978 |
my ( $self, @long ) = @_; |
|
979 |
my $long_last = scalar @long; |
|
980 |
while ( @long ) { |
|
981 |
foreach my $i ( 0..$#long ) { |
|
982 |
my $long = $long[$i]; |
|
983 |
next unless $long; |
|
984 |
my $opt = $self->{opts}->{$long}; |
|
985 |
if ( $opt->{got} ) { |
|
986 |
if ( exists $self->{disables}->{$long} ) { |
|
987 |
my @disable_opts = @{$self->{disables}->{$long}}; |
|
988 |
map { $self->{opts}->{$_}->{value} = undef; } @disable_opts; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
989 |
PTDEBUG && _d('Unset options', @disable_opts, |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
990 |
'because', $long,'disables them'); |
991 |
}
|
|
992 |
||
993 |
if ( exists $self->{allowed_groups}->{$long} ) { |
|
994 |
||
995 |
my @restricted_groups = grep { |
|
996 |
!exists $self->{allowed_groups}->{$long}->{$_} |
|
997 |
} keys %{$self->{groups}}; |
|
998 |
||
999 |
my @restricted_opts; |
|
1000 |
foreach my $restricted_group ( @restricted_groups ) { |
|
1001 |
RESTRICTED_OPT:
|
|
1002 |
foreach my $restricted_opt ( |
|
1003 |
keys %{$self->{groups}->{$restricted_group}} ) |
|
1004 |
{
|
|
1005 |
next RESTRICTED_OPT if $restricted_opt eq $long; |
|
1006 |
push @restricted_opts, $restricted_opt |
|
1007 |
if $self->{opts}->{$restricted_opt}->{got}; |
|
1008 |
}
|
|
1009 |
}
|
|
1010 |
||
1011 |
if ( @restricted_opts ) { |
|
1012 |
my $err; |
|
1013 |
if ( @restricted_opts == 1 ) { |
|
1014 |
$err = "--$restricted_opts[0]"; |
|
1015 |
}
|
|
1016 |
else { |
|
1017 |
$err = join(', ', |
|
1018 |
map { "--$self->{opts}->{$_}->{long}" } |
|
1019 |
grep { $_ } |
|
1020 |
@restricted_opts[0..scalar(@restricted_opts) - 2] |
|
1021 |
)
|
|
1022 |
. ' or --'.$self->{opts}->{$restricted_opts[-1]}->{long}; |
|
1023 |
}
|
|
1024 |
$self->save_error("--$long is not allowed with $err"); |
|
1025 |
}
|
|
1026 |
}
|
|
1027 |
||
1028 |
}
|
|
1029 |
elsif ( $opt->{is_required} ) { |
|
1030 |
$self->save_error("Required option --$long must be specified"); |
|
1031 |
}
|
|
1032 |
||
1033 |
$self->_validate_type($opt); |
|
1034 |
if ( $opt->{parsed} ) { |
|
1035 |
delete $long[$i]; |
|
1036 |
}
|
|
1037 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1038 |
PTDEBUG && _d('Temporarily failed to parse', $long); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1039 |
}
|
1040 |
}
|
|
1041 |
||
1042 |
die "Failed to parse options, possibly due to circular dependencies" |
|
1043 |
if @long == $long_last; |
|
1044 |
$long_last = @long; |
|
1045 |
}
|
|
1046 |
||
1047 |
return; |
|
1048 |
}
|
|
1049 |
||
1050 |
sub _validate_type { |
|
1051 |
my ( $self, $opt ) = @_; |
|
1052 |
return unless $opt; |
|
1053 |
||
1054 |
if ( !$opt->{type} ) { |
|
1055 |
$opt->{parsed} = 1; |
|
1056 |
return; |
|
1057 |
}
|
|
1058 |
||
1059 |
my $val = $opt->{value}; |
|
1060 |
||
1061 |
if ( $val && $opt->{type} eq 'm' ) { # type time |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1062 |
PTDEBUG && _d('Parsing option', $opt->{long}, 'as a time value'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1063 |
my ( $prefix, $num, $suffix ) = $val =~ m/([+-]?)(\d+)([a-z])?$/; |
1064 |
if ( !$suffix ) { |
|
1065 |
my ( $s ) = $opt->{desc} =~ m/\(suffix (.)\)/; |
|
1066 |
$suffix = $s || 's'; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1067 |
PTDEBUG && _d('No suffix given; using', $suffix, 'for', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1068 |
$opt->{long}, '(value:', $val, ')'); |
1069 |
}
|
|
1070 |
if ( $suffix =~ m/[smhd]/ ) { |
|
1071 |
$val = $suffix eq 's' ? $num # Seconds |
|
1072 |
: $suffix eq 'm' ? $num * 60 # Minutes |
|
1073 |
: $suffix eq 'h' ? $num * 3600 # Hours |
|
1074 |
: $num * 86400; # Days |
|
1075 |
$opt->{value} = ($prefix || '') . $val; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1076 |
PTDEBUG && _d('Setting option', $opt->{long}, 'to', $val); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1077 |
}
|
1078 |
else { |
|
1079 |
$self->save_error("Invalid time suffix for --$opt->{long}"); |
|
1080 |
}
|
|
1081 |
}
|
|
1082 |
elsif ( $val && $opt->{type} eq 'd' ) { # type DSN |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1083 |
PTDEBUG && _d('Parsing option', $opt->{long}, 'as a DSN'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1084 |
my $prev = {}; |
1085 |
my $from_key = $self->{defaults_to}->{ $opt->{long} }; |
|
1086 |
if ( $from_key ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1087 |
PTDEBUG && _d($opt->{long}, 'DSN copies from', $from_key, 'DSN'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1088 |
if ( $self->{opts}->{$from_key}->{parsed} ) { |
1089 |
$prev = $self->{opts}->{$from_key}->{value}; |
|
1090 |
}
|
|
1091 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1092 |
PTDEBUG && _d('Cannot parse', $opt->{long}, 'until', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1093 |
$from_key, 'parsed'); |
1094 |
return; |
|
1095 |
}
|
|
1096 |
}
|
|
1097 |
my $defaults = $self->{DSNParser}->parse_options($self); |
|
1098 |
$opt->{value} = $self->{DSNParser}->parse($val, $prev, $defaults); |
|
1099 |
}
|
|
1100 |
elsif ( $val && $opt->{type} eq 'z' ) { # type size |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1101 |
PTDEBUG && _d('Parsing option', $opt->{long}, 'as a size value'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1102 |
$self->_parse_size($opt, $val); |
1103 |
}
|
|
1104 |
elsif ( $opt->{type} eq 'H' || (defined $val && $opt->{type} eq 'h') ) { |
|
1105 |
$opt->{value} = { map { $_ => 1 } split(/(?<!\\),\s*/, ($val || '')) }; |
|
1106 |
}
|
|
1107 |
elsif ( $opt->{type} eq 'A' || (defined $val && $opt->{type} eq 'a') ) { |
|
1108 |
$opt->{value} = [ split(/(?<!\\),\s*/, ($val || '')) ]; |
|
1109 |
}
|
|
1110 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1111 |
PTDEBUG && _d('Nothing to validate for option', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1112 |
$opt->{long}, 'type', $opt->{type}, 'value', $val); |
1113 |
}
|
|
1114 |
||
1115 |
$opt->{parsed} = 1; |
|
1116 |
return; |
|
1117 |
}
|
|
1118 |
||
1119 |
sub get { |
|
1120 |
my ( $self, $opt ) = @_; |
|
1121 |
my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); |
|
1122 |
die "Option $opt does not exist" |
|
1123 |
unless $long && exists $self->{opts}->{$long}; |
|
1124 |
return $self->{opts}->{$long}->{value}; |
|
1125 |
}
|
|
1126 |
||
1127 |
sub got { |
|
1128 |
my ( $self, $opt ) = @_; |
|
1129 |
my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); |
|
1130 |
die "Option $opt does not exist" |
|
1131 |
unless $long && exists $self->{opts}->{$long}; |
|
1132 |
return $self->{opts}->{$long}->{got}; |
|
1133 |
}
|
|
1134 |
||
1135 |
sub has { |
|
1136 |
my ( $self, $opt ) = @_; |
|
1137 |
my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); |
|
1138 |
return defined $long ? exists $self->{opts}->{$long} : 0; |
|
1139 |
}
|
|
1140 |
||
1141 |
sub set { |
|
1142 |
my ( $self, $opt, $val ) = @_; |
|
1143 |
my $long = (length $opt == 1 ? $self->{short_opts}->{$opt} : $opt); |
|
1144 |
die "Option $opt does not exist" |
|
1145 |
unless $long && exists $self->{opts}->{$long}; |
|
1146 |
$self->{opts}->{$long}->{value} = $val; |
|
1147 |
return; |
|
1148 |
}
|
|
1149 |
||
1150 |
sub save_error { |
|
1151 |
my ( $self, $error ) = @_; |
|
1152 |
push @{$self->{errors}}, $error; |
|
1153 |
return; |
|
1154 |
}
|
|
1155 |
||
1156 |
sub errors { |
|
1157 |
my ( $self ) = @_; |
|
1158 |
return $self->{errors}; |
|
1159 |
}
|
|
1160 |
||
1161 |
sub usage { |
|
1162 |
my ( $self ) = @_; |
|
1163 |
warn "No usage string is set" unless $self->{usage}; # XXX |
|
1164 |
return "Usage: " . ($self->{usage} || '') . "\n"; |
|
1165 |
}
|
|
1166 |
||
1167 |
sub descr { |
|
1168 |
my ( $self ) = @_; |
|
1169 |
warn "No description string is set" unless $self->{description}; # XXX |
|
1170 |
my $descr = ($self->{description} || $self->{program_name} || '') |
|
1171 |
. " For more details, please use the --help option, " |
|
1172 |
. "or try 'perldoc $PROGRAM_NAME' " |
|
1173 |
. "for complete documentation."; |
|
1174 |
$descr = join("\n", $descr =~ m/(.{0,80})(?:\s+|$)/g) |
|
1175 |
unless $ENV{DONT_BREAK_LINES}; |
|
1176 |
$descr =~ s/ +$//mg; |
|
1177 |
return $descr; |
|
1178 |
}
|
|
1179 |
||
1180 |
sub usage_or_errors { |
|
1181 |
my ( $self, $file, $return ) = @_; |
|
1182 |
$file ||= $self->{file} || __FILE__; |
|
1183 |
||
1184 |
if ( !$self->{description} || !$self->{usage} ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1185 |
PTDEBUG && _d("Getting description and usage from SYNOPSIS in", $file); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1186 |
my %synop = $self->_parse_synopsis($file); |
1187 |
$self->{description} ||= $synop{description}; |
|
1188 |
$self->{usage} ||= $synop{usage}; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1189 |
PTDEBUG && _d("Description:", $self->{description}, |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1190 |
"\nUsage:", $self->{usage}); |
1191 |
}
|
|
1192 |
||
1193 |
if ( $self->{opts}->{help}->{got} ) { |
|
1194 |
print $self->print_usage() or die "Cannot print usage: $OS_ERROR"; |
|
1195 |
exit 0 unless $return; |
|
1196 |
}
|
|
1197 |
elsif ( scalar @{$self->{errors}} ) { |
|
1198 |
print $self->print_errors() or die "Cannot print errors: $OS_ERROR"; |
|
424.1.3
by Daniel Nichter
Update OptionParser in all tools. |
1199 |
exit 1 unless $return; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1200 |
}
|
1201 |
||
1202 |
return; |
|
1203 |
}
|
|
1204 |
||
1205 |
sub print_errors { |
|
1206 |
my ( $self ) = @_; |
|
1207 |
my $usage = $self->usage() . "\n"; |
|
1208 |
if ( (my @errors = @{$self->{errors}}) ) { |
|
1209 |
$usage .= join("\n * ", 'Errors in command-line arguments:', @errors) |
|
1210 |
. "\n"; |
|
1211 |
}
|
|
1212 |
return $usage . "\n" . $self->descr(); |
|
1213 |
}
|
|
1214 |
||
1215 |
sub print_usage { |
|
1216 |
my ( $self ) = @_; |
|
1217 |
die "Run get_opts() before print_usage()" unless $self->{got_opts}; |
|
1218 |
my @opts = values %{$self->{opts}}; |
|
1219 |
||
1220 |
my $maxl = max( |
|
1221 |
map { |
|
1222 |
length($_->{long}) # option long name |
|
1223 |
+ ($_->{is_negatable} ? 4 : 0) # "[no]" if opt is negatable |
|
1224 |
+ ($_->{type} ? 2 : 0) # "=x" where x is the opt type |
|
1225 |
}
|
|
1226 |
@opts); |
|
1227 |
||
1228 |
my $maxs = max(0, |
|
1229 |
map { |
|
1230 |
length($_) |
|
1231 |
+ ($self->{opts}->{$_}->{is_negatable} ? 4 : 0) |
|
1232 |
+ ($self->{opts}->{$_}->{type} ? 2 : 0) |
|
1233 |
}
|
|
1234 |
values %{$self->{short_opts}}); |
|
1235 |
||
1236 |
my $lcol = max($maxl, ($maxs + 3)); |
|
1237 |
my $rcol = 80 - $lcol - 6; |
|
1238 |
my $rpad = ' ' x ( 80 - $rcol ); |
|
1239 |
||
1240 |
$maxs = max($lcol - 3, $maxs); |
|
1241 |
||
1242 |
my $usage = $self->descr() . "\n" . $self->usage(); |
|
1243 |
||
1244 |
my @groups = reverse sort grep { $_ ne 'default'; } keys %{$self->{groups}}; |
|
1245 |
push @groups, 'default'; |
|
1246 |
||
1247 |
foreach my $group ( reverse @groups ) { |
|
1248 |
$usage .= "\n".($group eq 'default' ? 'Options' : $group).":\n\n"; |
|
1249 |
foreach my $opt ( |
|
1250 |
sort { $a->{long} cmp $b->{long} } |
|
1251 |
grep { $_->{group} eq $group } |
|
1252 |
@opts ) |
|
1253 |
{
|
|
1254 |
my $long = $opt->{is_negatable} ? "[no]$opt->{long}" : $opt->{long}; |
|
1255 |
my $short = $opt->{short}; |
|
1256 |
my $desc = $opt->{desc}; |
|
1257 |
||
1258 |
$long .= $opt->{type} ? "=$opt->{type}" : ""; |
|
1259 |
||
1260 |
if ( $opt->{type} && $opt->{type} eq 'm' ) { |
|
1261 |
my ($s) = $desc =~ m/\(suffix (.)\)/; |
|
1262 |
$s ||= 's'; |
|
1263 |
$desc =~ s/\s+\(suffix .\)//; |
|
1264 |
$desc .= ". Optional suffix s=seconds, m=minutes, h=hours, " |
|
1265 |
. "d=days; if no suffix, $s is used."; |
|
1266 |
}
|
|
472.1.2
by Brian Fraser
Update modules for all tools using DSNParser |
1267 |
$desc = join("\n$rpad", grep { $_ } $desc =~ m/(.{0,$rcol}(?!\W))(?:\s+|(?<=\W)|$)/g); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1268 |
$desc =~ s/ +$//mg; |
1269 |
if ( $short ) { |
|
1270 |
$usage .= sprintf(" --%-${maxs}s -%s %s\n", $long, $short, $desc); |
|
1271 |
}
|
|
1272 |
else { |
|
1273 |
$usage .= sprintf(" --%-${lcol}s %s\n", $long, $desc); |
|
1274 |
}
|
|
1275 |
}
|
|
1276 |
}
|
|
1277 |
||
1278 |
$usage .= "\nOption types: s=string, i=integer, f=float, h/H/a/A=comma-separated list, d=DSN, z=size, m=time\n"; |
|
1279 |
||
1280 |
if ( (my @rules = @{$self->{rules}}) ) { |
|
1281 |
$usage .= "\nRules:\n\n"; |
|
1282 |
$usage .= join("\n", map { " $_" } @rules) . "\n"; |
|
1283 |
}
|
|
1284 |
if ( $self->{DSNParser} ) { |
|
1285 |
$usage .= "\n" . $self->{DSNParser}->usage(); |
|
1286 |
}
|
|
1287 |
$usage .= "\nOptions and values after processing arguments:\n\n"; |
|
1288 |
foreach my $opt ( sort { $a->{long} cmp $b->{long} } @opts ) { |
|
1289 |
my $val = $opt->{value}; |
|
1290 |
my $type = $opt->{type} || ''; |
|
1291 |
my $bool = $opt->{spec} =~ m/^[\w-]+(?:\|[\w-])?!?$/; |
|
1292 |
$val = $bool ? ( $val ? 'TRUE' : 'FALSE' ) |
|
1293 |
: !defined $val ? '(No value)' |
|
1294 |
: $type eq 'd' ? $self->{DSNParser}->as_string($val) |
|
1295 |
: $type =~ m/H|h/ ? join(',', sort keys %$val) |
|
1296 |
: $type =~ m/A|a/ ? join(',', @$val) |
|
1297 |
: $val; |
|
1298 |
$usage .= sprintf(" --%-${lcol}s %s\n", $opt->{long}, $val); |
|
1299 |
}
|
|
1300 |
return $usage; |
|
1301 |
}
|
|
1302 |
||
1303 |
sub prompt_noecho { |
|
1304 |
shift @_ if ref $_[0] eq __PACKAGE__; |
|
1305 |
my ( $prompt ) = @_; |
|
1306 |
local $OUTPUT_AUTOFLUSH = 1; |
|
1307 |
print $prompt |
|
1308 |
or die "Cannot print: $OS_ERROR"; |
|
1309 |
my $response; |
|
1310 |
eval { |
|
1311 |
require Term::ReadKey; |
|
1312 |
Term::ReadKey::ReadMode('noecho'); |
|
1313 |
chomp($response = <STDIN>); |
|
1314 |
Term::ReadKey::ReadMode('normal'); |
|
1315 |
print "\n" |
|
1316 |
or die "Cannot print: $OS_ERROR"; |
|
1317 |
};
|
|
1318 |
if ( $EVAL_ERROR ) { |
|
1319 |
die "Cannot read response; is Term::ReadKey installed? $EVAL_ERROR"; |
|
1320 |
}
|
|
1321 |
return $response; |
|
1322 |
}
|
|
1323 |
||
1324 |
sub _read_config_file { |
|
1325 |
my ( $self, $filename ) = @_; |
|
1326 |
open my $fh, "<", $filename or die "Cannot open $filename: $OS_ERROR\n"; |
|
1327 |
my @args; |
|
1328 |
my $prefix = '--'; |
|
1329 |
my $parse = 1; |
|
1330 |
||
1331 |
LINE:
|
|
1332 |
while ( my $line = <$fh> ) { |
|
1333 |
chomp $line; |
|
1334 |
next LINE if $line =~ m/^\s*(?:\#|\;|$)/; |
|
1335 |
$line =~ s/\s+#.*$//g; |
|
1336 |
$line =~ s/^\s+|\s+$//g; |
|
1337 |
if ( $line eq '--' ) { |
|
1338 |
$prefix = ''; |
|
1339 |
$parse = 0; |
|
1340 |
next LINE; |
|
1341 |
}
|
|
1342 |
if ( $parse |
|
1343 |
&& (my($opt, $arg) = $line =~ m/^\s*([^=\s]+?)(?:\s*=\s*(.*?)\s*)?$/) |
|
1344 |
) { |
|
1345 |
push @args, grep { defined $_ } ("$prefix$opt", $arg); |
|
1346 |
}
|
|
1347 |
elsif ( $line =~ m/./ ) { |
|
1348 |
push @args, $line; |
|
1349 |
}
|
|
1350 |
else { |
|
1351 |
die "Syntax error in file $filename at line $INPUT_LINE_NUMBER"; |
|
1352 |
}
|
|
1353 |
}
|
|
1354 |
close $fh; |
|
1355 |
return @args; |
|
1356 |
}
|
|
1357 |
||
1358 |
sub read_para_after { |
|
1359 |
my ( $self, $file, $regex ) = @_; |
|
1360 |
open my $fh, "<", $file or die "Can't open $file: $OS_ERROR"; |
|
1361 |
local $INPUT_RECORD_SEPARATOR = ''; |
|
1362 |
my $para; |
|
1363 |
while ( $para = <$fh> ) { |
|
1364 |
next unless $para =~ m/^=pod$/m; |
|
1365 |
last; |
|
1366 |
}
|
|
1367 |
while ( $para = <$fh> ) { |
|
1368 |
next unless $para =~ m/$regex/; |
|
1369 |
last; |
|
1370 |
}
|
|
1371 |
$para = <$fh>; |
|
1372 |
chomp($para); |
|
1373 |
close $fh or die "Can't close $file: $OS_ERROR"; |
|
1374 |
return $para; |
|
1375 |
}
|
|
1376 |
||
1377 |
sub clone { |
|
1378 |
my ( $self ) = @_; |
|
1379 |
||
1380 |
my %clone = map { |
|
1381 |
my $hashref = $self->{$_}; |
|
1382 |
my $val_copy = {}; |
|
1383 |
foreach my $key ( keys %$hashref ) { |
|
1384 |
my $ref = ref $hashref->{$key}; |
|
1385 |
$val_copy->{$key} = !$ref ? $hashref->{$key} |
|
1386 |
: $ref eq 'HASH' ? { %{$hashref->{$key}} } |
|
1387 |
: $ref eq 'ARRAY' ? [ @{$hashref->{$key}} ] |
|
1388 |
: $hashref->{$key}; |
|
1389 |
}
|
|
1390 |
$_ => $val_copy; |
|
1391 |
} qw(opts short_opts defaults); |
|
1392 |
||
1393 |
foreach my $scalar ( qw(got_opts) ) { |
|
1394 |
$clone{$scalar} = $self->{$scalar}; |
|
1395 |
}
|
|
1396 |
||
1397 |
return bless \%clone; |
|
1398 |
}
|
|
1399 |
||
1400 |
sub _parse_size { |
|
1401 |
my ( $self, $opt, $val ) = @_; |
|
1402 |
||
1403 |
if ( lc($val || '') eq 'null' ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1404 |
PTDEBUG && _d('NULL size for', $opt->{long}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1405 |
$opt->{value} = 'null'; |
1406 |
return; |
|
1407 |
}
|
|
1408 |
||
1409 |
my %factor_for = (k => 1_024, M => 1_048_576, G => 1_073_741_824); |
|
1410 |
my ($pre, $num, $factor) = $val =~ m/^([+-])?(\d+)([kMG])?$/; |
|
1411 |
if ( defined $num ) { |
|
1412 |
if ( $factor ) { |
|
1413 |
$num *= $factor_for{$factor}; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1414 |
PTDEBUG && _d('Setting option', $opt->{y}, |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1415 |
'to num', $num, '* factor', $factor); |
1416 |
}
|
|
1417 |
$opt->{value} = ($pre || '') . $num; |
|
1418 |
}
|
|
1419 |
else { |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1420 |
$self->save_error("Invalid size for --$opt->{long}: $val"); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1421 |
}
|
1422 |
return; |
|
1423 |
}
|
|
1424 |
||
1425 |
sub _parse_attribs { |
|
1426 |
my ( $self, $option, $attribs ) = @_; |
|
1427 |
my $types = $self->{types}; |
|
1428 |
return $option |
|
1429 |
. ($attribs->{'short form'} ? '|' . $attribs->{'short form'} : '' ) |
|
1430 |
. ($attribs->{'negatable'} ? '!' : '' ) |
|
1431 |
. ($attribs->{'cumulative'} ? '+' : '' ) |
|
435.5.1
by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm |
1432 |
. ($attribs->{'type'} ? '=' . $types->{$attribs->{type}} : '' ); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1433 |
}
|
1434 |
||
1435 |
sub _parse_synopsis { |
|
1436 |
my ( $self, $file ) = @_; |
|
1437 |
$file ||= $self->{file} || __FILE__; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1438 |
PTDEBUG && _d("Parsing SYNOPSIS in", $file); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1439 |
|
1440 |
local $INPUT_RECORD_SEPARATOR = ''; # read paragraphs |
|
1441 |
open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; |
|
1442 |
my $para; |
|
1443 |
1 while defined($para = <$fh>) && $para !~ m/^=head1 SYNOPSIS/; |
|
1444 |
die "$file does not contain a SYNOPSIS section" unless $para; |
|
1445 |
my @synop; |
|
1446 |
for ( 1..2 ) { # 1 for the usage, 2 for the description |
|
1447 |
my $para = <$fh>; |
|
1448 |
push @synop, $para; |
|
1449 |
}
|
|
1450 |
close $fh; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1451 |
PTDEBUG && _d("Raw SYNOPSIS text:", @synop); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1452 |
my ($usage, $desc) = @synop; |
1453 |
die "The SYNOPSIS section in $file is not formatted properly" |
|
1454 |
unless $usage && $desc; |
|
1455 |
||
1456 |
$usage =~ s/^\s*Usage:\s+(.+)/$1/; |
|
1457 |
chomp $usage; |
|
1458 |
||
1459 |
$desc =~ s/\n/ /g; |
|
1460 |
$desc =~ s/\s{2,}/ /g; |
|
1461 |
$desc =~ s/\. ([A-Z][a-z])/. $1/g; |
|
1462 |
$desc =~ s/\s+$//; |
|
1463 |
||
1464 |
return ( |
|
1465 |
description => $desc, |
|
1466 |
usage => $usage, |
|
1467 |
);
|
|
1468 |
};
|
|
1469 |
||
531.2.2
by Daniel Nichter
Update OptionParser and DSNParser in all tools. |
1470 |
sub set_vars { |
1471 |
my ($self, $file) = @_; |
|
1472 |
$file ||= $self->{file} || __FILE__; |
|
1473 |
||
1474 |
my %user_vars; |
|
1475 |
my $user_vars = $self->has('set-vars') ? $self->get('set-vars') : undef; |
|
1476 |
if ( $user_vars ) { |
|
1477 |
foreach my $var_val ( @$user_vars ) { |
|
1478 |
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/; |
|
1479 |
die "Invalid --set-vars value: $var_val\n" unless $var && $val; |
|
1480 |
$user_vars{$var} = { |
|
1481 |
val => $val, |
|
1482 |
default => 0, |
|
1483 |
};
|
|
1484 |
}
|
|
1485 |
}
|
|
1486 |
||
1487 |
my %default_vars; |
|
1488 |
my $default_vars = $self->read_para_after($file, qr/MAGIC_set_vars/); |
|
1489 |
if ( $default_vars ) { |
|
1490 |
%default_vars = map { |
|
1491 |
my $var_val = $_; |
|
1492 |
my ($var, $val) = $var_val =~ m/([^\s=]+)=(\S+)/; |
|
1493 |
die "Invalid --set-vars value: $var_val\n" unless $var && $val; |
|
1494 |
$var => { |
|
1495 |
val => $val, |
|
1496 |
default => 1, |
|
1497 |
};
|
|
1498 |
} split("\n", $default_vars); |
|
1499 |
}
|
|
1500 |
||
1501 |
my %vars = ( |
|
1502 |
%default_vars, # first the tool's defaults |
|
1503 |
%user_vars, # then the user's which overwrite the defaults |
|
1504 |
);
|
|
1505 |
PTDEBUG && _d('--set-vars:', Dumper(\%vars)); |
|
1506 |
return \%vars; |
|
1507 |
}
|
|
1508 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1509 |
sub _d { |
1510 |
my ($package, undef, $line) = caller 0; |
|
1511 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
1512 |
map { defined $_ ? $_ : 'undef' } |
|
1513 |
@_; |
|
1514 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
1515 |
}
|
|
1516 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1517 |
if ( PTDEBUG ) { |
76.1.2
by Daniel Nichter
Update OptionParser in all tools. |
1518 |
print '# ', $^X, ' ', $], "\n"; |
1519 |
if ( my $uname = `uname -a` ) { |
|
1520 |
$uname =~ s/\s+/ /g; |
|
1521 |
print "# $uname\n"; |
|
1522 |
}
|
|
1523 |
print '# Arguments: ', |
|
1524 |
join(' ', map { my $a = "_[$_]_"; $a =~ s/\n/\n# /g; $a; } @ARGV), "\n"; |
|
1525 |
}
|
|
1526 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1527 |
1; |
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1528 |
}
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1529 |
# ###########################################################################
|
1530 |
# End OptionParser package
|
|
1531 |
# ###########################################################################
|
|
1532 |
||
1533 |
# ###########################################################################
|
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1534 |
# Quoter package
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1535 |
# This package is a copy without comments from the original. The original
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1536 |
# with comments and its test file can be found in the Bazaar repository at,
|
1537 |
# lib/Quoter.pm
|
|
1538 |
# t/lib/Quoter.t
|
|
1539 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1540 |
# ###########################################################################
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1541 |
{
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1542 |
package Quoter; |
1543 |
||
1544 |
use strict; |
|
1545 |
use warnings FATAL => 'all'; |
|
1546 |
use English qw(-no_match_vars); |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1547 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1548 |
|
503.16.8
by Daniel Nichter
Updqte Quoter in all tools. |
1549 |
use Data::Dumper; |
1550 |
$Data::Dumper::Indent = 1; |
|
1551 |
$Data::Dumper::Sortkeys = 1; |
|
1552 |
$Data::Dumper::Quotekeys = 0; |
|
1553 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1554 |
sub new { |
1555 |
my ( $class, %args ) = @_; |
|
1556 |
return bless {}, $class; |
|
1557 |
}
|
|
1558 |
||
1559 |
sub quote { |
|
1560 |
my ( $self, @vals ) = @_; |
|
1561 |
foreach my $val ( @vals ) { |
|
1562 |
$val =~ s/`/``/g; |
|
1563 |
}
|
|
1564 |
return join('.', map { '`' . $_ . '`' } @vals); |
|
1565 |
}
|
|
1566 |
||
1567 |
sub quote_val { |
|
362.6.2
by Brian Fraser
Updated Quoter and ChangeHandler in all the modules |
1568 |
my ( $self, $val, %args ) = @_; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1569 |
|
1570 |
return 'NULL' unless defined $val; # undef = NULL |
|
1571 |
return "''" if $val eq ''; # blank string = '' |
|
362.6.2
by Brian Fraser
Updated Quoter and ChangeHandler in all the modules |
1572 |
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data |
1573 |
&& !$args{is_char}; # unless is_char is true |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1574 |
|
1575 |
$val =~ s/(['\\])/\\$1/g; |
|
1576 |
return "'$val'"; |
|
1577 |
}
|
|
1578 |
||
1579 |
sub split_unquote { |
|
1580 |
my ( $self, $db_tbl, $default_db ) = @_; |
|
1581 |
my ( $db, $tbl ) = split(/[.]/, $db_tbl); |
|
1582 |
if ( !$tbl ) { |
|
1583 |
$tbl = $db; |
|
1584 |
$db = $default_db; |
|
1585 |
}
|
|
459.1.6
by Brian Fraser
Pushed the lib/Percona/Toolkit.pm version, and added extra tests to t/lib/Percona/Toolkit.t |
1586 |
for ($db, $tbl) { |
1587 |
next unless $_; |
|
1588 |
s/\A`//; |
|
1589 |
s/`\z//; |
|
1590 |
s/``/`/g; |
|
1591 |
}
|
|
1592 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1593 |
return ($db, $tbl); |
1594 |
}
|
|
1595 |
||
1596 |
sub literal_like { |
|
1597 |
my ( $self, $like ) = @_; |
|
1598 |
return unless $like; |
|
1599 |
$like =~ s/([%_])/\\$1/g; |
|
1600 |
return "'$like'"; |
|
1601 |
}
|
|
1602 |
||
1603 |
sub join_quote { |
|
1604 |
my ( $self, $default_db, $db_tbl ) = @_; |
|
1605 |
return unless $db_tbl; |
|
1606 |
my ($db, $tbl) = split(/[.]/, $db_tbl); |
|
1607 |
if ( !$tbl ) { |
|
1608 |
$tbl = $db; |
|
1609 |
$db = $default_db; |
|
1610 |
}
|
|
1611 |
$db = "`$db`" if $db && $db !~ m/^`/; |
|
1612 |
$tbl = "`$tbl`" if $tbl && $tbl !~ m/^`/; |
|
1613 |
return $db ? "$db.$tbl" : $tbl; |
|
1614 |
}
|
|
1615 |
||
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1616 |
sub serialize_list { |
1617 |
my ( $self, @args ) = @_; |
|
503.16.8
by Daniel Nichter
Updqte Quoter in all tools. |
1618 |
PTDEBUG && _d('Serializing', Dumper(\@args)); |
503.16.11
by Daniel Nichter
Update Quoter in all tools again. |
1619 |
return unless @args; |
503.16.8
by Daniel Nichter
Updqte Quoter in all tools. |
1620 |
|
1621 |
my @parts; |
|
1622 |
foreach my $arg ( @args ) { |
|
1623 |
if ( defined $arg ) { |
|
1624 |
$arg =~ s/,/\\,/g; # escape commas |
|
1625 |
$arg =~ s/\\N/\\\\N/g; # escape literal \N |
|
1626 |
push @parts, $arg; |
|
1627 |
}
|
|
1628 |
else { |
|
1629 |
push @parts, '\N'; |
|
1630 |
}
|
|
1631 |
}
|
|
1632 |
||
1633 |
my $string = join(',', @parts); |
|
1634 |
PTDEBUG && _d('Serialized: <', $string, '>'); |
|
1635 |
return $string; |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1636 |
}
|
1637 |
||
1638 |
sub deserialize_list { |
|
1639 |
my ( $self, $string ) = @_; |
|
503.16.8
by Daniel Nichter
Updqte Quoter in all tools. |
1640 |
PTDEBUG && _d('Deserializing <', $string, '>'); |
1641 |
die "Cannot deserialize an undefined string" unless defined $string; |
|
1642 |
||
1643 |
my @parts; |
|
1644 |
foreach my $arg ( split(/(?<!\\),/, $string) ) { |
|
1645 |
if ( $arg eq '\N' ) { |
|
1646 |
$arg = undef; |
|
503.16.2
by Brian Fraser
Update all modules that use Quoter |
1647 |
}
|
1648 |
else { |
|
503.16.8
by Daniel Nichter
Updqte Quoter in all tools. |
1649 |
$arg =~ s/\\,/,/g; |
1650 |
$arg =~ s/\\\\N/\\N/g; |
|
503.16.2
by Brian Fraser
Update all modules that use Quoter |
1651 |
}
|
503.16.8
by Daniel Nichter
Updqte Quoter in all tools. |
1652 |
push @parts, $arg; |
1653 |
}
|
|
1654 |
||
1655 |
if ( !@parts ) { |
|
1656 |
my $n_empty_strings = $string =~ tr/,//; |
|
1657 |
$n_empty_strings++; |
|
1658 |
PTDEBUG && _d($n_empty_strings, 'empty strings'); |
|
1659 |
map { push @parts, '' } 1..$n_empty_strings; |
|
1660 |
}
|
|
1661 |
elsif ( $string =~ m/(?<!\\),$/ ) { |
|
1662 |
PTDEBUG && _d('Last value is an empty string'); |
|
1663 |
push @parts, ''; |
|
1664 |
}
|
|
1665 |
||
1666 |
PTDEBUG && _d('Deserialized', Dumper(\@parts)); |
|
1667 |
return @parts; |
|
1668 |
}
|
|
1669 |
||
1670 |
sub _d { |
|
1671 |
my ($package, undef, $line) = caller 0; |
|
1672 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
1673 |
map { defined $_ ? $_ : 'undef' } |
|
1674 |
@_; |
|
1675 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1676 |
}
|
1677 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1678 |
1; |
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1679 |
}
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1680 |
# ###########################################################################
|
1681 |
# End Quoter package
|
|
1682 |
# ###########################################################################
|
|
1683 |
||
1684 |
# ###########################################################################
|
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1685 |
# TableParser package
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1686 |
# This package is a copy without comments from the original. The original
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1687 |
# with comments and its test file can be found in the Bazaar repository at,
|
1688 |
# lib/TableParser.pm
|
|
1689 |
# t/lib/TableParser.t
|
|
1690 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1691 |
# ###########################################################################
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1692 |
{
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1693 |
package TableParser; |
1694 |
||
1695 |
use strict; |
|
1696 |
use warnings FATAL => 'all'; |
|
1697 |
use English qw(-no_match_vars); |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1698 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
1699 |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1700 |
use Data::Dumper; |
1701 |
$Data::Dumper::Indent = 1; |
|
1702 |
$Data::Dumper::Sortkeys = 1; |
|
1703 |
$Data::Dumper::Quotekeys = 0; |
|
1704 |
||
459.1.6
by Brian Fraser
Pushed the lib/Percona/Toolkit.pm version, and added extra tests to t/lib/Percona/Toolkit.t |
1705 |
local $EVAL_ERROR; |
1706 |
eval { |
|
1707 |
require Quoter; |
|
1708 |
};
|
|
1709 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1710 |
sub new { |
1711 |
my ( $class, %args ) = @_; |
|
1712 |
my $self = { %args }; |
|
459.1.6
by Brian Fraser
Pushed the lib/Percona/Toolkit.pm version, and added extra tests to t/lib/Percona/Toolkit.t |
1713 |
$self->{Quoter} ||= Quoter->new(); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1714 |
return bless $self, $class; |
1715 |
}
|
|
1716 |
||
459.1.6
by Brian Fraser
Pushed the lib/Percona/Toolkit.pm version, and added extra tests to t/lib/Percona/Toolkit.t |
1717 |
sub Quoter { shift->{Quoter} } |
1718 |
||
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1719 |
sub get_create_table { |
1720 |
my ( $self, $dbh, $db, $tbl ) = @_; |
|
1721 |
die "I need a dbh parameter" unless $dbh; |
|
1722 |
die "I need a db parameter" unless $db; |
|
1723 |
die "I need a tbl parameter" unless $tbl; |
|
1724 |
my $q = $self->{Quoter}; |
|
1725 |
||
1726 |
my $new_sql_mode |
|
410.1.3
by Daniel Nichter
Update TableParser in all tools. |
1727 |
= q{/*!40101 SET @OLD_SQL_MODE := @@SQL_MODE, } |
1728 |
. q{@@SQL_MODE := '', } |
|
1729 |
. q{@OLD_QUOTE := @@SQL_QUOTE_SHOW_CREATE, } |
|
1730 |
. q{@@SQL_QUOTE_SHOW_CREATE := 1 */}; |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1731 |
|
410.1.3
by Daniel Nichter
Update TableParser in all tools. |
1732 |
my $old_sql_mode |
1733 |
= q{/*!40101 SET @@SQL_MODE := @OLD_SQL_MODE, } |
|
1734 |
. q{@@SQL_QUOTE_SHOW_CREATE := @OLD_QUOTE */}; |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1735 |
|
1736 |
PTDEBUG && _d($new_sql_mode); |
|
1737 |
eval { $dbh->do($new_sql_mode); }; |
|
1738 |
PTDEBUG && $EVAL_ERROR && _d($EVAL_ERROR); |
|
1739 |
||
1740 |
my $use_sql = 'USE ' . $q->quote($db); |
|
1741 |
PTDEBUG && _d($dbh, $use_sql); |
|
1742 |
$dbh->do($use_sql); |
|
1743 |
||
1744 |
my $show_sql = "SHOW CREATE TABLE " . $q->quote($db, $tbl); |
|
1745 |
PTDEBUG && _d($show_sql); |
|
1746 |
my $href; |
|
1747 |
eval { $href = $dbh->selectrow_hashref($show_sql); }; |
|
435.6.1
by Brian Fraser
Fix for 1047335: SchemaIterator fails when it encounters a crashed table |
1748 |
if ( my $e = $EVAL_ERROR ) { |
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1749 |
PTDEBUG && _d($old_sql_mode); |
1750 |
$dbh->do($old_sql_mode); |
|
1751 |
||
435.6.1
by Brian Fraser
Fix for 1047335: SchemaIterator fails when it encounters a crashed table |
1752 |
die $e; |
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1753 |
}
|
1754 |
||
1755 |
PTDEBUG && _d($old_sql_mode); |
|
1756 |
$dbh->do($old_sql_mode); |
|
1757 |
||
1758 |
my ($key) = grep { m/create (?:table|view)/i } keys %$href; |
|
1759 |
if ( !$key ) { |
|
1760 |
die "Error: no 'Create Table' or 'Create View' in result set from " |
|
1761 |
. "$show_sql: " . Dumper($href); |
|
1762 |
}
|
|
1763 |
||
1764 |
return $href->{$key}; |
|
1765 |
}
|
|
1766 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1767 |
sub parse { |
1768 |
my ( $self, $ddl, $opts ) = @_; |
|
1769 |
return unless $ddl; |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1770 |
|
1771 |
if ( $ddl =~ m/CREATE (?:TEMPORARY )?TABLE "/ ) { |
|
1772 |
$ddl = $self->ansi_to_legacy($ddl); |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1773 |
}
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1774 |
elsif ( $ddl !~ m/CREATE (?:TEMPORARY )?TABLE `/ ) { |
1775 |
die "TableParser doesn't handle CREATE TABLE without quoting."; |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1776 |
}
|
1777 |
||
1778 |
my ($name) = $ddl =~ m/CREATE (?:TEMPORARY )?TABLE\s+(`.+?`)/; |
|
1779 |
(undef, $name) = $self->{Quoter}->split_unquote($name) if $name; |
|
1780 |
||
1781 |
$ddl =~ s/(`[^`]+`)/\L$1/g; |
|
1782 |
||
1783 |
my $engine = $self->get_engine($ddl); |
|
1784 |
||
1785 |
my @defs = $ddl =~ m/^(\s+`.*?),?$/gm; |
|
1786 |
my @cols = map { $_ =~ m/`([^`]+)`/ } @defs; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1787 |
PTDEBUG && _d('Table cols:', join(', ', map { "`$_`" } @cols)); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1788 |
|
1789 |
my %def_for; |
|
1790 |
@def_for{@cols} = @defs; |
|
1791 |
||
1792 |
my (@nums, @null); |
|
1793 |
my (%type_for, %is_nullable, %is_numeric, %is_autoinc); |
|
1794 |
foreach my $col ( @cols ) { |
|
1795 |
my $def = $def_for{$col}; |
|
1796 |
my ( $type ) = $def =~ m/`[^`]+`\s([a-z]+)/; |
|
1797 |
die "Can't determine column type for $def" unless $type; |
|
1798 |
$type_for{$col} = $type; |
|
1799 |
if ( $type =~ m/(?:(?:tiny|big|medium|small)?int|float|double|decimal|year)/ ) { |
|
1800 |
push @nums, $col; |
|
1801 |
$is_numeric{$col} = 1; |
|
1802 |
}
|
|
1803 |
if ( $def !~ m/NOT NULL/ ) { |
|
1804 |
push @null, $col; |
|
1805 |
$is_nullable{$col} = 1; |
|
1806 |
}
|
|
1807 |
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0; |
|
1808 |
}
|
|
1809 |
||
1810 |
my ($keys, $clustered_key) = $self->get_keys($ddl, $opts, \%is_nullable); |
|
1811 |
||
1812 |
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/; |
|
1813 |
||
1814 |
return { |
|
1815 |
name => $name, |
|
1816 |
cols => \@cols, |
|
1817 |
col_posn => { map { $cols[$_] => $_ } 0..$#cols }, |
|
1818 |
is_col => { map { $_ => 1 } @cols }, |
|
1819 |
null_cols => \@null, |
|
1820 |
is_nullable => \%is_nullable, |
|
1821 |
is_autoinc => \%is_autoinc, |
|
1822 |
clustered_key => $clustered_key, |
|
1823 |
keys => $keys, |
|
1824 |
defs => \%def_for, |
|
1825 |
numeric_cols => \@nums, |
|
1826 |
is_numeric => \%is_numeric, |
|
1827 |
engine => $engine, |
|
1828 |
type_for => \%type_for, |
|
1829 |
charset => $charset, |
|
1830 |
};
|
|
1831 |
}
|
|
1832 |
||
1833 |
sub sort_indexes { |
|
1834 |
my ( $self, $tbl ) = @_; |
|
1835 |
||
1836 |
my @indexes |
|
1837 |
= sort { |
|
1838 |
(($a ne 'PRIMARY') <=> ($b ne 'PRIMARY')) |
|
1839 |
|| ( !$tbl->{keys}->{$a}->{is_unique} <=> !$tbl->{keys}->{$b}->{is_unique} ) |
|
1840 |
|| ( $tbl->{keys}->{$a}->{is_nullable} <=> $tbl->{keys}->{$b}->{is_nullable} ) |
|
1841 |
|| ( scalar(@{$tbl->{keys}->{$a}->{cols}}) <=> scalar(@{$tbl->{keys}->{$b}->{cols}}) ) |
|
1842 |
}
|
|
1843 |
grep { |
|
1844 |
$tbl->{keys}->{$_}->{type} eq 'BTREE' |
|
1845 |
}
|
|
1846 |
sort keys %{$tbl->{keys}}; |
|
1847 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1848 |
PTDEBUG && _d('Indexes sorted best-first:', join(', ', @indexes)); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1849 |
return @indexes; |
1850 |
}
|
|
1851 |
||
1852 |
sub find_best_index { |
|
1853 |
my ( $self, $tbl, $index ) = @_; |
|
1854 |
my $best; |
|
1855 |
if ( $index ) { |
|
1856 |
($best) = grep { uc $_ eq uc $index } keys %{$tbl->{keys}}; |
|
1857 |
}
|
|
1858 |
if ( !$best ) { |
|
1859 |
if ( $index ) { |
|
1860 |
die "Index '$index' does not exist in table"; |
|
1861 |
}
|
|
1862 |
else { |
|
1863 |
($best) = $self->sort_indexes($tbl); |
|
1864 |
}
|
|
1865 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1866 |
PTDEBUG && _d('Best index found is', $best); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1867 |
return $best; |
1868 |
}
|
|
1869 |
||
1870 |
sub find_possible_keys { |
|
1871 |
my ( $self, $dbh, $database, $table, $quoter, $where ) = @_; |
|
1872 |
return () unless $where; |
|
1873 |
my $sql = 'EXPLAIN SELECT * FROM ' . $quoter->quote($database, $table) |
|
1874 |
. ' WHERE ' . $where; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1875 |
PTDEBUG && _d($sql); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1876 |
my $expl = $dbh->selectrow_hashref($sql); |
1877 |
$expl = { map { lc($_) => $expl->{$_} } keys %$expl }; |
|
1878 |
if ( $expl->{possible_keys} ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1879 |
PTDEBUG && _d('possible_keys =', $expl->{possible_keys}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1880 |
my @candidates = split(',', $expl->{possible_keys}); |
1881 |
my %possible = map { $_ => 1 } @candidates; |
|
1882 |
if ( $expl->{key} ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1883 |
PTDEBUG && _d('MySQL chose', $expl->{key}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1884 |
unshift @candidates, grep { $possible{$_} } split(',', $expl->{key}); |
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1885 |
PTDEBUG && _d('Before deduping:', join(', ', @candidates)); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1886 |
my %seen; |
1887 |
@candidates = grep { !$seen{$_}++ } @candidates; |
|
1888 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1889 |
PTDEBUG && _d('Final list:', join(', ', @candidates)); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1890 |
return @candidates; |
1891 |
}
|
|
1892 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1893 |
PTDEBUG && _d('No keys in possible_keys'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1894 |
return (); |
1895 |
}
|
|
1896 |
}
|
|
1897 |
||
1898 |
sub check_table { |
|
1899 |
my ( $self, %args ) = @_; |
|
1900 |
my @required_args = qw(dbh db tbl); |
|
1901 |
foreach my $arg ( @required_args ) { |
|
1902 |
die "I need a $arg argument" unless $args{$arg}; |
|
1903 |
}
|
|
1904 |
my ($dbh, $db, $tbl) = @args{@required_args}; |
|
520
by Brian Fraser
Merged use-lmo. |
1905 |
my $q = $self->{Quoter} || 'Quoter'; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1906 |
my $db_tbl = $q->quote($db, $tbl); |
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1907 |
PTDEBUG && _d('Checking', $db_tbl); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1908 |
|
1909 |
my $sql = "SHOW TABLES FROM " . $q->quote($db) |
|
1910 |
. ' LIKE ' . $q->literal_like($tbl); |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1911 |
PTDEBUG && _d($sql); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1912 |
my $row; |
1913 |
eval { |
|
1914 |
$row = $dbh->selectrow_arrayref($sql); |
|
1915 |
};
|
|
1916 |
if ( $EVAL_ERROR ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1917 |
PTDEBUG && _d($EVAL_ERROR); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1918 |
return 0; |
1919 |
}
|
|
1920 |
if ( !$row->[0] || $row->[0] ne $tbl ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1921 |
PTDEBUG && _d('Table does not exist'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1922 |
return 0; |
1923 |
}
|
|
1924 |
||
416.1.3
by Daniel Nichter
Remove TableParser::check_table() privs check (re bug 1036747). |
1925 |
PTDEBUG && _d('Table', $db, $tbl, 'exists'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1926 |
return 1; |
416.1.3
by Daniel Nichter
Remove TableParser::check_table() privs check (re bug 1036747). |
1927 |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1928 |
}
|
1929 |
||
1930 |
sub get_engine { |
|
1931 |
my ( $self, $ddl, $opts ) = @_; |
|
1932 |
my ( $engine ) = $ddl =~ m/\).*?(?:ENGINE|TYPE)=(\w+)/; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1933 |
PTDEBUG && _d('Storage engine:', $engine); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1934 |
return $engine || undef; |
1935 |
}
|
|
1936 |
||
1937 |
sub get_keys { |
|
1938 |
my ( $self, $ddl, $opts, $is_nullable ) = @_; |
|
1939 |
my $engine = $self->get_engine($ddl); |
|
1940 |
my $keys = {}; |
|
1941 |
my $clustered_key = undef; |
|
1942 |
||
1943 |
KEY:
|
|
1944 |
foreach my $key ( $ddl =~ m/^ ((?:[A-Z]+ )?KEY .*)$/gm ) { |
|
1945 |
||
1946 |
next KEY if $key =~ m/FOREIGN/; |
|
1947 |
||
1948 |
my $key_ddl = $key; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1949 |
PTDEBUG && _d('Parsed key:', $key_ddl); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1950 |
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1951 |
if ( !$engine || $engine !~ m/MEMORY|HEAP/ ) { |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1952 |
$key =~ s/USING HASH/USING BTREE/; |
1953 |
}
|
|
1954 |
||
1955 |
my ( $type, $cols ) = $key =~ m/(?:USING (\w+))? \((.+)\)/; |
|
1956 |
my ( $special ) = $key =~ m/(FULLTEXT|SPATIAL)/; |
|
1957 |
$type = $type || $special || 'BTREE'; |
|
1958 |
my ($name) = $key =~ m/(PRIMARY|`[^`]*`)/; |
|
1959 |
my $unique = $key =~ m/PRIMARY|UNIQUE/ ? 1 : 0; |
|
1960 |
my @cols; |
|
1961 |
my @col_prefixes; |
|
1962 |
foreach my $col_def ( $cols =~ m/`[^`]+`(?:\(\d+\))?/g ) { |
|
1963 |
my ($name, $prefix) = $col_def =~ m/`([^`]+)`(?:\((\d+)\))?/; |
|
1964 |
push @cols, $name; |
|
1965 |
push @col_prefixes, $prefix; |
|
1966 |
}
|
|
1967 |
$name =~ s/`//g; |
|
1968 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1969 |
PTDEBUG && _d( $name, 'key cols:', join(', ', map { "`$_`" } @cols)); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1970 |
|
1971 |
$keys->{$name} = { |
|
1972 |
name => $name, |
|
1973 |
type => $type, |
|
1974 |
colnames => $cols, |
|
1975 |
cols => \@cols, |
|
1976 |
col_prefixes => \@col_prefixes, |
|
1977 |
is_unique => $unique, |
|
1978 |
is_nullable => scalar(grep { $is_nullable->{$_} } @cols), |
|
1979 |
is_col => { map { $_ => 1 } @cols }, |
|
1980 |
ddl => $key_ddl, |
|
1981 |
};
|
|
1982 |
||
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
1983 |
if ( ($engine || '') =~ m/InnoDB/i && !$clustered_key ) { |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1984 |
my $this_key = $keys->{$name}; |
1985 |
if ( $this_key->{name} eq 'PRIMARY' ) { |
|
1986 |
$clustered_key = 'PRIMARY'; |
|
1987 |
}
|
|
1988 |
elsif ( $this_key->{is_unique} && !$this_key->{is_nullable} ) { |
|
1989 |
$clustered_key = $this_key->{name}; |
|
1990 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
1991 |
PTDEBUG && $clustered_key && _d('This key is the clustered key'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
1992 |
}
|
1993 |
}
|
|
1994 |
||
1995 |
return $keys, $clustered_key; |
|
1996 |
}
|
|
1997 |
||
1998 |
sub get_fks { |
|
1999 |
my ( $self, $ddl, $opts ) = @_; |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2000 |
my $q = $self->{Quoter}; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2001 |
my $fks = {}; |
2002 |
||
2003 |
foreach my $fk ( |
|
2004 |
$ddl =~ m/CONSTRAINT .* FOREIGN KEY .* REFERENCES [^\)]*\)/mg ) |
|
2005 |
{
|
|
2006 |
my ( $name ) = $fk =~ m/CONSTRAINT `(.*?)`/; |
|
2007 |
my ( $cols ) = $fk =~ m/FOREIGN KEY \(([^\)]+)\)/; |
|
2008 |
my ( $parent, $parent_cols ) = $fk =~ m/REFERENCES (\S+) \(([^\)]+)\)/; |
|
2009 |
||
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2010 |
my ($db, $tbl) = $q->split_unquote($parent, $opts->{database}); |
2011 |
my %parent_tbl = (tbl => $tbl); |
|
2012 |
$parent_tbl{db} = $db if $db; |
|
2013 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2014 |
if ( $parent !~ m/\./ && $opts->{database} ) { |
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2015 |
$parent = $q->quote($opts->{database}) . ".$parent"; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2016 |
}
|
2017 |
||
2018 |
$fks->{$name} = { |
|
2019 |
name => $name, |
|
2020 |
colnames => $cols, |
|
2021 |
cols => [ map { s/[ `]+//g; $_; } split(',', $cols) ], |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2022 |
parent_tbl => \%parent_tbl, |
2023 |
parent_tblname => $parent, |
|
2024 |
parent_cols => [ map { s/[ `]+//g; $_; } split(',', $parent_cols) ], |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2025 |
parent_colnames=> $parent_cols, |
2026 |
ddl => $fk, |
|
2027 |
};
|
|
2028 |
}
|
|
2029 |
||
2030 |
return $fks; |
|
2031 |
}
|
|
2032 |
||
2033 |
sub remove_auto_increment { |
|
2034 |
my ( $self, $ddl ) = @_; |
|
2035 |
$ddl =~ s/(^\).*?) AUTO_INCREMENT=\d+\b/$1/m; |
|
2036 |
return $ddl; |
|
2037 |
}
|
|
2038 |
||
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
2039 |
sub get_table_status { |
2040 |
my ( $self, $dbh, $db, $like ) = @_; |
|
2041 |
my $q = $self->{Quoter}; |
|
2042 |
my $sql = "SHOW TABLE STATUS FROM " . $q->quote($db); |
|
2043 |
my @params; |
|
2044 |
if ( $like ) { |
|
2045 |
$sql .= ' LIKE ?'; |
|
2046 |
push @params, $like; |
|
2047 |
}
|
|
2048 |
PTDEBUG && _d($sql, @params); |
|
2049 |
my $sth = $dbh->prepare($sql); |
|
2050 |
eval { $sth->execute(@params); }; |
|
2051 |
if ($EVAL_ERROR) { |
|
2052 |
PTDEBUG && _d($EVAL_ERROR); |
|
2053 |
return; |
|
2054 |
}
|
|
2055 |
my @tables = @{$sth->fetchall_arrayref({})}; |
|
2056 |
@tables = map { |
|
2057 |
my %tbl; # Make a copy with lowercased keys |
|
2058 |
@tbl{ map { lc $_ } keys %$_ } = values %$_; |
|
2059 |
$tbl{engine} ||= $tbl{type} || $tbl{comment}; |
|
2060 |
delete $tbl{type}; |
|
2061 |
\%tbl; |
|
2062 |
} @tables; |
|
2063 |
return @tables; |
|
2064 |
}
|
|
2065 |
||
2066 |
my $ansi_quote_re = qr/" [^"]* (?: "" [^"]* )* (?<=.) "/ismx; |
|
2067 |
sub ansi_to_legacy { |
|
2068 |
my ($self, $ddl) = @_; |
|
2069 |
$ddl =~ s/($ansi_quote_re)/ansi_quote_replace($1)/ge; |
|
2070 |
return $ddl; |
|
2071 |
}
|
|
2072 |
||
2073 |
sub ansi_quote_replace { |
|
2074 |
my ($val) = @_; |
|
2075 |
$val =~ s/^"|"$//g; |
|
2076 |
$val =~ s/`/``/g; |
|
2077 |
$val =~ s/""/"/g; |
|
2078 |
return "`$val`"; |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2079 |
}
|
2080 |
||
2081 |
sub _d { |
|
2082 |
my ($package, undef, $line) = caller 0; |
|
2083 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
2084 |
map { defined $_ ? $_ : 'undef' } |
|
2085 |
@_; |
|
2086 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
2087 |
}
|
|
2088 |
||
2089 |
1; |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2090 |
}
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2091 |
# ###########################################################################
|
2092 |
# End TableParser package
|
|
2093 |
# ###########################################################################
|
|
2094 |
||
2095 |
# ###########################################################################
|
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2096 |
# Daemon package
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2097 |
# This package is a copy without comments from the original. The original
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2098 |
# with comments and its test file can be found in the Bazaar repository at,
|
2099 |
# lib/Daemon.pm
|
|
2100 |
# t/lib/Daemon.t
|
|
2101 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2102 |
# ###########################################################################
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2103 |
{
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2104 |
package Daemon; |
2105 |
||
2106 |
use strict; |
|
2107 |
use warnings FATAL => 'all'; |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2108 |
use English qw(-no_match_vars); |
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2109 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2110 |
|
2111 |
use POSIX qw(setsid); |
|
2112 |
||
2113 |
sub new { |
|
2114 |
my ( $class, %args ) = @_; |
|
2115 |
foreach my $arg ( qw(o) ) { |
|
2116 |
die "I need a $arg argument" unless $args{$arg}; |
|
2117 |
}
|
|
2118 |
my $o = $args{o}; |
|
2119 |
my $self = { |
|
2120 |
o => $o, |
|
2121 |
log_file => $o->has('log') ? $o->get('log') : undef, |
|
2122 |
PID_file => $o->has('pid') ? $o->get('pid') : undef, |
|
2123 |
};
|
|
2124 |
||
2125 |
check_PID_file(undef, $self->{PID_file}); |
|
2126 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2127 |
PTDEBUG && _d('Daemonized child will log to', $self->{log_file}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2128 |
return bless $self, $class; |
2129 |
}
|
|
2130 |
||
2131 |
sub daemonize { |
|
2132 |
my ( $self ) = @_; |
|
2133 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2134 |
PTDEBUG && _d('About to fork and daemonize'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2135 |
defined (my $pid = fork()) or die "Cannot fork: $OS_ERROR"; |
2136 |
if ( $pid ) { |
|
212
by Daniel Nichter
Update Daemon in all tools (bug 944420). |
2137 |
PTDEBUG && _d('Parent PID', $PID, 'exiting after forking child PID',$pid); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2138 |
exit; |
2139 |
}
|
|
2140 |
||
212
by Daniel Nichter
Update Daemon in all tools (bug 944420). |
2141 |
PTDEBUG && _d('Daemonizing child PID', $PID); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2142 |
$self->{PID_owner} = $PID; |
2143 |
$self->{child} = 1; |
|
2144 |
||
2145 |
POSIX::setsid() or die "Cannot start a new session: $OS_ERROR"; |
|
2146 |
chdir '/' or die "Cannot chdir to /: $OS_ERROR"; |
|
2147 |
||
2148 |
$self->_make_PID_file(); |
|
2149 |
||
2150 |
$OUTPUT_AUTOFLUSH = 1; |
|
2151 |
||
212
by Daniel Nichter
Update Daemon in all tools (bug 944420). |
2152 |
PTDEBUG && _d('Redirecting STDIN to /dev/null'); |
2153 |
close STDIN; |
|
2154 |
open STDIN, '/dev/null' |
|
2155 |
or die "Cannot reopen STDIN to /dev/null: $OS_ERROR"; |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2156 |
|
2157 |
if ( $self->{log_file} ) { |
|
212
by Daniel Nichter
Update Daemon in all tools (bug 944420). |
2158 |
PTDEBUG && _d('Redirecting STDOUT and STDERR to', $self->{log_file}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2159 |
close STDOUT; |
2160 |
open STDOUT, '>>', $self->{log_file} |
|
2161 |
or die "Cannot open log file $self->{log_file}: $OS_ERROR"; |
|
2162 |
||
2163 |
close STDERR; |
|
2164 |
open STDERR, ">&STDOUT" |
|
2165 |
or die "Cannot dupe STDERR to STDOUT: $OS_ERROR"; |
|
2166 |
}
|
|
2167 |
else { |
|
2168 |
if ( -t STDOUT ) { |
|
212
by Daniel Nichter
Update Daemon in all tools (bug 944420). |
2169 |
PTDEBUG && _d('No log file and STDOUT is a terminal;', |
2170 |
'redirecting to /dev/null'); |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2171 |
close STDOUT; |
2172 |
open STDOUT, '>', '/dev/null' |
|
2173 |
or die "Cannot reopen STDOUT to /dev/null: $OS_ERROR"; |
|
2174 |
}
|
|
2175 |
if ( -t STDERR ) { |
|
212
by Daniel Nichter
Update Daemon in all tools (bug 944420). |
2176 |
PTDEBUG && _d('No log file and STDERR is a terminal;', |
2177 |
'redirecting to /dev/null'); |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2178 |
close STDERR; |
2179 |
open STDERR, '>', '/dev/null' |
|
2180 |
or die "Cannot reopen STDERR to /dev/null: $OS_ERROR"; |
|
2181 |
}
|
|
2182 |
}
|
|
2183 |
||
2184 |
return; |
|
2185 |
}
|
|
2186 |
||
2187 |
sub check_PID_file { |
|
2188 |
my ( $self, $file ) = @_; |
|
2189 |
my $PID_file = $self ? $self->{PID_file} : $file; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2190 |
PTDEBUG && _d('Checking PID file', $PID_file); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2191 |
if ( $PID_file && -f $PID_file ) { |
2192 |
my $pid; |
|
94.18.3
by Daniel Nichter
Update Daemon.pm in all tools. |
2193 |
eval { |
2194 |
chomp($pid = (slurp_file($PID_file) || '')); |
|
2195 |
};
|
|
2196 |
if ( $EVAL_ERROR ) { |
|
2197 |
die "The PID file $PID_file already exists but it cannot be read: " |
|
2198 |
. $EVAL_ERROR; |
|
2199 |
}
|
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2200 |
PTDEBUG && _d('PID file exists; it contains PID', $pid); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2201 |
if ( $pid ) { |
2202 |
my $pid_is_alive = kill 0, $pid; |
|
2203 |
if ( $pid_is_alive ) { |
|
2204 |
die "The PID file $PID_file already exists " |
|
2205 |
. " and the PID that it contains, $pid, is running"; |
|
2206 |
}
|
|
2207 |
else { |
|
2208 |
warn "Overwriting PID file $PID_file because the PID that it " |
|
2209 |
. "contains, $pid, is not running"; |
|
2210 |
}
|
|
2211 |
}
|
|
2212 |
else { |
|
2213 |
die "The PID file $PID_file already exists but it does not " |
|
2214 |
. "contain a PID"; |
|
2215 |
}
|
|
2216 |
}
|
|
2217 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2218 |
PTDEBUG && _d('No PID file'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2219 |
}
|
2220 |
return; |
|
2221 |
}
|
|
2222 |
||
2223 |
sub make_PID_file { |
|
2224 |
my ( $self ) = @_; |
|
2225 |
if ( exists $self->{child} ) { |
|
2226 |
die "Do not call Daemon::make_PID_file() for daemonized scripts"; |
|
2227 |
}
|
|
2228 |
$self->_make_PID_file(); |
|
2229 |
$self->{PID_owner} = $PID; |
|
2230 |
return; |
|
2231 |
}
|
|
2232 |
||
2233 |
sub _make_PID_file { |
|
2234 |
my ( $self ) = @_; |
|
2235 |
||
2236 |
my $PID_file = $self->{PID_file}; |
|
2237 |
if ( !$PID_file ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2238 |
PTDEBUG && _d('No PID file to create'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2239 |
return; |
2240 |
}
|
|
2241 |
||
2242 |
$self->check_PID_file(); |
|
2243 |
||
2244 |
open my $PID_FH, '>', $PID_file |
|
2245 |
or die "Cannot open PID file $PID_file: $OS_ERROR"; |
|
2246 |
print $PID_FH $PID |
|
2247 |
or die "Cannot print to PID file $PID_file: $OS_ERROR"; |
|
2248 |
close $PID_FH |
|
2249 |
or die "Cannot close PID file $PID_file: $OS_ERROR"; |
|
2250 |
||
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2251 |
PTDEBUG && _d('Created PID file:', $self->{PID_file}); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2252 |
return; |
2253 |
}
|
|
2254 |
||
2255 |
sub _remove_PID_file { |
|
2256 |
my ( $self ) = @_; |
|
2257 |
if ( $self->{PID_file} && -f $self->{PID_file} ) { |
|
2258 |
unlink $self->{PID_file} |
|
2259 |
or warn "Cannot remove PID file $self->{PID_file}: $OS_ERROR"; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2260 |
PTDEBUG && _d('Removed PID file'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2261 |
}
|
2262 |
else { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
2263 |
PTDEBUG && _d('No PID to remove'); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2264 |
}
|
2265 |
return; |
|
2266 |
}
|
|
2267 |
||
2268 |
sub DESTROY { |
|
2269 |
my ( $self ) = @_; |
|
2270 |
||
2271 |
$self->_remove_PID_file() if ($self->{PID_owner} || 0) == $PID; |
|
2272 |
||
2273 |
return; |
|
2274 |
}
|
|
2275 |
||
94.18.3
by Daniel Nichter
Update Daemon.pm in all tools. |
2276 |
sub slurp_file { |
2277 |
my ($file) = @_; |
|
2278 |
return unless $file; |
|
2279 |
open my $fh, "<", $file or die "Cannot open $file: $OS_ERROR"; |
|
2280 |
return do { local $/; <$fh> }; |
|
2281 |
}
|
|
2282 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2283 |
sub _d { |
2284 |
my ($package, undef, $line) = caller 0; |
|
2285 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
2286 |
map { defined $_ ? $_ : 'undef' } |
|
2287 |
@_; |
|
2288 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
2289 |
}
|
|
2290 |
||
2291 |
1; |
|
19
by Daniel Nichter
Update all modules in all tools. Remove pt-table-usage. Make update-modules ignore non-Perl tools. |
2292 |
}
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
2293 |
# ###########################################################################
|
2294 |
# End Daemon package
|
|
2295 |
# ###########################################################################
|
|
2296 |
||
2297 |
# ###########################################################################
|
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2298 |
# HTTPMicro package
|
2299 |
# This package is a copy without comments from the original. The original
|
|
2300 |
# with comments and its test file can be found in the Bazaar repository at,
|
|
2301 |
# lib/HTTPMicro.pm
|
|
2302 |
# t/lib/HTTPMicro.t
|
|
2303 |
# See https://launchpad.net/percona-toolkit for more information.
|
|
2304 |
# ###########################################################################
|
|
2305 |
{
|
|
2306 |
||
350.1.18
by fraserb at gmail
Fix several test failures by doing s/HTTP::Micro/HTTPMicro/ |
2307 |
package HTTPMicro; |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2308 |
BEGIN { |
350.1.18
by fraserb at gmail
Fix several test failures by doing s/HTTP::Micro/HTTPMicro/ |
2309 |
$HTTPMicro::VERSION = '0.001'; |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2310 |
}
|
2311 |
use strict; |
|
2312 |
use warnings; |
|
2313 |
||
2314 |
use Carp (); |
|
2315 |
||
2316 |
||
2317 |
my @attributes; |
|
2318 |
BEGIN { |
|
2319 |
@attributes = qw(agent timeout); |
|
2320 |
no strict 'refs'; |
|
2321 |
for my $accessor ( @attributes ) { |
|
2322 |
*{$accessor} = sub { |
|
2323 |
@_ > 1 ? $_[0]->{$accessor} = $_[1] : $_[0]->{$accessor}; |
|
2324 |
};
|
|
2325 |
}
|
|
2326 |
}
|
|
2327 |
||
2328 |
sub new { |
|
2329 |
my($class, %args) = @_; |
|
2330 |
(my $agent = $class) =~ s{::}{-}g; |
|
2331 |
my $self = { |
|
2332 |
agent => $agent . "/" . ($class->VERSION || 0), |
|
2333 |
timeout => 60, |
|
2334 |
};
|
|
2335 |
for my $key ( @attributes ) { |
|
2336 |
$self->{$key} = $args{$key} if exists $args{$key} |
|
2337 |
}
|
|
2338 |
return bless $self, $class; |
|
2339 |
}
|
|
2340 |
||
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2341 |
my %DefaultPort = ( |
2342 |
http => 80, |
|
2343 |
https => 443, |
|
2344 |
);
|
|
2345 |
||
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2346 |
sub request { |
2347 |
my ($self, $method, $url, $args) = @_; |
|
2348 |
@_ == 3 || (@_ == 4 && ref $args eq 'HASH') |
|
2349 |
or Carp::croak(q/Usage: $http->request(METHOD, URL, [HASHREF])/); |
|
2350 |
$args ||= {}; # we keep some state in this during _request |
|
2351 |
||
2352 |
my $response; |
|
2353 |
for ( 0 .. 1 ) { |
|
2354 |
$response = eval { $self->_request($method, $url, $args) }; |
|
2355 |
last unless $@ && $method eq 'GET' |
|
2356 |
&& $@ =~ m{^(?:Socket closed|Unexpected end)}; |
|
2357 |
}
|
|
2358 |
||
2359 |
if (my $e = "$@") { |
|
2360 |
$response = { |
|
2361 |
success => q{}, |
|
2362 |
status => 599, |
|
2363 |
reason => 'Internal Exception', |
|
2364 |
content => $e, |
|
2365 |
headers => { |
|
2366 |
'content-type' => 'text/plain', |
|
2367 |
'content-length' => length $e, |
|
2368 |
}
|
|
2369 |
};
|
|
2370 |
}
|
|
2371 |
return $response; |
|
2372 |
}
|
|
2373 |
||
2374 |
sub _request { |
|
2375 |
my ($self, $method, $url, $args) = @_; |
|
2376 |
||
2377 |
my ($scheme, $host, $port, $path_query) = $self->_split_url($url); |
|
2378 |
||
2379 |
my $request = { |
|
2380 |
method => $method, |
|
2381 |
scheme => $scheme, |
|
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2382 |
host_port => ($port == $DefaultPort{$scheme} ? $host : "$host:$port"), |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2383 |
uri => $path_query, |
2384 |
headers => {}, |
|
2385 |
};
|
|
2386 |
||
350.1.18
by fraserb at gmail
Fix several test failures by doing s/HTTP::Micro/HTTPMicro/ |
2387 |
my $handle = HTTPMicro::Handle->new(timeout => $self->{timeout}); |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2388 |
|
2389 |
$handle->connect($scheme, $host, $port); |
|
2390 |
||
2391 |
$self->_prepare_headers_and_cb($request, $args); |
|
2392 |
$handle->write_request_header(@{$request}{qw/method uri headers/}); |
|
2393 |
$handle->write_content_body($request) if $request->{content}; |
|
2394 |
||
2395 |
my $response; |
|
2396 |
do { $response = $handle->read_response_header } |
|
2397 |
until (substr($response->{status},0,1) ne '1'); |
|
2398 |
||
2399 |
if (!($method eq 'HEAD' || $response->{status} =~ /^[23]04/)) { |
|
2400 |
$response->{content} = ''; |
|
2401 |
$handle->read_content_body(sub { $_[1]->{content} .= $_[0] }, $response); |
|
2402 |
}
|
|
2403 |
||
2404 |
$handle->close; |
|
2405 |
$response->{success} = substr($response->{status},0,1) eq '2'; |
|
2406 |
return $response; |
|
2407 |
}
|
|
2408 |
||
2409 |
sub _prepare_headers_and_cb { |
|
2410 |
my ($self, $request, $args) = @_; |
|
2411 |
||
2412 |
for ($args->{headers}) { |
|
2413 |
next unless defined; |
|
2414 |
while (my ($k, $v) = each %$_) { |
|
2415 |
$request->{headers}{lc $k} = $v; |
|
2416 |
}
|
|
2417 |
}
|
|
2418 |
$request->{headers}{'host'} = $request->{host_port}; |
|
2419 |
$request->{headers}{'connection'} = "close"; |
|
2420 |
$request->{headers}{'user-agent'} ||= $self->{agent}; |
|
2421 |
||
2422 |
if (defined $args->{content}) { |
|
2423 |
$request->{headers}{'content-type'} ||= "application/octet-stream"; |
|
2424 |
utf8::downgrade($args->{content}, 1) |
|
2425 |
or Carp::croak(q/Wide character in request message body/); |
|
2426 |
$request->{headers}{'content-length'} = length $args->{content}; |
|
2427 |
$request->{content} = $args->{content}; |
|
2428 |
}
|
|
2429 |
return; |
|
2430 |
}
|
|
2431 |
||
2432 |
sub _split_url { |
|
2433 |
my $url = pop; |
|
2434 |
||
2435 |
my ($scheme, $authority, $path_query) = $url =~ m<\A([^:/?#]+)://([^/?#]*)([^#]*)> |
|
2436 |
or Carp::croak(qq/Cannot parse URL: '$url'/); |
|
2437 |
||
2438 |
$scheme = lc $scheme; |
|
2439 |
$path_query = "/$path_query" unless $path_query =~ m<\A/>; |
|
2440 |
||
2441 |
my $host = (length($authority)) ? lc $authority : 'localhost'; |
|
2442 |
$host =~ s/\A[^@]*@//; # userinfo |
|
2443 |
my $port = do { |
|
2444 |
$host =~ s/:([0-9]*)\z// && length $1 |
|
2445 |
? $1 |
|
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2446 |
: $DefaultPort{$scheme} |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2447 |
};
|
2448 |
||
2449 |
return ($scheme, $host, $port, $path_query); |
|
2450 |
}
|
|
2451 |
||
2452 |
package
|
|
350.1.18
by fraserb at gmail
Fix several test failures by doing s/HTTP::Micro/HTTPMicro/ |
2453 |
HTTPMicro::Handle; # hide from PAUSE/indexers |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2454 |
use strict; |
2455 |
use warnings; |
|
2456 |
||
2457 |
use Carp qw[croak]; |
|
2458 |
use Errno qw[EINTR EPIPE]; |
|
2459 |
use IO::Socket qw[SOCK_STREAM]; |
|
2460 |
||
2461 |
sub BUFSIZE () { 32768 } |
|
2462 |
||
2463 |
my $Printable = sub { |
|
2464 |
local $_ = shift; |
|
2465 |
s/\r/\\r/g; |
|
2466 |
s/\n/\\n/g; |
|
2467 |
s/\t/\\t/g; |
|
2468 |
s/([^\x20-\x7E])/sprintf('\\x%.2X', ord($1))/ge; |
|
2469 |
$_; |
|
2470 |
};
|
|
2471 |
||
2472 |
sub new { |
|
2473 |
my ($class, %args) = @_; |
|
2474 |
return bless { |
|
2475 |
rbuf => '', |
|
2476 |
timeout => 60, |
|
2477 |
max_line_size => 16384, |
|
2478 |
%args
|
|
2479 |
}, $class; |
|
2480 |
}
|
|
2481 |
||
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2482 |
my $ssl_verify_args = { |
2483 |
check_cn => "when_only", |
|
2484 |
wildcards_in_alt => "anywhere", |
|
2485 |
wildcards_in_cn => "anywhere" |
|
2486 |
};
|
|
2487 |
||
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2488 |
sub connect { |
2489 |
@_ == 4 || croak(q/Usage: $handle->connect(scheme, host, port)/); |
|
2490 |
my ($self, $scheme, $host, $port) = @_; |
|
2491 |
||
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2492 |
if ( $scheme eq 'https' ) { |
2493 |
eval "require IO::Socket::SSL" |
|
2494 |
unless exists $INC{'IO/Socket/SSL.pm'}; |
|
2495 |
croak(qq/IO::Socket::SSL must be installed for https support\n/) |
|
2496 |
unless $INC{'IO/Socket/SSL.pm'}; |
|
2497 |
}
|
|
2498 |
elsif ( $scheme ne 'http' ) { |
|
2499 |
croak(qq/Unsupported URL scheme '$scheme'\n/); |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2500 |
}
|
2501 |
||
2502 |
$self->{fh} = 'IO::Socket::INET'->new( |
|
2503 |
PeerHost => $host, |
|
2504 |
PeerPort => $port, |
|
2505 |
Proto => 'tcp', |
|
2506 |
Type => SOCK_STREAM, |
|
2507 |
Timeout => $self->{timeout} |
|
2508 |
) or croak(qq/Could not connect to '$host:$port': $@/); |
|
2509 |
||
2510 |
binmode($self->{fh}) |
|
2511 |
or croak(qq/Could not binmode() socket: '$!'/); |
|
2512 |
||
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2513 |
if ( $scheme eq 'https') { |
2514 |
IO::Socket::SSL->start_SSL($self->{fh}); |
|
2515 |
ref($self->{fh}) eq 'IO::Socket::SSL' |
|
2516 |
or die(qq/SSL connection failed for $host\n/); |
|
395.1.8
by Brian Fraser
HTTPMicro: Inline part of IO::Socket::SSL for cases when the local version of the module isn't high enough to support ->verify_hostname(), like in centos5 |
2517 |
if ( $self->{fh}->can("verify_hostname") ) { |
2518 |
$self->{fh}->verify_hostname( $host, $ssl_verify_args ); |
|
2519 |
}
|
|
2520 |
else { |
|
2521 |
my $fh = $self->{fh}; |
|
2522 |
_verify_hostname_of_cert($host, _peer_certificate($fh), $ssl_verify_args) |
|
2523 |
or die(qq/SSL certificate not valid for $host\n/); |
|
2524 |
}
|
|
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
2525 |
}
|
2526 |
||
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2527 |
$self->{host} = $host; |
2528 |
$self->{port} = $port; |
|
2529 |
||
2530 |
return $self; |
|
2531 |
}
|
|
2532 |
||
2533 |
sub close { |
|
2534 |
@_ == 1 || croak(q/Usage: $handle->close()/); |
|
2535 |
my ($self) = @_; |
|
2536 |
CORE::close($self->{fh}) |
|
2537 |
or croak(qq/Could not close socket: '$!'/); |
|
2538 |
}
|
|
2539 |
||
2540 |
sub write { |
|
2541 |
@_ == 2 || croak(q/Usage: $handle->write(buf)/); |
|
2542 |
my ($self, $buf) = @_; |
|
2543 |
||
2544 |
my $len = length $buf; |
|
2545 |
my $off = 0; |
|
2546 |
||
2547 |
local $SIG{PIPE} = 'IGNORE'; |
|
2548 |
||
2549 |
while () { |
|
2550 |
$self->can_write |
|
2551 |
or croak(q/Timed out while waiting for socket to become ready for writing/); |
|
2552 |
my $r = syswrite($self->{fh}, $buf, $len, $off); |
|
2553 |
if (defined $r) { |
|
2554 |
$len -= $r; |
|
2555 |
$off += $r; |
|
2556 |
last unless $len > 0; |
|
2557 |
}
|
|
2558 |
elsif ($! == EPIPE) { |
|
2559 |
croak(qq/Socket closed by remote server: $!/); |
|
2560 |
}
|
|
2561 |
elsif ($! != EINTR) { |
|
2562 |
croak(qq/Could not write to socket: '$!'/); |
|
2563 |
}
|
|
2564 |
}
|
|
2565 |
return $off; |
|
2566 |
}
|
|
2567 |
||
2568 |
sub read { |
|
2569 |
@_ == 2 || @_ == 3 || croak(q/Usage: $handle->read(len)/); |
|
2570 |
my ($self, $len) = @_; |
|
2571 |
||
2572 |
my $buf = ''; |
|
2573 |
my $got = length $self->{rbuf}; |
|
2574 |
||
2575 |
if ($got) { |
|
2576 |
my $take = ($got < $len) ? $got : $len; |
|
2577 |
$buf = substr($self->{rbuf}, 0, $take, ''); |
|
2578 |
$len -= $take; |
|
2579 |
}
|
|
2580 |
||
2581 |
while ($len > 0) { |
|
2582 |
$self->can_read |
|
2583 |
or croak(q/Timed out while waiting for socket to become ready for reading/); |
|
2584 |
my $r = sysread($self->{fh}, $buf, $len, length $buf); |
|
2585 |
if (defined $r) { |
|
2586 |
last unless $r; |
|
2587 |
$len -= $r; |
|
2588 |
}
|
|
2589 |
elsif ($! != EINTR) { |
|
2590 |
croak(qq/Could not read from socket: '$!'/); |
|
2591 |
}
|
|
2592 |
}
|
|
2593 |
if ($len) { |
|
2594 |
croak(q/Unexpected end of stream/); |
|
2595 |
}
|
|
2596 |
return $buf; |
|
2597 |
}
|
|
2598 |
||
2599 |
sub readline { |
|
2600 |
@_ == 1 || croak(q/Usage: $handle->readline()/); |
|
2601 |
my ($self) = @_; |
|
2602 |
||
2603 |
while () { |
|
2604 |
if ($self->{rbuf} =~ s/\A ([^\x0D\x0A]* \x0D?\x0A)//x) { |
|
2605 |
return $1; |
|
2606 |
}
|
|
2607 |
$self->can_read |
|
2608 |
or croak(q/Timed out while waiting for socket to become ready for reading/); |
|
2609 |
my $r = sysread($self->{fh}, $self->{rbuf}, BUFSIZE, length $self->{rbuf}); |
|
2610 |
if (defined $r) { |
|
2611 |
last unless $r; |
|
2612 |
}
|
|
2613 |
elsif ($! != EINTR) { |
|
2614 |
croak(qq/Could not read from socket: '$!'/); |
|
2615 |
}
|
|
2616 |
}
|
|
2617 |
croak(q/Unexpected end of stream while looking for line/); |
|
2618 |
}
|
|
2619 |
||
2620 |
sub read_header_lines { |
|
2621 |
@_ == 1 || @_ == 2 || croak(q/Usage: $handle->read_header_lines([headers])/); |
|
2622 |
my ($self, $headers) = @_; |
|
2623 |
$headers ||= {}; |
|
2624 |
my $lines = 0; |
|
2625 |
my $val; |
|
2626 |
||
2627 |
while () { |
|
2628 |
my $line = $self->readline; |
|
2629 |
||
2630 |
if ($line =~ /\A ([^\x00-\x1F\x7F:]+) : [\x09\x20]* ([^\x0D\x0A]*)/x) { |
|
2631 |
my ($field_name) = lc $1; |
|
2632 |
$val = \($headers->{$field_name} = $2); |
|
2633 |
}
|
|
2634 |
elsif ($line =~ /\A [\x09\x20]+ ([^\x0D\x0A]*)/x) { |
|
2635 |
$val
|
|
2636 |
or croak(q/Unexpected header continuation line/); |
|
2637 |
next unless length $1; |
|
2638 |
$$val .= ' ' if length $$val; |
|
2639 |
$$val .= $1; |
|
2640 |
}
|
|
2641 |
elsif ($line =~ /\A \x0D?\x0A \z/x) { |
|
2642 |
last; |
|
2643 |
}
|
|
2644 |
else { |
|
2645 |
croak(q/Malformed header line: / . $Printable->($line)); |
|
2646 |
}
|
|
2647 |
}
|
|
2648 |
return $headers; |
|
2649 |
}
|
|
2650 |
||
2651 |
sub write_header_lines { |
|
2652 |
(@_ == 2 && ref $_[1] eq 'HASH') || croak(q/Usage: $handle->write_header_lines(headers)/); |
|
2653 |
my($self, $headers) = @_; |
|
2654 |
||
2655 |
my $buf = ''; |
|
2656 |
while (my ($k, $v) = each %$headers) { |
|
2657 |
my $field_name = lc $k; |
|
2658 |
$field_name =~ /\A [\x21\x23-\x27\x2A\x2B\x2D\x2E\x30-\x39\x41-\x5A\x5E-\x7A\x7C\x7E]+ \z/x |
|
2659 |
or croak(q/Invalid HTTP header field name: / . $Printable->($field_name)); |
|
2660 |
$field_name =~ s/\b(\w)/\u$1/g; |
|
2661 |
$buf .= "$field_name: $v\x0D\x0A"; |
|
2662 |
}
|
|
2663 |
$buf .= "\x0D\x0A"; |
|
2664 |
return $self->write($buf); |
|
2665 |
}
|
|
2666 |
||
2667 |
sub read_content_body { |
|
2668 |
@_ == 3 || @_ == 4 || croak(q/Usage: $handle->read_content_body(callback, response, [read_length])/); |
|
2669 |
my ($self, $cb, $response, $len) = @_; |
|
2670 |
$len ||= $response->{headers}{'content-length'}; |
|
2671 |
||
2672 |
croak("No content-length in the returned response, and this " |
|
2673 |
. "UA doesn't implement chunking") unless defined $len; |
|
2674 |
||
2675 |
while ($len > 0) { |
|
2676 |
my $read = ($len > BUFSIZE) ? BUFSIZE : $len; |
|
2677 |
$cb->($self->read($read), $response); |
|
2678 |
$len -= $read; |
|
2679 |
}
|
|
2680 |
||
2681 |
return; |
|
2682 |
}
|
|
2683 |
||
2684 |
sub write_content_body { |
|
2685 |
@_ == 2 || croak(q/Usage: $handle->write_content_body(request)/); |
|
2686 |
my ($self, $request) = @_; |
|
2687 |
my ($len, $content_length) = (0, $request->{headers}{'content-length'}); |
|
2688 |
||
2689 |
$len += $self->write($request->{content}); |
|
2690 |
||
2691 |
$len == $content_length |
|
2692 |
or croak(qq/Content-Length missmatch (got: $len expected: $content_length)/); |
|
2693 |
||
2694 |
return $len; |
|
2695 |
}
|
|
2696 |
||
2697 |
sub read_response_header { |
|
2698 |
@_ == 1 || croak(q/Usage: $handle->read_response_header()/); |
|
2699 |
my ($self) = @_; |
|
2700 |
||
2701 |
my $line = $self->readline; |
|
2702 |
||
2703 |
$line =~ /\A (HTTP\/(0*\d+\.0*\d+)) [\x09\x20]+ ([0-9]{3}) [\x09\x20]+ ([^\x0D\x0A]*) \x0D?\x0A/x |
|
2704 |
or croak(q/Malformed Status-Line: / . $Printable->($line)); |
|
2705 |
||
2706 |
my ($protocol, $version, $status, $reason) = ($1, $2, $3, $4); |
|
2707 |
||
2708 |
return { |
|
2709 |
status => $status, |
|
2710 |
reason => $reason, |
|
2711 |
headers => $self->read_header_lines, |
|
2712 |
protocol => $protocol, |
|
2713 |
};
|
|
2714 |
}
|
|
2715 |
||
2716 |
sub write_request_header { |
|
2717 |
@_ == 4 || croak(q/Usage: $handle->write_request_header(method, request_uri, headers)/); |
|
2718 |
my ($self, $method, $request_uri, $headers) = @_; |
|
2719 |
||
2720 |
return $self->write("$method $request_uri HTTP/1.1\x0D\x0A") |
|
2721 |
+ $self->write_header_lines($headers); |
|
2722 |
}
|
|
2723 |
||
2724 |
sub _do_timeout { |
|
2725 |
my ($self, $type, $timeout) = @_; |
|
2726 |
$timeout = $self->{timeout} |
|
2727 |
unless defined $timeout && $timeout >= 0; |
|
2728 |
||
2729 |
my $fd = fileno $self->{fh}; |
|
2730 |
defined $fd && $fd >= 0 |
|
2731 |
or croak(q/select(2): 'Bad file descriptor'/); |
|
2732 |
||
2733 |
my $initial = time; |
|
2734 |
my $pending = $timeout; |
|
2735 |
my $nfound; |
|
2736 |
||
2737 |
vec(my $fdset = '', $fd, 1) = 1; |
|
2738 |
||
2739 |
while () { |
|
2740 |
$nfound = ($type eq 'read') |
|
2741 |
? select($fdset, undef, undef, $pending) |
|
2742 |
: select(undef, $fdset, undef, $pending) ; |
|
2743 |
if ($nfound == -1) { |
|
2744 |
$! == EINTR |
|
2745 |
or croak(qq/select(2): '$!'/); |
|
2746 |
redo if !$timeout || ($pending = $timeout - (time - $initial)) > 0; |
|
2747 |
$nfound = 0; |
|
2748 |
}
|
|
2749 |
last; |
|
2750 |
}
|
|
2751 |
$! = 0; |
|
2752 |
return $nfound; |
|
2753 |
}
|
|
2754 |
||
2755 |
sub can_read { |
|
2756 |
@_ == 1 || @_ == 2 || croak(q/Usage: $handle->can_read([timeout])/); |
|
2757 |
my $self = shift; |
|
2758 |
return $self->_do_timeout('read', @_) |
|
2759 |
}
|
|
2760 |
||
2761 |
sub can_write { |
|
2762 |
@_ == 1 || @_ == 2 || croak(q/Usage: $handle->can_write([timeout])/); |
|
2763 |
my $self = shift; |
|
2764 |
return $self->_do_timeout('write', @_) |
|
2765 |
}
|
|
2766 |
||
395.1.8
by Brian Fraser
HTTPMicro: Inline part of IO::Socket::SSL for cases when the local version of the module isn't high enough to support ->verify_hostname(), like in centos5 |
2767 |
my $prog = <<'EOP'; |
2768 |
BEGIN {
|
|
2769 |
if ( defined &IO::Socket::SSL::CAN_IPV6 ) {
|
|
2770 |
*CAN_IPV6 = \*IO::Socket::SSL::CAN_IPV6;
|
|
2771 |
}
|
|
2772 |
else {
|
|
2773 |
constant->import( CAN_IPV6 => '' );
|
|
2774 |
}
|
|
2775 |
my %const = (
|
|
2776 |
NID_CommonName => 13,
|
|
2777 |
GEN_DNS => 2,
|
|
2778 |
GEN_IPADD => 7,
|
|
2779 |
);
|
|
2780 |
while ( my ($name,$value) = each %const ) {
|
|
2781 |
no strict 'refs';
|
|
2782 |
*{$name} = UNIVERSAL::can( 'Net::SSLeay', $name ) || sub { $value };
|
|
2783 |
}
|
|
2784 |
}
|
|
2785 |
{
|
|
2786 |
my %dispatcher = (
|
|
2787 |
issuer => sub { Net::SSLeay::X509_NAME_oneline( Net::SSLeay::X509_get_issuer_name( shift )) },
|
|
2788 |
subject => sub { Net::SSLeay::X509_NAME_oneline( Net::SSLeay::X509_get_subject_name( shift )) },
|
|
2789 |
);
|
|
2790 |
if ( $Net::SSLeay::VERSION >= 1.30 ) {
|
|
2791 |
$dispatcher{commonName} = sub {
|
|
2792 |
my $cn = Net::SSLeay::X509_NAME_get_text_by_NID(
|
|
2793 |
Net::SSLeay::X509_get_subject_name( shift ), NID_CommonName);
|
|
2794 |
$cn =~s{\0$}{}; # work around Bug in Net::SSLeay <1.33
|
|
2795 |
$cn;
|
|
2796 |
}
|
|
2797 |
} else {
|
|
2798 |
$dispatcher{commonName} = sub {
|
|
2799 |
croak "you need at least Net::SSLeay version 1.30 for getting commonName"
|
|
2800 |
}
|
|
2801 |
}
|
|
2802 |
||
2803 |
if ( $Net::SSLeay::VERSION >= 1.33 ) {
|
|
2804 |
$dispatcher{subjectAltNames} = sub { Net::SSLeay::X509_get_subjectAltNames( shift ) };
|
|
2805 |
} else {
|
|
2806 |
$dispatcher{subjectAltNames} = sub {
|
|
2807 |
return;
|
|
2808 |
};
|
|
2809 |
}
|
|
2810 |
||
2811 |
$dispatcher{authority} = $dispatcher{issuer};
|
|
2812 |
$dispatcher{owner} = $dispatcher{subject};
|
|
2813 |
$dispatcher{cn} = $dispatcher{commonName};
|
|
2814 |
||
2815 |
sub _peer_certificate {
|
|
2816 |
my ($self, $field) = @_;
|
|
2817 |
my $ssl = $self->_get_ssl_object or return;
|
|
2818 |
||
2819 |
my $cert = ${*$self}{_SSL_certificate}
|
|
2820 |
||= Net::SSLeay::get_peer_certificate($ssl)
|
|
2821 |
or return $self->error("Could not retrieve peer certificate");
|
|
2822 |
||
2823 |
if ($field) {
|
|
2824 |
my $sub = $dispatcher{$field} or croak
|
|
2825 |
"invalid argument for peer_certificate, valid are: ".join( " ",keys %dispatcher ).
|
|
2826 |
"\nMaybe you need to upgrade your Net::SSLeay";
|
|
2827 |
return $sub->($cert);
|
|
2828 |
} else {
|
|
2829 |
return $cert
|
|
2830 |
}
|
|
2831 |
}
|
|
2832 |
||
2833 |
||
2834 |
my %scheme = (
|
|
2835 |
ldap => {
|
|
2836 |
wildcards_in_cn => 0,
|
|
2837 |
wildcards_in_alt => 'leftmost',
|
|
2838 |
check_cn => 'always',
|
|
2839 |
},
|
|
2840 |
http => {
|
|
2841 |
wildcards_in_cn => 'anywhere',
|
|
2842 |
wildcards_in_alt => 'anywhere',
|
|
2843 |
check_cn => 'when_only',
|
|
2844 |
},
|
|
2845 |
smtp => {
|
|
2846 |
wildcards_in_cn => 0,
|
|
2847 |
wildcards_in_alt => 0,
|
|
2848 |
check_cn => 'always'
|
|
2849 |
},
|
|
2850 |
none => {}, # do not check
|
|
2851 |
);
|
|
2852 |
||
2853 |
$scheme{www} = $scheme{http}; # alias
|
|
2854 |
$scheme{xmpp} = $scheme{http}; # rfc 3920
|
|
2855 |
$scheme{pop3} = $scheme{ldap}; # rfc 2595
|
|
2856 |
$scheme{imap} = $scheme{ldap}; # rfc 2595
|
|
2857 |
$scheme{acap} = $scheme{ldap}; # rfc 2595
|
|
2858 |
$scheme{nntp} = $scheme{ldap}; # rfc 4642
|
|
2859 |
$scheme{ftp} = $scheme{http}; # rfc 4217
|
|
2860 |
||
2861 |
||
2862 |
sub _verify_hostname_of_cert {
|
|
2863 |
my $identity = shift;
|
|
2864 |
my $cert = shift;
|
|
2865 |
my $scheme = shift || 'none';
|
|
2866 |
if ( ! ref($scheme) ) {
|
|
2867 |
$scheme = $scheme{$scheme} or croak "scheme $scheme not defined";
|
|
2868 |
}
|
|
2869 |
||
2870 |
return 1 if ! %$scheme; # 'none'
|
|
2871 |
||
2872 |
my $commonName = $dispatcher{cn}->($cert);
|
|
2873 |
my @altNames = $dispatcher{subjectAltNames}->($cert);
|
|
2874 |
||
2875 |
if ( my $sub = $scheme->{callback} ) {
|
|
2876 |
return $sub->($identity,$commonName,@altNames);
|
|
2877 |
}
|
|
2878 |
||
2879 |
||
2880 |
my $ipn;
|
|
2881 |
if ( CAN_IPV6 and $identity =~m{:} ) {
|
|
2882 |
$ipn = IO::Socket::SSL::inet_pton(IO::Socket::SSL::AF_INET6,$identity)
|
|
2883 |
or croak "'$identity' is not IPv6, but neither IPv4 nor hostname";
|
|
2884 |
} elsif ( $identity =~m{^\d+\.\d+\.\d+\.\d+$} ) {
|
|
2885 |
$ipn = IO::Socket::SSL::inet_aton( $identity ) or croak "'$identity' is not IPv4, but neither IPv6 nor hostname";
|
|
2886 |
} else {
|
|
2887 |
if ( $identity =~m{[^a-zA-Z0-9_.\-]} ) {
|
|
2888 |
$identity =~m{\0} and croak("name '$identity' has \\0 byte");
|
|
2889 |
$identity = IO::Socket::SSL::idn_to_ascii($identity) or
|
|
2890 |
croak "Warning: Given name '$identity' could not be converted to IDNA!";
|
|
2891 |
}
|
|
2892 |
}
|
|
2893 |
||
2894 |
my $check_name = sub {
|
|
2895 |
my ($name,$identity,$wtyp) = @_;
|
|
2896 |
$wtyp ||= '';
|
|
2897 |
my $pattern;
|
|
2898 |
if ( $wtyp eq 'anywhere' and $name =~m{^([a-zA-Z0-9_\-]*)\*(.+)} ) {
|
|
2899 |
$pattern = qr{^\Q$1\E[a-zA-Z0-9_\-]*\Q$2\E$}i;
|
|
2900 |
} elsif ( $wtyp eq 'leftmost' and $name =~m{^\*(\..+)$} ) {
|
|
2901 |
$pattern = qr{^[a-zA-Z0-9_\-]*\Q$1\E$}i;
|
|
2902 |
} else {
|
|
2903 |
$pattern = qr{^\Q$name\E$}i;
|
|
2904 |
}
|
|
2905 |
return $identity =~ $pattern;
|
|
2906 |
};
|
|
2907 |
||
2908 |
my $alt_dnsNames = 0;
|
|
2909 |
while (@altNames) {
|
|
2910 |
my ($type, $name) = splice (@altNames, 0, 2);
|
|
2911 |
if ( $ipn and $type == GEN_IPADD ) {
|
|
2912 |
return 1 if $ipn eq $name;
|
|
2913 |
||
2914 |
} elsif ( ! $ipn and $type == GEN_DNS ) {
|
|
2915 |
$name =~s/\s+$//; $name =~s/^\s+//;
|
|
2916 |
$alt_dnsNames++;
|
|
2917 |
$check_name->($name,$identity,$scheme->{wildcards_in_alt})
|
|
2918 |
and return 1;
|
|
2919 |
}
|
|
2920 |
}
|
|
2921 |
||
2922 |
if ( ! $ipn and (
|
|
2923 |
$scheme->{check_cn} eq 'always' or
|
|
2924 |
$scheme->{check_cn} eq 'when_only' and !$alt_dnsNames)) {
|
|
2925 |
$check_name->($commonName,$identity,$scheme->{wildcards_in_cn})
|
|
2926 |
and return 1;
|
|
2927 |
}
|
|
2928 |
||
2929 |
return 0; # no match
|
|
2930 |
}
|
|
2931 |
}
|
|
2932 |
EOP
|
|
2933 |
||
2934 |
eval { require IO::Socket::SSL }; |
|
2935 |
if ( $INC{"IO/Socket/SSL.pm"} ) { |
|
2936 |
eval $prog; |
|
2937 |
die $@ if $@; |
|
2938 |
}
|
|
2939 |
||
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2940 |
1; |
2941 |
}
|
|
2942 |
# ###########################################################################
|
|
2943 |
# End HTTPMicro package
|
|
2944 |
# ###########################################################################
|
|
2945 |
||
2946 |
# ###########################################################################
|
|
522
by Daniel Nichter
Rename Pingback.pm to VersionCheck.pm. |
2947 |
# VersionCheck package
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2948 |
# This package is a copy without comments from the original. The original
|
2949 |
# with comments and its test file can be found in the Bazaar repository at,
|
|
522
by Daniel Nichter
Rename Pingback.pm to VersionCheck.pm. |
2950 |
# lib/VersionCheck.pm
|
2951 |
# t/lib/VersionCheck.t
|
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2952 |
# See https://launchpad.net/percona-toolkit for more information.
|
2953 |
# ###########################################################################
|
|
2954 |
{
|
|
522
by Daniel Nichter
Rename Pingback.pm to VersionCheck.pm. |
2955 |
package VersionCheck; |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2956 |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
2957 |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2958 |
use strict; |
2959 |
use warnings FATAL => 'all'; |
|
2960 |
use English qw(-no_match_vars); |
|
2961 |
||
2962 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
|
2963 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
2964 |
use Data::Dumper; |
2965 |
local $Data::Dumper::Indent = 1; |
|
2966 |
local $Data::Dumper::Sortkeys = 1; |
|
2967 |
local $Data::Dumper::Quotekeys = 0; |
|
2968 |
||
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
2969 |
use Digest::MD5 qw(md5_hex); |
2970 |
use Sys::Hostname qw(hostname); |
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
2971 |
use File::Basename qw(); |
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
2972 |
use File::Spec; |
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
2973 |
use FindBin qw(); |
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
2974 |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2975 |
eval { |
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
2976 |
require Percona::Toolkit; |
350.1.18
by fraserb at gmail
Fix several test failures by doing s/HTTP::Micro/HTTPMicro/ |
2977 |
require HTTPMicro; |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
2978 |
};
|
2979 |
||
526.1.4
by Daniel Nichter
Change version_check_file() to prefer global system dirs first. |
2980 |
{
|
2981 |
my $file = 'percona-version-check'; |
|
2982 |
my $home = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; |
|
2983 |
my @vc_dirs = ( |
|
2984 |
'/etc/percona', |
|
2985 |
'/etc/percona-toolkit', |
|
2986 |
'/tmp', |
|
2987 |
"$home", |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
2988 |
);
|
526.1.4
by Daniel Nichter
Change version_check_file() to prefer global system dirs first. |
2989 |
|
2990 |
sub version_check_file { |
|
2991 |
foreach my $dir ( @vc_dirs ) { |
|
2992 |
if ( -d $dir && -w $dir ) { |
|
2993 |
PTDEBUG && _d('Version check file', $file, 'in', $dir); |
|
2994 |
return $dir . '/' . $file; |
|
2995 |
}
|
|
2996 |
}
|
|
2997 |
PTDEBUG && _d('Version check file', $file, 'in', $ENV{PWD}); |
|
2998 |
return $file; # in the CWD |
|
2999 |
}
|
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3000 |
}
|
3001 |
||
3002 |
sub version_check_time_limit { |
|
3003 |
return 60 * 60 * 24; # one day |
|
3004 |
}
|
|
3005 |
||
3006 |
||
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3007 |
sub version_check { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3008 |
my (%args) = @_; |
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3009 |
|
3010 |
my $instances = $args{instances} || []; |
|
3011 |
my $instances_to_check; |
|
3012 |
||
526.1.13
by Daniel Nichter
Check for ../../.bzr for when a tool is ran as a module in a test. |
3013 |
PTDEBUG && _d('FindBin::Bin:', $FindBin::Bin); |
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
3014 |
if ( !$args{force} ) { |
526.1.13
by Daniel Nichter
Check for ../../.bzr for when a tool is ran as a module in a test. |
3015 |
if ( $FindBin::Bin |
3016 |
&& (-d "$FindBin::Bin/../.bzr" || -d "$FindBin::Bin/../../.bzr") ) { |
|
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
3017 |
PTDEBUG && _d("$FindBin::Bin/../.bzr disables --version-check"); |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3018 |
return; |
3019 |
}
|
|
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
3020 |
}
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3021 |
|
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
3022 |
eval { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3023 |
foreach my $instance ( @$instances ) { |
3024 |
my ($name, $id) = get_instance_id($instance); |
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3025 |
$instance->{name} = $name; |
3026 |
$instance->{id} = $id; |
|
3027 |
}
|
|
3028 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3029 |
push @$instances, { name => 'system', id => 0 }; |
3030 |
||
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3031 |
$instances_to_check = get_instances_to_check( |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3032 |
instances => $instances, |
3033 |
vc_file => $args{vc_file}, # testing |
|
3034 |
now => $args{now}, # testing |
|
3035 |
);
|
|
3036 |
PTDEBUG && _d(scalar @$instances_to_check, 'instances to check'); |
|
3037 |
return unless @$instances_to_check; |
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3038 |
|
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3039 |
my $protocol = 'https'; # optimistic, but... |
3040 |
eval { require IO::Socket::SSL; }; |
|
3041 |
if ( $EVAL_ERROR ) { |
|
3042 |
PTDEBUG && _d($EVAL_ERROR); |
|
3043 |
$protocol = 'http'; |
|
435.5.1
by fraserb at gmail
Removed optional_value, made --version-check have default: off, updated the tools and documentation with the changes, and added the auto value to Pingback.pm |
3044 |
}
|
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3045 |
PTDEBUG && _d('Using', $protocol); |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3046 |
|
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3047 |
my $advice = pingback( |
3048 |
instances => $instances_to_check, |
|
3049 |
protocol => $protocol, |
|
3050 |
url => $args{url} # testing |
|
3051 |
|| $ENV{PERCONA_VERSION_CHECK_URL} # testing |
|
3052 |
|| "$protocol://v.percona.com", |
|
3053 |
);
|
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3054 |
if ( $advice ) { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3055 |
PTDEBUG && _d('Advice:', Dumper($advice)); |
3056 |
if ( scalar @$advice > 1) { |
|
3057 |
print "\n# " . scalar @$advice . " software updates are " |
|
3058 |
. "available:\n"; |
|
3059 |
}
|
|
3060 |
else { |
|
3061 |
print "\n# A software update is available:\n"; |
|
3062 |
}
|
|
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
3063 |
print join("\n", map { "# * $_" } @$advice), "\n\n"; |
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3064 |
}
|
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3065 |
};
|
3066 |
if ( $EVAL_ERROR ) { |
|
3067 |
PTDEBUG && _d('Version check failed:', $EVAL_ERROR); |
|
3068 |
}
|
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3069 |
|
526.1.10
by Daniel Nichter
Update VersionCheck in all tools. |
3070 |
if ( @$instances_to_check ) { |
3071 |
eval { |
|
3072 |
update_check_times( |
|
3073 |
instances => $instances_to_check, |
|
3074 |
vc_file => $args{vc_file}, # testing |
|
3075 |
now => $args{now}, # testing |
|
3076 |
);
|
|
3077 |
};
|
|
3078 |
if ( $EVAL_ERROR ) { |
|
3079 |
PTDEBUG && _d('Error updating version check file:', $EVAL_ERROR); |
|
3080 |
}
|
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3081 |
}
|
3082 |
||
3083 |
if ( $ENV{PTDEBUG_VERSION_CHECK} ) { |
|
3084 |
warn "Exiting because the PTDEBUG_VERSION_CHECK " |
|
3085 |
. "environment variable is defined.\n"; |
|
3086 |
exit 255; |
|
3087 |
}
|
|
3088 |
||
3089 |
return; |
|
3090 |
}
|
|
3091 |
||
3092 |
sub get_instances_to_check { |
|
3093 |
my (%args) = @_; |
|
3094 |
||
3095 |
my $instances = $args{instances}; |
|
3096 |
my $now = $args{now} || int(time); |
|
3097 |
my $vc_file = $args{vc_file} || version_check_file(); |
|
3098 |
||
3099 |
if ( !-f $vc_file ) { |
|
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3100 |
PTDEBUG && _d('Version check file', $vc_file, 'does not exist;', |
3101 |
'version checking all instances'); |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3102 |
return $instances; |
3103 |
}
|
|
3104 |
||
3105 |
open my $fh, '<', $vc_file or die "Cannot open $vc_file: $OS_ERROR"; |
|
3106 |
chomp(my $file_contents = do { local $/ = undef; <$fh> }); |
|
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3107 |
PTDEBUG && _d('Version check file', $vc_file, 'contents:', $file_contents); |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3108 |
close $fh; |
3109 |
my %last_check_time_for = $file_contents =~ /^([^,]+),(.+)$/mg; |
|
3110 |
||
3111 |
my $check_time_limit = version_check_time_limit(); |
|
3112 |
my @instances_to_check; |
|
3113 |
foreach my $instance ( @$instances ) { |
|
3114 |
my $last_check_time = $last_check_time_for{ $instance->{id} }; |
|
3115 |
PTDEBUG && _d('Intsance', $instance->{id}, 'last checked', |
|
526.1.3
by Daniel Nichter
Fix get_perl_module_version(). Add 'hours until next check' to debug output. |
3116 |
$last_check_time, 'now', $now, 'diff', $now - ($last_check_time || 0), |
3117 |
'hours until next check', |
|
3118 |
sprintf '%.2f', |
|
3119 |
($check_time_limit - ($now - ($last_check_time || 0))) / 3600); |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3120 |
if ( !defined $last_check_time |
3121 |
|| ($now - $last_check_time) >= $check_time_limit ) { |
|
3122 |
PTDEBUG && _d('Time to check', Dumper($instance)); |
|
3123 |
push @instances_to_check, $instance; |
|
3124 |
}
|
|
3125 |
}
|
|
3126 |
||
3127 |
return \@instances_to_check; |
|
3128 |
}
|
|
3129 |
||
3130 |
sub update_check_times { |
|
3131 |
my (%args) = @_; |
|
3132 |
||
3133 |
my $instances = $args{instances}; |
|
3134 |
my $now = $args{now} || int(time); |
|
3135 |
my $vc_file = $args{vc_file} || version_check_file(); |
|
3136 |
PTDEBUG && _d('Updating last check time:', $now); |
|
3137 |
||
567
by Daniel Nichter
Hot-fix --version-check. |
3138 |
my %all_instances = map { |
3139 |
$_->{id} => { name => $_->{name}, ts => $now } |
|
3140 |
} @$instances; |
|
3141 |
||
3142 |
if ( -f $vc_file ) { |
|
3143 |
open my $fh, '<', $vc_file or die "Cannot read $vc_file: $OS_ERROR"; |
|
3144 |
my $contents = do { local $/ = undef; <$fh> }; |
|
3145 |
close $fh; |
|
3146 |
||
3147 |
foreach my $line ( split("\n", ($contents || '')) ) { |
|
3148 |
my ($id, $ts) = split(',', $line); |
|
3149 |
if ( !exists $all_instances{$id} ) { |
|
3150 |
$all_instances{$id} = { ts => $ts }; # original ts, not updated |
|
3151 |
}
|
|
3152 |
}
|
|
3153 |
}
|
|
3154 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3155 |
open my $fh, '>', $vc_file or die "Cannot write to $vc_file: $OS_ERROR"; |
567
by Daniel Nichter
Hot-fix --version-check. |
3156 |
foreach my $id ( sort keys %all_instances ) { |
3157 |
PTDEBUG && _d('Updated:', $id, Dumper($all_instances{$id})); |
|
3158 |
print { $fh } $id . ',' . $all_instances{$id}->{ts} . "\n"; |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3159 |
}
|
3160 |
close $fh; |
|
3161 |
||
3162 |
return; |
|
3163 |
}
|
|
3164 |
||
3165 |
sub get_instance_id { |
|
3166 |
my ($instance) = @_; |
|
3167 |
||
3168 |
my $dbh = $instance->{dbh}; |
|
3169 |
my $dsn = $instance->{dsn}; |
|
3170 |
||
3171 |
my $sql = q{SELECT CONCAT(@@hostname, @@port)}; |
|
3172 |
PTDEBUG && _d($sql); |
|
3173 |
my ($name) = eval { $dbh->selectrow_array($sql) }; |
|
3174 |
if ( $EVAL_ERROR ) { |
|
3175 |
PTDEBUG && _d($EVAL_ERROR); |
|
3176 |
$sql = q{SELECT @@hostname}; |
|
3177 |
PTDEBUG && _d($sql); |
|
3178 |
($name) = eval { $dbh->selectrow_array($sql) }; |
|
3179 |
if ( $EVAL_ERROR ) { |
|
3180 |
PTDEBUG && _d($EVAL_ERROR); |
|
3181 |
$name = ($dsn->{h} || 'localhost') . ($dsn->{P} || 3306); |
|
3182 |
}
|
|
395.1.7
by Brian Fraser
Minor update to --version-check: Let the user know if there were no suggestions |
3183 |
else { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3184 |
$sql = q{SHOW VARIABLES LIKE 'port'}; |
3185 |
PTDEBUG && _d($sql); |
|
3186 |
my (undef, $port) = eval { $dbh->selectrow_array($sql) }; |
|
3187 |
PTDEBUG && _d('port:', $port); |
|
3188 |
$name .= $port || ''; |
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3189 |
}
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3190 |
}
|
3191 |
my $id = md5_hex($name); |
|
3192 |
||
567
by Daniel Nichter
Hot-fix --version-check. |
3193 |
PTDEBUG && _d('MySQL instance:', $id, $name, Dumper($dsn)); |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3194 |
|
3195 |
return $name, $id; |
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3196 |
}
|
3197 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3198 |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3199 |
sub pingback { |
3200 |
my (%args) = @_; |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3201 |
my @required_args = qw(url instances); |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3202 |
foreach my $arg ( @required_args ) { |
3203 |
die "I need a $arg arugment" unless $args{$arg}; |
|
3204 |
}
|
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3205 |
my $url = $args{url}; |
3206 |
my $instances = $args{instances}; |
|
3207 |
||
526.1.6
by Daniel Nichter
Don't try https and http: use https if possible, else http. Lower timeout from 5 to 3 seconds. Start updating/fixing pt-archiver/version_check.t. |
3208 |
my $ua = $args{ua} || HTTPMicro->new( timeout => 3 ); |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3209 |
|
3210 |
my $response = $ua->request('GET', $url); |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3211 |
PTDEBUG && _d('Server response:', Dumper($response)); |
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3212 |
die "No response from GET $url" |
3213 |
if !$response; |
|
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
3214 |
die("GET on $url returned HTTP status $response->{status}; expected 200\n", |
3215 |
($response->{content} || '')) if $response->{status} != 200; |
|
3216 |
die("GET on $url did not return any programs to check") |
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3217 |
if !$response->{content}; |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3218 |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3219 |
my $items = parse_server_response( |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3220 |
response => $response->{content} |
3221 |
);
|
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3222 |
die "Failed to parse server requested programs: $response->{content}" |
3223 |
if !scalar keys %$items; |
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3224 |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3225 |
my $versions = get_versions( |
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3226 |
items => $items, |
3227 |
instances => $instances, |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3228 |
);
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3229 |
die "Failed to get any program versions; should have at least gotten Perl" |
3230 |
if !scalar keys %$versions; |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3231 |
|
3232 |
my $client_content = encode_client_response( |
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3233 |
items => $items, |
3234 |
versions => $versions, |
|
3235 |
general_id => md5_hex( hostname() ), |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3236 |
);
|
3237 |
||
3238 |
my $client_response = { |
|
3239 |
headers => { "X-Percona-Toolkit-Tool" => File::Basename::basename($0) }, |
|
3240 |
content => $client_content, |
|
3241 |
};
|
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3242 |
PTDEBUG && _d('Client response:', Dumper($client_response)); |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3243 |
|
3244 |
$response = $ua->request('POST', $url, $client_response); |
|
3245 |
PTDEBUG && _d('Server suggestions:', Dumper($response)); |
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3246 |
die "No response from POST $url $client_response" |
3247 |
if !$response; |
|
3248 |
die "POST $url returned HTTP status $response->{status}; expected 200" |
|
3249 |
if $response->{status} != 200; |
|
3250 |
||
3251 |
return unless $response->{content}; |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3252 |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3253 |
$items = parse_server_response( |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3254 |
response => $response->{content}, |
3255 |
split_vars => 0, |
|
3256 |
);
|
|
350.1.23
by Daniel Nichter
Put everything in Pingback::version_check(). Change HTTP::Micro to HTTPMicro in pingback(). Simplify time_to_check() a little and add more debug. Fix Pingback.t now that client response doesn't have TYPE and no response causes die. |
3257 |
die "Failed to parse server suggestions: $response->{content}" |
3258 |
if !scalar keys %$items; |
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3259 |
my @suggestions = map { $_->{vars} } |
3260 |
sort { $a->{item} cmp $b->{item} } |
|
3261 |
values %$items; |
|
3262 |
||
3263 |
return \@suggestions; |
|
3264 |
}
|
|
3265 |
||
3266 |
sub encode_client_response { |
|
3267 |
my (%args) = @_; |
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3268 |
my @required_args = qw(items versions general_id); |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3269 |
foreach my $arg ( @required_args ) { |
3270 |
die "I need a $arg arugment" unless $args{$arg}; |
|
3271 |
}
|
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3272 |
my ($items, $versions, $general_id) = @args{@required_args}; |
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3273 |
|
3274 |
my @lines; |
|
3275 |
foreach my $item ( sort keys %$items ) { |
|
3276 |
next unless exists $versions->{$item}; |
|
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3277 |
if ( ref($versions->{$item}) eq 'HASH' ) { |
3278 |
my $mysql_versions = $versions->{$item}; |
|
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
3279 |
for my $id ( sort keys %$mysql_versions ) { |
366.2.4
by Daniel Nichter
Simplify how Pingback handles MySQL instances. Remove Percona::Toolkit::slurp_file() because it was causing 'sub redefined' errors, probably due to PerconaTest::slurp_file(). Add more PTVCDEBUG statements. |
3280 |
push @lines, join(';', $id, $item, $mysql_versions->{$id}); |
3281 |
}
|
|
3282 |
}
|
|
3283 |
else { |
|
3284 |
push @lines, join(';', $general_id, $item, $versions->{$item}); |
|
3285 |
}
|
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3286 |
}
|
3287 |
||
3288 |
my $client_response = join("\n", @lines) . "\n"; |
|
3289 |
return $client_response; |
|
3290 |
}
|
|
3291 |
||
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3292 |
sub parse_server_response { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3293 |
my (%args) = @_; |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3294 |
my @required_args = qw(response); |
3295 |
foreach my $arg ( @required_args ) { |
|
3296 |
die "I need a $arg arugment" unless $args{$arg}; |
|
3297 |
}
|
|
3298 |
my ($response) = @args{@required_args}; |
|
3299 |
||
3300 |
my %items = map { |
|
3301 |
my ($item, $type, $vars) = split(";", $_); |
|
3302 |
if ( !defined $args{split_vars} || $args{split_vars} ) { |
|
3303 |
$vars = [ split(",", ($vars || '')) ]; |
|
3304 |
}
|
|
3305 |
$item => { |
|
3306 |
item => $item, |
|
3307 |
type => $type, |
|
3308 |
vars => $vars, |
|
3309 |
};
|
|
3310 |
} split("\n", $response); |
|
3311 |
||
3312 |
PTDEBUG && _d('Items:', Dumper(\%items)); |
|
3313 |
||
3314 |
return \%items; |
|
3315 |
}
|
|
3316 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3317 |
my %sub_for_type = ( |
3318 |
os_version => \&get_os_version, |
|
3319 |
perl_version => \&get_perl_version, |
|
3320 |
perl_module_version => \&get_perl_module_version, |
|
3321 |
mysql_variable => \&get_mysql_variable, |
|
3322 |
bin_version => \&get_bin_version, |
|
3323 |
);
|
|
3324 |
||
3325 |
sub valid_item { |
|
3326 |
my ($item) = @_; |
|
3327 |
return unless $item; |
|
3328 |
if ( !exists $sub_for_type{ $item->{type} } ) { |
|
3329 |
PTDEBUG && _d('Invalid type:', $item->{type}); |
|
3330 |
return 0; |
|
3331 |
}
|
|
3332 |
return 1; |
|
3333 |
}
|
|
3334 |
||
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3335 |
sub get_versions { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3336 |
my (%args) = @_; |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3337 |
my @required_args = qw(items); |
3338 |
foreach my $arg ( @required_args ) { |
|
3339 |
die "I need a $arg arugment" unless $args{$arg}; |
|
3340 |
}
|
|
3341 |
my ($items) = @args{@required_args}; |
|
3342 |
||
3343 |
my %versions; |
|
3344 |
foreach my $item ( values %$items ) { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3345 |
next unless valid_item($item); |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3346 |
eval { |
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3347 |
my $version = $sub_for_type{ $item->{type} }->( |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3348 |
item => $item, |
3349 |
instances => $args{instances}, |
|
3350 |
);
|
|
3351 |
if ( $version ) { |
|
3352 |
chomp $version unless ref($version); |
|
3353 |
$versions{$item->{item}} = $version; |
|
3354 |
}
|
|
3355 |
};
|
|
3356 |
if ( $EVAL_ERROR ) { |
|
3357 |
PTDEBUG && _d('Error getting version for', Dumper($item), $EVAL_ERROR); |
|
3358 |
}
|
|
3359 |
}
|
|
3360 |
||
3361 |
return \%versions; |
|
3362 |
}
|
|
3363 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3364 |
|
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3365 |
sub get_os_version { |
3366 |
if ( $OSNAME eq 'MSWin32' ) { |
|
3367 |
require Win32; |
|
3368 |
return Win32::GetOSDisplayName(); |
|
3369 |
}
|
|
3370 |
||
3371 |
chomp(my $platform = `uname -s`); |
|
3372 |
PTDEBUG && _d('platform:', $platform); |
|
3373 |
return $OSNAME unless $platform; |
|
3374 |
||
3375 |
chomp(my $lsb_release |
|
3376 |
= `which lsb_release 2>/dev/null | awk '{print \$1}'` || ''); |
|
3377 |
PTDEBUG && _d('lsb_release:', $lsb_release); |
|
3378 |
||
3379 |
my $release = ""; |
|
3380 |
||
3381 |
if ( $platform eq 'Linux' ) { |
|
3382 |
if ( -f "/etc/fedora-release" ) { |
|
3383 |
$release = `cat /etc/fedora-release`; |
|
3384 |
}
|
|
3385 |
elsif ( -f "/etc/redhat-release" ) { |
|
3386 |
$release = `cat /etc/redhat-release`; |
|
3387 |
}
|
|
3388 |
elsif ( -f "/etc/system-release" ) { |
|
3389 |
$release = `cat /etc/system-release`; |
|
3390 |
}
|
|
3391 |
elsif ( $lsb_release ) { |
|
3392 |
$release = `$lsb_release -ds`; |
|
3393 |
}
|
|
3394 |
elsif ( -f "/etc/lsb-release" ) { |
|
3395 |
$release = `grep DISTRIB_DESCRIPTION /etc/lsb-release`; |
|
3396 |
$release =~ s/^\w+="([^"]+)".+/$1/; |
|
3397 |
}
|
|
3398 |
elsif ( -f "/etc/debian_version" ) { |
|
3399 |
chomp(my $rel = `cat /etc/debian_version`); |
|
3400 |
$release = "Debian $rel"; |
|
3401 |
if ( -f "/etc/apt/sources.list" ) { |
|
3402 |
chomp(my $code_name = `awk '/^deb/ {print \$3}' /etc/apt/sources.list | awk -F/ '{print \$1}'| awk 'BEGIN {FS="|"} {print \$1}' | sort | uniq -c | sort -rn | head -n1 | awk '{print \$2}'`); |
|
3403 |
$release .= " ($code_name)" if $code_name; |
|
3404 |
}
|
|
3405 |
}
|
|
3406 |
elsif ( -f "/etc/os-release" ) { # openSUSE |
|
3407 |
chomp($release = `grep PRETTY_NAME /etc/os-release`); |
|
3408 |
$release =~ s/^PRETTY_NAME="(.+)"$/$1/; |
|
3409 |
}
|
|
3410 |
elsif ( `ls /etc/*release 2>/dev/null` ) { |
|
3411 |
if ( `grep DISTRIB_DESCRIPTION /etc/*release 2>/dev/null` ) { |
|
3412 |
$release = `grep DISTRIB_DESCRIPTION /etc/*release | head -n1`; |
|
3413 |
}
|
|
3414 |
else { |
|
3415 |
$release = `cat /etc/*release | head -n1`; |
|
3416 |
}
|
|
3417 |
}
|
|
3418 |
}
|
|
3419 |
elsif ( $platform =~ m/(?:BSD|^Darwin)$/ ) { |
|
3420 |
my $rel = `uname -r`; |
|
3421 |
$release = "$platform $rel"; |
|
3422 |
}
|
|
3423 |
elsif ( $platform eq "SunOS" ) { |
|
3424 |
my $rel = `head -n1 /etc/release` || `uname -r`; |
|
3425 |
$release = "$platform $rel"; |
|
3426 |
}
|
|
3427 |
||
3428 |
if ( !$release ) { |
|
3429 |
PTDEBUG && _d('Failed to get the release, using platform'); |
|
3430 |
$release = $platform; |
|
3431 |
}
|
|
3432 |
chomp($release); |
|
3433 |
||
3434 |
$release =~ s/^"|"$//g; |
|
3435 |
||
3436 |
PTDEBUG && _d('OS version =', $release); |
|
3437 |
return $release; |
|
3438 |
}
|
|
3439 |
||
3440 |
sub get_perl_version { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3441 |
my (%args) = @_; |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3442 |
my $item = $args{item}; |
3443 |
return unless $item; |
|
3444 |
||
3445 |
my $version = sprintf '%vd', $PERL_VERSION; |
|
3446 |
PTDEBUG && _d('Perl version', $version); |
|
3447 |
return $version; |
|
3448 |
}
|
|
3449 |
||
3450 |
sub get_perl_module_version { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3451 |
my (%args) = @_; |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3452 |
my $item = $args{item}; |
3453 |
return unless $item; |
|
3454 |
||
526.1.3
by Daniel Nichter
Fix get_perl_module_version(). Add 'hours until next check' to debug output. |
3455 |
my $var = '$' . $item->{item} . '::VERSION'; |
3456 |
my $version = eval "use $item->{item}; $var;"; |
|
3457 |
PTDEBUG && _d('Perl version for', $var, '=', $version); |
|
3458 |
return $version; |
|
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3459 |
}
|
3460 |
||
3461 |
sub get_mysql_variable { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3462 |
return get_from_mysql( |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3463 |
show => 'VARIABLES', |
3464 |
@_, |
|
3465 |
);
|
|
3466 |
}
|
|
3467 |
||
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3468 |
sub get_from_mysql { |
3469 |
my (%args) = @_; |
|
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3470 |
my $show = $args{show}; |
3471 |
my $item = $args{item}; |
|
3472 |
my $instances = $args{instances}; |
|
3473 |
return unless $show && $item; |
|
3474 |
||
3475 |
if ( !$instances || !@$instances ) { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3476 |
PTDEBUG && _d('Cannot check', $item, |
3477 |
'because there are no MySQL instances'); |
|
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3478 |
return; |
3479 |
}
|
|
3480 |
||
3481 |
my @versions; |
|
3482 |
my %version_for; |
|
3483 |
foreach my $instance ( @$instances ) { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3484 |
next unless $instance->{id}; # special system instance has id=0 |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3485 |
my $dbh = $instance->{dbh}; |
3486 |
local $dbh->{FetchHashKeyName} = 'NAME_lc'; |
|
3487 |
my $sql = qq/SHOW $show/; |
|
3488 |
PTDEBUG && _d($sql); |
|
3489 |
my $rows = $dbh->selectall_hashref($sql, 'variable_name'); |
|
3490 |
||
3491 |
my @versions; |
|
3492 |
foreach my $var ( @{$item->{vars}} ) { |
|
3493 |
$var = lc($var); |
|
3494 |
my $version = $rows->{$var}->{value}; |
|
3495 |
PTDEBUG && _d('MySQL version for', $item->{item}, '=', $version, |
|
3496 |
'on', $instance->{name}); |
|
3497 |
push @versions, $version; |
|
3498 |
}
|
|
3499 |
$version_for{ $instance->{id} } = join(' ', @versions); |
|
3500 |
}
|
|
3501 |
||
3502 |
return \%version_for; |
|
3503 |
}
|
|
3504 |
||
3505 |
sub get_bin_version { |
|
526.1.2
by Daniel Nichter
Update, clean up VersionCheck. Update it all tools. |
3506 |
my (%args) = @_; |
517.2.2
by Brian Fraser
Update files to use the merged Pingback+VersionCheck |
3507 |
my $item = $args{item}; |
3508 |
my $cmd = $item->{item}; |
|
3509 |
return unless $cmd; |
|
3510 |
||
3511 |
my $sanitized_command = File::Basename::basename($cmd); |
|
3512 |
PTDEBUG && _d('cmd:', $cmd, 'sanitized:', $sanitized_command); |
|
3513 |
return if $sanitized_command !~ /\A[a-zA-Z0-9_-]+\z/; |
|
3514 |
||
3515 |
my $output = `$sanitized_command --version 2>&1`; |
|
3516 |
PTDEBUG && _d('output:', $output); |
|
3517 |
||
3518 |
my ($version) = $output =~ /v?([0-9]+\.[0-9]+(?:\.[\w-]+)?)/; |
|
3519 |
||
3520 |
PTDEBUG && _d('Version for', $sanitized_command, '=', $version); |
|
3521 |
return $version; |
|
3522 |
}
|
|
3523 |
||
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3524 |
sub _d { |
3525 |
my ($package, undef, $line) = caller 0; |
|
3526 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
3527 |
map { defined $_ ? $_ : 'undef' } |
|
3528 |
@_; |
|
3529 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
3530 |
}
|
|
3531 |
||
3532 |
1; |
|
3533 |
}
|
|
3534 |
# ###########################################################################
|
|
522
by Daniel Nichter
Rename Pingback.pm to VersionCheck.pm. |
3535 |
# End VersionCheck package
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
3536 |
# ###########################################################################
|
3537 |
||
3538 |
# ###########################################################################
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3539 |
# This is a combination of modules and programs in one -- a runnable module.
|
3540 |
# http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last
|
|
3541 |
# Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition.
|
|
3542 |
#
|
|
3543 |
# Check at the end of this package for the call to main() which actually runs
|
|
3544 |
# the program.
|
|
3545 |
# ###########################################################################
|
|
5
by Daniel Nichter
Change tool packages from mk_ to pt_. |
3546 |
package pt_find; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3547 |
|
3548 |
use strict; |
|
3549 |
use warnings FATAL => 'all'; |
|
3550 |
use English qw(-no_match_vars); |
|
3551 |
||
350.1.15
by Daniel Nichter
Remove _d from Percona::Toolkit because I can't get it to export correctly. Put Percona::Toolkit in most tools. |
3552 |
use Percona::Toolkit; |
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
3553 |
use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3554 |
|
3555 |
$OUTPUT_AUTOFLUSH = 1; |
|
3556 |
||
3557 |
# ############################################################################
|
|
3558 |
# Lookup tables and global variables
|
|
3559 |
# ############################################################################
|
|
3560 |
my $o; # OptionParser obj |
|
3561 |
my %fmt_for; # Interpolated strings |
|
3562 |
my %time_for; # Holds time constants for mmin, mtime etc |
|
3563 |
my %connections; # Holds a list of thread IDs connected |
|
3564 |
my $server_id; # Holds the server's @@SERVER_ID |
|
3565 |
my $dbh; # This program's $dbh |
|
3566 |
my $exec_dbh; # The $dbh to use for exec and exec-plus |
|
3567 |
my $tp; |
|
3568 |
||
3569 |
# Functions to call while evaluating tests.
|
|
3570 |
my %test_for = ( |
|
3571 |
autoinc => sub { |
|
3572 |
my ( $table ) = @_; |
|
3573 |
return test_number($table, 'Auto_increment', $o->get('autoinc')); |
|
3574 |
},
|
|
3575 |
avgrowlen => sub { |
|
3576 |
my ( $table ) = @_; |
|
3577 |
return test_number($table, 'Avg_row_length', $o->get('avgrowlen')); |
|
3578 |
},
|
|
3579 |
checksum => sub { |
|
3580 |
my ( $table ) = @_; |
|
3581 |
return test_number($table, 'Checksum', $o->get('checksum')); |
|
3582 |
},
|
|
3583 |
cmin => sub { |
|
3584 |
my ( $table ) = @_; |
|
3585 |
return test_date($table, 'Create_time', 'cmin'); |
|
3586 |
},
|
|
3587 |
collation => sub { |
|
3588 |
my ( $table ) = @_; |
|
3589 |
return test_regex($table, 'Collation', $o->get('collation')); |
|
3590 |
},
|
|
3591 |
'column-name' => sub { |
|
3592 |
my ( $table ) = @_; |
|
3593 |
my $struct = $table->{struct}; |
|
3594 |
return unless $struct; |
|
3595 |
my $test = $o->get('column-name'); |
|
3596 |
if ( $o->get('case-insensitive') ) { |
|
3597 |
$test = "(?i)$test"; |
|
3598 |
}
|
|
3599 |
foreach my $col ( @{$struct->{cols}} ) { |
|
3600 |
return 1 if $col =~ m/$test/; |
|
3601 |
}
|
|
3602 |
return 0; |
|
3603 |
},
|
|
3604 |
'column-type' => sub { |
|
3605 |
my ( $table ) = @_; |
|
3606 |
my $struct = $table->{struct}; |
|
3607 |
return unless $struct; |
|
3608 |
my $test = lc($o->get('column-type')); |
|
3609 |
my $type_for = $struct->{type_for}; |
|
3610 |
foreach my $col ( keys %$type_for ) { |
|
3611 |
return 1 if $type_for->{$col} eq $test; |
|
3612 |
}
|
|
3613 |
return 0; |
|
3614 |
},
|
|
3615 |
comment => sub { |
|
3616 |
my ( $table ) = @_; |
|
3617 |
return test_regex($table, 'Comment', $o->get('comment')); |
|
3618 |
},
|
|
3619 |
createopts => sub { |
|
3620 |
my ( $table ) = @_; |
|
3621 |
return test_regex($table, 'Create_options', $o->get('createopts')); |
|
3622 |
},
|
|
3623 |
ctime => sub { |
|
3624 |
my ( $table ) = @_; |
|
3625 |
return test_date($table, 'Create_time', 'ctime'); |
|
3626 |
},
|
|
3627 |
datafree => sub { |
|
3628 |
my ( $table ) = @_; |
|
3629 |
return test_number($table, 'Data_free', $o->get('datafree')); |
|
3630 |
},
|
|
3631 |
datasize => sub { |
|
3632 |
my ( $table ) = @_; |
|
3633 |
return test_number($table, 'Data_length', $o->get('datasize')); |
|
3634 |
},
|
|
3635 |
dbregex => sub { |
|
3636 |
my ( $table ) = @_; |
|
3637 |
return test_regex($table, 'Database', $o->get('dbregex')); |
|
3638 |
},
|
|
3639 |
empty => sub { |
|
3640 |
my ( $table ) = @_; |
|
3641 |
return test_number($table, 'Rows', '0'); |
|
3642 |
},
|
|
3643 |
engine => sub { |
|
3644 |
my ( $table ) = @_; |
|
3645 |
return test_regex($table, 'Engine', $o->get('engine')); |
|
3646 |
},
|
|
3647 |
function => sub { |
|
3648 |
my ( $table ) = @_; |
|
3649 |
return unless $table->{stored_code} && $table->{stored_code} eq 'FUNCTION'; |
|
3650 |
my $def = $table->{def}; |
|
3651 |
return unless $def; |
|
3652 |
my $test = $o->get('function'); |
|
3653 |
if ( $o->get('case-insensitive') ) { |
|
3654 |
$test = "(?i)$test"; |
|
3655 |
}
|
|
3656 |
return $def =~ m/$test/; |
|
3657 |
},
|
|
3658 |
indexsize => sub { |
|
3659 |
my ( $table ) = @_; |
|
3660 |
return test_number($table, 'Index_length', $o->get('indexsize')); |
|
3661 |
},
|
|
3662 |
kmin => sub { |
|
3663 |
my ( $table ) = @_; |
|
3664 |
return test_date($table, 'Check_time', 'kmin'); |
|
3665 |
},
|
|
3666 |
ktime => sub { |
|
3667 |
my ( $table ) = @_; |
|
3668 |
return test_date($table, 'Check_time', 'ktime'); |
|
3669 |
},
|
|
3670 |
mmin => sub { |
|
3671 |
my ( $table ) = @_; |
|
3672 |
return test_date($table, 'Update_time', 'mmin'); |
|
3673 |
},
|
|
3674 |
mtime => sub { |
|
3675 |
my ( $table ) = @_; |
|
3676 |
return test_date($table, 'Update_time', 'mtime'); |
|
3677 |
},
|
|
3678 |
'connection-id' => sub { |
|
3679 |
my ( $table ) = @_; |
|
3680 |
my $test = $o->get('case-insensitive') ? "(?i)".$o->get('connection-id') |
|
3681 |
: $o->get('connection-id'); |
|
3682 |
my ( $pid ) = $table->{Name} =~ m/$test/; |
|
3683 |
return $pid && !exists $connections{$pid}; |
|
3684 |
},
|
|
3685 |
procedure => sub { |
|
3686 |
my ( $table ) = @_; |
|
3687 |
return unless $table->{stored_code} && $table->{stored_code} eq 'PROCEDURE'; |
|
3688 |
my $def = $table->{def}; |
|
3689 |
return unless $def; |
|
3690 |
my $test = $o->get('procedure'); |
|
3691 |
if ( $o->get('case-insensitive') ) { |
|
3692 |
$test = "(?i)$test"; |
|
3693 |
}
|
|
3694 |
return $def =~ m/$test/; |
|
3695 |
},
|
|
3696 |
rows => sub { |
|
3697 |
my ( $table ) = @_; |
|
3698 |
return test_number($table, 'Rows', $o->get('rows')); |
|
3699 |
},
|
|
3700 |
rowformat => sub { |
|
3701 |
my ( $table ) = @_; |
|
3702 |
return test_regex($table, 'Row_format', $o->get('rowformat')); |
|
3703 |
},
|
|
3704 |
'server-id' => sub { |
|
3705 |
my ( $table ) = @_; |
|
3706 |
my $test = $o->get('case-insensitive') ? "(?i)".$o->get('server-id') |
|
3707 |
: $o->get('server-id'); |
|
3708 |
my ( $sid ) = $table->{Name} =~ m/$test/; |
|
3709 |
return $sid && $sid == $server_id; |
|
3710 |
},
|
|
3711 |
tablesize => sub { |
|
3712 |
my ( $table ) = @_; |
|
3713 |
return test_number($table, 'Table_length', $o->get('tablesize')); |
|
3714 |
},
|
|
3715 |
tblregex => sub { |
|
3716 |
my ( $table ) = @_; |
|
3717 |
return test_regex($table, 'Name', $o->get('tblregex')); |
|
3718 |
},
|
|
3719 |
tblversion => sub { |
|
3720 |
my ( $table ) = @_; |
|
3721 |
return test_number($table, 'Version', $o->get('tblversion')); |
|
3722 |
},
|
|
3723 |
trigger => sub { |
|
3724 |
my ( $table ) = @_; |
|
3725 |
return unless $table->{stored_code} && $table->{stored_code} eq 'TRIGGER'; |
|
3726 |
my $def = $table->{def}; |
|
3727 |
return unless $def; |
|
3728 |
my $test = $o->get('trigger'); |
|
3729 |
if ( $o->get('case-insensitive') ) { |
|
3730 |
$test = "(?i)$test"; |
|
3731 |
}
|
|
3732 |
return $def =~ m/$test/; |
|
3733 |
},
|
|
3734 |
'trigger-table' => sub { |
|
3735 |
my ( $table ) = @_; |
|
3736 |
return unless $table->{stored_code} && $table->{stored_code} eq 'TRIGGER'; |
|
3737 |
my $test = $o->get('trigger-table'); |
|
3738 |
if ( $o->get('case-insensitive') ) { |
|
3739 |
$test = "(?i)$test"; |
|
3740 |
}
|
|
3741 |
return $table->{trigger_table} =~ m/$test/; |
|
3742 |
},
|
|
3743 |
view => sub { |
|
3744 |
my ( $table ) = @_; |
|
3745 |
my $view = $table->{view}; |
|
3746 |
return unless $view; |
|
3747 |
my $test = $o->get('view'); |
|
3748 |
if ( $o->get('case-insensitive') ) { |
|
3749 |
$test = "(?i)$test"; |
|
3750 |
}
|
|
3751 |
return $view =~ m/$test/; |
|
3752 |
},
|
|
3753 |
);
|
|
3754 |
||
3755 |
# Functions to call when doing actions
|
|
3756 |
my %action_for = ( |
|
3757 |
print => sub { |
|
3758 |
my ( $table ) = @_; |
|
3759 |
print "$table->{Database}.$table->{Name}\n"; |
|
3760 |
},
|
|
3761 |
exec => sub { |
|
3762 |
my ( $table ) = @_; |
|
3763 |
my $sql = sprintf($fmt_for{exec}->{str}, |
|
3764 |
map { defined $_ ? $_ : '' } |
|
3765 |
@{$table}{@{$fmt_for{exec}->{arg_names}}}); |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
3766 |
PTDEBUG && _d($sql); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3767 |
$exec_dbh->do($sql); |
3768 |
},
|
|
3769 |
printf => sub { |
|
3770 |
my ( $table ) = @_; |
|
3771 |
printf($fmt_for{printf}->{str}, |
|
3772 |
map { defined $_ ? $_ : '' } |
|
3773 |
@{$table}{@{$fmt_for{printf}->{arg_names}}}); |
|
3774 |
},
|
|
3775 |
);
|
|
3776 |
||
3777 |
my %arg_for = ( |
|
3778 |
a => 'Auto_increment', |
|
3779 |
A => 'Avg_row_length', |
|
3780 |
c => 'Checksum', |
|
3781 |
C => 'Create_time', |
|
3782 |
D => 'Database', |
|
3783 |
d => 'Data_length', |
|
3784 |
E => 'Engine', |
|
3785 |
F => 'Data_free', |
|
3786 |
f => 'Innodb_free', |
|
3787 |
I => 'Index_length', |
|
3788 |
K => 'Check_time', |
|
3789 |
L => 'Collation', |
|
3790 |
M => 'Max_data_length', |
|
3791 |
N => 'Name', |
|
3792 |
O => 'Comment', |
|
3793 |
P => 'Create_options', |
|
3794 |
R => 'Row_format', |
|
3795 |
S => 'Rows', |
|
3796 |
T => 'Table_length', |
|
3797 |
U => 'Update_time', |
|
3798 |
V => 'Version', |
|
3799 |
);
|
|
3800 |
||
3801 |
my @table_struct_tests = qw( |
|
3802 |
column-name
|
|
3803 |
column-type
|
|
3804 |
view
|
|
3805 |
); |
|
3806 |
||
3807 |
my @stored_code_tests = qw( |
|
3808 |
procedure
|
|
3809 |
function
|
|
3810 |
trigger
|
|
3811 |
); |
|
3812 |
||
3813 |
sub main { |
|
350.1.24
by Daniel Nichter
Add $ENV{PERCONA_VERSION_CHECK}=0 to PerconaTest so tests don't version-check. Implement v-c in half the tools. Make util/update-modules clean up its temp files. |
3814 |
local @ARGV = @_; # set global ARGV for this package |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3815 |
|
3816 |
# ########################################################################
|
|
3817 |
# Get configuration information.
|
|
3818 |
# ########################################################################
|
|
3819 |
my $q = new Quoter(); |
|
3820 |
$o = new OptionParser(); |
|
3821 |
$o->get_specs(); |
|
3822 |
$o->get_opts(); |
|
3823 |
||
3824 |
my $dp = $o->DSNParser(); |
|
531.2.1
by Daniel Nichter
Update --set-vars and ->prop() in all tools. |
3825 |
$dp->prop('set-vars', $o->set_vars()); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3826 |
|
3827 |
# Make sure OptionParser understands that these options are used.
|
|
3828 |
# cmin ctime empty kmin ktime mmin mtime exec printf
|
|
3829 |
||
3830 |
# Ensure there is a capture group.
|
|
3831 |
if ( $o->get('connection-id') && $o->get('connection-id') !~ m/\(\\d\+\)/ ) { |
|
3832 |
$o->save_error("--connection-id regex doesn't capture digits with (\\d+)"); |
|
3833 |
}
|
|
3834 |
||
3835 |
# Ensure there is a capture group.
|
|
3836 |
if ( $o->get('server-id') && $o->get('server-id') !~ m/\(\\d\+\)/ ) { |
|
3837 |
$o->save_error("--server-id regex doesn't capture digits with (\\d+)"); |
|
3838 |
}
|
|
3839 |
||
3840 |
$o->usage_or_errors(); |
|
3841 |
||
3842 |
# Interpolate strings for printf and exec. At the same time discover whether
|
|
3843 |
# I must use SHOW TABLE STATUS (slower than SHOW TABLES) to fetch data.
|
|
3844 |
my $showstat |
|
3845 |
= grep { $o->get($_) } qw( |
|
3846 |
autoinc avgrowlen checksum cmin collation comment createopts ctime
|
|
3847 |
datasize datafree empty engine indexsize kmin ktime mmin mtime rows
|
|
3848 |
rowformat tablesize tblversion); |
|
3849 |
foreach my $thing (qw(exec printf)) { |
|
3850 |
next unless $o->get($thing); |
|
3851 |
my ($str, $arg_names) = interpolate($o->get($thing)); |
|
3852 |
$fmt_for{$thing} = { str => $str, arg_names => $arg_names }; |
|
3853 |
if ( grep { $_ !~ m/^(Database|Name)$/ } @$arg_names ) { |
|
3854 |
$showstat = 1; |
|
3855 |
}
|
|
3856 |
}
|
|
3857 |
||
3858 |
# Discover if we need to parse SHOW CREATE TABLE.
|
|
3859 |
my $need_table_struct = grep { $o->got($_); } @table_struct_tests; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
3860 |
PTDEBUG && _d('Need table struct:', $need_table_struct); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3861 |
if ( $need_table_struct ) { |
3862 |
$tp = new TableParser(Quoter => $q); |
|
3863 |
}
|
|
3864 |
||
3865 |
# ########################################################################
|
|
3866 |
# If --pid, check it first since we'll die if it already exits.
|
|
3867 |
# ########################################################################
|
|
3868 |
my $daemon; |
|
3869 |
if ( $o->get('pid') ) { |
|
3870 |
# We're not daemoninzing, it just handles PID stuff. Keep $daemon
|
|
3871 |
# in the the scope of main() because when it's destroyed it automatically
|
|
3872 |
# removes the PID file.
|
|
3873 |
$daemon = new Daemon(o=>$o); |
|
3874 |
$daemon->make_PID_file(); |
|
3875 |
}
|
|
3876 |
||
3877 |
# ########################################################################
|
|
3878 |
# Get ready to do the main work.
|
|
3879 |
# ########################################################################
|
|
3880 |
||
3881 |
# Connect to the database.
|
|
3882 |
if ( $o->get('ask-pass') ) { |
|
3883 |
$o->set('password', OptionParser::prompt_noecho("Enter password: ")); |
|
3884 |
}
|
|
3885 |
||
3886 |
my $dsn = $dp->parse_options($o); |
|
3887 |
$dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 } ); |
|
3888 |
if ( $o->get('exec-dsn') ) { |
|
3889 |
my $exec_dsn = $dp->parse($o->get('exec-dsn'), $dsn); |
|
3890 |
$exec_dbh = $dp->get_dbh($dp->get_cxn_params($exec_dsn), |
|
3891 |
{ AutoCommit => 1 }); |
|
3892 |
}
|
|
3893 |
else { |
|
3894 |
$exec_dbh = $dbh; |
|
3895 |
}
|
|
3896 |
||
3897 |
# If no other action was given, the default action is to print.
|
|
3898 |
if ( !grep { $o->get($_) } qw( exec exec-plus print printf ) ) { |
|
3899 |
$o->set('print', 1); |
|
3900 |
}
|
|
3901 |
||
3902 |
# Figure out the time referred to by date/time options.
|
|
3903 |
my $basetime; |
|
3904 |
foreach my $option ( |
|
3905 |
grep { defined $o->get($_) } qw(cmin ctime kmin ktime mmin mtime) ) |
|
3906 |
{
|
|
3907 |
# Initialize a consistent point in time.
|
|
3908 |
$basetime ||= |
|
3909 |
$dbh->selectcol_arrayref( |
|
3910 |
"SELECT " . ($o->get('day-start') ? 'CURRENT_DATE' |
|
3911 |
: 'CURRENT_TIMESTAMP') |
|
3912 |
)->[0]; |
|
3913 |
||
3914 |
my ($val) = $o->get($option) =~ m/(\d+)/; |
|
3915 |
my $inter = $option =~ m/min/ ? 'MINUTE' : 'DAY'; |
|
3916 |
my $query = "SELECT DATE_SUB('$basetime', INTERVAL $val $inter)"; |
|
3917 |
$time_for{$option} = $dbh->selectcol_arrayref($query)->[0]; |
|
3918 |
}
|
|
3919 |
||
3920 |
# Fetch and save a list of processes currently running.
|
|
3921 |
if ( $o->get('connection-id') ) { |
|
3922 |
# Ensure I have the PROCESS privilege.
|
|
3923 |
my $proc = |
|
3924 |
grep { m/ALL PRIVILEGES.*?\*\.\*|PROCESS/ } |
|
3925 |
@{$dbh->selectcol_arrayref('SHOW GRANTS')}; |
|
3926 |
if ( !$proc ) { |
|
3927 |
die "--connection-id requires the PROCESS privilege for safety.\n"; |
|
3928 |
}
|
|
3929 |
}
|
|
3930 |
||
3931 |
($server_id) = $dbh->selectrow_array('SELECT @@SERVER_ID'); |
|
3932 |
||
3933 |
# Discover if we need to get stored code. Need dbh to do this.
|
|
303.2.25
by Brian Fraser
Update modules & cut the VP and Mo dependency from several tools |
3934 |
my $need_stored_code = grep { $o->got($_); } @stored_code_tests; |
350.1.24
by Daniel Nichter
Add $ENV{PERCONA_VERSION_CHECK}=0 to PerconaTest so tests don't version-check. Implement v-c in half the tools. Make util/update-modules clean up its temp files. |
3935 |
|
3936 |
# ########################################################################
|
|
3937 |
# Do the version-check
|
|
3938 |
# ########################################################################
|
|
526.1.1
by Daniel Nichter
Change --version-check to --[no]version-check, update POD text and how version_check() is called. |
3939 |
if ( $o->get('version-check') && (!$o->has('quiet') || !$o->get('quiet')) ) { |
522
by Daniel Nichter
Rename Pingback.pm to VersionCheck.pm. |
3940 |
VersionCheck::version_check( |
526.1.12
by Daniel Nichter
Add force => ->got('version-check') to tools. |
3941 |
force => $o->got('version-check'), |
526.1.1
by Daniel Nichter
Change --version-check to --[no]version-check, update POD text and how version_check() is called. |
3942 |
instances => [ { dbh => $dbh, dsn => $dsn } ], |
390.1.1
by Brian Fraser
v-c: Re-enable https by default, make --version-check take an optional protocol argument |
3943 |
);
|
350.1.24
by Daniel Nichter
Add $ENV{PERCONA_VERSION_CHECK}=0 to PerconaTest so tests don't version-check. Implement v-c in half the tools. Make util/update-modules clean up its temp files. |
3944 |
}
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3945 |
|
3946 |
# ########################################################################
|
|
3947 |
# Go do it.
|
|
3948 |
# ########################################################################
|
|
3949 |
my @databases = @ARGV ? @ARGV |
|
3950 |
: $o->get('dblike') ? @{$dbh->selectcol_arrayref('SHOW DATABASES LIKE ?', {}, $o->get('dblike'))} |
|
3951 |
: @{$dbh->selectcol_arrayref('SHOW DATABASES')}; |
|
3952 |
||
3953 |
my @exec_plus; |
|
3954 |
DATABASE:
|
|
3955 |
foreach my $database ( @databases ) { |
|
3956 |
next DATABASE if $database =~ m/^(?:information_schema|lost\+found)$/mi; |
|
3957 |
||
3958 |
my $sta = $showstat ? ' STATUS' : 'S'; |
|
3959 |
my $sth = $o->get('tbllike') |
|
3960 |
? $dbh->prepare("SHOW TABLE$sta FROM `$database` LIKE ?") |
|
3961 |
: $dbh->prepare("SHOW TABLE$sta FROM `$database`"); |
|
3962 |
||
3963 |
$sth->execute($o->get('tbllike') || ()); |
|
3964 |
my @tables = @{$sth->fetchall_arrayref({})}; |
|
3965 |
||
3966 |
# Must re-fetch every time; there are too many ways things can go wrong
|
|
3967 |
# otherwise (for example, the counter wraps over the unsigned int
|
|
3968 |
# boundary).
|
|
3969 |
if ( $o->get('connection-id') ) { |
|
3970 |
%connections = map { $_ => 1 } |
|
3971 |
@{$dbh->selectcol_arrayref('SHOW FULL PROCESSLIST')}; |
|
3972 |
}
|
|
3973 |
||
3974 |
# Make results uniform across MySQL versions, and generate additional
|
|
3975 |
# properties.
|
|
3976 |
foreach my $table ( @tables ) { |
|
3977 |
if ( $showstat ) { |
|
3978 |
my ($ib_free) = $table->{Comment} && $table->{Comment} =~ m/InnoDB free: (\d+) kB/; |
|
3979 |
$table->{Engine} ||= $table->{Type}; |
|
3980 |
$table->{Table_length} = ($table->{Index_length} || 0) + ($table->{Data_length} || 0); |
|
3981 |
$table->{Innodb_free} = $ib_free ? 1_024 * $ib_free : undef; |
|
3982 |
delete $table->{Type}; |
|
3983 |
}
|
|
3984 |
else { |
|
3985 |
my ($name) = values %$table; |
|
3986 |
$table = { Name => $name }; |
|
3987 |
}
|
|
3988 |
$table->{Database} = $database; |
|
3989 |
||
3990 |
if ( $need_table_struct ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
3991 |
PTDEBUG && _d('Getting table struct for', |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3992 |
$database, '.', $table->{Name}); |
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
3993 |
my $ddl = $tp->get_create_table($dbh, $database, $table->{Name}); |
3994 |
if ( $ddl =~ m/CREATE TABLE/ ) { |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3995 |
my $table_struct; |
3996 |
eval { $table_struct = $tp->parse($ddl) }; |
|
3997 |
if ( $EVAL_ERROR ) { |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
3998 |
PTDEBUG && _d('Failed to parse table:', $EVAL_ERROR); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
3999 |
}
|
4000 |
$table->{struct} = $table_struct; |
|
4001 |
}
|
|
94.2.184
by Baron Schwartz
Fix a bazillion tests with ANSI sql_mode, and get rid of a bunch of MySQLDump usage. |
4002 |
else { |
4003 |
$table->{view} = $ddl; |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4004 |
}
|
4005 |
}
|
|
4006 |
}
|
|
4007 |
||
4008 |
if ( $need_stored_code ) { |
|
4009 |
foreach my $type ( qw(PROCEDURE FUNCTION) ) { |
|
4010 |
my $sql = "SELECT ROUTINE_NAME AS name, " |
|
4011 |
. " ROUTINE_DEFINITION AS definition " |
|
4012 |
. " FROM INFORMATION_SCHEMA.ROUTINES " |
|
4013 |
. " WHERE ROUTINE_SCHEMA = '$database' " |
|
4014 |
. " AND ROUTINE_TYPE = '$type'"; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
4015 |
PTDEBUG && _d($sql); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4016 |
my $codes = $dbh->selectall_arrayref($sql); |
4017 |
foreach my $code ( @$codes ) { |
|
4018 |
push @tables, { |
|
4019 |
Database => $database, |
|
4020 |
Name => "$type $code->[0]", |
|
4021 |
stored_code => $type, |
|
4022 |
def => $code->[1], |
|
4023 |
};
|
|
4024 |
}
|
|
4025 |
}
|
|
4026 |
||
4027 |
my $sql = "SELECT TRIGGER_NAME AS name, " |
|
4028 |
. " ACTION_STATEMENT AS action, " |
|
4029 |
. " EVENT_OBJECT_TABLE AS `table`, " |
|
4030 |
. " EVENT_MANIPULATION AS type " |
|
4031 |
. " FROM INFORMATION_SCHEMA.TRIGGERS " |
|
4032 |
. " WHERE EVENT_OBJECT_SCHEMA = '$database'"; |
|
123
by Daniel Nichter
Change MKDEBUG to PTDEBUG. Remove 1.0.2 from release notes. |
4033 |
PTDEBUG && _d($sql); |
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4034 |
my $trigs = $dbh->selectall_arrayref($sql); |
4035 |
my $codes = $dbh->selectall_arrayref($sql); |
|
4036 |
foreach my $trig ( @$trigs ) { |
|
4037 |
push @tables, { |
|
4038 |
Database => $database, |
|
4039 |
Name => "$trig->[3] TRIGGER $trig->[0] on $trig->[2]", |
|
4040 |
trigger_table => $trig->[2], |
|
4041 |
stored_code => 'TRIGGER', |
|
4042 |
def => $trig->[1], |
|
4043 |
};
|
|
4044 |
}
|
|
4045 |
}
|
|
4046 |
||
4047 |
# Apply the tests to find the matching tables.
|
|
4048 |
@tables = grep { |
|
4049 |
my $table = $_; |
|
4050 |
my @tests = grep { $o->get($_) } keys %test_for; |
|
4051 |
if ( @tests ) { |
|
4052 |
($o->get('or') ? any($table, @tests) : all($table, @tests)); |
|
4053 |
}
|
|
4054 |
else { |
|
4055 |
$table; # No tests == all tables (issue 549). |
|
4056 |
}
|
|
4057 |
} @tables; |
|
4058 |
||
4059 |
# Quote database and table names if desired.
|
|
4060 |
if ( $o->get('quote') ) { |
|
4061 |
foreach my $table ( @tables ) { |
|
4062 |
$table->{Database} = $q->quote($table->{Database}); |
|
4063 |
$table->{Name} = $q->quote($table->{Name}); |
|
4064 |
}
|
|
4065 |
}
|
|
4066 |
||
4067 |
foreach my $table ( @tables ) { |
|
4068 |
my @actions = grep { $o->get($_) } keys %action_for; |
|
4069 |
foreach my $action ( @actions ) { |
|
4070 |
$action_for{$action}->($table); |
|
4071 |
}
|
|
4072 |
}
|
|
4073 |
||
4074 |
push @exec_plus, @tables; |
|
4075 |
}
|
|
4076 |
||
4077 |
# Handle exec-plus.
|
|
4078 |
if ( $o->get('exec-plus') ) { |
|
4079 |
my $table_list = join(', ',map {"$_->{Database}.$_->{Name}"} @exec_plus); |
|
4080 |
(my $sql = $o->get('exec-plus')) =~ s/%s/$table_list/g; |
|
4081 |
$exec_dbh->do($sql); |
|
4082 |
}
|
|
4083 |
||
4084 |
return 0; |
|
4085 |
}
|
|
4086 |
||
4087 |
# ############################################################################
|
|
4088 |
# Subroutines
|
|
4089 |
# ############################################################################
|
|
4090 |
||
4091 |
# One test is true
|
|
4092 |
sub any { |
|
4093 |
my ( $table, @tests ) = @_; |
|
4094 |
foreach my $test ( @tests ) { |
|
4095 |
return 1 if $test_for{$test}->($table); |
|
4096 |
}
|
|
4097 |
return 0; |
|
4098 |
}
|
|
4099 |
||
4100 |
# All tests are true
|
|
4101 |
sub all { |
|
4102 |
my ( $table, @tests ) = @_; |
|
4103 |
foreach my $test ( @tests ) { |
|
4104 |
return 0 unless $test_for{$test}->($table); |
|
4105 |
}
|
|
4106 |
return 1; |
|
4107 |
}
|
|
4108 |
||
4109 |
# Checks the given property of the given table to see if it passes the test
|
|
4110 |
sub test_number { |
|
4111 |
my ( $table, $prop, $test ) = @_; |
|
4112 |
||
4113 |
# E.g. --datasize NULL.
|
|
4114 |
if ( $test eq 'null' ) { |
|
4115 |
return !defined $table->{$prop}; |
|
4116 |
}
|
|
4117 |
||
4118 |
my ($num) = $test =~ m/(\d+)/; |
|
4119 |
return defined $table->{$prop} && ( |
|
4120 |
( $test =~ m/-/ && $table->{$prop} < $num ) |
|
4121 |
|| ( $test =~ m/\+/ && $table->{$prop} > $num ) |
|
4122 |
|| ( $table->{$prop} == $num )); |
|
4123 |
}
|
|
4124 |
||
4125 |
# Checks the given property of the given table to see if it passes the test
|
|
4126 |
sub test_date { |
|
4127 |
my ( $table, $prop, $test ) = @_; |
|
4128 |
return defined $table->{$prop} && ( |
|
4129 |
( $o->get($test) =~ m/-/ && $table->{$prop} gt $time_for{$test} ) |
|
4130 |
|| ( $o->get($test) =~ m/\+/ && $table->{$prop} lt $time_for{$test} ) |
|
4131 |
|| ( $table->{$prop} eq $time_for{$test} )); |
|
4132 |
}
|
|
4133 |
||
4134 |
# Checks the given property of the given table to see if it passes the test
|
|
4135 |
sub test_regex { |
|
4136 |
my ( $table, $prop, $test ) = @_; |
|
4137 |
if ( $o->get('case-insensitive') ) { |
|
4138 |
$test = "(?i)$test"; |
|
4139 |
}
|
|
4140 |
return defined $table->{$prop} && $table->{$prop} =~ m/$test/; |
|
4141 |
}
|
|
4142 |
||
4143 |
# Does string-interpolation and stuff. Returns the string and a list of the
|
|
4144 |
# properties that go into the resulting placeholders.
|
|
4145 |
sub interpolate { |
|
4146 |
my ( $str ) = @_; |
|
4147 |
my @arg_names; |
|
4148 |
||
4149 |
# Replace % directives
|
|
4150 |
$str =~ s/%(.)/(exists $arg_for{$1} && push @arg_names, $arg_for{$1} ) ? '\%s' : "$1"/xge; |
|
4151 |
||
4152 |
# Get Perl to interpolate escape sequences
|
|
4153 |
$str =~ s/(?<!\\)"/\\"/g; |
|
4154 |
$str = eval qq{"$str"}; |
|
4155 |
return ( $str, \@arg_names ); |
|
4156 |
}
|
|
4157 |
||
4158 |
sub expand { |
|
4159 |
my ( $test ) = @_; |
|
4160 |
my %factor_for = (k => 1_024, M => 1_048_576, G => 1_073_741_824); |
|
4161 |
my ($pre, $num, $factor) = $test =~ m/([+-])?(\d+)([kMG])?/; |
|
4162 |
if ( $factor ) { |
|
4163 |
$num *= $factor_for{$factor}; |
|
4164 |
}
|
|
4165 |
return "$pre$num"; |
|
4166 |
}
|
|
4167 |
||
4168 |
sub _d { |
|
4169 |
my ($package, undef, $line) = caller 0; |
|
4170 |
@_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } |
|
4171 |
map { defined $_ ? $_ : 'undef' } |
|
4172 |
@_; |
|
4173 |
print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; |
|
4174 |
}
|
|
4175 |
||
4176 |
# ############################################################################
|
|
4177 |
# Run the program.
|
|
4178 |
# ############################################################################
|
|
4179 |
if ( !caller ) { exit main(@ARGV); } |
|
4180 |
||
4181 |
1; # Because this is a module as well as a script. |
|
4182 |
||
4183 |
# ############################################################################
|
|
4184 |
# Documentation
|
|
4185 |
# ############################################################################
|
|
4186 |
||
4187 |
=pod
|
|
4188 |
||
4189 |
=head1 NAME
|
|
4190 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4191 |
pt-find - Find MySQL tables and execute actions, like GNU find.
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4192 |
|
4193 |
=head1 SYNOPSIS
|
|
4194 |
||
548.1.1
by Daniel Nichter
Update RISKS section in all tools. |
4195 |
Usage: pt-find [OPTIONS] [DATABASES]
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4196 |
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4197 |
pt-find searches for MySQL tables and executes actions, like GNU find. The
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4198 |
default action is to print the database and table name.
|
4199 |
||
4200 |
Find all tables created more than a day ago, which use the MyISAM engine, and
|
|
4201 |
print their names:
|
|
4202 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4203 |
pt-find --ctime +1 --engine MyISAM
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4204 |
|
435.1.1
by Daniel Nichter
Remove doc example that doesn't exist. |
4205 |
Find InnoDB tables and convert them to MyISAM:
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4206 |
|
435.1.1
by Daniel Nichter
Remove doc example that doesn't exist. |
4207 |
pt-find --engine InnoDB --exec "ALTER TABLE %D.%N ENGINE=MyISAM"
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4208 |
|
4209 |
Find tables created by a process that no longer exists, following the
|
|
4210 |
name_sid_pid naming convention, and remove them.
|
|
4211 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4212 |
pt-find --connection-id '\D_\d+_(\d+)$' --server-id '\D_(\d+)_\d+$' --exec-plus "DROP TABLE %s"
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4213 |
|
4214 |
Find empty tables in the test and junk databases, and delete them:
|
|
4215 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4216 |
pt-find --empty junk test --exec-plus "DROP TABLE %s"
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4217 |
|
4218 |
Find tables more than five gigabytes in total size:
|
|
4219 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4220 |
pt-find --tablesize +5G
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4221 |
|
4222 |
Find all tables and print their total data and index size, and sort largest
|
|
4223 |
tables first (sort is a different program, by the way).
|
|
4224 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4225 |
pt-find --printf "%T\t%D.%N\n" | sort -rn
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4226 |
|
4227 |
As above, but this time, insert the data back into the database for posterity:
|
|
4228 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4229 |
pt-find --noquote --exec "INSERT INTO sysdata.tblsize(db, tbl, size) VALUES('%D', '%N', %T)"
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4230 |
|
4231 |
=head1 RISKS
|
|
4232 |
||
548.1.1
by Daniel Nichter
Update RISKS section in all tools. |
4233 |
Percona Toolkit is mature, proven in the real world, and well tested,
|
4234 |
but all database tools can pose a risk to the system and the database
|
|
4235 |
server. Before using this tool, please:
|
|
4236 |
||
4237 |
=over
|
|
4238 |
||
4239 |
=item * Read the tool's documentation
|
|
4240 |
||
4241 |
=item * Review the tool's known L<"BUGS">
|
|
4242 |
||
4243 |
=item * Test the tool on a non-production server
|
|
4244 |
||
4245 |
=item * Backup your production server and verify the backups
|
|
4246 |
||
4247 |
=back
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4248 |
|
4249 |
=head1 DESCRIPTION
|
|
4250 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4251 |
pt-find looks for MySQL tables that pass the tests you specify, and executes
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4252 |
the actions you specify. The default action is to print the database and table
|
4253 |
name to STDOUT.
|
|
4254 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4255 |
pt-find is simpler than GNU find. It doesn't allow you to specify
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4256 |
complicated expressions on the command line.
|
4257 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4258 |
pt-find uses SHOW TABLES when possible, and SHOW TABLE STATUS when needed.
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4259 |
|
4260 |
=head1 OPTION TYPES
|
|
4261 |
||
4262 |
There are three types of options: normal options, which determine some behavior
|
|
4263 |
or setting; tests, which determine whether a table should be included in the
|
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4264 |
list of tables found; and actions, which do something to the tables pt-find
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4265 |
finds.
|
4266 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4267 |
pt-find uses standard Getopt::Long option parsing, so you should use double
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4268 |
dashes in front of long option names, unlike GNU find.
|
4269 |
||
4270 |
=head1 OPTIONS
|
|
4271 |
||
4272 |
This tool accepts additional command-line arguments. Refer to the
|
|
4273 |
L<"SYNOPSIS"> and usage information for details.
|
|
4274 |
||
4275 |
=over
|
|
4276 |
||
4277 |
=item --ask-pass
|
|
4278 |
||
4279 |
Prompt for a password when connecting to MySQL.
|
|
4280 |
||
4281 |
=item --case-insensitive
|
|
4282 |
||
4283 |
Specifies that all regular expression searches are case-insensitive.
|
|
4284 |
||
4285 |
=item --charset
|
|
4286 |
||
4287 |
short form: -A; type: string
|
|
4288 |
||
4289 |
Default character set. If the value is utf8, sets Perl's binmode on
|
|
4290 |
STDOUT to utf8, passes the mysql_enable_utf8 option to DBD::mysql, and runs SET
|
|
4291 |
NAMES UTF8 after connecting to MySQL. Any other value sets binmode on STDOUT
|
|
4292 |
without the utf8 layer, and runs SET NAMES after connecting to MySQL.
|
|
4293 |
||
4294 |
=item --config
|
|
4295 |
||
4296 |
type: Array
|
|
4297 |
||
4298 |
Read this comma-separated list of config files; if specified, this must be the
|
|
4299 |
first option on the command line.
|
|
4300 |
||
547.4.1
by Brian Fraser
Fix for 1008796: Several tools lack --database |
4301 |
=item --database
|
4302 |
||
4303 |
short form: -D; type: string
|
|
4304 |
||
4305 |
Connect to this database.
|
|
4306 |
||
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4307 |
=item --day-start
|
4308 |
||
4309 |
Measure times (for L<"--mmin">, etc) from the beginning of today rather than
|
|
4310 |
from the current time.
|
|
4311 |
||
4312 |
=item --defaults-file
|
|
4313 |
||
4314 |
short form: -F; type: string
|
|
4315 |
||
4316 |
Only read mysql options from the given file. You must give an absolute
|
|
4317 |
pathname.
|
|
4318 |
||
4319 |
=item --help
|
|
4320 |
||
4321 |
Show help and exit.
|
|
4322 |
||
4323 |
=item --host
|
|
4324 |
||
4325 |
short form: -h; type: string
|
|
4326 |
||
4327 |
Connect to host.
|
|
4328 |
||
4329 |
=item --or
|
|
4330 |
||
4331 |
Combine tests with OR, not AND.
|
|
4332 |
||
4333 |
By default, tests are evaluated as though there were an AND between them. This
|
|
4334 |
option switches it to OR.
|
|
4335 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4336 |
Option parsing is not implemented by pt-find itself, so you cannot specify
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4337 |
complicated expressions with parentheses and mixtures of OR and AND.
|
4338 |
||
4339 |
=item --password
|
|
4340 |
||
4341 |
short form: -p; type: string
|
|
4342 |
||
4343 |
Password to use when connecting.
|
|
4344 |
||
4345 |
=item --pid
|
|
4346 |
||
4347 |
type: string
|
|
4348 |
||
530.1.8
by Daniel Nichter
Use the same blurb for --pid in all tools. |
4349 |
Create the given PID file. The tool won't start if the PID file already
|
4350 |
exists and the PID it contains is different than the current PID. However,
|
|
4351 |
if the PID file exists and the PID it contains is no longer running, the
|
|
4352 |
tool will overwrite the PID file with the current PID. The PID file is
|
|
4353 |
removed automatically when the tool exits.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4354 |
|
4355 |
=item --port
|
|
4356 |
||
4357 |
short form: -P; type: int
|
|
4358 |
||
4359 |
Port number to use for connection.
|
|
4360 |
||
4361 |
=item --[no]quote
|
|
4362 |
||
4363 |
default: yes
|
|
4364 |
||
4365 |
Quotes MySQL identifier names with MySQL's standard backtick character.
|
|
4366 |
||
4367 |
Quoting happens after tests are run, and before actions are run.
|
|
4368 |
||
4369 |
=item --set-vars
|
|
4370 |
||
531.2.1
by Daniel Nichter
Update --set-vars and ->prop() in all tools. |
4371 |
type: Array
|
4372 |
||
4373 |
Set the MySQL variables in this comma-separated list of C<variable=value> pairs.
|
|
4374 |
||
4375 |
By default, the tool sets:
|
|
4376 |
||
4377 |
=for comment ignore-pt-internal-value
|
|
4378 |
MAGIC_set_vars
|
|
4379 |
||
4380 |
wait_timeout=10000
|
|
4381 |
||
4382 |
Variables specified on the command line override these defaults. For
|
|
4383 |
example, specifying C<--set-vars wait_timeout=500> overrides the defaultvalue of C<10000>.
|
|
4384 |
||
4385 |
The tool prints a warning and continues if a variable cannot be set.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4386 |
|
4387 |
=item --socket
|
|
4388 |
||
4389 |
short form: -S; type: string
|
|
4390 |
||
4391 |
Socket file to use for connection.
|
|
4392 |
||
4393 |
=item --user
|
|
4394 |
||
4395 |
short form: -u; type: string
|
|
4396 |
||
4397 |
User for login if not current user.
|
|
4398 |
||
4399 |
=item --version
|
|
4400 |
||
4401 |
Show version and exit.
|
|
4402 |
||
526.1.1
by Daniel Nichter
Change --version-check to --[no]version-check, update POD text and how version_check() is called. |
4403 |
=item --[no]version-check
|
4404 |
||
4405 |
default: yes
|
|
4406 |
||
4407 |
Check for the latest version of Percona Toolkit, MySQL, and other programs.
|
|
4408 |
||
4409 |
This is a standard "check for updates automatically" feature, with two
|
|
4410 |
additional features. First, the tool checks the version of other programs
|
|
4411 |
on the local system in addition to its own version. For example, it checks
|
|
4412 |
the version of every MySQL server it connects to, Perl, and the Perl module
|
|
4413 |
DBD::mysql. Second, it checks for and warns about versions with known
|
|
4414 |
problems. For example, MySQL 5.5.25 had a critical bug and was re-released
|
|
4415 |
as 5.5.25a.
|
|
4416 |
||
4417 |
Any updates or known problems are printed to STDOUT before the tool's normal
|
|
4418 |
output. This feature should never interfere with the normal operation of the
|
|
4419 |
tool.
|
|
4420 |
||
4421 |
For more information, visit L<https://www.percona.com/version-check>.
|
|
350.1.16
by Daniel Nichter
Add --[no]version-check, VersionCheck, Pingback, and HTTPMicro to tools having the version check feature. |
4422 |
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4423 |
=back
|
4424 |
||
4425 |
=head2 TESTS
|
|
4426 |
||
4427 |
Most tests check some criterion against a column of SHOW TABLE STATUS output.
|
|
4428 |
Numeric arguments can be specified as +n for greater than n, -n for less than n,
|
|
4429 |
and n for exactly n. All numeric options can take an optional suffix multiplier
|
|
4430 |
of k, M or G (1_024, 1_048_576, and 1_073_741_824 respectively). All patterns
|
|
4431 |
are Perl regular expressions (see 'man perlre') unless specified as SQL LIKE
|
|
4432 |
patterns.
|
|
4433 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4434 |
Dates and times are all measured relative to the same instant, when pt-find
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4435 |
first asks the database server what time it is. All date and time manipulation
|
4436 |
is done in SQL, so if you say to find tables modified 5 days ago, that
|
|
4437 |
translates to SELECT DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 5 DAY). If you
|
|
4438 |
specify L<"--day-start">, if course it's relative to CURRENT_DATE instead.
|
|
4439 |
||
4440 |
However, table sizes and other metrics are not consistent at an instant in
|
|
4441 |
time. It can take some time for MySQL to process all the SHOW queries, and
|
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4442 |
pt-find can't do anything about that. These measurements are as of the
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4443 |
time they're taken.
|
4444 |
||
4445 |
If you need some test that's not in this list, file a bug report and I'll
|
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4446 |
enhance pt-find for you. It's really easy.
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4447 |
|
4448 |
=over
|
|
4449 |
||
4450 |
=item --autoinc
|
|
4451 |
||
4452 |
type: string; group: Tests
|
|
4453 |
||
4454 |
Table's next AUTO_INCREMENT is n. This tests the Auto_increment column.
|
|
4455 |
||
4456 |
=item --avgrowlen
|
|
4457 |
||
4458 |
type: size; group: Tests
|
|
4459 |
||
4460 |
Table avg row len is n bytes. This tests the Avg_row_length column.
|
|
4461 |
The specified size can be "NULL" to test where Avg_row_length IS NULL.
|
|
4462 |
||
4463 |
=item --checksum
|
|
4464 |
||
4465 |
type: string; group: Tests
|
|
4466 |
||
4467 |
Table checksum is n. This tests the Checksum column.
|
|
4468 |
||
4469 |
=item --cmin
|
|
4470 |
||
4471 |
type: size; group: Tests
|
|
4472 |
||
4473 |
Table was created n minutes ago. This tests the Create_time column.
|
|
4474 |
||
4475 |
=item --collation
|
|
4476 |
||
4477 |
type: string; group: Tests
|
|
4478 |
||
4479 |
Table collation matches pattern. This tests the Collation column.
|
|
4480 |
||
4481 |
=item --column-name
|
|
4482 |
||
4483 |
type: string; group: Tests
|
|
4484 |
||
4485 |
A column name in the table matches pattern.
|
|
4486 |
||
4487 |
=item --column-type
|
|
4488 |
||
4489 |
type: string; group: Tests
|
|
4490 |
||
4491 |
A column in the table matches this type (case-insensitive).
|
|
4492 |
||
4493 |
Examples of types are: varchar, char, int, smallint, bigint, decimal, year,
|
|
4494 |
timestamp, text, enum.
|
|
4495 |
||
4496 |
=item --comment
|
|
4497 |
||
4498 |
type: string; group: Tests
|
|
4499 |
||
4500 |
Table comment matches pattern. This tests the Comment column.
|
|
4501 |
||
4502 |
=item --connection-id
|
|
4503 |
||
4504 |
type: string; group: Tests
|
|
4505 |
||
4506 |
Table name has nonexistent MySQL connection ID. This tests the table name for
|
|
4507 |
a pattern. The argument to this test must be a Perl regular expression that
|
|
4508 |
captures digits like this: (\d+). If the table name matches the pattern,
|
|
4509 |
these captured digits are taken to be the MySQL connection ID of some process.
|
|
4510 |
If the connection doesn't exist according to SHOW FULL PROCESSLIST, the test
|
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4511 |
returns true. If the connection ID is greater than pt-find's own
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4512 |
connection ID, the test returns false for safety.
|
4513 |
||
4514 |
Why would you want to do this? If you use MySQL statement-based replication,
|
|
4515 |
you probably know the trouble temporary tables can cause. You might choose to
|
|
4516 |
work around this by creating real tables with unique names, instead of
|
|
4517 |
temporary tables. One way to do this is to append your connection ID to the
|
|
4518 |
end of the table, thusly: scratch_table_12345. This assures the table name is
|
|
4519 |
unique and lets you have a way to find which connection it was associated
|
|
4520 |
with. And perhaps most importantly, if the connection no longer exists, you
|
|
4521 |
can assume the connection died without cleaning up its tables, and this table
|
|
4522 |
is a candidate for removal.
|
|
4523 |
||
4524 |
This is how I manage scratch tables, and that's why I included this test in
|
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4525 |
pt-find.
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4526 |
|
4527 |
The argument I use to L<"--connection-id"> is "\D_(\d+)$". That finds tables
|
|
4528 |
with a series of numbers at the end, preceded by an underscore and some
|
|
4529 |
non-number character (the latter criterion prevents me from examining tables
|
|
4530 |
with a date at the end, which people tend to do: baron_scratch_2007_05_07 for
|
|
4531 |
example). It's better to keep the scratch tables separate of course.
|
|
4532 |
||
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4533 |
If you do this, make sure the user pt-find runs as has the PROCESS privilege!
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4534 |
Otherwise it will only see connections from the same user, and might think some
|
6
by Daniel Nichter
Change mk- to pt- in all tools. |
4535 |
tables are ready to remove when they're still in use. For safety, pt-find
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4536 |
checks this for you.
|
4537 |
||
4538 |
See also L<"--server-id">.
|
|
4539 |
||
4540 |
=item --createopts
|
|
4541 |
||
4542 |
type: string; group: Tests
|
|
4543 |
||
4544 |
Table create option matches pattern. This tests the Create_options column.
|
|
4545 |
||
4546 |
=item --ctime
|
|
4547 |
||
4548 |
type: size; group: Tests
|
|
4549 |
||
4550 |
Table was created n days ago. This tests the Create_time column.
|
|
4551 |
||
4552 |
=item --datafree
|
|
4553 |
||
4554 |
type: size; group: Tests
|
|
4555 |
||
4556 |
Table has n bytes of free space. This tests the Data_free column.
|
|
4557 |
The specified size can be "NULL" to test where Data_free IS NULL.
|
|
4558 |
||
4559 |
=item --datasize
|
|
4560 |
||
4561 |
type: size; group: Tests
|
|
4562 |
||
4563 |
Table data uses n bytes of space. This tests the Data_length column.
|
|
4564 |
The specified size can be "NULL" to test where Data_length IS NULL.
|
|
4565 |
||
4566 |
=item --dblike
|
|
4567 |
||
4568 |
type: string; group: Tests
|
|
4569 |
||
4570 |
Database name matches SQL LIKE pattern.
|
|
4571 |
||
4572 |
=item --dbregex
|
|
4573 |
||
4574 |
type: string; group: Tests
|
|
4575 |
||
4576 |
Database name matches this pattern.
|
|
4577 |
||
4578 |
=item --empty
|
|
4579 |
||
4580 |
group: Tests
|
|
4581 |
||
4582 |
Table has no rows. This tests the Rows column.
|
|
4583 |
||
4584 |
=item --engine
|
|
4585 |
||
4586 |
type: string; group: Tests
|
|
4587 |
||
4588 |
Table storage engine matches this pattern. This tests the Engine column, or in
|
|
4589 |
earlier versions of MySQL, the Type column.
|
|
4590 |
||
4591 |
=item --function
|
|
4592 |
||
4593 |
type: string; group: Tests
|
|
4594 |
||
4595 |
Function definition matches pattern.
|
|
4596 |
||
4597 |
=item --indexsize
|
|
4598 |
||
4599 |
type: size; group: Tests
|
|
4600 |
||
4601 |
Table indexes use n bytes of space. This tests the Index_length column.
|
|
4602 |
The specified size can be "NULL" to test where Index_length IS NULL.
|
|
4603 |
||
4604 |
=item --kmin
|
|
4605 |
||
4606 |
type: size; group: Tests
|
|
4607 |
||
4608 |
Table was checked n minutes ago. This tests the Check_time column.
|
|
4609 |
||
4610 |
=item --ktime
|
|
4611 |
||
4612 |
type: size; group: Tests
|
|
4613 |
||
4614 |
Table was checked n days ago. This tests the Check_time column.
|
|
4615 |
||
4616 |
=item --mmin
|
|
4617 |
||
4618 |
type: size; group: Tests
|
|
4619 |
||
4620 |
Table was last modified n minutes ago. This tests the Update_time column.
|
|
4621 |
||
4622 |
=item --mtime
|
|
4623 |
||
4624 |
type: size; group: Tests
|
|
4625 |
||
4626 |
Table was last modified n days ago. This tests the Update_time column.
|
|
4627 |
||
4628 |
=item --procedure
|
|
4629 |
||
4630 |
type: string; group: Tests
|
|
4631 |
||
4632 |
Procedure definition matches pattern.
|
|
4633 |
||
4634 |
=item --rowformat
|
|
4635 |
||
4636 |
type: string; group: Tests
|
|
4637 |
||
4638 |
Table row format matches pattern. This tests the Row_format column.
|
|
4639 |
||
4640 |
=item --rows
|
|
4641 |
||
4642 |
type: size; group: Tests
|
|
4643 |
||
4644 |
Table has n rows. This tests the Rows column.
|
|
4645 |
The specified size can be "NULL" to test where Rows IS NULL.
|
|
4646 |
||
4647 |
=item --server-id
|
|
4648 |
||
4649 |
type: string; group: Tests
|
|
4650 |
||
4651 |
Table name contains the server ID. If you create temporary tables with the
|
|
4652 |
naming convention explained in L<"--connection-id">, but also add the server ID of the
|
|
4653 |
server on which the tables are created, then you can use this pattern match to
|
|
4654 |
ensure tables are dropped only on the server they're created on. This prevents
|
|
4655 |
a table from being accidentally dropped on a slave while it's in use (provided
|
|
4656 |
that your server IDs are all unique, which they should be for replication to
|
|
4657 |
work).
|
|
4658 |
||
4659 |
For example, on the master (server ID 22) you create a table called
|
|
4660 |
scratch_table_22_12345. If you see this table on the slave (server ID 23), you
|
|
4661 |
might think it can be dropped safely if there's no such connection 12345. But
|
|
4662 |
if you also force the name to match the server ID with C<--server-id '\D_(\d+)_\d+$'>,
|
|
4663 |
the table won't be dropped on the slave.
|
|
4664 |
||
4665 |
=item --tablesize
|
|
4666 |
||
4667 |
type: size; group: Tests
|
|
4668 |
||
4669 |
Table uses n bytes of space. This tests the sum of the Data_length and
|
|
4670 |
Index_length columns.
|
|
4671 |
||
4672 |
=item --tbllike
|
|
4673 |
||
4674 |
type: string; group: Tests
|
|
4675 |
||
4676 |
Table name matches SQL LIKE pattern.
|
|
4677 |
||
4678 |
=item --tblregex
|
|
4679 |
||
4680 |
type: string; group: Tests
|
|
4681 |
||
4682 |
Table name matches this pattern.
|
|
4683 |
||
4684 |
=item --tblversion
|
|
4685 |
||
4686 |
type: size; group: Tests
|
|
4687 |
||
4688 |
Table version is n. This tests the Version column.
|
|
4689 |
||
4690 |
=item --trigger
|
|
4691 |
||
4692 |
type: string; group: Tests
|
|
4693 |
||
4694 |
Trigger action statement matches pattern.
|
|
4695 |
||
4696 |
=item --trigger-table
|
|
4697 |
||
4698 |
type: string; group: Tests
|
|
4699 |
||
4700 |
L<"--trigger"> is defined on table matching pattern.
|
|
4701 |
||
4702 |
=item --view
|
|
4703 |
||
4704 |
type: string; group: Tests
|
|
4705 |
||
4706 |
CREATE VIEW matches this pattern.
|
|
4707 |
||
4708 |
=back
|
|
4709 |
||
4710 |
=head2 ACTIONS
|
|
4711 |
||
4712 |
The L<"--exec-plus"> action happens after everything else, but otherwise actions
|
|
4713 |
happen in an indeterminate order. If you need determinism, file a bug report
|
|
4714 |
and I'll add this feature.
|
|
4715 |
||
4716 |
=over
|
|
4717 |
||
4718 |
=item --exec
|
|
4719 |
||
4720 |
type: string; group: Actions
|
|
4721 |
||
4722 |
Execute this SQL with each item found. The SQL can contain escapes and
|
|
4723 |
formatting directives (see L<"--printf">).
|
|
4724 |
||
4725 |
=item --exec-dsn
|
|
4726 |
||
4727 |
type: string; group: Actions
|
|
4728 |
||
4729 |
Specify a DSN in key-value format to use when executing SQL with L<"--exec"> and
|
|
4730 |
L<"--exec-plus">. Any values not specified are inherited from command-line
|
|
4731 |
arguments.
|
|
4732 |
||
4733 |
=item --exec-plus
|
|
4734 |
||
4735 |
type: string; group: Actions
|
|
4736 |
||
4737 |
Execute this SQL with all items at once. This option is unlike L<"--exec">. There
|
|
4738 |
are no escaping or formatting directives; there is only one special placeholder
|
|
4739 |
for the list of database and table names, %s. The list of tables found will be
|
|
4740 |
joined together with commas and substituted wherever you place %s.
|
|
4741 |
||
4742 |
You might use this, for example, to drop all the tables you found:
|
|
4743 |
||
4744 |
DROP TABLE %s
|
|
4745 |
||
4746 |
This is sort of like GNU find's "-exec command {} +" syntax. Only it's not
|
|
4747 |
totally cryptic. And it doesn't require me to write a command-line parser.
|
|
4748 |
||
4749 |
=item --print
|
|
4750 |
||
4751 |
group: Actions
|
|
4752 |
||
4753 |
Print the database and table name, followed by a newline. This is the default
|
|
4754 |
action if no other action is specified.
|
|
4755 |
||
4756 |
=item --printf
|
|
4757 |
||
4758 |
type: string; group: Actions
|
|
4759 |
||
4760 |
Print format on the standard output, interpreting '\' escapes and '%'
|
|
4761 |
directives. Escapes are backslashed characters, like \n and \t. Perl
|
|
4762 |
interprets these, so you can use any escapes Perl knows about. Directives are
|
|
4763 |
replaced by %s, and as of this writing, you can't add any special formatting
|
|
4764 |
instructions, like field widths or alignment (though I'm musing over ways to do
|
|
4765 |
that).
|
|
4766 |
||
4767 |
Here is a list of the directives. Note that most of them simply come from
|
|
4768 |
columns of SHOW TABLE STATUS. If the column is NULL or doesn't exist, you get
|
|
4769 |
an empty string in the output. A % character followed by any character not in
|
|
4770 |
the following list is discarded (but the other character is printed).
|
|
4771 |
||
4772 |
CHAR DATA SOURCE NOTES
|
|
4773 |
---- ------------------ ------------------------------------------
|
|
4774 |
a Auto_increment
|
|
4775 |
A Avg_row_length
|
|
4776 |
c Checksum
|
|
4777 |
C Create_time
|
|
4778 |
D Database The database name in which the table lives
|
|
4779 |
d Data_length
|
|
4780 |
E Engine In older versions of MySQL, this is Type
|
|
4781 |
F Data_free
|
|
4782 |
f Innodb_free Parsed from the Comment field
|
|
4783 |
I Index_length
|
|
4784 |
K Check_time
|
|
4785 |
L Collation
|
|
4786 |
M Max_data_length
|
|
4787 |
N Name
|
|
4788 |
O Comment
|
|
4789 |
P Create_options
|
|
4790 |
R Row_format
|
|
4791 |
S Rows
|
|
4792 |
T Table_length Data_length+Index_length
|
|
4793 |
U Update_time
|
|
4794 |
V Version
|
|
4795 |
||
4796 |
=back
|
|
4797 |
||
4798 |
=head1 DSN OPTIONS
|
|
4799 |
||
4800 |
These DSN options are used to create a DSN. Each option is given like
|
|
4801 |
C<option=value>. The options are case-sensitive, so P and p are not the
|
|
4802 |
same option. There cannot be whitespace before or after the C<=> and
|
|
4803 |
if the value contains whitespace it must be quoted. DSN options are
|
|
20
by Daniel Nichter
Finish re-branding tools. Remove pt-schema-advisor. |
4804 |
comma-separated. See the L<percona-toolkit> manpage for full details.
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4805 |
|
4806 |
=over
|
|
4807 |
||
4808 |
=item * A
|
|
4809 |
||
4810 |
dsn: charset; copy: yes
|
|
4811 |
||
4812 |
Default character set.
|
|
4813 |
||
4814 |
=item * D
|
|
4815 |
||
4816 |
dsn: database; copy: yes
|
|
4817 |
||
4818 |
Default database.
|
|
4819 |
||
4820 |
=item * F
|
|
4821 |
||
4822 |
dsn: mysql_read_default_file; copy: yes
|
|
4823 |
||
4824 |
Only read default options from the given file
|
|
4825 |
||
4826 |
=item * h
|
|
4827 |
||
4828 |
dsn: host; copy: yes
|
|
4829 |
||
4830 |
Connect to host.
|
|
4831 |
||
4832 |
=item * p
|
|
4833 |
||
4834 |
dsn: password; copy: yes
|
|
4835 |
||
4836 |
Password to use when connecting.
|
|
4837 |
||
4838 |
=item * P
|
|
4839 |
||
4840 |
dsn: port; copy: yes
|
|
4841 |
||
4842 |
Port number to use for connection.
|
|
4843 |
||
4844 |
=item * S
|
|
4845 |
||
4846 |
dsn: mysql_socket; copy: yes
|
|
4847 |
||
4848 |
Socket file to use for connection.
|
|
4849 |
||
4850 |
=item * u
|
|
4851 |
||
4852 |
dsn: user; copy: yes
|
|
4853 |
||
4854 |
User for login if not current user.
|
|
4855 |
||
4856 |
=back
|
|
4857 |
||
4858 |
=head1 ENVIRONMENT
|
|
4859 |
||
13
by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT. |
4860 |
The environment variable C<PTDEBUG> enables verbose debugging output to STDERR.
|
4861 |
To enable debugging and capture all output to a file, run the tool like:
|
|
4862 |
||
14
by Daniel Nichter
Replace $TOOL with tool name. |
4863 |
PTDEBUG=1 pt-find ... > FILE 2>&1
|
13
by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT. |
4864 |
|
4865 |
Be careful: debugging output is voluminous and can generate several megabytes
|
|
4866 |
of output.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4867 |
|
4868 |
=head1 SYSTEM REQUIREMENTS
|
|
4869 |
||
13
by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT. |
4870 |
You need Perl, DBI, DBD::mysql, and some core packages that ought to be
|
4871 |
installed in any reasonably new version of Perl.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4872 |
|
4873 |
=head1 BUGS
|
|
4874 |
||
14
by Daniel Nichter
Replace $TOOL with tool name. |
4875 |
For a list of known bugs, see L<http://www.percona.com/bugs/pt-find>.
|
13
by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT. |
4876 |
|
4877 |
Please report bugs at L<https://bugs.launchpad.net/percona-toolkit>.
|
|
4878 |
Include the following information in your bug report:
|
|
4879 |
||
4880 |
=over
|
|
4881 |
||
4882 |
=item * Complete command-line used to run the tool
|
|
4883 |
||
4884 |
=item * Tool L<"--version">
|
|
4885 |
||
4886 |
=item * MySQL version of all servers involved
|
|
4887 |
||
4888 |
=item * Output from the tool including STDERR
|
|
4889 |
||
4890 |
=item * Input files (log/dump/config files, etc.)
|
|
4891 |
||
4892 |
=back
|
|
4893 |
||
4894 |
If possible, include debugging output by running the tool with C<PTDEBUG>;
|
|
4895 |
see L<"ENVIRONMENT">.
|
|
4896 |
||
59
by Daniel
Add RISKS section to Bash tools. Re-order all tools' DOWNLOADING section. Remove some unused options. |
4897 |
=head1 DOWNLOADING
|
4898 |
||
4899 |
Visit L<http://www.percona.com/software/percona-toolkit/> to download the
|
|
4900 |
latest release of Percona Toolkit. Or, get the latest release from the
|
|
4901 |
command line:
|
|
4902 |
||
4903 |
wget percona.com/get/percona-toolkit.tar.gz
|
|
4904 |
||
4905 |
wget percona.com/get/percona-toolkit.rpm
|
|
4906 |
||
4907 |
wget percona.com/get/percona-toolkit.deb
|
|
4908 |
||
4909 |
You can also get individual tools from the latest release:
|
|
4910 |
||
4911 |
wget percona.com/get/TOOL
|
|
4912 |
||
4913 |
Replace C<TOOL> with the name of any tool.
|
|
4914 |
||
13
by Daniel Nichter
Re-brand standard POD sections (DOWNLOADING, ENVIRONMENT, etc). Change ABOUT MAATKIT to ABOUT PERCONA TOOLKIT. |
4915 |
=head1 AUTHORS
|
4916 |
||
4917 |
Baron Schwartz
|
|
4918 |
||
4919 |
=head1 ABOUT PERCONA TOOLKIT
|
|
4920 |
||
4921 |
This tool is part of Percona Toolkit, a collection of advanced command-line
|
|
548.1.2
by Daniel Nichter
Update the ABOUT PERCONA TOOLKIT secction in all tools. |
4922 |
tools for MySQL developed by Percona. Percona Toolkit was forked from two
|
4923 |
projects in June, 2011: Maatkit and Aspersa. Those projects were created by
|
|
4924 |
Baron Schwartz and primarily developed by him and Daniel Nichter. Visit
|
|
4925 |
L<http://www.percona.com/software/> to learn about other free, open-source
|
|
4926 |
software from Percona.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4927 |
|
12
by Daniel Nichter
Remove duplicate copyright notices. Add POD and copyright for Aspersa tools. Fix checking for "pt-pmp" instead of "pmp", etc. |
4928 |
=head1 COPYRIGHT, LICENSE, AND WARRANTY
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4929 |
|
503.6.1
by Daniel Nichter
s/Percona Inc/Percona Ireland Ltd/g |
4930 |
This program is copyright 2011-2013 Percona Ireland Ltd,
|
4931 |
2007-2011 Baron Schwartz.
|
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4932 |
|
4933 |
THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
4934 |
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
|
4935 |
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
4936 |
||
4937 |
This program is free software; you can redistribute it and/or modify it under
|
|
4938 |
the terms of the GNU General Public License as published by the Free Software
|
|
4939 |
Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
|
|
4940 |
systems, you can issue `man perlgpl' or `man perlartistic' to read these
|
|
4941 |
licenses.
|
|
4942 |
||
4943 |
You should have received a copy of the GNU General Public License along with
|
|
4944 |
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
4945 |
Place, Suite 330, Boston, MA 02111-1307 USA.
|
|
4946 |
||
4947 |
=head1 VERSION
|
|
4948 |
||
580.1.3
by Brian Fraser
Build percona-toolkit-2.2.2 |
4949 |
pt-find 2.2.2
|
3
by Daniel Nichter
Add forked Maatkit tools in bin/ and their tests in t/. |
4950 |
|
4951 |
=cut
|