Merge lp:~percona-toolkit-dev/percona-toolkit/pt-fke-logger-2.2 into lp:percona-toolkit/2.2
- pt-fke-logger-2.2
- Merge into 2.2
Proposed by
Daniel Nichter
Status: | Merged |
---|---|
Approved by: | Daniel Nichter |
Approved revision: | 539 |
Merged at revision: | 534 |
Proposed branch: | lp:~percona-toolkit-dev/percona-toolkit/pt-fke-logger-2.2 |
Merge into: | lp:percona-toolkit/2.2 |
Diff against target: |
3998 lines (+1891/-858) 35 files modified
bin/pt-archiver (+5/-4) bin/pt-config-diff (+53/-34) bin/pt-deadlock-logger (+734/-334) bin/pt-duplicate-key-checker (+5/-8) bin/pt-fifo-split (+5/-8) bin/pt-find (+5/-8) bin/pt-fk-error-logger (+489/-131) bin/pt-heartbeat (+5/-4) bin/pt-kill (+61/-21) bin/pt-online-schema-change (+51/-21) bin/pt-query-advisor (+5/-5) bin/pt-query-digest (+5/-5) bin/pt-show-grants (+5/-8) bin/pt-slave-delay (+5/-5) bin/pt-slave-find (+5/-8) bin/pt-slave-restart (+5/-5) bin/pt-stalk (+5/-1) bin/pt-table-checksum (+51/-25) bin/pt-table-sync (+5/-8) bin/pt-table-usage (+5/-5) bin/pt-upgrade (+5/-5) bin/pt-variable-advisor (+5/-5) bin/pt-visual-explain (+5/-8) docs/percona-toolkit.pod (+28/-0) lib/Cxn.pm (+48/-17) lib/Runtime.pm (+23/-36) t/lib/Cxn.t (+58/-2) t/pt-deadlock-logger/basics.t (+54/-42) t/pt-deadlock-logger/clear_deadlocks.t (+2/-5) t/pt-deadlock-logger/create_dest_table.t (+12/-9) t/pt-deadlock-logger/option_sanity.t (+1/-1) t/pt-deadlock-logger/standard_options.t (+73/-38) t/pt-fk-error-logger/basics.t (+66/-8) t/pt-fk-error-logger/get_fk_error.t (+2/-2) t/pt-fk-error-logger/standard_options.t (+0/-32) |
To merge this branch: | bzr merge lp:~percona-toolkit-dev/percona-toolkit/pt-fke-logger-2.2 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brian Fraser (community) | Approve | ||
Daniel Nichter | Approve | ||
Review via email: mp+150704@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) wrote : | # |
Revision history for this message
Daniel Nichter (daniel-nichter) : | # |
review:
Approve
Revision history for this message
Brian Fraser (fraserbn) : | # |
review:
Approve
- 539. By Daniel Nichter
-
Don't manually re-set AutoCommit. Use =for comment instead of inline MAGIC.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'bin/pt-archiver' | |||
2 | --- bin/pt-archiver 2013-02-22 17:47:57 +0000 | |||
3 | +++ bin/pt-archiver 2013-02-27 23:41:26 +0000 | |||
4 | @@ -6958,10 +6958,11 @@ | |||
5 | 6958 | 6958 | ||
6 | 6959 | type: string | 6959 | type: string |
7 | 6960 | 6960 | ||
12 | 6961 | Create the given PID file when daemonized. The file contains the process ID of | 6961 | Create the given PID file. The tool won't start if the PID file already |
13 | 6962 | the daemonized instance. The PID file is removed when the daemonized instance | 6962 | exists and the PID it contains is different than the current PID. However, |
14 | 6963 | exits. The program checks for the existence of the PID file when starting; if | 6963 | if the PID file exists and the PID it contains is no longer running, the |
15 | 6964 | it exists and the process with the matching PID exists, the program exits. | 6964 | tool will overwrite the PID file with the current PID. The PID file is |
16 | 6965 | removed automatically when the tool exits. | ||
17 | 6965 | 6966 | ||
18 | 6966 | =item --plugin | 6967 | =item --plugin |
19 | 6967 | 6968 | ||
20 | 6968 | 6969 | ||
21 | === modified file 'bin/pt-config-diff' | |||
22 | --- bin/pt-config-diff 2013-02-22 15:00:55 +0000 | |||
23 | +++ bin/pt-config-diff 2013-02-27 23:41:26 +0000 | |||
24 | @@ -2138,23 +2138,24 @@ | |||
25 | 2138 | } | 2138 | } |
26 | 2139 | 2139 | ||
27 | 2140 | my $self = { | 2140 | my $self = { |
37 | 2141 | dsn => $dsn, | 2141 | dsn => $dsn, |
38 | 2142 | dbh => $args{dbh}, | 2142 | dbh => $args{dbh}, |
39 | 2143 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | 2143 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
40 | 2144 | hostname => '', | 2144 | hostname => '', |
41 | 2145 | set => $args{set}, | 2145 | set => $args{set}, |
42 | 2146 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | 2146 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, |
43 | 2147 | dbh_set => 0, | 2147 | dbh_set => 0, |
44 | 2148 | OptionParser => $o, | 2148 | OptionParser => $o, |
45 | 2149 | DSNParser => $dp, | 2149 | DSNParser => $dp, |
46 | 2150 | is_cluster_node => undef, | 2150 | is_cluster_node => undef, |
47 | 2151 | parent => $args{parent}, | ||
48 | 2151 | }; | 2152 | }; |
49 | 2152 | 2153 | ||
50 | 2153 | return bless $self, $class; | 2154 | return bless $self, $class; |
51 | 2154 | } | 2155 | } |
52 | 2155 | 2156 | ||
53 | 2156 | sub connect { | 2157 | sub connect { |
55 | 2157 | my ( $self ) = @_; | 2158 | my ( $self, %opts ) = @_; |
56 | 2158 | my $dsn = $self->{dsn}; | 2159 | my $dsn = $self->{dsn}; |
57 | 2159 | my $dp = $self->{DSNParser}; | 2160 | my $dp = $self->{DSNParser}; |
58 | 2160 | my $o = $self->{OptionParser}; | 2161 | my $o = $self->{OptionParser}; |
59 | @@ -2165,11 +2166,18 @@ | |||
60 | 2165 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | 2166 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); |
61 | 2166 | $self->{asked_for_pass} = 1; | 2167 | $self->{asked_for_pass} = 1; |
62 | 2167 | } | 2168 | } |
64 | 2168 | $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 }); | 2169 | $dbh = $dp->get_dbh( |
65 | 2170 | $dp->get_cxn_params($dsn), | ||
66 | 2171 | { | ||
67 | 2172 | AutoCommit => 1, | ||
68 | 2173 | %opts, | ||
69 | 2174 | }, | ||
70 | 2175 | ); | ||
71 | 2169 | } | 2176 | } |
72 | 2170 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{name}); | ||
73 | 2171 | 2177 | ||
75 | 2172 | return $self->set_dbh($dbh); | 2178 | $dbh = $self->set_dbh($dbh); |
76 | 2179 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
77 | 2180 | return $dbh; | ||
78 | 2173 | } | 2181 | } |
79 | 2174 | 2182 | ||
80 | 2175 | sub set_dbh { | 2183 | sub set_dbh { |
81 | @@ -2192,6 +2200,11 @@ | |||
82 | 2192 | $self->{hostname} = $hostname; | 2200 | $self->{hostname} = $hostname; |
83 | 2193 | } | 2201 | } |
84 | 2194 | 2202 | ||
85 | 2203 | if ( $self->{parent} ) { | ||
86 | 2204 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
87 | 2205 | $dbh->{InactiveDestroy} = 1; | ||
88 | 2206 | } | ||
89 | 2207 | |||
90 | 2195 | if ( my $set = $self->{set}) { | 2208 | if ( my $set = $self->{set}) { |
91 | 2196 | $set->($dbh); | 2209 | $set->($dbh); |
92 | 2197 | } | 2210 | } |
93 | @@ -2201,6 +2214,13 @@ | |||
94 | 2201 | return $dbh; | 2214 | return $dbh; |
95 | 2202 | } | 2215 | } |
96 | 2203 | 2216 | ||
97 | 2217 | sub lost_connection { | ||
98 | 2218 | my ($self, $e) = @_; | ||
99 | 2219 | return 0 unless $e; | ||
100 | 2220 | return $e =~ m/MySQL server has gone away/ | ||
101 | 2221 | || $e =~ m/Lost connection to MySQL server/; | ||
102 | 2222 | } | ||
103 | 2223 | |||
104 | 2204 | sub dbh { | 2224 | sub dbh { |
105 | 2205 | my ($self) = @_; | 2225 | my ($self) = @_; |
106 | 2206 | return $self->{dbh}; | 2226 | return $self->{dbh}; |
107 | @@ -2219,12 +2239,21 @@ | |||
108 | 2219 | 2239 | ||
109 | 2220 | sub DESTROY { | 2240 | sub DESTROY { |
110 | 2221 | my ($self) = @_; | 2241 | my ($self) = @_; |
115 | 2222 | if ( $self->{dbh} | 2242 | |
116 | 2223 | && blessed($self->{dbh}) | 2243 | PTDEBUG && _d('Destroying cxn'); |
117 | 2224 | && $self->{dbh}->can("disconnect") ) { | 2244 | |
118 | 2225 | PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name}); | 2245 | if ( $self->{parent} ) { |
119 | 2246 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
120 | 2247 | } | ||
121 | 2248 | elsif ( $self->{dbh} | ||
122 | 2249 | && blessed($self->{dbh}) | ||
123 | 2250 | && $self->{dbh}->can("disconnect") ) | ||
124 | 2251 | { | ||
125 | 2252 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
126 | 2253 | $self->{dsn_name}); | ||
127 | 2226 | $self->{dbh}->disconnect(); | 2254 | $self->{dbh}->disconnect(); |
128 | 2227 | } | 2255 | } |
129 | 2256 | |||
130 | 2228 | return; | 2257 | return; |
131 | 2229 | } | 2258 | } |
132 | 2230 | 2259 | ||
133 | @@ -5022,12 +5051,7 @@ | |||
134 | 5022 | # Daemonize now that everything is setup and ready to work. | 5051 | # Daemonize now that everything is setup and ready to work. |
135 | 5023 | # ######################################################################## | 5052 | # ######################################################################## |
136 | 5024 | my $daemon; | 5053 | my $daemon; |
143 | 5025 | if ( $o->get('daemonize') ) { | 5054 | if ( $o->get('pid') ) { |
138 | 5026 | $daemon = new Daemon(o=>$o); | ||
139 | 5027 | $daemon->daemonize(); | ||
140 | 5028 | PTDEBUG && _d('I am a daemon now'); | ||
141 | 5029 | } | ||
142 | 5030 | elsif ( $o->get('pid') ) { | ||
144 | 5031 | # We're not daemoninzing, it just handles PID stuff. | 5055 | # We're not daemoninzing, it just handles PID stuff. |
145 | 5032 | $daemon = new Daemon(o=>$o); | 5056 | $daemon = new Daemon(o=>$o); |
146 | 5033 | $daemon->make_PID_file(); | 5057 | $daemon->make_PID_file(); |
147 | @@ -5118,7 +5142,7 @@ | |||
148 | 5118 | 5142 | ||
149 | 5119 | =head1 SYNOPSIS | 5143 | =head1 SYNOPSIS |
150 | 5120 | 5144 | ||
152 | 5121 | Usage: pt-config-diff [OPTION...] CONFIG CONFIG [CONFIG...] | 5145 | Usage: pt-config-diff [OPTIONS] CONFIG CONFIG [CONFIG...] |
153 | 5122 | 5146 | ||
154 | 5123 | pt-config-diff diffs MySQL configuration files and server variables. | 5147 | pt-config-diff diffs MySQL configuration files and server variables. |
155 | 5124 | CONFIG can be a filename or a DSN. At least two CONFIG sources must be given. | 5148 | CONFIG can be a filename or a DSN. At least two CONFIG sources must be given. |
156 | @@ -5238,11 +5262,6 @@ | |||
157 | 5238 | first option on the command line. (This option does not specify a CONFIG; | 5262 | first option on the command line. (This option does not specify a CONFIG; |
158 | 5239 | it's equivalent to C<--defaults-file>.) | 5263 | it's equivalent to C<--defaults-file>.) |
159 | 5240 | 5264 | ||
160 | 5241 | =item --daemonize | ||
161 | 5242 | |||
162 | 5243 | Fork to the background and detach from the shell. POSIX | ||
163 | 5244 | operating systems only. | ||
164 | 5245 | |||
165 | 5246 | =item --defaults-file | 5265 | =item --defaults-file |
166 | 5247 | 5266 | ||
167 | 5248 | short form: -F; type: string | 5267 | short form: -F; type: string |
168 | @@ -5276,11 +5295,11 @@ | |||
169 | 5276 | 5295 | ||
170 | 5277 | type: string | 5296 | type: string |
171 | 5278 | 5297 | ||
177 | 5279 | Create the given PID file when daemonized. The file contains the process | 5298 | Create the given PID file. The tool won't start if the PID file already |
178 | 5280 | ID of the daemonized instance. The PID file is removed when the | 5299 | exists and the PID it contains is different than the current PID. However, |
179 | 5281 | daemonized instance exits. The program checks for the existence of the | 5300 | if the PID file exists and the PID it contains is no longer running, the |
180 | 5282 | PID file when starting; if it exists and the process with the matching PID | 5301 | tool will overwrite the PID file with the current PID. The PID file is |
181 | 5283 | exists, the program exits. | 5302 | removed automatically when the tool exits. |
182 | 5284 | 5303 | ||
183 | 5285 | =item --port | 5304 | =item --port |
184 | 5286 | 5305 | ||
185 | 5287 | 5306 | ||
186 | === modified file 'bin/pt-deadlock-logger' | |||
187 | --- bin/pt-deadlock-logger 2013-02-22 17:47:57 +0000 | |||
188 | +++ bin/pt-deadlock-logger 2013-02-27 23:41:26 +0000 | |||
189 | @@ -23,9 +23,11 @@ | |||
190 | 23 | VersionParser | 23 | VersionParser |
191 | 24 | Quoter | 24 | Quoter |
192 | 25 | DSNParser | 25 | DSNParser |
193 | 26 | Cxn | ||
194 | 26 | Daemon | 27 | Daemon |
195 | 27 | HTTPMicro | 28 | HTTPMicro |
196 | 28 | VersionCheck | 29 | VersionCheck |
197 | 30 | Runtime | ||
198 | 29 | )); | 31 | )); |
199 | 30 | } | 32 | } |
200 | 31 | 33 | ||
201 | @@ -2439,6 +2441,181 @@ | |||
202 | 2439 | # ########################################################################### | 2441 | # ########################################################################### |
203 | 2440 | 2442 | ||
204 | 2441 | # ########################################################################### | 2443 | # ########################################################################### |
205 | 2444 | # Cxn package | ||
206 | 2445 | # This package is a copy without comments from the original. The original | ||
207 | 2446 | # with comments and its test file can be found in the Bazaar repository at, | ||
208 | 2447 | # lib/Cxn.pm | ||
209 | 2448 | # t/lib/Cxn.t | ||
210 | 2449 | # See https://launchpad.net/percona-toolkit for more information. | ||
211 | 2450 | # ########################################################################### | ||
212 | 2451 | { | ||
213 | 2452 | package Cxn; | ||
214 | 2453 | |||
215 | 2454 | use strict; | ||
216 | 2455 | use warnings FATAL => 'all'; | ||
217 | 2456 | use English qw(-no_match_vars); | ||
218 | 2457 | use Scalar::Util qw(blessed); | ||
219 | 2458 | use constant { | ||
220 | 2459 | PTDEBUG => $ENV{PTDEBUG} || 0, | ||
221 | 2460 | PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0, | ||
222 | 2461 | }; | ||
223 | 2462 | |||
224 | 2463 | sub new { | ||
225 | 2464 | my ( $class, %args ) = @_; | ||
226 | 2465 | my @required_args = qw(DSNParser OptionParser); | ||
227 | 2466 | foreach my $arg ( @required_args ) { | ||
228 | 2467 | die "I need a $arg argument" unless $args{$arg}; | ||
229 | 2468 | }; | ||
230 | 2469 | my ($dp, $o) = @args{@required_args}; | ||
231 | 2470 | |||
232 | 2471 | my $dsn_defaults = $dp->parse_options($o); | ||
233 | 2472 | my $prev_dsn = $args{prev_dsn}; | ||
234 | 2473 | my $dsn = $args{dsn}; | ||
235 | 2474 | if ( !$dsn ) { | ||
236 | 2475 | $args{dsn_string} ||= 'h=' . ($dsn_defaults->{h} || 'localhost'); | ||
237 | 2476 | |||
238 | 2477 | $dsn = $dp->parse( | ||
239 | 2478 | $args{dsn_string}, $prev_dsn, $dsn_defaults); | ||
240 | 2479 | } | ||
241 | 2480 | elsif ( $prev_dsn ) { | ||
242 | 2481 | $dsn = $dp->copy($prev_dsn, $dsn); | ||
243 | 2482 | } | ||
244 | 2483 | |||
245 | 2484 | my $self = { | ||
246 | 2485 | dsn => $dsn, | ||
247 | 2486 | dbh => $args{dbh}, | ||
248 | 2487 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | ||
249 | 2488 | hostname => '', | ||
250 | 2489 | set => $args{set}, | ||
251 | 2490 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | ||
252 | 2491 | dbh_set => 0, | ||
253 | 2492 | OptionParser => $o, | ||
254 | 2493 | DSNParser => $dp, | ||
255 | 2494 | is_cluster_node => undef, | ||
256 | 2495 | parent => $args{parent}, | ||
257 | 2496 | }; | ||
258 | 2497 | |||
259 | 2498 | return bless $self, $class; | ||
260 | 2499 | } | ||
261 | 2500 | |||
262 | 2501 | sub connect { | ||
263 | 2502 | my ( $self, %opts ) = @_; | ||
264 | 2503 | my $dsn = $self->{dsn}; | ||
265 | 2504 | my $dp = $self->{DSNParser}; | ||
266 | 2505 | my $o = $self->{OptionParser}; | ||
267 | 2506 | |||
268 | 2507 | my $dbh = $self->{dbh}; | ||
269 | 2508 | if ( !$dbh || !$dbh->ping() ) { | ||
270 | 2509 | if ( $o->get('ask-pass') && !$self->{asked_for_pass} ) { | ||
271 | 2510 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | ||
272 | 2511 | $self->{asked_for_pass} = 1; | ||
273 | 2512 | } | ||
274 | 2513 | $dbh = $dp->get_dbh( | ||
275 | 2514 | $dp->get_cxn_params($dsn), | ||
276 | 2515 | { | ||
277 | 2516 | AutoCommit => 1, | ||
278 | 2517 | %opts, | ||
279 | 2518 | }, | ||
280 | 2519 | ); | ||
281 | 2520 | } | ||
282 | 2521 | |||
283 | 2522 | $dbh = $self->set_dbh($dbh); | ||
284 | 2523 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
285 | 2524 | return $dbh; | ||
286 | 2525 | } | ||
287 | 2526 | |||
288 | 2527 | sub set_dbh { | ||
289 | 2528 | my ($self, $dbh) = @_; | ||
290 | 2529 | |||
291 | 2530 | if ( $self->{dbh} && $self->{dbh} == $dbh && $self->{dbh_set} ) { | ||
292 | 2531 | PTDEBUG && _d($dbh, 'Already set dbh'); | ||
293 | 2532 | return $dbh; | ||
294 | 2533 | } | ||
295 | 2534 | |||
296 | 2535 | PTDEBUG && _d($dbh, 'Setting dbh'); | ||
297 | 2536 | |||
298 | 2537 | $dbh->{FetchHashKeyName} = 'NAME_lc' if $self->{NAME_lc}; | ||
299 | 2538 | |||
300 | 2539 | my $sql = 'SELECT @@hostname, @@server_id'; | ||
301 | 2540 | PTDEBUG && _d($dbh, $sql); | ||
302 | 2541 | my ($hostname, $server_id) = $dbh->selectrow_array($sql); | ||
303 | 2542 | PTDEBUG && _d($dbh, 'hostname:', $hostname, $server_id); | ||
304 | 2543 | if ( $hostname ) { | ||
305 | 2544 | $self->{hostname} = $hostname; | ||
306 | 2545 | } | ||
307 | 2546 | |||
308 | 2547 | if ( $self->{parent} ) { | ||
309 | 2548 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
310 | 2549 | $dbh->{InactiveDestroy} = 1; | ||
311 | 2550 | } | ||
312 | 2551 | |||
313 | 2552 | if ( my $set = $self->{set}) { | ||
314 | 2553 | $set->($dbh); | ||
315 | 2554 | } | ||
316 | 2555 | |||
317 | 2556 | $self->{dbh} = $dbh; | ||
318 | 2557 | $self->{dbh_set} = 1; | ||
319 | 2558 | return $dbh; | ||
320 | 2559 | } | ||
321 | 2560 | |||
322 | 2561 | sub lost_connection { | ||
323 | 2562 | my ($self, $e) = @_; | ||
324 | 2563 | return 0 unless $e; | ||
325 | 2564 | return $e =~ m/MySQL server has gone away/ | ||
326 | 2565 | || $e =~ m/Lost connection to MySQL server/; | ||
327 | 2566 | } | ||
328 | 2567 | |||
329 | 2568 | sub dbh { | ||
330 | 2569 | my ($self) = @_; | ||
331 | 2570 | return $self->{dbh}; | ||
332 | 2571 | } | ||
333 | 2572 | |||
334 | 2573 | sub dsn { | ||
335 | 2574 | my ($self) = @_; | ||
336 | 2575 | return $self->{dsn}; | ||
337 | 2576 | } | ||
338 | 2577 | |||
339 | 2578 | sub name { | ||
340 | 2579 | my ($self) = @_; | ||
341 | 2580 | return $self->{dsn_name} if PERCONA_TOOLKIT_TEST_USE_DSN_NAMES; | ||
342 | 2581 | return $self->{hostname} || $self->{dsn_name} || 'unknown host'; | ||
343 | 2582 | } | ||
344 | 2583 | |||
345 | 2584 | sub DESTROY { | ||
346 | 2585 | my ($self) = @_; | ||
347 | 2586 | |||
348 | 2587 | PTDEBUG && _d('Destroying cxn'); | ||
349 | 2588 | |||
350 | 2589 | if ( $self->{parent} ) { | ||
351 | 2590 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
352 | 2591 | } | ||
353 | 2592 | elsif ( $self->{dbh} | ||
354 | 2593 | && blessed($self->{dbh}) | ||
355 | 2594 | && $self->{dbh}->can("disconnect") ) | ||
356 | 2595 | { | ||
357 | 2596 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
358 | 2597 | $self->{dsn_name}); | ||
359 | 2598 | $self->{dbh}->disconnect(); | ||
360 | 2599 | } | ||
361 | 2600 | |||
362 | 2601 | return; | ||
363 | 2602 | } | ||
364 | 2603 | |||
365 | 2604 | sub _d { | ||
366 | 2605 | my ($package, undef, $line) = caller 0; | ||
367 | 2606 | @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } | ||
368 | 2607 | map { defined $_ ? $_ : 'undef' } | ||
369 | 2608 | @_; | ||
370 | 2609 | print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; | ||
371 | 2610 | } | ||
372 | 2611 | |||
373 | 2612 | 1; | ||
374 | 2613 | } | ||
375 | 2614 | # ########################################################################### | ||
376 | 2615 | # End Cxn package | ||
377 | 2616 | # ########################################################################### | ||
378 | 2617 | |||
379 | 2618 | # ########################################################################### | ||
380 | 2442 | # Daemon package | 2619 | # Daemon package |
381 | 2443 | # This package is a copy without comments from the original. The original | 2620 | # This package is a copy without comments from the original. The original |
382 | 2444 | # with comments and its test file can be found in the Bazaar repository at, | 2621 | # with comments and its test file can be found in the Bazaar repository at, |
383 | @@ -3865,6 +4042,139 @@ | |||
384 | 3865 | # ########################################################################### | 4042 | # ########################################################################### |
385 | 3866 | 4043 | ||
386 | 3867 | # ########################################################################### | 4044 | # ########################################################################### |
387 | 4045 | # Runtime package | ||
388 | 4046 | # This package is a copy without comments from the original. The original | ||
389 | 4047 | # with comments and its test file can be found in the Bazaar repository at, | ||
390 | 4048 | # lib/Runtime.pm | ||
391 | 4049 | # t/lib/Runtime.t | ||
392 | 4050 | # See https://launchpad.net/percona-toolkit for more information. | ||
393 | 4051 | # ########################################################################### | ||
394 | 4052 | { | ||
395 | 4053 | package Runtime; | ||
396 | 4054 | |||
397 | 4055 | use strict; | ||
398 | 4056 | use warnings FATAL => 'all'; | ||
399 | 4057 | use English qw(-no_match_vars); | ||
400 | 4058 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; | ||
401 | 4059 | |||
402 | 4060 | sub new { | ||
403 | 4061 | my ( $class, %args ) = @_; | ||
404 | 4062 | my @required_args = qw(run_time now); | ||
405 | 4063 | foreach my $arg ( @required_args ) { | ||
406 | 4064 | die "I need a $arg argument" unless exists $args{$arg}; | ||
407 | 4065 | } | ||
408 | 4066 | |||
409 | 4067 | my $run_time = $args{run_time}; | ||
410 | 4068 | if ( defined $run_time ) { | ||
411 | 4069 | die "run_time must be > 0" if $run_time <= 0; | ||
412 | 4070 | } | ||
413 | 4071 | |||
414 | 4072 | my $now = $args{now}; | ||
415 | 4073 | die "now must be a callback" unless ref $now eq 'CODE'; | ||
416 | 4074 | |||
417 | 4075 | my $self = { | ||
418 | 4076 | run_time => $run_time, | ||
419 | 4077 | now => $now, | ||
420 | 4078 | start_time => undef, | ||
421 | 4079 | end_time => undef, | ||
422 | 4080 | time_left => undef, | ||
423 | 4081 | stop => 0, | ||
424 | 4082 | }; | ||
425 | 4083 | |||
426 | 4084 | return bless $self, $class; | ||
427 | 4085 | } | ||
428 | 4086 | |||
429 | 4087 | sub time_left { | ||
430 | 4088 | my ( $self, %args ) = @_; | ||
431 | 4089 | |||
432 | 4090 | if ( $self->{stop} ) { | ||
433 | 4091 | PTDEBUG && _d("No time left because stop was called"); | ||
434 | 4092 | return 0; | ||
435 | 4093 | } | ||
436 | 4094 | |||
437 | 4095 | my $now = $self->{now}->(%args); | ||
438 | 4096 | PTDEBUG && _d("Current time:", $now); | ||
439 | 4097 | |||
440 | 4098 | if ( !defined $self->{start_time} ) { | ||
441 | 4099 | $self->{start_time} = $now; | ||
442 | 4100 | } | ||
443 | 4101 | |||
444 | 4102 | return unless defined $now; | ||
445 | 4103 | |||
446 | 4104 | my $run_time = $self->{run_time}; | ||
447 | 4105 | return unless defined $run_time; | ||
448 | 4106 | |||
449 | 4107 | if ( !$self->{end_time} ) { | ||
450 | 4108 | $self->{end_time} = $now + $run_time; | ||
451 | 4109 | PTDEBUG && _d("End time:", $self->{end_time}); | ||
452 | 4110 | } | ||
453 | 4111 | |||
454 | 4112 | $self->{time_left} = $self->{end_time} - $now; | ||
455 | 4113 | PTDEBUG && _d("Time left:", $self->{time_left}); | ||
456 | 4114 | return $self->{time_left}; | ||
457 | 4115 | } | ||
458 | 4116 | |||
459 | 4117 | sub have_time { | ||
460 | 4118 | my ( $self, %args ) = @_; | ||
461 | 4119 | my $time_left = $self->time_left(%args); | ||
462 | 4120 | return 1 if !defined $time_left; # run forever | ||
463 | 4121 | return $time_left <= 0 ? 0 : 1; # <=0s means run time has elapsed | ||
464 | 4122 | } | ||
465 | 4123 | |||
466 | 4124 | sub time_elapsed { | ||
467 | 4125 | my ( $self, %args ) = @_; | ||
468 | 4126 | |||
469 | 4127 | my $start_time = $self->{start_time}; | ||
470 | 4128 | return 0 unless $start_time; | ||
471 | 4129 | |||
472 | 4130 | my $now = $self->{now}->(%args); | ||
473 | 4131 | PTDEBUG && _d("Current time:", $now); | ||
474 | 4132 | |||
475 | 4133 | my $time_elapsed = $now - $start_time; | ||
476 | 4134 | PTDEBUG && _d("Time elapsed:", $time_elapsed); | ||
477 | 4135 | if ( $time_elapsed < 0 ) { | ||
478 | 4136 | warn "Current time $now is earlier than start time $start_time"; | ||
479 | 4137 | } | ||
480 | 4138 | return $time_elapsed; | ||
481 | 4139 | } | ||
482 | 4140 | |||
483 | 4141 | sub reset { | ||
484 | 4142 | my ( $self ) = @_; | ||
485 | 4143 | $self->{start_time} = undef; | ||
486 | 4144 | $self->{end_time} = undef; | ||
487 | 4145 | $self->{time_left} = undef; | ||
488 | 4146 | $self->{stop} = 0; | ||
489 | 4147 | PTDEBUG && _d("Reset run time"); | ||
490 | 4148 | return; | ||
491 | 4149 | } | ||
492 | 4150 | |||
493 | 4151 | sub stop { | ||
494 | 4152 | my ( $self ) = @_; | ||
495 | 4153 | $self->{stop} = 1; | ||
496 | 4154 | return; | ||
497 | 4155 | } | ||
498 | 4156 | |||
499 | 4157 | sub start { | ||
500 | 4158 | my ( $self ) = @_; | ||
501 | 4159 | $self->{stop} = 0; | ||
502 | 4160 | return; | ||
503 | 4161 | } | ||
504 | 4162 | |||
505 | 4163 | sub _d { | ||
506 | 4164 | my ($package, undef, $line) = caller 0; | ||
507 | 4165 | @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } | ||
508 | 4166 | map { defined $_ ? $_ : 'undef' } | ||
509 | 4167 | @_; | ||
510 | 4168 | print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; | ||
511 | 4169 | } | ||
512 | 4170 | |||
513 | 4171 | 1; | ||
514 | 4172 | } | ||
515 | 4173 | # ########################################################################### | ||
516 | 4174 | # End Runtime package | ||
517 | 4175 | # ########################################################################### | ||
518 | 4176 | |||
519 | 4177 | # ########################################################################### | ||
520 | 3868 | # This is a combination of modules and programs in one -- a runnable module. | 4178 | # This is a combination of modules and programs in one -- a runnable module. |
521 | 3869 | # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last | 4179 | # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last |
522 | 3870 | # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. | 4180 | # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. |
523 | @@ -3877,21 +4187,15 @@ | |||
524 | 3877 | use English qw(-no_match_vars); | 4187 | use English qw(-no_match_vars); |
525 | 3878 | use List::Util qw(max); | 4188 | use List::Util qw(max); |
526 | 3879 | use Socket qw(inet_aton); | 4189 | use Socket qw(inet_aton); |
528 | 3880 | use sigtrap qw(handler finish untrapped normal-signals); | 4190 | use Time::HiRes qw(sleep); |
529 | 4191 | use File::Temp qw(tempfile); | ||
530 | 4192 | use File::Spec; | ||
531 | 4193 | |||
532 | 4194 | use sigtrap 'handler', \&sig_int, 'normal-signals'; | ||
533 | 3881 | 4195 | ||
534 | 3882 | use Percona::Toolkit; | 4196 | use Percona::Toolkit; |
535 | 3883 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; | 4197 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
536 | 3884 | 4198 | ||
537 | 3885 | my $o; | ||
538 | 3886 | my $oktorun; | ||
539 | 3887 | my $dp; | ||
540 | 3888 | |||
541 | 3889 | # ######################################################################## | ||
542 | 3890 | # Configuration info. | ||
543 | 3891 | # ######################################################################## | ||
544 | 3892 | my $source_dsn; | ||
545 | 3893 | my $dest_dsn; | ||
546 | 3894 | |||
547 | 3895 | # Some common patterns and variables | 4199 | # Some common patterns and variables |
548 | 3896 | my $d = qr/(\d+)/; # Digit | 4200 | my $d = qr/(\d+)/; # Digit |
549 | 3897 | my $t = qr/((?:\d+ \d+)|(?:[A-Fa-f0-9]+))/; # Transaction ID | 4201 | my $t = qr/((?:\d+ \d+)|(?:[A-Fa-f0-9]+))/; # Transaction ID |
550 | @@ -3934,48 +4238,54 @@ | |||
551 | 3934 | 'update' => 1, | 4238 | 'update' => 1, |
552 | 3935 | ); | 4239 | ); |
553 | 3936 | 4240 | ||
554 | 4241 | my $oktorun = 1; | ||
555 | 4242 | my $exit_status = 0; | ||
556 | 4243 | |||
557 | 3937 | sub main { | 4244 | sub main { |
561 | 3938 | local @ARGV = @_; # set global ARGV for this package | 4245 | local @ARGV = @_; # set global ARGV for this package |
562 | 3939 | 4246 | $oktorun = 1; | |
563 | 3940 | my $q = new Quoter(); | 4247 | $exit_status = 0; |
564 | 3941 | 4248 | ||
565 | 3942 | # ######################################################################## | 4249 | # ######################################################################## |
566 | 3943 | # Get configuration information. | 4250 | # Get configuration information. |
567 | 3944 | # ######################################################################## | 4251 | # ######################################################################## |
569 | 3945 | $o = new OptionParser(); | 4252 | my $o = new OptionParser(); |
570 | 3946 | $o->get_specs(); | 4253 | $o->get_specs(); |
571 | 3947 | $o->get_opts(); | 4254 | $o->get_opts(); |
572 | 3948 | 4255 | ||
587 | 3949 | $o->set('collapse', $o->get('print')) unless $o->got('collapse'); | 4256 | my $dp = $o->DSNParser(); |
588 | 3950 | 4257 | $dp->prop('set-vars', $o->get('set-vars')); | |
589 | 3951 | $dp = $o->DSNParser(); | 4258 | |
590 | 3952 | my $dsn_defaults = $dp->parse_options($o); | 4259 | my $src; |
591 | 3953 | $source_dsn = @ARGV ? $dp->parse(shift @ARGV,$dsn_defaults) : $dsn_defaults; | 4260 | if ( my $src_dsn_string = shift @ARGV ) { |
592 | 3954 | $dest_dsn = $o->get('dest'); | 4261 | $src = Cxn->new( |
593 | 3955 | 4262 | dsn_string => $src_dsn_string, | |
594 | 3956 | # The source dsn is not an option so --dest cannot use OptionParser | 4263 | parent => $o->get('daemonize'), |
595 | 3957 | # to inherit values from it. Thus, we do it manually. --dest will | 4264 | DSNParser => $dp, |
596 | 3958 | # inherit from --user, --port, etc. | 4265 | OptionParser => $o, |
597 | 3959 | if ( $source_dsn && $dest_dsn ) { | 4266 | ); |
598 | 3960 | # If dest DSN only has D and t, this will copy h, P, S, etc. | 4267 | } |
599 | 3961 | # from the source DSN. | 4268 | |
600 | 3962 | $dest_dsn = $dp->copy($source_dsn, $dest_dsn); | 4269 | my $dst; |
601 | 4270 | if ( my $dst_dsn = $o->get('dest') ) { | ||
602 | 4271 | $dst = Cxn->new( | ||
603 | 4272 | dsn => $dst_dsn, | ||
604 | 4273 | prev_dsn => ($src ? $src->dsn : undef), | ||
605 | 4274 | parent => $o->get('daemonize'), | ||
606 | 4275 | DSNParser => $dp, | ||
607 | 4276 | OptionParser => $o, | ||
608 | 4277 | ); | ||
609 | 3963 | } | 4278 | } |
610 | 3964 | 4279 | ||
611 | 3965 | if ( !$o->get('help') ) { | 4280 | if ( !$o->get('help') ) { |
625 | 3966 | if ( !$source_dsn ) { | 4281 | if ( !$src ) { |
626 | 3967 | $o->save_error('Missing or invalid source host'); | 4282 | $o->save_error('No DSN was specified.'); |
627 | 3968 | } | 4283 | } |
628 | 3969 | if ( $dest_dsn && !$dest_dsn->{D} ) { | 4284 | if ( $dst && !$dst->dsn->{D} ) { |
629 | 3970 | $o->save_error("--dest requires a 'D' (database) part"); | 4285 | $o->save_error("--dest requires a 'D' (database) part."); |
630 | 3971 | } | 4286 | } |
631 | 3972 | if ( $dest_dsn && !$dest_dsn->{t} ) { | 4287 | if ( $dst && !$dst->dsn->{t} ) { |
632 | 3973 | $o->save_error("--dest requires a 't' (table) part"); | 4288 | $o->save_error("--dest requires a 't' (table) part."); |
620 | 3974 | } | ||
621 | 3975 | |||
622 | 3976 | # Avoid running forever with zero second interval. | ||
623 | 3977 | if ( $o->get('run-time') && !$o->get('interval') ) { | ||
624 | 3978 | $o->set('interval', 1); | ||
633 | 3979 | } | 4289 | } |
634 | 3980 | } | 4290 | } |
635 | 3981 | 4291 | ||
636 | @@ -3984,43 +4294,29 @@ | |||
637 | 3984 | # ######################################################################## | 4294 | # ######################################################################## |
638 | 3985 | # Connect to MySQL and set up the --dest, if any. | 4295 | # Connect to MySQL and set up the --dest, if any. |
639 | 3986 | # ######################################################################## | 4296 | # ######################################################################## |
643 | 3987 | my $dbh = get_cxn($source_dsn, 1); | 4297 | my $q = new Quoter(); |
644 | 3988 | my $dest_dbh; | 4298 | |
645 | 3989 | my $sth; | 4299 | $src->connect(); |
646 | 4300 | |||
647 | 4301 | my @cols = @{ $o->get('columns') }; | ||
648 | 3990 | my $ins_sth; | 4302 | my $ins_sth; |
670 | 3991 | 4303 | my $ins_sql; | |
671 | 3992 | # Since the user might not have specified a hostname for the connection, | 4304 | if ( $dst ) { |
672 | 3993 | # try to extract it from the $dbh | 4305 | $dst->connect(AutoCommit => 0); |
673 | 3994 | if ( !$source_dsn->{h} ) { | 4306 | |
674 | 3995 | ($source_dsn->{h}) = $dbh->{mysql_hostinfo} =~ m/(\w+) via/; | 4307 | my $db_tbl = $q->join_quote($dst->dsn->{D}, $dst->dsn->{t}); |
654 | 3996 | PTDEBUG && _d('Got source host from dbh:', $source_dsn->{h}); | ||
655 | 3997 | } | ||
656 | 3998 | |||
657 | 3999 | my @cols = qw( server ts thread txn_id txn_time user hostname ip db tbl idx | ||
658 | 4000 | lock_type lock_mode wait_hold victim query ); | ||
659 | 4001 | if ( $o->got('columns') ) { | ||
660 | 4002 | @cols = grep { $o->get('columns')->{$_} } @cols; | ||
661 | 4003 | } | ||
662 | 4004 | |||
663 | 4005 | if ( $dest_dsn ) { | ||
664 | 4006 | my $db_tbl = | ||
665 | 4007 | join('.', | ||
666 | 4008 | map { $q->quote($_) } | ||
667 | 4009 | grep { $_ } | ||
668 | 4010 | ( $dest_dsn->{D}, $dest_dsn->{t} )); | ||
669 | 4011 | $dest_dbh = get_cxn($dest_dsn, 0); | ||
675 | 4012 | my $cols = join(',', map { $q->quote($_) } @cols); | 4308 | my $cols = join(',', map { $q->quote($_) } @cols); |
680 | 4013 | my $parms = join(',', map { '?' } @cols); | 4309 | my $parms = join(',', map { '?' } @cols); |
681 | 4014 | my $sql = "INSERT IGNORE INTO $db_tbl($cols) VALUES($parms)"; | 4310 | $ins_sql = "INSERT IGNORE INTO $db_tbl ($cols) VALUES ($parms) " |
682 | 4015 | PTDEBUG && _d($sql); | 4311 | . "/* pt-deadlock-logger */"; |
683 | 4016 | $ins_sth = $dest_dbh->prepare($sql); | 4312 | PTDEBUG && _d($ins_sql); |
684 | 4313 | $ins_sth = $dst->dbh->prepare($ins_sql); | ||
685 | 4017 | 4314 | ||
686 | 4018 | if ( $o->get('create-dest-table') ) { | 4315 | if ( $o->get('create-dest-table') ) { |
690 | 4019 | my $db_tbl = $q->quote($dest_dsn->{D}, $dest_dsn->{t}); | 4316 | my $sql = $o->read_para_after(__FILE__, qr/MAGIC_dest_table/); |
691 | 4020 | $sql = $o->read_para_after(__FILE__, qr/MAGIC_dest_table/); | 4317 | $sql =~ s/deadlocks/IF NOT EXISTS $db_tbl/; |
689 | 4021 | $sql =~ s/deadlocks/IF NOT EXISTS $db_tbl/; | ||
692 | 4022 | PTDEBUG && _d($sql); | 4318 | PTDEBUG && _d($sql); |
694 | 4023 | $dest_dbh->do($sql); | 4319 | $dst->dbh->do($sql); |
695 | 4024 | } | 4320 | } |
696 | 4025 | } | 4321 | } |
697 | 4026 | 4322 | ||
698 | @@ -4039,6 +4335,16 @@ | |||
699 | 4039 | $daemon->make_PID_file(); | 4335 | $daemon->make_PID_file(); |
700 | 4040 | } | 4336 | } |
701 | 4041 | 4337 | ||
702 | 4338 | # If we daemonized, the parent has already exited and we're the child. | ||
703 | 4339 | # We shared a copy of every Cxn with the parent, and the parent's copies | ||
704 | 4340 | # were destroyed but the dbhs were not disconnected because the parent | ||
705 | 4341 | # attrib was true. Now, as the child, set it false so the dbhs will be | ||
706 | 4342 | # disconnected when our Cxn copies are destroyed. If we didn't daemonize, | ||
707 | 4343 | # then we're not really a parent (since we have no children), so set it | ||
708 | 4344 | # false to auto-disconnect the dbhs when our Cxns are destroyed. | ||
709 | 4345 | $src->{parent} = 0; | ||
710 | 4346 | $dst->{parent} = 0 if $dst; | ||
711 | 4347 | |||
712 | 4042 | # ######################################################################## | 4348 | # ######################################################################## |
713 | 4043 | # Do the version-check | 4349 | # Do the version-check |
714 | 4044 | # ######################################################################## | 4350 | # ######################################################################## |
715 | @@ -4046,117 +4352,155 @@ | |||
716 | 4046 | VersionCheck::version_check( | 4352 | VersionCheck::version_check( |
717 | 4047 | force => $o->got('version-check'), | 4353 | force => $o->got('version-check'), |
718 | 4048 | instances => [ | 4354 | instances => [ |
721 | 4049 | { dbh => $dbh, dsn => $source_dsn }, | 4355 | { dbh => $src->dbh, dsn => $src->dsn }, |
722 | 4050 | ($dest_dsn ? { dbh => $dest_dsn, dsn => $dest_dsn } : ()), | 4356 | ($dst ? { dbh => $dst->dbh, dsn => $dst->dsn } : ()) |
723 | 4051 | ], | 4357 | ], |
724 | 4052 | ); | 4358 | ); |
725 | 4053 | } | 4359 | } |
726 | 4054 | 4360 | ||
727 | 4055 | # ######################################################################## | 4361 | # ######################################################################## |
728 | 4362 | # Set upt the --clear-deadlocks table. | ||
729 | 4363 | # ######################################################################## | ||
730 | 4364 | my $clear_deadlocks_table_def; | ||
731 | 4365 | my $clear_deadlocks_table = $o->get('clear-deadlocks'); | ||
732 | 4366 | if ( $clear_deadlocks_table ) { | ||
733 | 4367 | $clear_deadlocks_table_def | ||
734 | 4368 | = $o->read_para_after(__FILE__, qr/MAGIC_clear_deadlocks/); | ||
735 | 4369 | if ( VersionParser->new($src->dbh) < '4.1.2') { | ||
736 | 4370 | $clear_deadlocks_table_def =~ s/ENGINE=/TYPE=/; | ||
737 | 4371 | } | ||
738 | 4372 | $clear_deadlocks_table_def | ||
739 | 4373 | =~ s/percona_schema.clear_deadlocks/$clear_deadlocks_table/; | ||
740 | 4374 | PTDEBUG && _d('--clear-deadlocks table:', $clear_deadlocks_table_def); | ||
741 | 4375 | } | ||
742 | 4376 | |||
743 | 4377 | # ######################################################################## | ||
744 | 4056 | # Start looking for and logging deadlocks. | 4378 | # Start looking for and logging deadlocks. |
745 | 4057 | # ######################################################################## | 4379 | # ######################################################################## |
761 | 4058 | my $last_fingerprint = ''; | 4380 | my $sep = $o->get('tab') ? "\t" : ' '; |
762 | 4059 | 4381 | my $last_fingerprint = ''; | |
763 | 4060 | $oktorun = 1; | 4382 | my $parse_deadlocks_options = { |
764 | 4061 | my $start = time(); | 4383 | 'server' => $src->dsn->{h} || $src->{hostname}, |
765 | 4062 | my $end = $start + ($o->get('run-time') || 0); # When we should exit | 4384 | 'numeric-ip' => $o->got('numeric-ip'), |
766 | 4063 | my $now = $start; | 4385 | }; |
767 | 4064 | while ( # Quit if: | 4386 | |
768 | 4065 | ($start == $end || $now < $end) # time is exceeded | 4387 | my $run_time = Runtime->new( |
769 | 4066 | && $oktorun # or instructed to quit | 4388 | run_time => $o->get('run-time'), |
770 | 4067 | ) | 4389 | now => sub { return time }, |
771 | 4068 | { | 4390 | ); |
772 | 4069 | my $text = $dbh->selectrow_hashref("SHOW /*!40100 ENGINE*/ INNODB STATUS")->{Status}; | 4391 | |
773 | 4070 | my $parse_deadlocks_options = { | 4392 | my $interval = $o->get('interval'); |
774 | 4071 | 'numeric-ip' => $o->got('numeric-ip'), | 4393 | my $iters = $o->get('iterations'); |
775 | 4072 | 'collapse' => $o->got('collapse'), | 4394 | PTDEBUG && _d('iterations:', $iters, 'interval:', $interval); |
776 | 4395 | |||
777 | 4396 | ITERATION: | ||
778 | 4397 | while ( | ||
779 | 4398 | $oktorun | ||
780 | 4399 | && $run_time->have_time() | ||
781 | 4400 | && (!defined $iters || $iters--) | ||
782 | 4401 | ) { | ||
783 | 4402 | |||
784 | 4403 | my %txns; | ||
785 | 4404 | my $fingerprint; | ||
786 | 4405 | eval { | ||
787 | 4406 | my $sql = "SHOW /*!40100 ENGINE*/ INNODB STATUS " | ||
788 | 4407 | . "/* pt-deadlock-logger */"; | ||
789 | 4408 | my $text = $src->dbh->selectrow_hashref($sql)->{status}; | ||
790 | 4409 | |||
791 | 4410 | %txns = %{parse_deadlocks($text, $parse_deadlocks_options)}; | ||
792 | 4411 | $fingerprint = fingerprint(\%txns); | ||
793 | 4073 | }; | 4412 | }; |
802 | 4074 | my %txns = %{parse_deadlocks($text, $parse_deadlocks_options)}; | 4413 | if ( my $e = $EVAL_ERROR ) { |
803 | 4075 | my $fingerprint = fingerprint(\%txns); | 4414 | PTDEBUG && _d('Error getting InnoDB status:', $e); |
804 | 4076 | 4415 | if ( $src->lost_connection($e) ) { | |
805 | 4077 | if ( $ins_sth ) { | 4416 | eval { $src->connect() }; |
806 | 4078 | foreach my $txn (sort { $a->{thread} <=> $b->{thread} } values %txns) { | 4417 | if ( $EVAL_ERROR ) { |
807 | 4079 | $ins_sth->execute(@{$txn}{@cols}); | 4418 | warn "Lost connection to " . $src->name . ". Will try " |
808 | 4080 | } | 4419 | . "to reconnect in the next iteration.\n"; |
809 | 4081 | $dest_dbh->commit(); | 4420 | } |
810 | 4421 | else { | ||
811 | 4422 | PTDEBUG && _d('Reconnected to MySQL'); | ||
812 | 4423 | redo ITERATION; | ||
813 | 4424 | } | ||
814 | 4425 | } | ||
815 | 4426 | else { | ||
816 | 4427 | warn "Error getting SHOW ENGINE INNODB STATUS: $EVAL_ERROR"; | ||
817 | 4428 | $exit_status |= 1; | ||
818 | 4429 | } | ||
819 | 4082 | } | 4430 | } |
820 | 4431 | else { | ||
821 | 4432 | if ( $ins_sth ) { | ||
822 | 4433 | eval { | ||
823 | 4434 | PTDEBUG && _d('Saving deadlock to --dest'); | ||
824 | 4435 | foreach my $txn ( | ||
825 | 4436 | sort { $a->{thread} <=> $b->{thread} } values %txns | ||
826 | 4437 | ) { | ||
827 | 4438 | $ins_sth->execute(@{$txn}{@cols}); | ||
828 | 4439 | } | ||
829 | 4440 | $dst->dbh->commit(); | ||
830 | 4441 | }; | ||
831 | 4442 | if ( my $e = $EVAL_ERROR ) { | ||
832 | 4443 | PTDEBUG && _d('Error saving to --dest:', $e); | ||
833 | 4444 | if ( $dst->lost_connection($e) ) { | ||
834 | 4445 | eval { | ||
835 | 4446 | $ins_sth->finish() if $ins_sth; | ||
836 | 4447 | $dst->dbh->disconnect() if $dst->dbh; | ||
837 | 4448 | $dst->connect(AutoCommit => 0); | ||
838 | 4449 | $ins_sth = $dst->dbh->prepare($ins_sql); | ||
839 | 4450 | }; | ||
840 | 4451 | if ( $EVAL_ERROR ) { | ||
841 | 4452 | warn "Lost connection to " . $dst->name . ". Will try " | ||
842 | 4453 | . "to reconnect in the next iteration.\n"; | ||
843 | 4454 | } | ||
844 | 4455 | else { | ||
845 | 4456 | PTDEBUG && _d('Reconnected to MySQL (--dest)'); | ||
846 | 4457 | redo ITERATION; | ||
847 | 4458 | } | ||
848 | 4459 | } | ||
849 | 4460 | else { | ||
850 | 4461 | warn "Error saving to --dest: $EVAL_ERROR"; | ||
851 | 4462 | $exit_status |= 1; | ||
852 | 4463 | } | ||
853 | 4464 | } | ||
854 | 4465 | } | ||
855 | 4083 | 4466 | ||
865 | 4084 | if ( $fingerprint ne $last_fingerprint ) { | 4467 | if ( $fingerprint ne $last_fingerprint ) { |
866 | 4085 | PTDEBUG && _d('New deadlock'); | 4468 | PTDEBUG && _d('New deadlock'); |
867 | 4086 | if ( $o->got('print') || !$o->got('dest') ) { | 4469 | if ( !$o->get('quiet') ) { |
868 | 4087 | my $sep = $o->get('tab') ? "\t" : ' '; | 4470 | print join($sep, @cols), "\n"; |
869 | 4088 | print join($sep, @cols), "\n"; | 4471 | foreach my $txn ( |
870 | 4089 | foreach my $txn (sort {$a->{thread}<=>$b->{thread}} values %txns) { | 4472 | sort { $a->{thread} <=> $b->{thread} } values %txns |
871 | 4090 | # If 'collapse' is on, it's already been taken care of, | 4473 | ) { |
863 | 4091 | # but if it's unset, by default strip whitespace. | ||
864 | 4092 | if ( !$o->got('collapse') ) { | ||
872 | 4093 | $txn->{query} =~ s/\s+/ /g; | 4474 | $txn->{query} =~ s/\s+/ /g; |
873 | 4475 | print join($sep, map { $txn->{$_} } @cols), "\n"; | ||
874 | 4094 | } | 4476 | } |
875 | 4095 | print join($sep, map { $txn->{$_} } @cols), "\n"; | ||
876 | 4096 | } | 4477 | } |
877 | 4097 | } | 4478 | } |
936 | 4098 | } | 4479 | else { |
937 | 4099 | else { | 4480 | PTDEBUG && _d('Same deadlock, not printing'); |
938 | 4100 | PTDEBUG && _d('Same deadlock, not printing'); | 4481 | } |
939 | 4101 | } | 4482 | |
940 | 4102 | # Save deadlock's fingerprint for next interval. | 4483 | $last_fingerprint = $fingerprint; |
941 | 4103 | $last_fingerprint = $fingerprint; | 4484 | |
942 | 4104 | 4485 | if ( $clear_deadlocks_table ) { | |
943 | 4105 | # If specified, clear the deadlock... | 4486 | clear_deadlocks( |
944 | 4106 | if ( my $db_tbl = $o->get('clear-deadlocks') ) { | 4487 | dsn => $src->dsn, |
945 | 4107 | PTDEBUG && _d('Creating --clear-deadlocks table', $db_tbl); | 4488 | table => $clear_deadlocks_table, |
946 | 4108 | $dbh->{AutoCommit} = 0; | 4489 | table_def => $clear_deadlocks_table_def, |
947 | 4109 | my $sql = $o->read_para_after(__FILE__, qr/MAGIC_clear_deadlocks/); | 4490 | DSNParser => $dp, |
948 | 4110 | 4491 | ); | |
949 | 4111 | if ( VersionParser->new($dbh) < '4.1.2') { | 4492 | } |
950 | 4112 | $sql =~ s/ENGINE=/TYPE=/; | 4493 | } |
951 | 4113 | } | 4494 | |
952 | 4114 | $sql =~ s/test.deadlock_maker/$db_tbl/; | 4495 | # Sleep if there's an --iteration left. |
953 | 4115 | PTDEBUG && _d($sql); | 4496 | if ( !defined $iters || $iters ) { |
954 | 4116 | $dbh->do($sql); | 4497 | PTDEBUG && _d('Sleeping', $interval, 'seconds'); |
955 | 4117 | $sql = "INSERT INTO $db_tbl(a) VALUES(1)"; | 4498 | sleep $interval; |
898 | 4118 | PTDEBUG && _d($sql); | ||
899 | 4119 | $dbh->do($sql); # I'm holding locks on the table now. | ||
900 | 4120 | |||
901 | 4121 | # Fork off a child to try to take a lock on the table. | ||
902 | 4122 | my $pid = fork(); | ||
903 | 4123 | if ( defined($pid) && $pid == 0 ) { # I am a child | ||
904 | 4124 | my $dbh_child = get_cxn($source_dsn, 0); | ||
905 | 4125 | $sql = "SELECT * FROM $db_tbl FOR UPDATE"; | ||
906 | 4126 | PTDEBUG && _d($sql); | ||
907 | 4127 | eval { $dbh_child->do($sql); }; # Should block against parent. | ||
908 | 4128 | PTDEBUG && _d($EVAL_ERROR); # Parent inserted value 0. | ||
909 | 4129 | $sql = "COMMIT"; | ||
910 | 4130 | PTDEBUG && _d($sql); | ||
911 | 4131 | $dbh_child->do($sql); | ||
912 | 4132 | exit; | ||
913 | 4133 | } | ||
914 | 4134 | elsif ( !defined($pid) ) { | ||
915 | 4135 | die("Unable to fork for clearing deadlocks!\n"); | ||
916 | 4136 | } | ||
917 | 4137 | sleep 1; | ||
918 | 4138 | $sql = "INSERT INTO $db_tbl(a) VALUES(0)";# Will make child deadlock | ||
919 | 4139 | PTDEBUG && _d($sql); | ||
920 | 4140 | eval { $dbh->do($sql); }; | ||
921 | 4141 | PTDEBUG && _d($EVAL_ERROR); | ||
922 | 4142 | waitpid($pid, 0); | ||
923 | 4143 | $sql = "DROP TABLE $db_tbl"; | ||
924 | 4144 | PTDEBUG && _d($sql); | ||
925 | 4145 | $dbh->do($sql); | ||
926 | 4146 | } | ||
927 | 4147 | |||
928 | 4148 | # If there's an --interval argument, run forever or till specified. | ||
929 | 4149 | # Otherwise just run once. | ||
930 | 4150 | if ( $o->get('interval') ) { | ||
931 | 4151 | sleep($o->get('interval')); | ||
932 | 4152 | $now = time(); | ||
933 | 4153 | } | ||
934 | 4154 | else { | ||
935 | 4155 | $oktorun = 0; | ||
956 | 4156 | } | 4499 | } |
957 | 4157 | } | 4500 | } |
958 | 4158 | 4501 | ||
960 | 4159 | return 0; | 4502 | PTDEBUG && _d('Done running, exiting', $exit_status); |
961 | 4503 | return $exit_status; | ||
962 | 4160 | } | 4504 | } |
963 | 4161 | 4505 | ||
964 | 4162 | # ############################################################################ | 4506 | # ############################################################################ |
965 | @@ -4244,7 +4588,7 @@ | |||
966 | 4244 | 4588 | ||
967 | 4245 | my ( $query_text ) = $body =~ m/\nMySQL thread id .*\n((?s).*)/; | 4589 | my ( $query_text ) = $body =~ m/\nMySQL thread id .*\n((?s).*)/; |
968 | 4246 | $query_text =~ s/\s+$//; | 4590 | $query_text =~ s/\s+$//; |
970 | 4247 | $query_text =~ s/\s+/ /g if $args->{'collapse'}; | 4591 | $query_text =~ s/\s+/ /g; |
971 | 4248 | 4592 | ||
972 | 4249 | @{$hash}{qw(thread hostname ip user query)} | 4593 | @{$hash}{qw(thread hostname ip user query)} |
973 | 4250 | = ($mysql_thread_id, $hostname, $ip, $user, $query_text); | 4594 | = ($mysql_thread_id, $hostname, $ip, $user, $query_text); |
974 | @@ -4290,13 +4634,100 @@ | |||
975 | 4290 | foreach my $txn ( values %txns ) { | 4634 | foreach my $txn ( values %txns ) { |
976 | 4291 | $txn->{victim} = $txn->{id} == $victim ? 1 : 0; | 4635 | $txn->{victim} = $txn->{id} == $victim ? 1 : 0; |
977 | 4292 | $txn->{ts} = $ts; | 4636 | $txn->{ts} = $ts; |
979 | 4293 | $txn->{server} = $source_dsn->{h} || ''; | 4637 | $txn->{server} = $args->{server} || ''; |
980 | 4294 | $txn->{ip} = inet_aton($txn->{ip}) if $args->{'numeric-ip'}; | 4638 | $txn->{ip} = inet_aton($txn->{ip}) if $args->{'numeric-ip'}; |
981 | 4295 | } | 4639 | } |
982 | 4296 | 4640 | ||
983 | 4297 | return \%txns; | 4641 | return \%txns; |
984 | 4298 | } | 4642 | } |
985 | 4299 | 4643 | ||
986 | 4644 | sub clear_deadlocks { | ||
987 | 4645 | my (%args) = @_; | ||
988 | 4646 | my @required_args = qw(dsn table table_def DSNParser); | ||
989 | 4647 | foreach my $arg ( @required_args ) { | ||
990 | 4648 | die "I need a $arg argument" unless $args{$arg}; | ||
991 | 4649 | } | ||
992 | 4650 | my $dsn = $args{dsn}; | ||
993 | 4651 | my $table = $args{table}; | ||
994 | 4652 | my $table_def = $args{table_def}; | ||
995 | 4653 | my $dp = $args{DSNParser}; | ||
996 | 4654 | PTDEBUG && _d('Clearing deadlocks with table', $table, $table_def); | ||
997 | 4655 | |||
998 | 4656 | my $parent_dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit=>0 }); | ||
999 | 4657 | $parent_dbh->{InactiveDestroy} = 1; # because of forking | ||
1000 | 4658 | |||
1001 | 4659 | # Create the deadlocks table. | ||
1002 | 4660 | PTDEBUG && _d($table_def); | ||
1003 | 4661 | $parent_dbh->do($table_def); | ||
1004 | 4662 | |||
1005 | 4663 | # Get a lock on it. | ||
1006 | 4664 | my $sql = "INSERT INTO $table (a) VALUES (1) " | ||
1007 | 4665 | . "/* pt-deadlock-logger clear deadlocks parent */"; | ||
1008 | 4666 | PTDEBUG && _d($sql); | ||
1009 | 4667 | $parent_dbh->do($sql); | ||
1010 | 4668 | |||
1011 | 4669 | my ($sync_fh, $sync_file) = tempfile( | ||
1012 | 4670 | 'pt-deadlock-logger-clear-deadlocks.XXXXXXX', | ||
1013 | 4671 | DIR => File::Spec->tmpdir(), | ||
1014 | 4672 | ); | ||
1015 | 4673 | PTDEBUG && _d('Sync file:', $sync_file); | ||
1016 | 4674 | close $sync_fh; | ||
1017 | 4675 | unlink $sync_file; | ||
1018 | 4676 | |||
1019 | 4677 | # Fork a child to try to take a lock on the table. | ||
1020 | 4678 | my $pid = fork(); | ||
1021 | 4679 | if ( defined($pid) && $pid == 0 ) { | ||
1022 | 4680 | # I am the child | ||
1023 | 4681 | PTDEBUG && _d('Clear deadlocks child', $PID); | ||
1024 | 4682 | my $child_dbh = $dp->get_dbh($dp->get_cxn_params($dsn), {AutoCommit=>0}); | ||
1025 | 4683 | my $sql = "SELECT * FROM $table FOR UPDATE " | ||
1026 | 4684 | . "/* pt-deadlock-logger clear deadlocks child */"; | ||
1027 | 4685 | PTDEBUG && _d($sql); | ||
1028 | 4686 | open my $fh, '>', $sync_file | ||
1029 | 4687 | or die "Error creating $sync_file: $OS_ERROR"; | ||
1030 | 4688 | close $fh; | ||
1031 | 4689 | PTDEBUG && _d('Clear deadlocks child ready (child)'); | ||
1032 | 4690 | eval { $child_dbh->do($sql); }; # Should block against parent. | ||
1033 | 4691 | PTDEBUG && _d($EVAL_ERROR); # Parent inserted value 0. | ||
1034 | 4692 | $child_dbh->commit(); | ||
1035 | 4693 | $child_dbh->disconnect(); | ||
1036 | 4694 | exit; | ||
1037 | 4695 | } | ||
1038 | 4696 | elsif ( !defined($pid) ) { | ||
1039 | 4697 | die "Failed to fork for --clear-deadlocks: " . ($OS_ERROR || ''); | ||
1040 | 4698 | } | ||
1041 | 4699 | |||
1042 | 4700 | # Wait up to 10s for the child to connect and become ready. | ||
1043 | 4701 | for ( 1..40 ) { | ||
1044 | 4702 | last if -f $sync_file; | ||
1045 | 4703 | PTDEBUG && _d('Waiting for the clear deadlocks child'); | ||
1046 | 4704 | sleep 0.25; | ||
1047 | 4705 | } | ||
1048 | 4706 | PTDEBUG && _d('Clear deadlocks child ready (parent)'); | ||
1049 | 4707 | sleep 0.25; # wait for child to exec its SELECT statement | ||
1050 | 4708 | |||
1051 | 4709 | # Make the child deadlock. | ||
1052 | 4710 | $sql = "INSERT INTO $table (a) VALUES (0) " | ||
1053 | 4711 | . "/* pt-deadlock-logger clear deadlocks parent */"; | ||
1054 | 4712 | PTDEBUG && _d($sql); | ||
1055 | 4713 | eval { $parent_dbh->do($sql); }; | ||
1056 | 4714 | PTDEBUG && _d($EVAL_ERROR); | ||
1057 | 4715 | |||
1058 | 4716 | # Reap the child. | ||
1059 | 4717 | waitpid($pid, 0); | ||
1060 | 4718 | |||
1061 | 4719 | # Drop the table. | ||
1062 | 4720 | $sql = "DROP TABLE IF EXISTS $table"; | ||
1063 | 4721 | PTDEBUG && _d($sql); | ||
1064 | 4722 | $parent_dbh->do($sql); | ||
1065 | 4723 | |||
1066 | 4724 | $parent_dbh->disconnect(); | ||
1067 | 4725 | |||
1068 | 4726 | unlink $sync_file; | ||
1069 | 4727 | |||
1070 | 4728 | return; | ||
1071 | 4729 | } | ||
1072 | 4730 | |||
1073 | 4300 | sub fingerprint { | 4731 | sub fingerprint { |
1074 | 4301 | my ( $txns ) = @_; | 4732 | my ( $txns ) = @_; |
1075 | 4302 | my $fingerprint = ''; | 4733 | my $fingerprint = ''; |
1076 | @@ -4308,21 +4739,11 @@ | |||
1077 | 4308 | return $fingerprint; | 4739 | return $fingerprint; |
1078 | 4309 | } | 4740 | } |
1079 | 4310 | 4741 | ||
1084 | 4311 | # Catches signals so the program can exit gracefully. | 4742 | sub sig_int { |
1085 | 4312 | sub finish { | 4743 | my ( $signal ) = @_; |
1082 | 4313 | my ($signal) = @_; | ||
1083 | 4314 | print STDERR "Exiting on SIG$signal.\n"; | ||
1086 | 4315 | $oktorun = 0; | 4744 | $oktorun = 0; |
1097 | 4316 | } | 4745 | print STDERR "# Caught SIG$signal. Use 'kill -ABRT $PID' if " |
1098 | 4317 | 4746 | . "the tool does not exit normally in a few seconds.\n"; | |
1089 | 4318 | sub get_cxn { | ||
1090 | 4319 | my ( $dsn, $ac ) = @_; | ||
1091 | 4320 | if ( $o->get('ask-pass') ) { | ||
1092 | 4321 | $dsn->{p} = OptionParser::prompt_noecho("Enter password: "); | ||
1093 | 4322 | } | ||
1094 | 4323 | my $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), {AutoCommit => $ac}); | ||
1095 | 4324 | $dbh->{InactiveDestroy} = 1; # Because of forking. | ||
1096 | 4325 | return $dbh; | ||
1099 | 4326 | } | 4747 | } |
1100 | 4327 | 4748 | ||
1101 | 4328 | sub _d { | 4749 | sub _d { |
1102 | @@ -4347,32 +4768,28 @@ | |||
1103 | 4347 | 4768 | ||
1104 | 4348 | =head1 NAME | 4769 | =head1 NAME |
1105 | 4349 | 4770 | ||
1107 | 4350 | pt-deadlock-logger - Extract and log MySQL deadlock information. | 4771 | pt-deadlock-logger - Log MySQL deadlocks. |
1108 | 4351 | 4772 | ||
1109 | 4352 | =head1 SYNOPSIS | 4773 | =head1 SYNOPSIS |
1110 | 4353 | 4774 | ||
1133 | 4354 | Usage: pt-deadlock-logger [OPTION...] SOURCE_DSN | 4775 | Usage: pt-deadlock-logger [OPTIONS] DSN |
1134 | 4355 | 4776 | ||
1135 | 4356 | pt-deadlock-logger extracts and saves information about the most recent deadlock | 4777 | pt-deadlock-logger logs information about MySQL deadlocks on the given |
1136 | 4357 | in a MySQL server. | 4778 | DSN. Information is printed to C<STDOUT>, and it can also be saved to a |
1137 | 4358 | 4779 | table by specifying L<"--dest">. The tool runs for forever unless | |
1138 | 4359 | Print deadlocks on SOURCE_DSN: | 4780 | L<"--run-time"> or L<"--iterations"> is specified. |
1139 | 4360 | 4781 | ||
1140 | 4361 | pt-deadlock-logger SOURCE_DSN | 4782 | Print deadlocks on host1: |
1141 | 4362 | 4783 | ||
1142 | 4363 | Store deadlock information from SOURCE_DSN in test.deadlocks table on SOURCE_DSN | 4784 | pt-fk-error-logger h=host1 |
1143 | 4364 | (source and destination are the same host): | 4785 | |
1144 | 4365 | 4786 | Print deadlocks on host1 once then exit: | |
1145 | 4366 | pt-deadlock-logger SOURCE_DSN --dest D=test,t=deadlocks | 4787 | |
1146 | 4367 | 4788 | pt-fk-error-logger h=host1 --iterations 1 | |
1147 | 4368 | Store deadlock information from SOURCE_DSN in test.deadlocks table on DEST_DSN | 4789 | |
1148 | 4369 | (source and destination are different hosts): | 4790 | Save deadlocks on host1 to percona_schema.fke on host2: |
1149 | 4370 | 4791 | ||
1150 | 4371 | pt-deadlock-logger SOURCE_DSN --dest DEST_DSN,D=test,t=deadlocks | 4792 | pt-fk-error-logger h=host1 --dest h=host2,D=percona_schema,t=deadlocks |
1129 | 4372 | |||
1130 | 4373 | Daemonize and check for deadlocks on SOURCE_DSN every 30 seconds for 4 hours: | ||
1131 | 4374 | |||
1132 | 4375 | pt-deadlock-logger SOURCE_DSN --dest D=test,t=deadlocks --daemonize --run-time 4h --interval 30s | ||
1151 | 4376 | 4793 | ||
1152 | 4377 | =head1 RISKS | 4794 | =head1 RISKS |
1153 | 4378 | 4795 | ||
1154 | @@ -4398,43 +4815,93 @@ | |||
1155 | 4398 | 4815 | ||
1156 | 4399 | =head1 DESCRIPTION | 4816 | =head1 DESCRIPTION |
1157 | 4400 | 4817 | ||
1190 | 4401 | pt-deadlock-logger extracts deadlock data from a MySQL server. Currently only | 4818 | pt-deadlock-logger prints information about MySQL deadlocks by polling |
1191 | 4402 | InnoDB deadlock information is available. You can print the information to | 4819 | and parsing C<SHOW ENGINE INNODB STATUS>. When a new deadlock occurs, |
1192 | 4403 | standard output, store it in a database table, or both. If neither | 4820 | it's printed to C<STDOUT> and, if specified, saved to L<"--dest">. |
1193 | 4404 | L<"--print"> nor L<"--dest"> are given, then the deadlock information is | 4821 | |
1194 | 4405 | printed by default. If only L<"--dest"> is given, then the deadlock | 4822 | Only new deadlocks are printed. A fingerprint for each deadlock is created |
1195 | 4406 | information is only stored. If both options are given, then the deadlock | 4823 | using the deadlock's server, ts, and thread values (even if these |
1196 | 4407 | information is printed and stored. | 4824 | columns are not specified by L<"--columns">). A deadlock is printed if |
1197 | 4408 | 4825 | its fingerprint is different than the last deadlock's fingerprint. | |
1198 | 4409 | The source host can be specified using one of two methods. The first method is | 4826 | |
1199 | 4410 | to use at least one of the standard connection-related command line options: | 4827 | The L<"--dest"> statement uses C<INSERT IGNORE> to eliminate duplicate |
1200 | 4411 | L<"--defaults-file">, L<"--password">, L<"--host">, L<"--port">, L<"--socket"> | 4828 | deadlocks, so every deadlock is saved for every L<"--iterations">. |
1169 | 4412 | or L<"--user">. These options only apply to the source host; they cannot be | ||
1170 | 4413 | used to specify the destination host. | ||
1171 | 4414 | |||
1172 | 4415 | The second method to specify the source host, or the optional destination host | ||
1173 | 4416 | using L<"--dest">, is a DSN. A DSN is a special syntax that can be either just | ||
1174 | 4417 | a hostname (like C<server.domain.com> or C<1.2.3.4>), or a | ||
1175 | 4418 | C<key=value,key=value> string. Keys are a single letter: | ||
1176 | 4419 | |||
1177 | 4420 | KEY MEANING | ||
1178 | 4421 | === ======= | ||
1179 | 4422 | h Connect to host | ||
1180 | 4423 | P Port number to use for connection | ||
1181 | 4424 | S Socket file to use for connection | ||
1182 | 4425 | u User for login if not current user | ||
1183 | 4426 | p Password to use when connecting | ||
1184 | 4427 | F Only read default options from the given file | ||
1185 | 4428 | |||
1186 | 4429 | If you omit any values from the destination host DSN, they are filled in with | ||
1187 | 4430 | values from the source host, so you don't need to specify them in both places. | ||
1188 | 4431 | C<pt-deadlock-logger> reads all normal MySQL option files, such as ~/.my.cnf, so | ||
1189 | 4432 | you may not need to specify username, password and other common options at all. | ||
1201 | 4433 | 4829 | ||
1202 | 4434 | =head1 OUTPUT | 4830 | =head1 OUTPUT |
1203 | 4435 | 4831 | ||
1206 | 4436 | You can choose which columns are output and/or saved to L<"--dest"> with the | 4832 | New deadlocks are printed to C<STDOUT>, unless L<"--quiet"> is specified. |
1207 | 4437 | L<"--columns"> argument. The default columns are as follows: | 4833 | Errors and warnings are printed to C<STDERR>. |
1208 | 4834 | |||
1209 | 4835 | See also L<"--columns"> and L<"--tab">. | ||
1210 | 4836 | |||
1211 | 4837 | =head1 INNODB CAVEATS AND DETAILS | ||
1212 | 4838 | |||
1213 | 4839 | InnoDB's output is hard to parse and sometimes there's no way to do it right. | ||
1214 | 4840 | |||
1215 | 4841 | Sometimes not all information (for example, username or IP address) is included | ||
1216 | 4842 | in the deadlock information. In this case there's nothing for the script to put | ||
1217 | 4843 | in those columns. It may also be the case that the deadlock output is so long | ||
1218 | 4844 | (because there were a lot of locks) that the whole thing is truncated. | ||
1219 | 4845 | |||
1220 | 4846 | Though there are usually two transactions involved in a deadlock, there are more | ||
1221 | 4847 | locks than that; at a minimum, one more lock than transactions is necessary to | ||
1222 | 4848 | create a cycle in the waits-for graph. pt-deadlock-logger prints the | ||
1223 | 4849 | transactions (always two in the InnoDB output, even when there are more | ||
1224 | 4850 | transactions in the waits-for graph than that) and fills in locks. It prefers | ||
1225 | 4851 | waited-for over held when choosing lock information to output, but you can | ||
1226 | 4852 | figure out the rest with a moment's thought. If you see one wait-for and one | ||
1227 | 4853 | held lock, you're looking at the same lock, so of course you'd prefer to see | ||
1228 | 4854 | both wait-for locks and get more information. If the two waited-for locks are | ||
1229 | 4855 | not on the same table, more than two transactions were involved in the deadlock. | ||
1230 | 4856 | |||
1231 | 4857 | Finally, keep in mind that, because usernames with spaces are not quoted by | ||
1232 | 4858 | InnoDB, the tool will generally misreport the second word of these usernames | ||
1233 | 4859 | as the hostname. | ||
1234 | 4860 | |||
1235 | 4861 | =head1 OPTIONS | ||
1236 | 4862 | |||
1237 | 4863 | This tool accepts additional command-line arguments. Refer to the | ||
1238 | 4864 | L<"SYNOPSIS"> and usage information for details. | ||
1239 | 4865 | |||
1240 | 4866 | =over | ||
1241 | 4867 | |||
1242 | 4868 | =item --ask-pass | ||
1243 | 4869 | |||
1244 | 4870 | Prompt for a password when connecting to MySQL. | ||
1245 | 4871 | |||
1246 | 4872 | =item --charset | ||
1247 | 4873 | |||
1248 | 4874 | short form: -A; type: string | ||
1249 | 4875 | |||
1250 | 4876 | Default character set. If the value is utf8, sets Perl's binmode on | ||
1251 | 4877 | STDOUT to utf8, passes the mysql_enable_utf8 option to DBD::mysql, and runs SET | ||
1252 | 4878 | NAMES UTF8 after connecting to MySQL. Any other value sets binmode on STDOUT | ||
1253 | 4879 | without the utf8 layer, and runs SET NAMES after connecting to MySQL. | ||
1254 | 4880 | |||
1255 | 4881 | =item --clear-deadlocks | ||
1256 | 4882 | |||
1257 | 4883 | type: string | ||
1258 | 4884 | |||
1259 | 4885 | Use this table to create a small deadlock. This usually has the effect of | ||
1260 | 4886 | clearing out a huge deadlock, which otherwise consumes the entire output of | ||
1261 | 4887 | C<SHOW INNODB STATUS>. The table must not exist. pt-deadlock-logger will | ||
1262 | 4888 | create it with the following structure: | ||
1263 | 4889 | |||
1264 | 4890 | =for comment ignore-pt-internal-value | ||
1265 | 4891 | MAGIC_clear_deadlocks | ||
1266 | 4892 | |||
1267 | 4893 | CREATE TABLE percona_schema.clear_deadlocks ( | ||
1268 | 4894 | a INT PRIMARY KEY | ||
1269 | 4895 | ) ENGINE=InnoDB | ||
1270 | 4896 | |||
1271 | 4897 | After creating the table and causing a small deadlock, the tool will drop the | ||
1272 | 4898 | table again. | ||
1273 | 4899 | |||
1274 | 4900 | =item --columns | ||
1275 | 4901 | |||
1276 | 4902 | type: Array; default: server, ts, thread, txn_id, txn_time, user, hostname, ip, db, tbl, idx, lock_type, lock_mode, wait_hold, victim, query | ||
1277 | 4903 | |||
1278 | 4904 | The columns are: | ||
1279 | 4438 | 4905 | ||
1280 | 4439 | =over | 4906 | =over |
1281 | 4440 | 4907 | ||
1282 | @@ -4509,78 +4976,6 @@ | |||
1283 | 4509 | 4976 | ||
1284 | 4510 | =back | 4977 | =back |
1285 | 4511 | 4978 | ||
1286 | 4512 | =head1 INNODB CAVEATS AND DETAILS | ||
1287 | 4513 | |||
1288 | 4514 | InnoDB's output is hard to parse and sometimes there's no way to do it right. | ||
1289 | 4515 | |||
1290 | 4516 | Sometimes not all information (for example, username or IP address) is included | ||
1291 | 4517 | in the deadlock information. In this case there's nothing for the script to put | ||
1292 | 4518 | in those columns. It may also be the case that the deadlock output is so long | ||
1293 | 4519 | (because there were a lot of locks) that the whole thing is truncated. | ||
1294 | 4520 | |||
1295 | 4521 | Though there are usually two transactions involved in a deadlock, there are more | ||
1296 | 4522 | locks than that; at a minimum, one more lock than transactions is necessary to | ||
1297 | 4523 | create a cycle in the waits-for graph. pt-deadlock-logger prints the | ||
1298 | 4524 | transactions (always two in the InnoDB output, even when there are more | ||
1299 | 4525 | transactions in the waits-for graph than that) and fills in locks. It prefers | ||
1300 | 4526 | waited-for over held when choosing lock information to output, but you can | ||
1301 | 4527 | figure out the rest with a moment's thought. If you see one wait-for and one | ||
1302 | 4528 | held lock, you're looking at the same lock, so of course you'd prefer to see | ||
1303 | 4529 | both wait-for locks and get more information. If the two waited-for locks are | ||
1304 | 4530 | not on the same table, more than two transactions were involved in the deadlock. | ||
1305 | 4531 | |||
1306 | 4532 | Finally, keep in mind that, because usernames with spaces are not quoted by | ||
1307 | 4533 | InnoDB, the tool will generally misreport the second word of these usernames | ||
1308 | 4534 | as the hostname. | ||
1309 | 4535 | |||
1310 | 4536 | =head1 OPTIONS | ||
1311 | 4537 | |||
1312 | 4538 | This tool accepts additional command-line arguments. Refer to the | ||
1313 | 4539 | L<"SYNOPSIS"> and usage information for details. | ||
1314 | 4540 | |||
1315 | 4541 | =over | ||
1316 | 4542 | |||
1317 | 4543 | =item --ask-pass | ||
1318 | 4544 | |||
1319 | 4545 | Prompt for a password when connecting to MySQL. | ||
1320 | 4546 | |||
1321 | 4547 | =item --charset | ||
1322 | 4548 | |||
1323 | 4549 | short form: -A; type: string | ||
1324 | 4550 | |||
1325 | 4551 | Default character set. If the value is utf8, sets Perl's binmode on | ||
1326 | 4552 | STDOUT to utf8, passes the mysql_enable_utf8 option to DBD::mysql, and runs SET | ||
1327 | 4553 | NAMES UTF8 after connecting to MySQL. Any other value sets binmode on STDOUT | ||
1328 | 4554 | without the utf8 layer, and runs SET NAMES after connecting to MySQL. | ||
1329 | 4555 | |||
1330 | 4556 | =item --clear-deadlocks | ||
1331 | 4557 | |||
1332 | 4558 | type: string | ||
1333 | 4559 | |||
1334 | 4560 | Use this table to create a small deadlock. This usually has the effect of | ||
1335 | 4561 | clearing out a huge deadlock, which otherwise consumes the entire output of | ||
1336 | 4562 | C<SHOW INNODB STATUS>. The table must not exist. pt-deadlock-logger will | ||
1337 | 4563 | create it with the following MAGIC_clear_deadlocks structure: | ||
1338 | 4564 | |||
1339 | 4565 | CREATE TABLE test.deadlock_maker(a INT PRIMARY KEY) ENGINE=InnoDB; | ||
1340 | 4566 | |||
1341 | 4567 | After creating the table and causing a small deadlock, the tool will drop the | ||
1342 | 4568 | table again. | ||
1343 | 4569 | |||
1344 | 4570 | =item --[no]collapse | ||
1345 | 4571 | |||
1346 | 4572 | Collapse whitespace in queries to a single space. This might make it easier to | ||
1347 | 4573 | inspect on the command line or in a query. By default, whitespace is collapsed | ||
1348 | 4574 | when printing with L<"--print">, but not modified when storing to L<"--dest">. | ||
1349 | 4575 | (That is, the default is different for each action). | ||
1350 | 4576 | |||
1351 | 4577 | =item --columns | ||
1352 | 4578 | |||
1353 | 4579 | type: hash | ||
1354 | 4580 | |||
1355 | 4581 | Output only this comma-separated list of columns. See L<"OUTPUT"> for more | ||
1356 | 4582 | details on columns. | ||
1357 | 4583 | |||
1358 | 4584 | =item --config | 4979 | =item --config |
1359 | 4585 | 4980 | ||
1360 | 4586 | type: Array | 4981 | type: Array |
1361 | @@ -4617,12 +5012,12 @@ | |||
1362 | 4617 | can usually omit most parts of this argument if you're storing deadlocks on the | 5012 | can usually omit most parts of this argument if you're storing deadlocks on the |
1363 | 4618 | same server on which they happen. | 5013 | same server on which they happen. |
1364 | 4619 | 5014 | ||
1369 | 4620 | By default, whitespace in the query column is left intact; | 5015 | The following table structure is suggested if you want to store all the |
1366 | 4621 | use L<"--[no]collapse"> if you want whitespace collapsed. | ||
1367 | 4622 | |||
1368 | 4623 | The following MAGIC_dest_table is suggested if you want to store all the | ||
1370 | 4624 | information pt-deadlock-logger can extract about deadlocks: | 5016 | information pt-deadlock-logger can extract about deadlocks: |
1371 | 4625 | 5017 | ||
1372 | 5018 | =for comment ignore-pt-internal-value | ||
1373 | 5019 | MAGIC_dest_table | ||
1374 | 5020 | |||
1375 | 4626 | CREATE TABLE deadlocks ( | 5021 | CREATE TABLE deadlocks ( |
1376 | 4627 | server char(20) NOT NULL, | 5022 | server char(20) NOT NULL, |
1377 | 4628 | ts datetime NOT NULL, | 5023 | ts datetime NOT NULL, |
1378 | @@ -4658,12 +5053,23 @@ | |||
1379 | 4658 | 5053 | ||
1380 | 4659 | =item --interval | 5054 | =item --interval |
1381 | 4660 | 5055 | ||
1383 | 4661 | type: time | 5056 | type: time; default: 30 |
1384 | 4662 | 5057 | ||
1385 | 4663 | How often to check for deadlocks. If no L<"--run-time"> is specified, | 5058 | How often to check for deadlocks. If no L<"--run-time"> is specified, |
1386 | 4664 | pt-deadlock-logger runs forever, checking for deadlocks at every interval. | 5059 | pt-deadlock-logger runs forever, checking for deadlocks at every interval. |
1387 | 4665 | See also L<"--run-time">. | 5060 | See also L<"--run-time">. |
1388 | 4666 | 5061 | ||
1389 | 5062 | =item --iterations | ||
1390 | 5063 | |||
1391 | 5064 | type: int | ||
1392 | 5065 | |||
1393 | 5066 | How many times to check for deadlocks. By default, this option | ||
1394 | 5067 | is undefined which means an infinite number of iterations. The tool always | ||
1395 | 5068 | exits for L<"--run-time">, regardless of the value specified for this option. | ||
1396 | 5069 | For example, the tool will exit after 1 minute with | ||
1397 | 5070 | C<--run-time 1m --iterations 4 --interval 30> because 4 iterations at 30 | ||
1398 | 5071 | second intervals would take 2 minutes, longer than the 1 mintue run-time. | ||
1399 | 5072 | |||
1400 | 4667 | =item --log | 5073 | =item --log |
1401 | 4668 | 5074 | ||
1402 | 4669 | type: string | 5075 | type: string |
1403 | @@ -4684,10 +5090,11 @@ | |||
1404 | 4684 | 5090 | ||
1405 | 4685 | type: string | 5091 | type: string |
1406 | 4686 | 5092 | ||
1411 | 4687 | Create the given PID file when daemonized. The file contains the process ID of | 5093 | Create the given PID file. The tool won't start if the PID file already |
1412 | 4688 | the daemonized instance. The PID file is removed when the daemonized instance | 5094 | exists and the PID it contains is different than the current PID. However, |
1413 | 4689 | exits. The program checks for the existence of the PID file when starting; if | 5095 | if the PID file exists and the PID it contains is no longer running, the |
1414 | 4690 | it exists and the process with the matching PID exists, the program exits. | 5096 | tool will overwrite the PID file with the current PID. The PID file is |
1415 | 5097 | removed automatically when the tool exits. | ||
1416 | 4691 | 5098 | ||
1417 | 4692 | =item --port | 5099 | =item --port |
1418 | 4693 | 5100 | ||
1419 | @@ -4695,16 +5102,9 @@ | |||
1420 | 4695 | 5102 | ||
1421 | 4696 | Port number to use for connection. | 5103 | Port number to use for connection. |
1422 | 4697 | 5104 | ||
1433 | 4698 | =item --print | 5105 | =item --quiet |
1434 | 4699 | 5106 | ||
1435 | 4700 | Print results on standard output. See L<"OUTPUT"> for more. By default, | 5107 | Do not deadlocks; only print errors and warnings to C<STDERR>. |
1426 | 4701 | enables L<"--[no]collapse"> unless you explicitly disable it. | ||
1427 | 4702 | |||
1428 | 4703 | If L<"--interval"> or L<"--run-time"> is specified, only new deadlocks are | ||
1429 | 4704 | printed at each interval. A fingerprint for each deadlock is created using | ||
1430 | 4705 | L<"--columns"> server, ts and thread (even if those columns were not specified | ||
1431 | 4706 | by L<"--columns">) and if the current deadlock's fingerprint is different from | ||
1432 | 4707 | the last deadlock's fingerprint, then it is printed. | ||
1436 | 4708 | 5108 | ||
1437 | 4709 | =item --run-time | 5109 | =item --run-time |
1438 | 4710 | 5110 | ||
1439 | @@ -4729,7 +5129,7 @@ | |||
1440 | 4729 | 5129 | ||
1441 | 4730 | =item --tab | 5130 | =item --tab |
1442 | 4731 | 5131 | ||
1444 | 4732 | Print tab-separated columns, instead of aligned. | 5132 | Use tabs to separate columns instead of spaces. |
1445 | 4733 | 5133 | ||
1446 | 4734 | =item --user | 5134 | =item --user |
1447 | 4735 | 5135 | ||
1448 | @@ -4886,7 +5286,7 @@ | |||
1449 | 4886 | 5286 | ||
1450 | 4887 | =head1 AUTHORS | 5287 | =head1 AUTHORS |
1451 | 4888 | 5288 | ||
1453 | 4889 | Baron Schwartz | 5289 | Baron Schwartz and Daniel Nichter |
1454 | 4890 | 5290 | ||
1455 | 4891 | =head1 ABOUT PERCONA TOOLKIT | 5291 | =head1 ABOUT PERCONA TOOLKIT |
1456 | 4892 | 5292 | ||
1457 | 4893 | 5293 | ||
1458 | === modified file 'bin/pt-duplicate-key-checker' | |||
1459 | --- bin/pt-duplicate-key-checker 2013-02-22 17:47:57 +0000 | |||
1460 | +++ bin/pt-duplicate-key-checker 2013-02-27 23:41:26 +0000 | |||
1461 | @@ -5130,14 +5130,11 @@ | |||
1462 | 5130 | 5130 | ||
1463 | 5131 | type: string | 5131 | type: string |
1464 | 5132 | 5132 | ||
1473 | 5133 | Create the given PID file. The file contains the process ID of the script. | 5133 | Create the given PID file. The tool won't start if the PID file already |
1474 | 5134 | The PID file is removed when the script exits. Before starting, the script | 5134 | exists and the PID it contains is different than the current PID. However, |
1475 | 5135 | checks if the PID file already exists. If it does not, then the script creates | 5135 | if the PID file exists and the PID it contains is no longer running, the |
1476 | 5136 | and writes its own PID to it. If it does, then the script checks the following: | 5136 | tool will overwrite the PID file with the current PID. The PID file is |
1477 | 5137 | if the file contains a PID and a process is running with that PID, then | 5137 | removed automatically when the tool exits. |
1470 | 5138 | the script dies; or, if there is no process running with that PID, then the | ||
1471 | 5139 | script overwrites the file with its own PID and starts; else, if the file | ||
1472 | 5140 | contains no PID, then the script dies. | ||
1478 | 5141 | 5138 | ||
1479 | 5142 | =item --port | 5139 | =item --port |
1480 | 5143 | 5140 | ||
1481 | 5144 | 5141 | ||
1482 | === modified file 'bin/pt-fifo-split' | |||
1483 | --- bin/pt-fifo-split 2013-01-03 00:54:18 +0000 | |||
1484 | +++ bin/pt-fifo-split 2013-02-27 23:41:26 +0000 | |||
1485 | @@ -1456,14 +1456,11 @@ | |||
1486 | 1456 | 1456 | ||
1487 | 1457 | type: string | 1457 | type: string |
1488 | 1458 | 1458 | ||
1497 | 1459 | Create the given PID file. The file contains the process ID of the script. | 1459 | Create the given PID file. The tool won't start if the PID file already |
1498 | 1460 | The PID file is removed when the script exits. Before starting, the script | 1460 | exists and the PID it contains is different than the current PID. However, |
1499 | 1461 | checks if the PID file already exists. If it does not, then the script creates | 1461 | if the PID file exists and the PID it contains is no longer running, the |
1500 | 1462 | and writes its own PID to it. If it does, then the script checks the following: | 1462 | tool will overwrite the PID file with the current PID. The PID file is |
1501 | 1463 | if the file contains a PID and a process is running with that PID, then | 1463 | removed automatically when the tool exits. |
1494 | 1464 | the script dies; or, if there is no process running with that PID, then the | ||
1495 | 1465 | script overwrites the file with its own PID and starts; else, if the file | ||
1496 | 1466 | contains no PID, then the script dies. | ||
1502 | 1467 | 1464 | ||
1503 | 1468 | =item --statistics | 1465 | =item --statistics |
1504 | 1469 | 1466 | ||
1505 | 1470 | 1467 | ||
1506 | === modified file 'bin/pt-find' | |||
1507 | --- bin/pt-find 2013-02-22 17:47:57 +0000 | |||
1508 | +++ bin/pt-find 2013-02-27 23:41:26 +0000 | |||
1509 | @@ -4241,14 +4241,11 @@ | |||
1510 | 4241 | 4241 | ||
1511 | 4242 | type: string | 4242 | type: string |
1512 | 4243 | 4243 | ||
1521 | 4244 | Create the given PID file. The file contains the process ID of the script. | 4244 | Create the given PID file. The tool won't start if the PID file already |
1522 | 4245 | The PID file is removed when the script exits. Before starting, the script | 4245 | exists and the PID it contains is different than the current PID. However, |
1523 | 4246 | checks if the PID file already exists. If it does not, then the script creates | 4246 | if the PID file exists and the PID it contains is no longer running, the |
1524 | 4247 | and writes its own PID to it. If it does, then the script checks the following: | 4247 | tool will overwrite the PID file with the current PID. The PID file is |
1525 | 4248 | if the file contains a PID and a process is running with that PID, then | 4248 | removed automatically when the tool exits. |
1518 | 4249 | the script dies; or, if there is no process running with that PID, then the | ||
1519 | 4250 | script overwrites the file with its own PID and starts; else, if the file | ||
1520 | 4251 | contains no PID, then the script dies. | ||
1526 | 4252 | 4249 | ||
1527 | 4253 | =item --port | 4250 | =item --port |
1528 | 4254 | 4251 | ||
1529 | 4255 | 4252 | ||
1530 | === modified file 'bin/pt-fk-error-logger' | |||
1531 | --- bin/pt-fk-error-logger 2013-02-22 17:47:57 +0000 | |||
1532 | +++ bin/pt-fk-error-logger 2013-02-27 23:41:26 +0000 | |||
1533 | @@ -17,10 +17,12 @@ | |||
1534 | 17 | OptionParser | 17 | OptionParser |
1535 | 18 | Quoter | 18 | Quoter |
1536 | 19 | DSNParser | 19 | DSNParser |
1537 | 20 | Cxn | ||
1538 | 20 | Daemon | 21 | Daemon |
1539 | 21 | Transformers | 22 | Transformers |
1540 | 22 | HTTPMicro | 23 | HTTPMicro |
1541 | 23 | VersionCheck | 24 | VersionCheck |
1542 | 25 | Runtime | ||
1543 | 24 | )); | 26 | )); |
1544 | 25 | } | 27 | } |
1545 | 26 | 28 | ||
1546 | @@ -1596,6 +1598,181 @@ | |||
1547 | 1596 | # ########################################################################### | 1598 | # ########################################################################### |
1548 | 1597 | 1599 | ||
1549 | 1598 | # ########################################################################### | 1600 | # ########################################################################### |
1550 | 1601 | # Cxn package | ||
1551 | 1602 | # This package is a copy without comments from the original. The original | ||
1552 | 1603 | # with comments and its test file can be found in the Bazaar repository at, | ||
1553 | 1604 | # lib/Cxn.pm | ||
1554 | 1605 | # t/lib/Cxn.t | ||
1555 | 1606 | # See https://launchpad.net/percona-toolkit for more information. | ||
1556 | 1607 | # ########################################################################### | ||
1557 | 1608 | { | ||
1558 | 1609 | package Cxn; | ||
1559 | 1610 | |||
1560 | 1611 | use strict; | ||
1561 | 1612 | use warnings FATAL => 'all'; | ||
1562 | 1613 | use English qw(-no_match_vars); | ||
1563 | 1614 | use Scalar::Util qw(blessed); | ||
1564 | 1615 | use constant { | ||
1565 | 1616 | PTDEBUG => $ENV{PTDEBUG} || 0, | ||
1566 | 1617 | PERCONA_TOOLKIT_TEST_USE_DSN_NAMES => $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} || 0, | ||
1567 | 1618 | }; | ||
1568 | 1619 | |||
1569 | 1620 | sub new { | ||
1570 | 1621 | my ( $class, %args ) = @_; | ||
1571 | 1622 | my @required_args = qw(DSNParser OptionParser); | ||
1572 | 1623 | foreach my $arg ( @required_args ) { | ||
1573 | 1624 | die "I need a $arg argument" unless $args{$arg}; | ||
1574 | 1625 | }; | ||
1575 | 1626 | my ($dp, $o) = @args{@required_args}; | ||
1576 | 1627 | |||
1577 | 1628 | my $dsn_defaults = $dp->parse_options($o); | ||
1578 | 1629 | my $prev_dsn = $args{prev_dsn}; | ||
1579 | 1630 | my $dsn = $args{dsn}; | ||
1580 | 1631 | if ( !$dsn ) { | ||
1581 | 1632 | $args{dsn_string} ||= 'h=' . ($dsn_defaults->{h} || 'localhost'); | ||
1582 | 1633 | |||
1583 | 1634 | $dsn = $dp->parse( | ||
1584 | 1635 | $args{dsn_string}, $prev_dsn, $dsn_defaults); | ||
1585 | 1636 | } | ||
1586 | 1637 | elsif ( $prev_dsn ) { | ||
1587 | 1638 | $dsn = $dp->copy($prev_dsn, $dsn); | ||
1588 | 1639 | } | ||
1589 | 1640 | |||
1590 | 1641 | my $self = { | ||
1591 | 1642 | dsn => $dsn, | ||
1592 | 1643 | dbh => $args{dbh}, | ||
1593 | 1644 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | ||
1594 | 1645 | hostname => '', | ||
1595 | 1646 | set => $args{set}, | ||
1596 | 1647 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | ||
1597 | 1648 | dbh_set => 0, | ||
1598 | 1649 | OptionParser => $o, | ||
1599 | 1650 | DSNParser => $dp, | ||
1600 | 1651 | is_cluster_node => undef, | ||
1601 | 1652 | parent => $args{parent}, | ||
1602 | 1653 | }; | ||
1603 | 1654 | |||
1604 | 1655 | return bless $self, $class; | ||
1605 | 1656 | } | ||
1606 | 1657 | |||
1607 | 1658 | sub connect { | ||
1608 | 1659 | my ( $self, %opts ) = @_; | ||
1609 | 1660 | my $dsn = $self->{dsn}; | ||
1610 | 1661 | my $dp = $self->{DSNParser}; | ||
1611 | 1662 | my $o = $self->{OptionParser}; | ||
1612 | 1663 | |||
1613 | 1664 | my $dbh = $self->{dbh}; | ||
1614 | 1665 | if ( !$dbh || !$dbh->ping() ) { | ||
1615 | 1666 | if ( $o->get('ask-pass') && !$self->{asked_for_pass} ) { | ||
1616 | 1667 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | ||
1617 | 1668 | $self->{asked_for_pass} = 1; | ||
1618 | 1669 | } | ||
1619 | 1670 | $dbh = $dp->get_dbh( | ||
1620 | 1671 | $dp->get_cxn_params($dsn), | ||
1621 | 1672 | { | ||
1622 | 1673 | AutoCommit => 1, | ||
1623 | 1674 | %opts, | ||
1624 | 1675 | }, | ||
1625 | 1676 | ); | ||
1626 | 1677 | } | ||
1627 | 1678 | |||
1628 | 1679 | $dbh = $self->set_dbh($dbh); | ||
1629 | 1680 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
1630 | 1681 | return $dbh; | ||
1631 | 1682 | } | ||
1632 | 1683 | |||
1633 | 1684 | sub set_dbh { | ||
1634 | 1685 | my ($self, $dbh) = @_; | ||
1635 | 1686 | |||
1636 | 1687 | if ( $self->{dbh} && $self->{dbh} == $dbh && $self->{dbh_set} ) { | ||
1637 | 1688 | PTDEBUG && _d($dbh, 'Already set dbh'); | ||
1638 | 1689 | return $dbh; | ||
1639 | 1690 | } | ||
1640 | 1691 | |||
1641 | 1692 | PTDEBUG && _d($dbh, 'Setting dbh'); | ||
1642 | 1693 | |||
1643 | 1694 | $dbh->{FetchHashKeyName} = 'NAME_lc' if $self->{NAME_lc}; | ||
1644 | 1695 | |||
1645 | 1696 | my $sql = 'SELECT @@hostname, @@server_id'; | ||
1646 | 1697 | PTDEBUG && _d($dbh, $sql); | ||
1647 | 1698 | my ($hostname, $server_id) = $dbh->selectrow_array($sql); | ||
1648 | 1699 | PTDEBUG && _d($dbh, 'hostname:', $hostname, $server_id); | ||
1649 | 1700 | if ( $hostname ) { | ||
1650 | 1701 | $self->{hostname} = $hostname; | ||
1651 | 1702 | } | ||
1652 | 1703 | |||
1653 | 1704 | if ( $self->{parent} ) { | ||
1654 | 1705 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
1655 | 1706 | $dbh->{InactiveDestroy} = 1; | ||
1656 | 1707 | } | ||
1657 | 1708 | |||
1658 | 1709 | if ( my $set = $self->{set}) { | ||
1659 | 1710 | $set->($dbh); | ||
1660 | 1711 | } | ||
1661 | 1712 | |||
1662 | 1713 | $self->{dbh} = $dbh; | ||
1663 | 1714 | $self->{dbh_set} = 1; | ||
1664 | 1715 | return $dbh; | ||
1665 | 1716 | } | ||
1666 | 1717 | |||
1667 | 1718 | sub lost_connection { | ||
1668 | 1719 | my ($self, $e) = @_; | ||
1669 | 1720 | return 0 unless $e; | ||
1670 | 1721 | return $e =~ m/MySQL server has gone away/ | ||
1671 | 1722 | || $e =~ m/Lost connection to MySQL server/; | ||
1672 | 1723 | } | ||
1673 | 1724 | |||
1674 | 1725 | sub dbh { | ||
1675 | 1726 | my ($self) = @_; | ||
1676 | 1727 | return $self->{dbh}; | ||
1677 | 1728 | } | ||
1678 | 1729 | |||
1679 | 1730 | sub dsn { | ||
1680 | 1731 | my ($self) = @_; | ||
1681 | 1732 | return $self->{dsn}; | ||
1682 | 1733 | } | ||
1683 | 1734 | |||
1684 | 1735 | sub name { | ||
1685 | 1736 | my ($self) = @_; | ||
1686 | 1737 | return $self->{dsn_name} if PERCONA_TOOLKIT_TEST_USE_DSN_NAMES; | ||
1687 | 1738 | return $self->{hostname} || $self->{dsn_name} || 'unknown host'; | ||
1688 | 1739 | } | ||
1689 | 1740 | |||
1690 | 1741 | sub DESTROY { | ||
1691 | 1742 | my ($self) = @_; | ||
1692 | 1743 | |||
1693 | 1744 | PTDEBUG && _d('Destroying cxn'); | ||
1694 | 1745 | |||
1695 | 1746 | if ( $self->{parent} ) { | ||
1696 | 1747 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
1697 | 1748 | } | ||
1698 | 1749 | elsif ( $self->{dbh} | ||
1699 | 1750 | && blessed($self->{dbh}) | ||
1700 | 1751 | && $self->{dbh}->can("disconnect") ) | ||
1701 | 1752 | { | ||
1702 | 1753 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
1703 | 1754 | $self->{dsn_name}); | ||
1704 | 1755 | $self->{dbh}->disconnect(); | ||
1705 | 1756 | } | ||
1706 | 1757 | |||
1707 | 1758 | return; | ||
1708 | 1759 | } | ||
1709 | 1760 | |||
1710 | 1761 | sub _d { | ||
1711 | 1762 | my ($package, undef, $line) = caller 0; | ||
1712 | 1763 | @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } | ||
1713 | 1764 | map { defined $_ ? $_ : 'undef' } | ||
1714 | 1765 | @_; | ||
1715 | 1766 | print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; | ||
1716 | 1767 | } | ||
1717 | 1768 | |||
1718 | 1769 | 1; | ||
1719 | 1770 | } | ||
1720 | 1771 | # ########################################################################### | ||
1721 | 1772 | # End Cxn package | ||
1722 | 1773 | # ########################################################################### | ||
1723 | 1774 | |||
1724 | 1775 | # ########################################################################### | ||
1725 | 1599 | # Daemon package | 1776 | # Daemon package |
1726 | 1600 | # This package is a copy without comments from the original. The original | 1777 | # This package is a copy without comments from the original. The original |
1727 | 1601 | # with comments and its test file can be found in the Bazaar repository at, | 1778 | # with comments and its test file can be found in the Bazaar repository at, |
1728 | @@ -3375,6 +3552,139 @@ | |||
1729 | 3375 | # ########################################################################### | 3552 | # ########################################################################### |
1730 | 3376 | 3553 | ||
1731 | 3377 | # ########################################################################### | 3554 | # ########################################################################### |
1732 | 3555 | # Runtime package | ||
1733 | 3556 | # This package is a copy without comments from the original. The original | ||
1734 | 3557 | # with comments and its test file can be found in the Bazaar repository at, | ||
1735 | 3558 | # lib/Runtime.pm | ||
1736 | 3559 | # t/lib/Runtime.t | ||
1737 | 3560 | # See https://launchpad.net/percona-toolkit for more information. | ||
1738 | 3561 | # ########################################################################### | ||
1739 | 3562 | { | ||
1740 | 3563 | package Runtime; | ||
1741 | 3564 | |||
1742 | 3565 | use strict; | ||
1743 | 3566 | use warnings FATAL => 'all'; | ||
1744 | 3567 | use English qw(-no_match_vars); | ||
1745 | 3568 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; | ||
1746 | 3569 | |||
1747 | 3570 | sub new { | ||
1748 | 3571 | my ( $class, %args ) = @_; | ||
1749 | 3572 | my @required_args = qw(run_time now); | ||
1750 | 3573 | foreach my $arg ( @required_args ) { | ||
1751 | 3574 | die "I need a $arg argument" unless exists $args{$arg}; | ||
1752 | 3575 | } | ||
1753 | 3576 | |||
1754 | 3577 | my $run_time = $args{run_time}; | ||
1755 | 3578 | if ( defined $run_time ) { | ||
1756 | 3579 | die "run_time must be > 0" if $run_time <= 0; | ||
1757 | 3580 | } | ||
1758 | 3581 | |||
1759 | 3582 | my $now = $args{now}; | ||
1760 | 3583 | die "now must be a callback" unless ref $now eq 'CODE'; | ||
1761 | 3584 | |||
1762 | 3585 | my $self = { | ||
1763 | 3586 | run_time => $run_time, | ||
1764 | 3587 | now => $now, | ||
1765 | 3588 | start_time => undef, | ||
1766 | 3589 | end_time => undef, | ||
1767 | 3590 | time_left => undef, | ||
1768 | 3591 | stop => 0, | ||
1769 | 3592 | }; | ||
1770 | 3593 | |||
1771 | 3594 | return bless $self, $class; | ||
1772 | 3595 | } | ||
1773 | 3596 | |||
1774 | 3597 | sub time_left { | ||
1775 | 3598 | my ( $self, %args ) = @_; | ||
1776 | 3599 | |||
1777 | 3600 | if ( $self->{stop} ) { | ||
1778 | 3601 | PTDEBUG && _d("No time left because stop was called"); | ||
1779 | 3602 | return 0; | ||
1780 | 3603 | } | ||
1781 | 3604 | |||
1782 | 3605 | my $now = $self->{now}->(%args); | ||
1783 | 3606 | PTDEBUG && _d("Current time:", $now); | ||
1784 | 3607 | |||
1785 | 3608 | if ( !defined $self->{start_time} ) { | ||
1786 | 3609 | $self->{start_time} = $now; | ||
1787 | 3610 | } | ||
1788 | 3611 | |||
1789 | 3612 | return unless defined $now; | ||
1790 | 3613 | |||
1791 | 3614 | my $run_time = $self->{run_time}; | ||
1792 | 3615 | return unless defined $run_time; | ||
1793 | 3616 | |||
1794 | 3617 | if ( !$self->{end_time} ) { | ||
1795 | 3618 | $self->{end_time} = $now + $run_time; | ||
1796 | 3619 | PTDEBUG && _d("End time:", $self->{end_time}); | ||
1797 | 3620 | } | ||
1798 | 3621 | |||
1799 | 3622 | $self->{time_left} = $self->{end_time} - $now; | ||
1800 | 3623 | PTDEBUG && _d("Time left:", $self->{time_left}); | ||
1801 | 3624 | return $self->{time_left}; | ||
1802 | 3625 | } | ||
1803 | 3626 | |||
1804 | 3627 | sub have_time { | ||
1805 | 3628 | my ( $self, %args ) = @_; | ||
1806 | 3629 | my $time_left = $self->time_left(%args); | ||
1807 | 3630 | return 1 if !defined $time_left; # run forever | ||
1808 | 3631 | return $time_left <= 0 ? 0 : 1; # <=0s means run time has elapsed | ||
1809 | 3632 | } | ||
1810 | 3633 | |||
1811 | 3634 | sub time_elapsed { | ||
1812 | 3635 | my ( $self, %args ) = @_; | ||
1813 | 3636 | |||
1814 | 3637 | my $start_time = $self->{start_time}; | ||
1815 | 3638 | return 0 unless $start_time; | ||
1816 | 3639 | |||
1817 | 3640 | my $now = $self->{now}->(%args); | ||
1818 | 3641 | PTDEBUG && _d("Current time:", $now); | ||
1819 | 3642 | |||
1820 | 3643 | my $time_elapsed = $now - $start_time; | ||
1821 | 3644 | PTDEBUG && _d("Time elapsed:", $time_elapsed); | ||
1822 | 3645 | if ( $time_elapsed < 0 ) { | ||
1823 | 3646 | warn "Current time $now is earlier than start time $start_time"; | ||
1824 | 3647 | } | ||
1825 | 3648 | return $time_elapsed; | ||
1826 | 3649 | } | ||
1827 | 3650 | |||
1828 | 3651 | sub reset { | ||
1829 | 3652 | my ( $self ) = @_; | ||
1830 | 3653 | $self->{start_time} = undef; | ||
1831 | 3654 | $self->{end_time} = undef; | ||
1832 | 3655 | $self->{time_left} = undef; | ||
1833 | 3656 | $self->{stop} = 0; | ||
1834 | 3657 | PTDEBUG && _d("Reset run time"); | ||
1835 | 3658 | return; | ||
1836 | 3659 | } | ||
1837 | 3660 | |||
1838 | 3661 | sub stop { | ||
1839 | 3662 | my ( $self ) = @_; | ||
1840 | 3663 | $self->{stop} = 1; | ||
1841 | 3664 | return; | ||
1842 | 3665 | } | ||
1843 | 3666 | |||
1844 | 3667 | sub start { | ||
1845 | 3668 | my ( $self ) = @_; | ||
1846 | 3669 | $self->{stop} = 0; | ||
1847 | 3670 | return; | ||
1848 | 3671 | } | ||
1849 | 3672 | |||
1850 | 3673 | sub _d { | ||
1851 | 3674 | my ($package, undef, $line) = caller 0; | ||
1852 | 3675 | @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; } | ||
1853 | 3676 | map { defined $_ ? $_ : 'undef' } | ||
1854 | 3677 | @_; | ||
1855 | 3678 | print STDERR "# $package:$line $PID ", join(' ', @_), "\n"; | ||
1856 | 3679 | } | ||
1857 | 3680 | |||
1858 | 3681 | 1; | ||
1859 | 3682 | } | ||
1860 | 3683 | # ########################################################################### | ||
1861 | 3684 | # End Runtime package | ||
1862 | 3685 | # ########################################################################### | ||
1863 | 3686 | |||
1864 | 3687 | # ########################################################################### | ||
1865 | 3378 | # This is a combination of modules and programs in one -- a runnable module. | 3688 | # This is a combination of modules and programs in one -- a runnable module. |
1866 | 3379 | # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last | 3689 | # http://www.perl.com/pub/a/2006/07/13/lightning-articles.html?page=last |
1867 | 3380 | # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. | 3690 | # Or, look it up in the Camel book on pages 642 and 643 in the 3rd edition. |
1868 | @@ -3387,18 +3697,21 @@ | |||
1869 | 3387 | use strict; | 3697 | use strict; |
1870 | 3388 | use warnings FATAL => 'all'; | 3698 | use warnings FATAL => 'all'; |
1871 | 3389 | use English qw(-no_match_vars); | 3699 | use English qw(-no_match_vars); |
1873 | 3390 | use sigtrap qw(handler finish untrapped normal-signals); | 3700 | |
1874 | 3701 | use sigtrap 'handler', \&sig_int, 'normal-signals'; | ||
1875 | 3391 | 3702 | ||
1876 | 3392 | use Percona::Toolkit; | 3703 | use Percona::Toolkit; |
1877 | 3393 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; | 3704 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
1878 | 3394 | 3705 | ||
1879 | 3395 | Transformers->import(qw(parse_timestamp)); | 3706 | Transformers->import(qw(parse_timestamp)); |
1880 | 3396 | 3707 | ||
1882 | 3397 | my $oktorun; | 3708 | my $oktorun = 1; |
1883 | 3709 | my $exit_status = 0; | ||
1884 | 3398 | 3710 | ||
1885 | 3399 | sub main { | 3711 | sub main { |
1888 | 3400 | local @ARGV = @_; # set global ARGV for this package | 3712 | local @ARGV = @_; # set global ARGV for this package |
1889 | 3401 | $oktorun = 1; | 3713 | $oktorun = 1; |
1890 | 3714 | $exit_status = 0; | ||
1891 | 3402 | 3715 | ||
1892 | 3403 | # ######################################################################## | 3716 | # ######################################################################## |
1893 | 3404 | # Get configuration information. | 3717 | # Get configuration information. |
1894 | @@ -3409,69 +3722,56 @@ | |||
1895 | 3409 | 3722 | ||
1896 | 3410 | my $dp = $o->DSNParser(); | 3723 | my $dp = $o->DSNParser(); |
1897 | 3411 | $dp->prop('set-vars', $o->get('set-vars')); | 3724 | $dp->prop('set-vars', $o->get('set-vars')); |
1909 | 3412 | my $dsn_defaults = $dp->parse_options($o); | 3725 | |
1910 | 3413 | my $src_dsn = @ARGV ? $dp->parse(shift @ARGV, $dsn_defaults) : $dsn_defaults; | 3726 | my $src; |
1911 | 3414 | my $dst_dsn = $o->get('dest'); | 3727 | if ( my $src_dsn_string = shift @ARGV ) { |
1912 | 3415 | 3728 | $src = Cxn->new( | |
1913 | 3416 | # The source dsn is not an option so --dest cannot use OptionParser | 3729 | dsn_string => $src_dsn_string, |
1914 | 3417 | # to inherit values from it. Thus, we do it manually. --dest will | 3730 | parent => $o->get('daemonize'), |
1915 | 3418 | # inherit from --user, --port, etc. | 3731 | DSNParser => $dp, |
1916 | 3419 | if ( $src_dsn && $dst_dsn ) { | 3732 | OptionParser => $o, |
1917 | 3420 | # If dest DSN only has D and t, this will copy h, P, S, etc. | 3733 | ); |
1918 | 3421 | # from the source DSN. | 3734 | } |
1919 | 3422 | $dst_dsn = $dp->copy($src_dsn, $dst_dsn); | 3735 | |
1920 | 3736 | my $dst; | ||
1921 | 3737 | if ( my $dst_dsn = $o->get('dest') ) { | ||
1922 | 3738 | $dst = Cxn->new( | ||
1923 | 3739 | dsn => $dst_dsn, | ||
1924 | 3740 | prev_dsn => ($src ? $src->dsn : undef), | ||
1925 | 3741 | parent => $o->get('daemonize'), | ||
1926 | 3742 | DSNParser => $dp, | ||
1927 | 3743 | OptionParser => $o, | ||
1928 | 3744 | ); | ||
1929 | 3423 | } | 3745 | } |
1930 | 3424 | 3746 | ||
1931 | 3425 | if ( !$o->get('help') ) { | 3747 | if ( !$o->get('help') ) { |
1940 | 3426 | if ( !$src_dsn ) { | 3748 | if ( !$src ) { |
1941 | 3427 | $o->save_error('Missing or invalid source host'); | 3749 | $o->save_error('No DSN was specified.'); |
1942 | 3428 | } | 3750 | } |
1943 | 3429 | if ( $dst_dsn && !$dst_dsn->{D} ) { | 3751 | if ( $dst && !$dst->dsn->{D} ) { |
1944 | 3430 | $o->save_error("--dest requires a 'D' (database) part"); | 3752 | $o->save_error("--dest requires a 'D' (database) part."); |
1945 | 3431 | } | 3753 | } |
1946 | 3432 | if ( $dst_dsn && !$dst_dsn->{t} ) { | 3754 | if ( $dst && !$dst->dsn->{t} ) { |
1947 | 3433 | $o->save_error("--dest requires a 't' (table) part"); | 3755 | $o->save_error("--dest requires a 't' (table) part."); |
1948 | 3434 | } | 3756 | } |
1949 | 3435 | } | 3757 | } |
1950 | 3436 | 3758 | ||
1951 | 3437 | $o->usage_or_errors(); | 3759 | $o->usage_or_errors(); |
1952 | 3438 | 3760 | ||
1953 | 3439 | # ######################################################################## | 3761 | # ######################################################################## |
1971 | 3440 | # Make common modules. | 3762 | # Connect to MySQL. |
1972 | 3441 | # ######################################################################## | 3763 | # ######################################################################## |
1973 | 3442 | my $q = new Quoter(); | 3764 | my $q = Quoter->new(); |
1974 | 3443 | my %modules = ( | 3765 | |
1975 | 3444 | o => $o, | 3766 | $src->connect(); |
1976 | 3445 | dp => $dp, | 3767 | |
1960 | 3446 | q => $q, | ||
1961 | 3447 | ); | ||
1962 | 3448 | |||
1963 | 3449 | # ######################################################################## | ||
1964 | 3450 | # Start working. | ||
1965 | 3451 | # ######################################################################## | ||
1966 | 3452 | my $dbh = get_cxn($src_dsn, 1, %modules); | ||
1967 | 3453 | my $start = time(); | ||
1968 | 3454 | my $end = $start + ($o->get('run-time') || 0); # When we should exit | ||
1969 | 3455 | my $now = $start; | ||
1970 | 3456 | my $dst_dbh; | ||
1977 | 3457 | my $ins_sth; | 3768 | my $ins_sth; |
1995 | 3458 | 3769 | if ( $dst ) { | |
1996 | 3459 | # Since the user might not have specified a hostname for the connection, | 3770 | $dst->connect(); |
1997 | 3460 | # try to extract it from the $dbh | 3771 | my $db_tbl = $q->join_quote($dst->dsn->{D}, $dst->dsn->{t}); |
1998 | 3461 | if ( !$src_dsn->{h} ) { | 3772 | my $sql = "INSERT IGNORE INTO $db_tbl VALUES (?, ?)"; |
1999 | 3462 | ($src_dsn->{h}) = $dbh->{mysql_hostinfo} =~ m/(\w+) via/; | 3773 | PTDEBUG && _d('--dest INSERT SQL:', $sql); |
2000 | 3463 | PTDEBUG && _d('Got source host from dbh:', $src_dsn->{h}); | 3774 | $ins_sth = $dst->dbh->prepare($sql); |
1984 | 3464 | } | ||
1985 | 3465 | |||
1986 | 3466 | if ( $dst_dsn ) { | ||
1987 | 3467 | my $db_tbl = join('.', | ||
1988 | 3468 | map { $q->quote($_) } | ||
1989 | 3469 | grep { $_ } | ||
1990 | 3470 | ( $dst_dsn->{D}, $dst_dsn->{t} )); | ||
1991 | 3471 | $dst_dbh = get_cxn($dst_dsn, 1, %modules); | ||
1992 | 3472 | my $sql = "INSERT IGNORE INTO $db_tbl VALUES (?, ?)"; | ||
1993 | 3473 | PTDEBUG && _d('insert sql:', $sql); | ||
1994 | 3474 | $ins_sth = $dst_dbh->prepare($sql); | ||
2001 | 3475 | } | 3775 | } |
2002 | 3476 | 3776 | ||
2003 | 3477 | # ######################################################################## | 3777 | # ######################################################################## |
2004 | @@ -3489,6 +3789,16 @@ | |||
2005 | 3489 | $daemon->make_PID_file(); | 3789 | $daemon->make_PID_file(); |
2006 | 3490 | } | 3790 | } |
2007 | 3491 | 3791 | ||
2008 | 3792 | # If we daemonized, the parent has already exited and we're the child. | ||
2009 | 3793 | # We shared a copy of every Cxn with the parent, and the parent's copies | ||
2010 | 3794 | # were destroyed but the dbhs were not disconnected because the parent | ||
2011 | 3795 | # attrib was true. Now, as the child, set it false so the dbhs will be | ||
2012 | 3796 | # disconnected when our Cxn copies are destroyed. If we didn't daemonize, | ||
2013 | 3797 | # then we're not really a parent (since we have no children), so set it | ||
2014 | 3798 | # false to auto-disconnect the dbhs when our Cxns are destroyed. | ||
2015 | 3799 | $src->{parent} = 0; | ||
2016 | 3800 | $dst->{parent} = 0 if $dst; | ||
2017 | 3801 | |||
2018 | 3492 | # ######################################################################## | 3802 | # ######################################################################## |
2019 | 3493 | # Do the version-check | 3803 | # Do the version-check |
2020 | 3494 | # ######################################################################## | 3804 | # ######################################################################## |
2021 | @@ -3496,8 +3806,8 @@ | |||
2022 | 3496 | VersionCheck::version_check( | 3806 | VersionCheck::version_check( |
2023 | 3497 | force => $o->got('version-check'), | 3807 | force => $o->got('version-check'), |
2024 | 3498 | instances => [ | 3808 | instances => [ |
2027 | 3499 | { dbh => $dbh, dsn => $src_dsn }, | 3809 | { dbh => $src->dbh, dsn => $src->dsn }, |
2028 | 3500 | ($dst_dbh ? { dbh => $dst_dbh, dsn => $dst_dsn } : ()) | 3810 | ($dst ? { dbh => $dst->dbh, dsn => $dst->dsn } : ()) |
2029 | 3501 | ], | 3811 | ], |
2030 | 3502 | ); | 3812 | ); |
2031 | 3503 | } | 3813 | } |
2032 | @@ -3505,43 +3815,77 @@ | |||
2033 | 3505 | # ######################################################################## | 3815 | # ######################################################################## |
2034 | 3506 | # Start finding and logging foreign key errors. | 3816 | # Start finding and logging foreign key errors. |
2035 | 3507 | # ######################################################################## | 3817 | # ######################################################################## |
2053 | 3508 | while ( # Quit if: | 3818 | my $run_time = Runtime->new( |
2054 | 3509 | ($start == $end || $now < $end) # time is exceeded | 3819 | run_time => $o->get('run-time'), |
2055 | 3510 | && $oktorun # or instructed to quit | 3820 | now => sub { return time }, |
2056 | 3511 | ) | 3821 | ); |
2057 | 3512 | { | 3822 | |
2058 | 3513 | my $text = $dbh->selectrow_hashref("SHOW /*!40100 ENGINE*/ INNODB STATUS")->{Status}; | 3823 | my $interval = $o->get('interval'); |
2059 | 3514 | my ($ts, $fk_error) = get_fk_error($text); | 3824 | my $iters = $o->get('iterations'); |
2060 | 3515 | PTDEBUG && _d('ts:', $ts, 'fk error:', $fk_error); | 3825 | PTDEBUG && _d('iterations:', $iters, 'interval:', $interval); |
2061 | 3516 | 3826 | ||
2062 | 3517 | if ( $ts && $fk_error ) { | 3827 | ITERATION: |
2063 | 3518 | # Save and/or print the foreign key error. | 3828 | while ( |
2064 | 3519 | if ( $ins_sth ) { | 3829 | $oktorun |
2065 | 3520 | my $fk_ts = parse_timestamp($ts); | 3830 | && $run_time->have_time() |
2066 | 3521 | PTDEBUG && _d('Saving fk error', $ts, $fk_error); | 3831 | && (!defined $iters || $iters--) |
2067 | 3522 | eval { | 3832 | ) { |
2068 | 3523 | $ins_sth->execute($fk_ts, $fk_error); | 3833 | my ($ts, $fk_error); |
2069 | 3524 | }; | 3834 | eval { |
2070 | 3835 | my $sql = "SHOW /*!40100 ENGINE*/ INNODB STATUS " | ||
2071 | 3836 | . "/* pt-fk-error-logger */"; | ||
2072 | 3837 | PTDEBUG && _d($sql); | ||
2073 | 3838 | my $text = $src->dbh->selectrow_hashref($sql)->{status}; | ||
2074 | 3839 | ($ts, $fk_error) = get_fk_error($text); | ||
2075 | 3840 | }; | ||
2076 | 3841 | if ( my $e = $EVAL_ERROR ) { | ||
2077 | 3842 | PTDEBUG && _d('Error getting InnoDB status:', $e); | ||
2078 | 3843 | if ( $src->lost_connection($e) ) { | ||
2079 | 3844 | eval { $src->connect() }; | ||
2080 | 3525 | if ( $EVAL_ERROR ) { | 3845 | if ( $EVAL_ERROR ) { |
2093 | 3526 | warn $EVAL_ERROR; | 3846 | warn "Lost connection to MySQL. Will try to reconnect " |
2094 | 3527 | PTDEBUG && _d($EVAL_ERROR); | 3847 | . "in the next iteration.\n"; |
2095 | 3528 | } | 3848 | } |
2096 | 3529 | } | 3849 | else { |
2097 | 3530 | print "$ts $fk_error\n\n" if $o->get('print') || !$o->got('dest'); | 3850 | PTDEBUG && _d('Reconnected to MySQL'); |
2098 | 3531 | } | 3851 | redo ITERATION; |
2099 | 3532 | 3852 | } | |
2100 | 3533 | # If there's an --interval argument, run forever or till specified. | 3853 | } |
2101 | 3534 | # Otherwise just run once. | 3854 | else { |
2102 | 3535 | if ( $o->get('interval') ) { | 3855 | warn "Error parsing SHOW ENGINE INNODB STATUS: $EVAL_ERROR"; |
2103 | 3536 | sleep($o->get('interval')); | 3856 | $exit_status |= 1; |
2104 | 3537 | $now = time(); | 3857 | } |
2105 | 3538 | } | 3858 | } |
2106 | 3539 | else { | 3859 | else { |
2108 | 3540 | $oktorun = 0; | 3860 | if ( $ts && $fk_error ) { |
2109 | 3861 | # Save and/or print the foreign key error. | ||
2110 | 3862 | if ( $ins_sth ) { | ||
2111 | 3863 | my $fk_ts = parse_timestamp($ts); | ||
2112 | 3864 | PTDEBUG && _d('Saving fk error', $ts, $fk_error); | ||
2113 | 3865 | eval { | ||
2114 | 3866 | $ins_sth->execute($fk_ts, $fk_error); | ||
2115 | 3867 | }; | ||
2116 | 3868 | if ( $EVAL_ERROR ) { | ||
2117 | 3869 | warn $EVAL_ERROR; | ||
2118 | 3870 | PTDEBUG && _d($EVAL_ERROR); | ||
2119 | 3871 | } | ||
2120 | 3872 | } | ||
2121 | 3873 | |||
2122 | 3874 | if ( !$o->get('quiet') ) { | ||
2123 | 3875 | print "$ts $fk_error\n\n"; | ||
2124 | 3876 | } | ||
2125 | 3877 | } | ||
2126 | 3878 | } | ||
2127 | 3879 | |||
2128 | 3880 | # Sleep if there's an --iteration left. | ||
2129 | 3881 | if ( !defined $iters || $iters ) { | ||
2130 | 3882 | PTDEBUG && _d('Sleeping', $interval, 'seconds'); | ||
2131 | 3883 | sleep $interval; | ||
2132 | 3541 | } | 3884 | } |
2133 | 3542 | } | 3885 | } |
2134 | 3543 | 3886 | ||
2136 | 3544 | return 0; | 3887 | PTDEBUG && _d('Done running, exiting', $exit_status); |
2137 | 3888 | return $exit_status; | ||
2138 | 3545 | } | 3889 | } |
2139 | 3546 | 3890 | ||
2140 | 3547 | # ############################################################################ | 3891 | # ############################################################################ |
2141 | @@ -3550,9 +3894,13 @@ | |||
2142 | 3550 | 3894 | ||
2143 | 3551 | sub get_fk_error { | 3895 | sub get_fk_error { |
2144 | 3552 | my ( $text ) = @_; | 3896 | my ( $text ) = @_; |
2145 | 3897 | PTDEBUG && _d($text); | ||
2146 | 3553 | 3898 | ||
2147 | 3554 | # Quick check if text even has a foreign key error. | 3899 | # Quick check if text even has a foreign key error. |
2149 | 3555 | return unless $text =~ m/LATEST FOREIGN KEY ERROR/; | 3900 | if ( $text !~ m/LATEST FOREIGN KEY ERROR/ ) { |
2150 | 3901 | PTDEBUG && _d('No fk error'); | ||
2151 | 3902 | return; | ||
2152 | 3903 | } | ||
2153 | 3556 | 3904 | ||
2154 | 3557 | # InnoDB timestamp | 3905 | # InnoDB timestamp |
2155 | 3558 | my $idb_ts = qr/((?:\d{6}|\d{4}-\d\d-\d\d) .\d:\d\d:\d\d)/; | 3906 | my $idb_ts = qr/((?:\d{6}|\d{4}-\d\d-\d\d) .\d:\d\d:\d\d)/; |
2156 | @@ -3564,24 +3912,11 @@ | |||
2157 | 3564 | return $ts, $fke; | 3912 | return $ts, $fke; |
2158 | 3565 | } | 3913 | } |
2159 | 3566 | 3914 | ||
2164 | 3567 | # Catches signals so the program can exit gracefully. | 3915 | sub sig_int { |
2165 | 3568 | sub finish { | 3916 | my ( $signal ) = @_; |
2162 | 3569 | my ($signal) = @_; | ||
2163 | 3570 | print STDERR "Exiting on SIG$signal.\n"; | ||
2166 | 3571 | $oktorun = 0; | 3917 | $oktorun = 0; |
2180 | 3572 | } | 3918 | print STDERR "# Caught SIG$signal. Use 'kill -ABRT $PID' if " |
2181 | 3573 | 3919 | . "the tool does not exit normally in a few seconds.\n"; | |
2169 | 3574 | sub get_cxn { | ||
2170 | 3575 | my ( $dsn, $ac, %args ) = @_; | ||
2171 | 3576 | my $o = $args{o}; | ||
2172 | 3577 | my $dp = $args{dp}; | ||
2173 | 3578 | |||
2174 | 3579 | if ( $o->get('ask-pass') ) { | ||
2175 | 3580 | $dsn->{p} = OptionParser::prompt_noecho("Enter password: "); | ||
2176 | 3581 | } | ||
2177 | 3582 | my $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), {AutoCommit => $ac}); | ||
2178 | 3583 | $dbh->{InactiveDestroy} = 1; # Because of forking. | ||
2179 | 3584 | return $dbh; | ||
2182 | 3585 | } | 3920 | } |
2183 | 3586 | 3921 | ||
2184 | 3587 | sub _d { | 3922 | sub _d { |
2185 | @@ -3606,22 +3941,28 @@ | |||
2186 | 3606 | 3941 | ||
2187 | 3607 | =head1 NAME | 3942 | =head1 NAME |
2188 | 3608 | 3943 | ||
2190 | 3609 | pt-fk-error-logger - Extract and log MySQL foreign key errors. | 3944 | pt-fk-error-logger - Log MySQL foreign key errors. |
2191 | 3610 | 3945 | ||
2192 | 3611 | =head1 SYNOPSIS | 3946 | =head1 SYNOPSIS |
2193 | 3612 | 3947 | ||
2195 | 3613 | Usage: pt-fk-error-logger [OPTION...] SOURCE_DSN | 3948 | Usage: pt-fk-error-logger [OPTIONS] DSN |
2196 | 3614 | 3949 | ||
2199 | 3615 | pt-fk-error-logger extracts and saves information about the most recent foreign | 3950 | pt-fk-error-logger logs information about foreign key errors on the given |
2200 | 3616 | key errors in a MySQL server. | 3951 | DSN. Information is printed to C<STDOUT>, and it can also be saved to a |
2201 | 3952 | table by specifying L<"--dest">. The tool runs for forever unless | ||
2202 | 3953 | L<"--run-time"> or L<"--iterations"> is specified. | ||
2203 | 3617 | 3954 | ||
2204 | 3618 | Print foreign key errors on host1: | 3955 | Print foreign key errors on host1: |
2205 | 3619 | 3956 | ||
2206 | 3620 | pt-fk-error-logger h=host1 | 3957 | pt-fk-error-logger h=host1 |
2207 | 3621 | 3958 | ||
2211 | 3622 | Save foreign key errors on host1 to db.foreign_key_errors table on host2: | 3959 | Print foreign key errors on host1 once then exit: |
2212 | 3623 | 3960 | ||
2213 | 3624 | pt-fk-error-logger h=host1 --dest h=host1,D=db,t=foreign_key_errors | 3961 | pt-fk-error-logger h=host1 --iterations 1 |
2214 | 3962 | |||
2215 | 3963 | Save foreign key errors on host1 to percona_schema.fke on host2: | ||
2216 | 3964 | |||
2217 | 3965 | pt-fk-error-logger h=host1 --dest h=host2,D=percona_schema,t=fke | ||
2218 | 3625 | 3966 | ||
2219 | 3626 | =head1 RISKS | 3967 | =head1 RISKS |
2220 | 3627 | 3968 | ||
2221 | @@ -3650,11 +3991,15 @@ | |||
2222 | 3650 | way. Foreign key errors are uniquely identified by their timestamp. | 3991 | way. Foreign key errors are uniquely identified by their timestamp. |
2223 | 3651 | Only new (more recent) errors are printed or saved. | 3992 | Only new (more recent) errors are printed or saved. |
2224 | 3652 | 3993 | ||
2225 | 3994 | By default the tool runs forever, checking every L<"--interval"> seconds | ||
2226 | 3995 | for new foreign key errors. Specify L<"--run-time"> and/or L<"--iterations"> | ||
2227 | 3996 | to limit how long the tool runs. | ||
2228 | 3997 | |||
2229 | 3653 | =head1 OUTPUT | 3998 | =head1 OUTPUT |
2230 | 3654 | 3999 | ||
2234 | 3655 | If L<"--print"> is given or no L<"--dest"> is given, then pt-fk-error-logger | 4000 | The foreign key error text from C<SHOW ENGINE INNODB STATUS> is printed |
2235 | 3656 | prints the foreign key error text to STDOUT exactly as it appeared in | 4001 | to C<STDOUT>, unless L<"--quiet"> is specified. Errors and warnings |
2236 | 3657 | C<SHOW INNODB STATUS>. | 4002 | are printed to C<STDERR>. |
2237 | 3658 | 4003 | ||
2238 | 3659 | =head1 OPTIONS | 4004 | =head1 OPTIONS |
2239 | 3660 | 4005 | ||
2240 | @@ -3698,11 +4043,12 @@ | |||
2241 | 3698 | 4043 | ||
2242 | 3699 | type: DSN | 4044 | type: DSN |
2243 | 3700 | 4045 | ||
2245 | 3701 | DSN for where to store foreign key errors; specify at least a database (D) and table (t). | 4046 | Save foreign key errors in this table. The DSN must specify a database (D) |
2246 | 4047 | and table (t). | ||
2247 | 3702 | 4048 | ||
2251 | 3703 | Missing values are filled in with the same values from the source host, so you | 4049 | Missing DSN values are inherited from the DSN being monitored, so you |
2252 | 3704 | can usually omit most parts of this argument if you're storing foreign key | 4050 | can omit most values if you're saving foreign key errors on the same |
2253 | 3705 | errors on the same server on which they happen. | 4051 | host. |
2254 | 3706 | 4052 | ||
2255 | 3707 | The following table is suggested: | 4053 | The following table is suggested: |
2256 | 3708 | 4054 | ||
2257 | @@ -3726,10 +4072,21 @@ | |||
2258 | 3726 | 4072 | ||
2259 | 3727 | =item --interval | 4073 | =item --interval |
2260 | 3728 | 4074 | ||
2262 | 3729 | type: time; default: 0 | 4075 | type: time; default: 30 |
2263 | 3730 | 4076 | ||
2264 | 3731 | How often to check for foreign key errors. | 4077 | How often to check for foreign key errors. |
2265 | 3732 | 4078 | ||
2266 | 4079 | =item --iterations | ||
2267 | 4080 | |||
2268 | 4081 | type: int | ||
2269 | 4082 | |||
2270 | 4083 | How many times to check for foreign key errors. By default, this option | ||
2271 | 4084 | is undefined which means an infinite number of iterations. The tool always | ||
2272 | 4085 | exits for L<"--run-time">, regardless of the value specified for this option. | ||
2273 | 4086 | For example, the tool will exit after 1 minute with | ||
2274 | 4087 | C<--run-time 1m --iterations 4 --interval 30> because 4 iterations at 30 | ||
2275 | 4088 | second intervals would take 2 minutes, longer than the 1 mintue run-time. | ||
2276 | 4089 | |||
2277 | 3733 | =item --log | 4090 | =item --log |
2278 | 3734 | 4091 | ||
2279 | 3735 | type: string | 4092 | type: string |
2280 | @@ -3746,10 +4103,11 @@ | |||
2281 | 3746 | 4103 | ||
2282 | 3747 | type: string | 4104 | type: string |
2283 | 3748 | 4105 | ||
2288 | 3749 | Create the given PID file when daemonized. The file contains the process ID of | 4106 | Create the given PID file. The tool won't start if the PID file already |
2289 | 3750 | the daemonized instance. The PID file is removed when the daemonized instance | 4107 | exists and the PID it contains is different than the current PID. However, |
2290 | 3751 | exits. The program checks for the existence of the PID file when starting; if | 4108 | if the PID file exists and the PID it contains is no longer running, the |
2291 | 3752 | it exists and the process with the matching PID exists, the program exits. | 4109 | tool will overwrite the PID file with the current PID. The PID file is |
2292 | 4110 | removed automatically when the tool exits. | ||
2293 | 3753 | 4111 | ||
2294 | 3754 | =item --port | 4112 | =item --port |
2295 | 3755 | 4113 | ||
2296 | @@ -3757,15 +4115,15 @@ | |||
2297 | 3757 | 4115 | ||
2298 | 3758 | Port number to use for connection. | 4116 | Port number to use for connection. |
2299 | 3759 | 4117 | ||
2301 | 3760 | =item --print | 4118 | =item --quiet |
2302 | 3761 | 4119 | ||
2304 | 3762 | Print results on standard output. See L<"OUTPUT"> for more. | 4120 | Do not print foreign key errors; only print errors and warnings to C<STDERR>. |
2305 | 3763 | 4121 | ||
2306 | 3764 | =item --run-time | 4122 | =item --run-time |
2307 | 3765 | 4123 | ||
2308 | 3766 | type: time | 4124 | type: time |
2309 | 3767 | 4125 | ||
2311 | 3768 | How long to run before exiting. | 4126 | How long to run before exiting. By default, the tool runs forever. |
2312 | 3769 | 4127 | ||
2313 | 3770 | =item --set-vars | 4128 | =item --set-vars |
2314 | 3771 | 4129 | ||
2315 | @@ -3948,7 +4306,7 @@ | |||
2316 | 3948 | 4306 | ||
2317 | 3949 | =head1 COPYRIGHT, LICENSE, AND WARRANTY | 4307 | =head1 COPYRIGHT, LICENSE, AND WARRANTY |
2318 | 3950 | 4308 | ||
2320 | 3951 | This program is copyright 2011-2012 Percona Ireland Ltd. | 4309 | This program is copyright 2011-2013 Percona Ireland Ltd. |
2321 | 3952 | 4310 | ||
2322 | 3953 | THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED | 4311 | THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
2323 | 3954 | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF | 4312 | WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
2324 | 3955 | 4313 | ||
2325 | === modified file 'bin/pt-heartbeat' | |||
2326 | --- bin/pt-heartbeat 2013-02-22 17:47:57 +0000 | |||
2327 | +++ bin/pt-heartbeat 2013-02-27 23:41:26 +0000 | |||
2328 | @@ -5664,10 +5664,11 @@ | |||
2329 | 5664 | 5664 | ||
2330 | 5665 | type: string | 5665 | type: string |
2331 | 5666 | 5666 | ||
2336 | 5667 | Create the given PID file when daemonized. The file contains the process ID of | 5667 | Create the given PID file. The tool won't start if the PID file already |
2337 | 5668 | the daemonized instance. The PID file is removed when the daemonized instance | 5668 | exists and the PID it contains is different than the current PID. However, |
2338 | 5669 | exits. The program checks for the existence of the PID file when starting; if | 5669 | if the PID file exists and the PID it contains is no longer running, the |
2339 | 5670 | it exists and the process with the matching PID exists, the program exits. | 5670 | tool will overwrite the PID file with the current PID. The PID file is |
2340 | 5671 | removed automatically when the tool exits. | ||
2341 | 5671 | 5672 | ||
2342 | 5672 | =item --port | 5673 | =item --port |
2343 | 5673 | 5674 | ||
2344 | 5674 | 5675 | ||
2345 | === modified file 'bin/pt-kill' | |||
2346 | --- bin/pt-kill 2013-02-22 17:47:57 +0000 | |||
2347 | +++ bin/pt-kill 2013-02-27 23:41:26 +0000 | |||
2348 | @@ -4969,23 +4969,24 @@ | |||
2349 | 4969 | } | 4969 | } |
2350 | 4970 | 4970 | ||
2351 | 4971 | my $self = { | 4971 | my $self = { |
2361 | 4972 | dsn => $dsn, | 4972 | dsn => $dsn, |
2362 | 4973 | dbh => $args{dbh}, | 4973 | dbh => $args{dbh}, |
2363 | 4974 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | 4974 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
2364 | 4975 | hostname => '', | 4975 | hostname => '', |
2365 | 4976 | set => $args{set}, | 4976 | set => $args{set}, |
2366 | 4977 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | 4977 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, |
2367 | 4978 | dbh_set => 0, | 4978 | dbh_set => 0, |
2368 | 4979 | OptionParser => $o, | 4979 | OptionParser => $o, |
2369 | 4980 | DSNParser => $dp, | 4980 | DSNParser => $dp, |
2370 | 4981 | is_cluster_node => undef, | 4981 | is_cluster_node => undef, |
2371 | 4982 | parent => $args{parent}, | ||
2372 | 4982 | }; | 4983 | }; |
2373 | 4983 | 4984 | ||
2374 | 4984 | return bless $self, $class; | 4985 | return bless $self, $class; |
2375 | 4985 | } | 4986 | } |
2376 | 4986 | 4987 | ||
2377 | 4987 | sub connect { | 4988 | sub connect { |
2379 | 4988 | my ( $self ) = @_; | 4989 | my ( $self, %opts ) = @_; |
2380 | 4989 | my $dsn = $self->{dsn}; | 4990 | my $dsn = $self->{dsn}; |
2381 | 4990 | my $dp = $self->{DSNParser}; | 4991 | my $dp = $self->{DSNParser}; |
2382 | 4991 | my $o = $self->{OptionParser}; | 4992 | my $o = $self->{OptionParser}; |
2383 | @@ -4996,11 +4997,18 @@ | |||
2384 | 4996 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | 4997 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); |
2385 | 4997 | $self->{asked_for_pass} = 1; | 4998 | $self->{asked_for_pass} = 1; |
2386 | 4998 | } | 4999 | } |
2388 | 4999 | $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 }); | 5000 | $dbh = $dp->get_dbh( |
2389 | 5001 | $dp->get_cxn_params($dsn), | ||
2390 | 5002 | { | ||
2391 | 5003 | AutoCommit => 1, | ||
2392 | 5004 | %opts, | ||
2393 | 5005 | }, | ||
2394 | 5006 | ); | ||
2395 | 5000 | } | 5007 | } |
2396 | 5001 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{name}); | ||
2397 | 5002 | 5008 | ||
2399 | 5003 | return $self->set_dbh($dbh); | 5009 | $dbh = $self->set_dbh($dbh); |
2400 | 5010 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
2401 | 5011 | return $dbh; | ||
2402 | 5004 | } | 5012 | } |
2403 | 5005 | 5013 | ||
2404 | 5006 | sub set_dbh { | 5014 | sub set_dbh { |
2405 | @@ -5023,6 +5031,11 @@ | |||
2406 | 5023 | $self->{hostname} = $hostname; | 5031 | $self->{hostname} = $hostname; |
2407 | 5024 | } | 5032 | } |
2408 | 5025 | 5033 | ||
2409 | 5034 | if ( $self->{parent} ) { | ||
2410 | 5035 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
2411 | 5036 | $dbh->{InactiveDestroy} = 1; | ||
2412 | 5037 | } | ||
2413 | 5038 | |||
2414 | 5026 | if ( my $set = $self->{set}) { | 5039 | if ( my $set = $self->{set}) { |
2415 | 5027 | $set->($dbh); | 5040 | $set->($dbh); |
2416 | 5028 | } | 5041 | } |
2417 | @@ -5032,6 +5045,13 @@ | |||
2418 | 5032 | return $dbh; | 5045 | return $dbh; |
2419 | 5033 | } | 5046 | } |
2420 | 5034 | 5047 | ||
2421 | 5048 | sub lost_connection { | ||
2422 | 5049 | my ($self, $e) = @_; | ||
2423 | 5050 | return 0 unless $e; | ||
2424 | 5051 | return $e =~ m/MySQL server has gone away/ | ||
2425 | 5052 | || $e =~ m/Lost connection to MySQL server/; | ||
2426 | 5053 | } | ||
2427 | 5054 | |||
2428 | 5035 | sub dbh { | 5055 | sub dbh { |
2429 | 5036 | my ($self) = @_; | 5056 | my ($self) = @_; |
2430 | 5037 | return $self->{dbh}; | 5057 | return $self->{dbh}; |
2431 | @@ -5050,12 +5070,21 @@ | |||
2432 | 5050 | 5070 | ||
2433 | 5051 | sub DESTROY { | 5071 | sub DESTROY { |
2434 | 5052 | my ($self) = @_; | 5072 | my ($self) = @_; |
2439 | 5053 | if ( $self->{dbh} | 5073 | |
2440 | 5054 | && blessed($self->{dbh}) | 5074 | PTDEBUG && _d('Destroying cxn'); |
2441 | 5055 | && $self->{dbh}->can("disconnect") ) { | 5075 | |
2442 | 5056 | PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name}); | 5076 | if ( $self->{parent} ) { |
2443 | 5077 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
2444 | 5078 | } | ||
2445 | 5079 | elsif ( $self->{dbh} | ||
2446 | 5080 | && blessed($self->{dbh}) | ||
2447 | 5081 | && $self->{dbh}->can("disconnect") ) | ||
2448 | 5082 | { | ||
2449 | 5083 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
2450 | 5084 | $self->{dsn_name}); | ||
2451 | 5057 | $self->{dbh}->disconnect(); | 5085 | $self->{dbh}->disconnect(); |
2452 | 5058 | } | 5086 | } |
2453 | 5087 | |||
2454 | 5059 | return; | 5088 | return; |
2455 | 5060 | } | 5089 | } |
2456 | 5061 | 5090 | ||
2457 | @@ -6464,6 +6493,7 @@ | |||
2458 | 6464 | $cxn = Cxn->new( | 6493 | $cxn = Cxn->new( |
2459 | 6465 | dsn_string => shift @ARGV, | 6494 | dsn_string => shift @ARGV, |
2460 | 6466 | NAME_lc => 0, | 6495 | NAME_lc => 0, |
2461 | 6496 | parent => $o->get('daemonize'), | ||
2462 | 6467 | DSNParser => $dp, | 6497 | DSNParser => $dp, |
2463 | 6468 | OptionParser => $o, | 6498 | OptionParser => $o, |
2464 | 6469 | ); | 6499 | ); |
2465 | @@ -6643,6 +6673,15 @@ | |||
2466 | 6643 | $daemon->make_PID_file(); | 6673 | $daemon->make_PID_file(); |
2467 | 6644 | } | 6674 | } |
2468 | 6645 | 6675 | ||
2469 | 6676 | # If we daemonized, the parent has already exited and we're the child. | ||
2470 | 6677 | # We shared a copy of every Cxn with the parent, and the parent's copies | ||
2471 | 6678 | # were destroyed but the dbhs were not disconnected because the parent | ||
2472 | 6679 | # attrib was true. Now, as the child, set it false so the dbhs will be | ||
2473 | 6680 | # disconnected when our Cxn copies are destroyed. If we didn't daemonize, | ||
2474 | 6681 | # then we're not really a parent (since we have no children), so set it | ||
2475 | 6682 | # false to auto-disconnect the dbhs when our Cxns are destroyed. | ||
2476 | 6683 | $cxn->{parent} = 0 if $cxn; | ||
2477 | 6684 | |||
2478 | 6646 | # ######################################################################## | 6685 | # ######################################################################## |
2479 | 6647 | # Do the version-check | 6686 | # Do the version-check |
2480 | 6648 | # ######################################################################## | 6687 | # ######################################################################## |
2481 | @@ -7311,10 +7350,11 @@ | |||
2482 | 7311 | 7350 | ||
2483 | 7312 | type: string | 7351 | type: string |
2484 | 7313 | 7352 | ||
2489 | 7314 | Create the given PID file when daemonized. The file contains the process ID of | 7353 | Create the given PID file. The tool won't start if the PID file already |
2490 | 7315 | the daemonized instance. The PID file is removed when the daemonized instance | 7354 | exists and the PID it contains is different than the current PID. However, |
2491 | 7316 | exits. The program checks for the existence of the PID file when starting; if | 7355 | if the PID file exists and the PID it contains is no longer running, the |
2492 | 7317 | it exists and the process with the matching PID exists, the program exits. | 7356 | tool will overwrite the PID file with the current PID. The PID file is |
2493 | 7357 | removed automatically when the tool exits. | ||
2494 | 7318 | 7358 | ||
2495 | 7319 | =item --port | 7359 | =item --port |
2496 | 7320 | 7360 | ||
2497 | 7321 | 7361 | ||
2498 | === modified file 'bin/pt-online-schema-change' | |||
2499 | --- bin/pt-online-schema-change 2013-02-22 17:47:57 +0000 | |||
2500 | +++ bin/pt-online-schema-change 2013-02-27 23:41:26 +0000 | |||
2501 | @@ -4018,23 +4018,24 @@ | |||
2502 | 4018 | } | 4018 | } |
2503 | 4019 | 4019 | ||
2504 | 4020 | my $self = { | 4020 | my $self = { |
2514 | 4021 | dsn => $dsn, | 4021 | dsn => $dsn, |
2515 | 4022 | dbh => $args{dbh}, | 4022 | dbh => $args{dbh}, |
2516 | 4023 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | 4023 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
2517 | 4024 | hostname => '', | 4024 | hostname => '', |
2518 | 4025 | set => $args{set}, | 4025 | set => $args{set}, |
2519 | 4026 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | 4026 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, |
2520 | 4027 | dbh_set => 0, | 4027 | dbh_set => 0, |
2521 | 4028 | OptionParser => $o, | 4028 | OptionParser => $o, |
2522 | 4029 | DSNParser => $dp, | 4029 | DSNParser => $dp, |
2523 | 4030 | is_cluster_node => undef, | 4030 | is_cluster_node => undef, |
2524 | 4031 | parent => $args{parent}, | ||
2525 | 4031 | }; | 4032 | }; |
2526 | 4032 | 4033 | ||
2527 | 4033 | return bless $self, $class; | 4034 | return bless $self, $class; |
2528 | 4034 | } | 4035 | } |
2529 | 4035 | 4036 | ||
2530 | 4036 | sub connect { | 4037 | sub connect { |
2532 | 4037 | my ( $self ) = @_; | 4038 | my ( $self, %opts ) = @_; |
2533 | 4038 | my $dsn = $self->{dsn}; | 4039 | my $dsn = $self->{dsn}; |
2534 | 4039 | my $dp = $self->{DSNParser}; | 4040 | my $dp = $self->{DSNParser}; |
2535 | 4040 | my $o = $self->{OptionParser}; | 4041 | my $o = $self->{OptionParser}; |
2536 | @@ -4045,11 +4046,18 @@ | |||
2537 | 4045 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | 4046 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); |
2538 | 4046 | $self->{asked_for_pass} = 1; | 4047 | $self->{asked_for_pass} = 1; |
2539 | 4047 | } | 4048 | } |
2541 | 4048 | $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 }); | 4049 | $dbh = $dp->get_dbh( |
2542 | 4050 | $dp->get_cxn_params($dsn), | ||
2543 | 4051 | { | ||
2544 | 4052 | AutoCommit => 1, | ||
2545 | 4053 | %opts, | ||
2546 | 4054 | }, | ||
2547 | 4055 | ); | ||
2548 | 4049 | } | 4056 | } |
2549 | 4050 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{name}); | ||
2550 | 4051 | 4057 | ||
2552 | 4052 | return $self->set_dbh($dbh); | 4058 | $dbh = $self->set_dbh($dbh); |
2553 | 4059 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
2554 | 4060 | return $dbh; | ||
2555 | 4053 | } | 4061 | } |
2556 | 4054 | 4062 | ||
2557 | 4055 | sub set_dbh { | 4063 | sub set_dbh { |
2558 | @@ -4072,6 +4080,11 @@ | |||
2559 | 4072 | $self->{hostname} = $hostname; | 4080 | $self->{hostname} = $hostname; |
2560 | 4073 | } | 4081 | } |
2561 | 4074 | 4082 | ||
2562 | 4083 | if ( $self->{parent} ) { | ||
2563 | 4084 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
2564 | 4085 | $dbh->{InactiveDestroy} = 1; | ||
2565 | 4086 | } | ||
2566 | 4087 | |||
2567 | 4075 | if ( my $set = $self->{set}) { | 4088 | if ( my $set = $self->{set}) { |
2568 | 4076 | $set->($dbh); | 4089 | $set->($dbh); |
2569 | 4077 | } | 4090 | } |
2570 | @@ -4081,6 +4094,13 @@ | |||
2571 | 4081 | return $dbh; | 4094 | return $dbh; |
2572 | 4082 | } | 4095 | } |
2573 | 4083 | 4096 | ||
2574 | 4097 | sub lost_connection { | ||
2575 | 4098 | my ($self, $e) = @_; | ||
2576 | 4099 | return 0 unless $e; | ||
2577 | 4100 | return $e =~ m/MySQL server has gone away/ | ||
2578 | 4101 | || $e =~ m/Lost connection to MySQL server/; | ||
2579 | 4102 | } | ||
2580 | 4103 | |||
2581 | 4084 | sub dbh { | 4104 | sub dbh { |
2582 | 4085 | my ($self) = @_; | 4105 | my ($self) = @_; |
2583 | 4086 | return $self->{dbh}; | 4106 | return $self->{dbh}; |
2584 | @@ -4099,12 +4119,21 @@ | |||
2585 | 4099 | 4119 | ||
2586 | 4100 | sub DESTROY { | 4120 | sub DESTROY { |
2587 | 4101 | my ($self) = @_; | 4121 | my ($self) = @_; |
2592 | 4102 | if ( $self->{dbh} | 4122 | |
2593 | 4103 | && blessed($self->{dbh}) | 4123 | PTDEBUG && _d('Destroying cxn'); |
2594 | 4104 | && $self->{dbh}->can("disconnect") ) { | 4124 | |
2595 | 4105 | PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name}); | 4125 | if ( $self->{parent} ) { |
2596 | 4126 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
2597 | 4127 | } | ||
2598 | 4128 | elsif ( $self->{dbh} | ||
2599 | 4129 | && blessed($self->{dbh}) | ||
2600 | 4130 | && $self->{dbh}->can("disconnect") ) | ||
2601 | 4131 | { | ||
2602 | 4132 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
2603 | 4133 | $self->{dsn_name}); | ||
2604 | 4106 | $self->{dbh}->disconnect(); | 4134 | $self->{dbh}->disconnect(); |
2605 | 4107 | } | 4135 | } |
2606 | 4136 | |||
2607 | 4108 | return; | 4137 | return; |
2608 | 4109 | } | 4138 | } |
2609 | 4110 | 4139 | ||
2610 | @@ -10839,10 +10868,11 @@ | |||
2611 | 10839 | 10868 | ||
2612 | 10840 | type: string | 10869 | type: string |
2613 | 10841 | 10870 | ||
2618 | 10842 | Create the given PID file. The file contains the process ID of the tool's | 10871 | Create the given PID file. The tool won't start if the PID file already |
2619 | 10843 | instance. The PID file is removed when the tool exits. The tool checks for | 10872 | exists and the PID it contains is different than the current PID. However, |
2620 | 10844 | the existence of the PID file when starting; if it exists and the process with | 10873 | if the PID file exists and the PID it contains is no longer running, the |
2621 | 10845 | the matching PID exists, the tool exits. | 10874 | tool will overwrite the PID file with the current PID. The PID file is |
2622 | 10875 | removed automatically when the tool exits. | ||
2623 | 10846 | 10876 | ||
2624 | 10847 | =item --port | 10877 | =item --port |
2625 | 10848 | 10878 | ||
2626 | 10849 | 10879 | ||
2627 | === modified file 'bin/pt-query-advisor' | |||
2628 | --- bin/pt-query-advisor 2013-02-22 17:47:57 +0000 | |||
2629 | +++ bin/pt-query-advisor 2013-02-27 23:41:26 +0000 | |||
2630 | @@ -9092,11 +9092,11 @@ | |||
2631 | 9092 | 9092 | ||
2632 | 9093 | type: string | 9093 | type: string |
2633 | 9094 | 9094 | ||
2639 | 9095 | Create the given PID file when daemonized. The file contains the process | 9095 | Create the given PID file. The tool won't start if the PID file already |
2640 | 9096 | ID of the daemonized instance. The PID file is removed when the | 9096 | exists and the PID it contains is different than the current PID. However, |
2641 | 9097 | daemonized instance exits. The program checks for the existence of the | 9097 | if the PID file exists and the PID it contains is no longer running, the |
2642 | 9098 | PID file when starting; if it exists and the process with the matching PID | 9098 | tool will overwrite the PID file with the current PID. The PID file is |
2643 | 9099 | exists, the program exits. | 9099 | removed automatically when the tool exits. |
2644 | 9100 | 9100 | ||
2645 | 9101 | =item --port | 9101 | =item --port |
2646 | 9102 | 9102 | ||
2647 | 9103 | 9103 | ||
2648 | === modified file 'bin/pt-query-digest' | |||
2649 | --- bin/pt-query-digest 2013-02-25 15:13:35 +0000 | |||
2650 | +++ bin/pt-query-digest 2013-02-27 23:41:26 +0000 | |||
2651 | @@ -14967,11 +14967,11 @@ | |||
2652 | 14967 | 14967 | ||
2653 | 14968 | type: string | 14968 | type: string |
2654 | 14969 | 14969 | ||
2660 | 14970 | Create the given PID file when daemonized. The file contains the process | 14970 | Create the given PID file. The tool won't start if the PID file already |
2661 | 14971 | ID of the daemonized instance. The PID file is removed when the | 14971 | exists and the PID it contains is different than the current PID. However, |
2662 | 14972 | daemonized instance exits. The program checks for the existence of the | 14972 | if the PID file exists and the PID it contains is no longer running, the |
2663 | 14973 | PID file when starting; if it exists and the process with the matching PID | 14973 | tool will overwrite the PID file with the current PID. The PID file is |
2664 | 14974 | exists, the program exits. | 14974 | removed automatically when the tool exits. |
2665 | 14975 | 14975 | ||
2666 | 14976 | =item --port | 14976 | =item --port |
2667 | 14977 | 14977 | ||
2668 | 14978 | 14978 | ||
2669 | === modified file 'bin/pt-show-grants' | |||
2670 | --- bin/pt-show-grants 2013-01-03 00:54:18 +0000 | |||
2671 | +++ bin/pt-show-grants 2013-02-27 23:41:26 +0000 | |||
2672 | @@ -2093,14 +2093,11 @@ | |||
2673 | 2093 | 2093 | ||
2674 | 2094 | type: string | 2094 | type: string |
2675 | 2095 | 2095 | ||
2684 | 2096 | Create the given PID file. The file contains the process ID of the script. | 2096 | Create the given PID file. The tool won't start if the PID file already |
2685 | 2097 | The PID file is removed when the script exits. Before starting, the script | 2097 | exists and the PID it contains is different than the current PID. However, |
2686 | 2098 | checks if the PID file already exists. If it does not, then the script creates | 2098 | if the PID file exists and the PID it contains is no longer running, the |
2687 | 2099 | and writes its own PID to it. If it does, then the script checks the following: | 2099 | tool will overwrite the PID file with the current PID. The PID file is |
2688 | 2100 | if the file contains a PID and a process is running with that PID, then | 2100 | removed automatically when the tool exits. |
2681 | 2101 | the script dies; or, if there is no process running with that PID, then the | ||
2682 | 2102 | script overwrites the file with its own PID and starts; else, if the file | ||
2683 | 2103 | contains no PID, then the script dies. | ||
2689 | 2104 | 2101 | ||
2690 | 2105 | =item --port | 2102 | =item --port |
2691 | 2106 | 2103 | ||
2692 | 2107 | 2104 | ||
2693 | === modified file 'bin/pt-slave-delay' | |||
2694 | --- bin/pt-slave-delay 2013-02-22 15:00:55 +0000 | |||
2695 | +++ bin/pt-slave-delay 2013-02-27 23:41:26 +0000 | |||
2696 | @@ -4478,11 +4478,11 @@ | |||
2697 | 4478 | 4478 | ||
2698 | 4479 | type: string | 4479 | type: string |
2699 | 4480 | 4480 | ||
2705 | 4481 | Create the given PID file when daemonized. The file contains the process | 4481 | Create the given PID file. The tool won't start if the PID file already |
2706 | 4482 | ID of the daemonized instance. The PID file is removed when the | 4482 | exists and the PID it contains is different than the current PID. However, |
2707 | 4483 | daemonized instance exits. The program checks for the existence of the | 4483 | if the PID file exists and the PID it contains is no longer running, the |
2708 | 4484 | PID file when starting; if it exists and the process with the matching PID | 4484 | tool will overwrite the PID file with the current PID. The PID file is |
2709 | 4485 | exists, the program exits. | 4485 | removed automatically when the tool exits. |
2710 | 4486 | 4486 | ||
2711 | 4487 | =item --port | 4487 | =item --port |
2712 | 4488 | 4488 | ||
2713 | 4489 | 4489 | ||
2714 | === modified file 'bin/pt-slave-find' | |||
2715 | --- bin/pt-slave-find 2013-02-01 17:06:13 +0000 | |||
2716 | +++ bin/pt-slave-find 2013-02-27 23:41:26 +0000 | |||
2717 | @@ -3960,14 +3960,11 @@ | |||
2718 | 3960 | 3960 | ||
2719 | 3961 | type: string | 3961 | type: string |
2720 | 3962 | 3962 | ||
2729 | 3963 | Create the given PID file. The file contains the process ID of the script. | 3963 | Create the given PID file. The tool won't start if the PID file already |
2730 | 3964 | The PID file is removed when the script exits. Before starting, the script | 3964 | exists and the PID it contains is different than the current PID. However, |
2731 | 3965 | checks if the PID file already exists. If it does not, then the script creates | 3965 | if the PID file exists and the PID it contains is no longer running, the |
2732 | 3966 | and writes its own PID to it. If it does, then the script checks the following: | 3966 | tool will overwrite the PID file with the current PID. The PID file is |
2733 | 3967 | if the file contains a PID and a process is running with that PID, then | 3967 | removed automatically when the tool exits. |
2726 | 3968 | the script dies; or, if there is no process running with that PID, then the | ||
2727 | 3969 | script overwrites the file with its own PID and starts; else, if the file | ||
2728 | 3970 | contains no PID, then the script dies. | ||
2734 | 3971 | 3968 | ||
2735 | 3972 | =item --port | 3969 | =item --port |
2736 | 3973 | 3970 | ||
2737 | 3974 | 3971 | ||
2738 | === modified file 'bin/pt-slave-restart' | |||
2739 | --- bin/pt-slave-restart 2013-02-22 17:47:57 +0000 | |||
2740 | +++ bin/pt-slave-restart 2013-02-27 23:41:26 +0000 | |||
2741 | @@ -5312,11 +5312,11 @@ | |||
2742 | 5312 | 5312 | ||
2743 | 5313 | type: string | 5313 | type: string |
2744 | 5314 | 5314 | ||
2750 | 5315 | Create the given PID file when daemonized. The file contains the process | 5315 | Create the given PID file. The tool won't start if the PID file already |
2751 | 5316 | ID of the daemonized instance. The PID file is removed when the | 5316 | exists and the PID it contains is different than the current PID. However, |
2752 | 5317 | daemonized instance exits. The program checks for the existence of the | 5317 | if the PID file exists and the PID it contains is no longer running, the |
2753 | 5318 | PID file when starting; if it exists and the process with the matching PID | 5318 | tool will overwrite the PID file with the current PID. The PID file is |
2754 | 5319 | exists, the program exits. | 5319 | removed automatically when the tool exits. |
2755 | 5320 | 5320 | ||
2756 | 5321 | =item --port | 5321 | =item --port |
2757 | 5322 | 5322 | ||
2758 | 5323 | 5323 | ||
2759 | === modified file 'bin/pt-stalk' | |||
2760 | --- bin/pt-stalk 2013-01-24 19:08:09 +0000 | |||
2761 | +++ bin/pt-stalk 2013-02-27 23:41:26 +0000 | |||
2762 | @@ -1723,7 +1723,11 @@ | |||
2763 | 1723 | 1723 | ||
2764 | 1724 | type: string; default: /var/run/pt-stalk.pid | 1724 | type: string; default: /var/run/pt-stalk.pid |
2765 | 1725 | 1725 | ||
2767 | 1726 | Create a PID file when daemonized. | 1726 | Create the given PID file. The tool won't start if the PID file already |
2768 | 1727 | exists and the PID it contains is different than the current PID. However, | ||
2769 | 1728 | if the PID file exists and the PID it contains is no longer running, the | ||
2770 | 1729 | tool will overwrite the PID file with the current PID. The PID file is | ||
2771 | 1730 | removed automatically when the tool exits. | ||
2772 | 1727 | 1731 | ||
2773 | 1728 | =item --plugin | 1732 | =item --plugin |
2774 | 1729 | 1733 | ||
2775 | 1730 | 1734 | ||
2776 | === modified file 'bin/pt-table-checksum' | |||
2777 | --- bin/pt-table-checksum 2013-02-22 17:47:57 +0000 | |||
2778 | +++ bin/pt-table-checksum 2013-02-27 23:41:26 +0000 | |||
2779 | @@ -3376,23 +3376,24 @@ | |||
2780 | 3376 | } | 3376 | } |
2781 | 3377 | 3377 | ||
2782 | 3378 | my $self = { | 3378 | my $self = { |
2792 | 3379 | dsn => $dsn, | 3379 | dsn => $dsn, |
2793 | 3380 | dbh => $args{dbh}, | 3380 | dbh => $args{dbh}, |
2794 | 3381 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | 3381 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
2795 | 3382 | hostname => '', | 3382 | hostname => '', |
2796 | 3383 | set => $args{set}, | 3383 | set => $args{set}, |
2797 | 3384 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | 3384 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, |
2798 | 3385 | dbh_set => 0, | 3385 | dbh_set => 0, |
2799 | 3386 | OptionParser => $o, | 3386 | OptionParser => $o, |
2800 | 3387 | DSNParser => $dp, | 3387 | DSNParser => $dp, |
2801 | 3388 | is_cluster_node => undef, | 3388 | is_cluster_node => undef, |
2802 | 3389 | parent => $args{parent}, | ||
2803 | 3389 | }; | 3390 | }; |
2804 | 3390 | 3391 | ||
2805 | 3391 | return bless $self, $class; | 3392 | return bless $self, $class; |
2806 | 3392 | } | 3393 | } |
2807 | 3393 | 3394 | ||
2808 | 3394 | sub connect { | 3395 | sub connect { |
2810 | 3395 | my ( $self ) = @_; | 3396 | my ( $self, %opts ) = @_; |
2811 | 3396 | my $dsn = $self->{dsn}; | 3397 | my $dsn = $self->{dsn}; |
2812 | 3397 | my $dp = $self->{DSNParser}; | 3398 | my $dp = $self->{DSNParser}; |
2813 | 3398 | my $o = $self->{OptionParser}; | 3399 | my $o = $self->{OptionParser}; |
2814 | @@ -3403,11 +3404,18 @@ | |||
2815 | 3403 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | 3404 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); |
2816 | 3404 | $self->{asked_for_pass} = 1; | 3405 | $self->{asked_for_pass} = 1; |
2817 | 3405 | } | 3406 | } |
2819 | 3406 | $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 }); | 3407 | $dbh = $dp->get_dbh( |
2820 | 3408 | $dp->get_cxn_params($dsn), | ||
2821 | 3409 | { | ||
2822 | 3410 | AutoCommit => 1, | ||
2823 | 3411 | %opts, | ||
2824 | 3412 | }, | ||
2825 | 3413 | ); | ||
2826 | 3407 | } | 3414 | } |
2827 | 3408 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{name}); | ||
2828 | 3409 | 3415 | ||
2830 | 3410 | return $self->set_dbh($dbh); | 3416 | $dbh = $self->set_dbh($dbh); |
2831 | 3417 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
2832 | 3418 | return $dbh; | ||
2833 | 3411 | } | 3419 | } |
2834 | 3412 | 3420 | ||
2835 | 3413 | sub set_dbh { | 3421 | sub set_dbh { |
2836 | @@ -3430,6 +3438,11 @@ | |||
2837 | 3430 | $self->{hostname} = $hostname; | 3438 | $self->{hostname} = $hostname; |
2838 | 3431 | } | 3439 | } |
2839 | 3432 | 3440 | ||
2840 | 3441 | if ( $self->{parent} ) { | ||
2841 | 3442 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
2842 | 3443 | $dbh->{InactiveDestroy} = 1; | ||
2843 | 3444 | } | ||
2844 | 3445 | |||
2845 | 3433 | if ( my $set = $self->{set}) { | 3446 | if ( my $set = $self->{set}) { |
2846 | 3434 | $set->($dbh); | 3447 | $set->($dbh); |
2847 | 3435 | } | 3448 | } |
2848 | @@ -3439,6 +3452,13 @@ | |||
2849 | 3439 | return $dbh; | 3452 | return $dbh; |
2850 | 3440 | } | 3453 | } |
2851 | 3441 | 3454 | ||
2852 | 3455 | sub lost_connection { | ||
2853 | 3456 | my ($self, $e) = @_; | ||
2854 | 3457 | return 0 unless $e; | ||
2855 | 3458 | return $e =~ m/MySQL server has gone away/ | ||
2856 | 3459 | || $e =~ m/Lost connection to MySQL server/; | ||
2857 | 3460 | } | ||
2858 | 3461 | |||
2859 | 3442 | sub dbh { | 3462 | sub dbh { |
2860 | 3443 | my ($self) = @_; | 3463 | my ($self) = @_; |
2861 | 3444 | return $self->{dbh}; | 3464 | return $self->{dbh}; |
2862 | @@ -3457,12 +3477,21 @@ | |||
2863 | 3457 | 3477 | ||
2864 | 3458 | sub DESTROY { | 3478 | sub DESTROY { |
2865 | 3459 | my ($self) = @_; | 3479 | my ($self) = @_; |
2870 | 3460 | if ( $self->{dbh} | 3480 | |
2871 | 3461 | && blessed($self->{dbh}) | 3481 | PTDEBUG && _d('Destroying cxn'); |
2872 | 3462 | && $self->{dbh}->can("disconnect") ) { | 3482 | |
2873 | 3463 | PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name}); | 3483 | if ( $self->{parent} ) { |
2874 | 3484 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
2875 | 3485 | } | ||
2876 | 3486 | elsif ( $self->{dbh} | ||
2877 | 3487 | && blessed($self->{dbh}) | ||
2878 | 3488 | && $self->{dbh}->can("disconnect") ) | ||
2879 | 3489 | { | ||
2880 | 3490 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
2881 | 3491 | $self->{dsn_name}); | ||
2882 | 3464 | $self->{dbh}->disconnect(); | 3492 | $self->{dbh}->disconnect(); |
2883 | 3465 | } | 3493 | } |
2884 | 3494 | |||
2885 | 3466 | return; | 3495 | return; |
2886 | 3467 | } | 3496 | } |
2887 | 3468 | 3497 | ||
2888 | @@ -11590,14 +11619,11 @@ | |||
2889 | 11590 | 11619 | ||
2890 | 11591 | type: string | 11620 | type: string |
2891 | 11592 | 11621 | ||
2900 | 11593 | Create the given PID file. The file contains the process ID of the script. | 11622 | Create the given PID file. The tool won't start if the PID file already |
2901 | 11594 | The PID file is removed when the script exits. Before starting, the script | 11623 | exists and the PID it contains is different than the current PID. However, |
2902 | 11595 | checks if the PID file already exists. If it does not, then the script creates | 11624 | if the PID file exists and the PID it contains is no longer running, the |
2903 | 11596 | and writes its own PID to it. If it does, then the script checks the following: | 11625 | tool will overwrite the PID file with the current PID. The PID file is |
2904 | 11597 | if the file contains a PID and a process is running with that PID, then | 11626 | removed automatically when the tool exits. |
2897 | 11598 | the script dies; or, if there is no process running with that PID, then the | ||
2898 | 11599 | script overwrites the file with its own PID and starts; else, if the file | ||
2899 | 11600 | contains no PID, then the script dies. | ||
2905 | 11601 | 11627 | ||
2906 | 11602 | =item --port | 11628 | =item --port |
2907 | 11603 | 11629 | ||
2908 | 11604 | 11630 | ||
2909 | === modified file 'bin/pt-table-sync' | |||
2910 | --- bin/pt-table-sync 2013-02-22 17:47:57 +0000 | |||
2911 | +++ bin/pt-table-sync 2013-02-27 23:41:26 +0000 | |||
2912 | @@ -12051,14 +12051,11 @@ | |||
2913 | 12051 | 12051 | ||
2914 | 12052 | type: string | 12052 | type: string |
2915 | 12053 | 12053 | ||
2924 | 12054 | Create the given PID file. The file contains the process ID of the script. | 12054 | Create the given PID file. The tool won't start if the PID file already |
2925 | 12055 | The PID file is removed when the script exits. Before starting, the script | 12055 | exists and the PID it contains is different than the current PID. However, |
2926 | 12056 | checks if the PID file already exists. If it does not, then the script creates | 12056 | if the PID file exists and the PID it contains is no longer running, the |
2927 | 12057 | and writes its own PID to it. If it does, then the script checks the following: | 12057 | tool will overwrite the PID file with the current PID. The PID file is |
2928 | 12058 | if the file contains a PID and a process is running with that PID, then | 12058 | removed automatically when the tool exits. |
2921 | 12059 | the script dies; or, if there is no process running with that PID, then the | ||
2922 | 12060 | script overwrites the file with its own PID and starts; else, if the file | ||
2923 | 12061 | contains no PID, then the script dies. | ||
2929 | 12062 | 12059 | ||
2930 | 12063 | =item --port | 12060 | =item --port |
2931 | 12064 | 12061 | ||
2932 | 12065 | 12062 | ||
2933 | === modified file 'bin/pt-table-usage' | |||
2934 | --- bin/pt-table-usage 2013-02-19 20:01:58 +0000 | |||
2935 | +++ bin/pt-table-usage 2013-02-27 23:41:26 +0000 | |||
2936 | @@ -7192,11 +7192,11 @@ | |||
2937 | 7192 | 7192 | ||
2938 | 7193 | type: string | 7193 | type: string |
2939 | 7194 | 7194 | ||
2945 | 7195 | Create the given PID file when running. The file contains the process | 7195 | Create the given PID file. The tool won't start if the PID file already |
2946 | 7196 | ID of the daemonized instance. The PID file is removed when the | 7196 | exists and the PID it contains is different than the current PID. However, |
2947 | 7197 | daemonized instance exits. The program checks for the existence of the | 7197 | if the PID file exists and the PID it contains is no longer running, the |
2948 | 7198 | PID file when starting; if it exists and the process with the matching PID | 7198 | tool will overwrite the PID file with the current PID. The PID file is |
2949 | 7199 | exists, the program exits. | 7199 | removed automatically when the tool exits. |
2950 | 7200 | 7200 | ||
2951 | 7201 | =item --port | 7201 | =item --port |
2952 | 7202 | 7202 | ||
2953 | 7203 | 7203 | ||
2954 | === modified file 'bin/pt-upgrade' | |||
2955 | --- bin/pt-upgrade 2013-02-22 17:47:57 +0000 | |||
2956 | +++ bin/pt-upgrade 2013-02-27 23:41:26 +0000 | |||
2957 | @@ -13483,11 +13483,11 @@ | |||
2958 | 13483 | 13483 | ||
2959 | 13484 | type: string | 13484 | type: string |
2960 | 13485 | 13485 | ||
2966 | 13486 | Create the given PID file when daemonized. The file contains the process | 13486 | Create the given PID file. The tool won't start if the PID file already |
2967 | 13487 | ID of the daemonized instance. The PID file is removed when the | 13487 | exists and the PID it contains is different than the current PID. However, |
2968 | 13488 | daemonized instance exits. The program checks for the existence of the | 13488 | if the PID file exists and the PID it contains is no longer running, the |
2969 | 13489 | PID file when starting; if it exists and the process with the matching PID | 13489 | tool will overwrite the PID file with the current PID. The PID file is |
2970 | 13490 | exists, the program exits. | 13490 | removed automatically when the tool exits. |
2971 | 13491 | 13491 | ||
2972 | 13492 | =item --port | 13492 | =item --port |
2973 | 13493 | 13493 | ||
2974 | 13494 | 13494 | ||
2975 | === modified file 'bin/pt-variable-advisor' | |||
2976 | --- bin/pt-variable-advisor 2013-02-22 15:00:55 +0000 | |||
2977 | +++ bin/pt-variable-advisor 2013-02-27 23:41:26 +0000 | |||
2978 | @@ -5752,11 +5752,11 @@ | |||
2979 | 5752 | 5752 | ||
2980 | 5753 | type: string | 5753 | type: string |
2981 | 5754 | 5754 | ||
2987 | 5755 | Create the given PID file when daemonized. The file contains the process | 5755 | Create the given PID file. The tool won't start if the PID file already |
2988 | 5756 | ID of the daemonized instance. The PID file is removed when the | 5756 | exists and the PID it contains is different than the current PID. However, |
2989 | 5757 | daemonized instance exits. The program checks for the existence of the | 5757 | if the PID file exists and the PID it contains is no longer running, the |
2990 | 5758 | PID file when starting; if it exists and the process with the matching PID | 5758 | tool will overwrite the PID file with the current PID. The PID file is |
2991 | 5759 | exists, the program exits. | 5759 | removed automatically when the tool exits. |
2992 | 5760 | 5760 | ||
2993 | 5761 | =item --port | 5761 | =item --port |
2994 | 5762 | 5762 | ||
2995 | 5763 | 5763 | ||
2996 | === modified file 'bin/pt-visual-explain' | |||
2997 | --- bin/pt-visual-explain 2013-02-19 20:01:58 +0000 | |||
2998 | +++ bin/pt-visual-explain 2013-02-27 23:41:26 +0000 | |||
2999 | @@ -2952,14 +2952,11 @@ | |||
3000 | 2952 | 2952 | ||
3001 | 2953 | type: string | 2953 | type: string |
3002 | 2954 | 2954 | ||
3011 | 2955 | Create the given PID file. The file contains the process ID of the script. | 2955 | Create the given PID file. The tool won't start if the PID file already |
3012 | 2956 | The PID file is removed when the script exits. Before starting, the script | 2956 | exists and the PID it contains is different than the current PID. However, |
3013 | 2957 | checks if the PID file already exists. If it does not, then the script creates | 2957 | if the PID file exists and the PID it contains is no longer running, the |
3014 | 2958 | and writes its own PID to it. If it does, then the script checks the following: | 2958 | tool will overwrite the PID file with the current PID. The PID file is |
3015 | 2959 | if the file contains a PID and a process is running with that PID, then | 2959 | removed automatically when the tool exits. |
3008 | 2960 | the script dies; or, if there is no process running with that PID, then the | ||
3009 | 2961 | script overwrites the file with its own PID and starts; else, if the file | ||
3010 | 2962 | contains no PID, then the script dies. | ||
3016 | 2963 | 2960 | ||
3017 | 2964 | =item --port | 2961 | =item --port |
3018 | 2965 | 2962 | ||
3019 | 2966 | 2963 | ||
3020 | === modified file 'docs/percona-toolkit.pod' | |||
3021 | --- docs/percona-toolkit.pod 2013-01-03 00:54:18 +0000 | |||
3022 | +++ docs/percona-toolkit.pod 2013-02-27 23:41:26 +0000 | |||
3023 | @@ -175,6 +175,34 @@ | |||
3024 | 175 | For more free, open-source software developed Percona, visit | 175 | For more free, open-source software developed Percona, visit |
3025 | 176 | L<http://www.percona.com/software/>. | 176 | L<http://www.percona.com/software/>. |
3026 | 177 | 177 | ||
3027 | 178 | =head1 SPECIAL OPTION TYPES | ||
3028 | 179 | |||
3029 | 180 | =over | ||
3030 | 181 | |||
3031 | 182 | =item time | ||
3032 | 183 | |||
3033 | 184 | Time values are seconds by default. For example, C<--run-time 60> means | ||
3034 | 185 | 60 seconds. Time values support an optional suffix: s (seconds), | ||
3035 | 186 | m (minutes), h (hours), d (days). C<--run-time 1m> means 1 minute | ||
3036 | 187 | (the same as 60 seconds). | ||
3037 | 188 | |||
3038 | 189 | =item size | ||
3039 | 190 | |||
3040 | 191 | Size values are bytes by default. For example, C<--disk-space-free 1024> | ||
3041 | 192 | means 1 Kibibyte. Size values support an optional suffix: k (Kibibyte), | ||
3042 | 193 | M (Mebibyte), G (Gibibyte). | ||
3043 | 194 | |||
3044 | 195 | =item DSN | ||
3045 | 196 | |||
3046 | 197 | See L<"DSN (DATA SOURCE NAME) SPECIFICATIONS">. | ||
3047 | 198 | |||
3048 | 199 | =item Hash, hash, Array, array | ||
3049 | 200 | |||
3050 | 201 | Hash, hash, Array, and array values are comma-separated lists of values. | ||
3051 | 202 | For example, C<--ignore-tables foo,bar> ignores tables C<foo> and C<bar>. | ||
3052 | 203 | |||
3053 | 204 | =back | ||
3054 | 205 | |||
3055 | 178 | =head1 CONFIGURATION FILES | 206 | =head1 CONFIGURATION FILES |
3056 | 179 | 207 | ||
3057 | 180 | Percona Toolkit tools can read options from configuration files. The | 208 | Percona Toolkit tools can read options from configuration files. The |
3058 | 181 | 209 | ||
3059 | === modified file 'lib/Cxn.pm' | |||
3060 | --- lib/Cxn.pm 2013-01-03 00:19:16 +0000 | |||
3061 | +++ lib/Cxn.pm 2013-02-27 23:41:26 +0000 | |||
3062 | @@ -98,23 +98,24 @@ | |||
3063 | 98 | } | 98 | } |
3064 | 99 | 99 | ||
3065 | 100 | my $self = { | 100 | my $self = { |
3075 | 101 | dsn => $dsn, | 101 | dsn => $dsn, |
3076 | 102 | dbh => $args{dbh}, | 102 | dbh => $args{dbh}, |
3077 | 103 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), | 103 | dsn_name => $dp->as_string($dsn, [qw(h P S)]), |
3078 | 104 | hostname => '', | 104 | hostname => '', |
3079 | 105 | set => $args{set}, | 105 | set => $args{set}, |
3080 | 106 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, | 106 | NAME_lc => defined($args{NAME_lc}) ? $args{NAME_lc} : 1, |
3081 | 107 | dbh_set => 0, | 107 | dbh_set => 0, |
3082 | 108 | OptionParser => $o, | 108 | OptionParser => $o, |
3083 | 109 | DSNParser => $dp, | 109 | DSNParser => $dp, |
3084 | 110 | is_cluster_node => undef, | 110 | is_cluster_node => undef, |
3085 | 111 | parent => $args{parent}, | ||
3086 | 111 | }; | 112 | }; |
3087 | 112 | 113 | ||
3088 | 113 | return bless $self, $class; | 114 | return bless $self, $class; |
3089 | 114 | } | 115 | } |
3090 | 115 | 116 | ||
3091 | 116 | sub connect { | 117 | sub connect { |
3093 | 117 | my ( $self ) = @_; | 118 | my ( $self, %opts ) = @_; |
3094 | 118 | my $dsn = $self->{dsn}; | 119 | my $dsn = $self->{dsn}; |
3095 | 119 | my $dp = $self->{DSNParser}; | 120 | my $dp = $self->{DSNParser}; |
3096 | 120 | my $o = $self->{OptionParser}; | 121 | my $o = $self->{OptionParser}; |
3097 | @@ -126,11 +127,18 @@ | |||
3098 | 126 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); | 127 | $dsn->{p} = OptionParser::prompt_noecho("Enter MySQL password: "); |
3099 | 127 | $self->{asked_for_pass} = 1; | 128 | $self->{asked_for_pass} = 1; |
3100 | 128 | } | 129 | } |
3102 | 129 | $dbh = $dp->get_dbh($dp->get_cxn_params($dsn), { AutoCommit => 1 }); | 130 | $dbh = $dp->get_dbh( |
3103 | 131 | $dp->get_cxn_params($dsn), | ||
3104 | 132 | { | ||
3105 | 133 | AutoCommit => 1, | ||
3106 | 134 | %opts, | ||
3107 | 135 | }, | ||
3108 | 136 | ); | ||
3109 | 130 | } | 137 | } |
3110 | 131 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{name}); | ||
3111 | 132 | 138 | ||
3113 | 133 | return $self->set_dbh($dbh); | 139 | $dbh = $self->set_dbh($dbh); |
3114 | 140 | PTDEBUG && _d($dbh, 'Connected dbh to', $self->{hostname},$self->{dsn_name}); | ||
3115 | 141 | return $dbh; | ||
3116 | 134 | } | 142 | } |
3117 | 135 | 143 | ||
3118 | 136 | sub set_dbh { | 144 | sub set_dbh { |
3119 | @@ -163,6 +171,11 @@ | |||
3120 | 163 | $self->{hostname} = $hostname; | 171 | $self->{hostname} = $hostname; |
3121 | 164 | } | 172 | } |
3122 | 165 | 173 | ||
3123 | 174 | if ( $self->{parent} ) { | ||
3124 | 175 | PTDEBUG && _d($dbh, 'Setting InactiveDestroy=1 in parent'); | ||
3125 | 176 | $dbh->{InactiveDestroy} = 1; | ||
3126 | 177 | } | ||
3127 | 178 | |||
3128 | 166 | # Call the set callback to let the caller SET any MySQL variables. | 179 | # Call the set callback to let the caller SET any MySQL variables. |
3129 | 167 | if ( my $set = $self->{set}) { | 180 | if ( my $set = $self->{set}) { |
3130 | 168 | $set->($dbh); | 181 | $set->($dbh); |
3131 | @@ -173,6 +186,15 @@ | |||
3132 | 173 | return $dbh; | 186 | return $dbh; |
3133 | 174 | } | 187 | } |
3134 | 175 | 188 | ||
3135 | 189 | sub lost_connection { | ||
3136 | 190 | my ($self, $e) = @_; | ||
3137 | 191 | return 0 unless $e; | ||
3138 | 192 | return $e =~ m/MySQL server has gone away/ | ||
3139 | 193 | || $e =~ m/Lost connection to MySQL server/; | ||
3140 | 194 | # The 1st pattern means that MySQL itself died or was stopped. | ||
3141 | 195 | # The 2nd pattern means that our cxn was killed (KILL <id>). | ||
3142 | 196 | } | ||
3143 | 197 | |||
3144 | 176 | # Sub: dbh | 198 | # Sub: dbh |
3145 | 177 | # Return the cxn's dbh. | 199 | # Return the cxn's dbh. |
3146 | 178 | sub dbh { | 200 | sub dbh { |
3147 | @@ -197,12 +219,21 @@ | |||
3148 | 197 | 219 | ||
3149 | 198 | sub DESTROY { | 220 | sub DESTROY { |
3150 | 199 | my ($self) = @_; | 221 | my ($self) = @_; |
3155 | 200 | if ( $self->{dbh} | 222 | |
3156 | 201 | && blessed($self->{dbh}) | 223 | PTDEBUG && _d('Destroying cxn'); |
3157 | 202 | && $self->{dbh}->can("disconnect") ) { | 224 | |
3158 | 203 | PTDEBUG && _d('Disconnecting dbh', $self->{dbh}, $self->{name}); | 225 | if ( $self->{parent} ) { |
3159 | 226 | PTDEBUG && _d($self->{dbh}, 'Not disconnecting dbh in parent'); | ||
3160 | 227 | } | ||
3161 | 228 | elsif ( $self->{dbh} | ||
3162 | 229 | && blessed($self->{dbh}) | ||
3163 | 230 | && $self->{dbh}->can("disconnect") ) | ||
3164 | 231 | { | ||
3165 | 232 | PTDEBUG && _d($self->{dbh}, 'Disconnecting dbh on', $self->{hostname}, | ||
3166 | 233 | $self->{dsn_name}); | ||
3167 | 204 | $self->{dbh}->disconnect(); | 234 | $self->{dbh}->disconnect(); |
3168 | 205 | } | 235 | } |
3169 | 236 | |||
3170 | 206 | return; | 237 | return; |
3171 | 207 | } | 238 | } |
3172 | 208 | 239 | ||
3173 | 209 | 240 | ||
3174 | === modified file 'lib/Runtime.pm' | |||
3175 | --- lib/Runtime.pm 2013-01-03 00:19:16 +0000 | |||
3176 | +++ lib/Runtime.pm 2013-02-27 23:41:26 +0000 | |||
3177 | @@ -18,13 +18,6 @@ | |||
3178 | 18 | # Runtime package | 18 | # Runtime package |
3179 | 19 | # ########################################################################### | 19 | # ########################################################################### |
3180 | 20 | { | 20 | { |
3181 | 21 | # Package: Runtime | ||
3182 | 22 | # Runtime keeps track of time to control how long a tool's main loop runs. | ||
3183 | 23 | # This package was created to handle mk-query-digest --run-time-mode event. | ||
3184 | 24 | # In essence, we abstract time so that the tool doesn't know/care whether | ||
3185 | 25 | # now() comes from a clock, a log timestamp, or wherever. The creator of | ||
3186 | 26 | # Runtime object determines how, or from where, time is gotten so that the | ||
3187 | 27 | # caller of the object can simply ask, "What time is it?". | ||
3188 | 28 | package Runtime; | 21 | package Runtime; |
3189 | 29 | 22 | ||
3190 | 30 | use strict; | 23 | use strict; |
3191 | @@ -32,30 +25,24 @@ | |||
3192 | 32 | use English qw(-no_match_vars); | 25 | use English qw(-no_match_vars); |
3193 | 33 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; | 26 | use constant PTDEBUG => $ENV{PTDEBUG} || 0; |
3194 | 34 | 27 | ||
3195 | 35 | # Sub: new | ||
3196 | 36 | # | ||
3197 | 37 | # Parameters: | ||
3198 | 38 | # %args - Arguments | ||
3199 | 39 | # | ||
3200 | 40 | # Required Arguments: | ||
3201 | 41 | # now - Callback that sets current time. | ||
3202 | 42 | # runtime - Amount of time to run in seconds, or undef for forever. | ||
3203 | 43 | # | ||
3204 | 44 | # Returns: | ||
3205 | 45 | # Runtime object | ||
3206 | 46 | sub new { | 28 | sub new { |
3207 | 47 | my ( $class, %args ) = @_; | 29 | my ( $class, %args ) = @_; |
3209 | 48 | my @required_args = qw(now); | 30 | my @required_args = qw(run_time now); |
3210 | 49 | foreach my $arg ( @required_args ) { | 31 | foreach my $arg ( @required_args ) { |
3217 | 50 | die "I need a $arg argument" unless $args{$arg}; | 32 | die "I need a $arg argument" unless exists $args{$arg}; |
3218 | 51 | } | 33 | } |
3219 | 52 | 34 | ||
3220 | 53 | if ( ($args{runtime} || 0) < 0 ) { | 35 | my $run_time = $args{run_time}; |
3221 | 54 | die "runtime argument must be greater than zero" | 36 | if ( defined $run_time ) { |
3222 | 55 | } | 37 | die "run_time must be > 0" if $run_time <= 0; |
3223 | 38 | } | ||
3224 | 39 | |||
3225 | 40 | my $now = $args{now}; | ||
3226 | 41 | die "now must be a callback" unless ref $now eq 'CODE'; | ||
3227 | 56 | 42 | ||
3228 | 57 | my $self = { | 43 | my $self = { |
3230 | 58 | %args, | 44 | run_time => $run_time, |
3231 | 45 | now => $now, | ||
3232 | 59 | start_time => undef, | 46 | start_time => undef, |
3233 | 60 | end_time => undef, | 47 | end_time => undef, |
3234 | 61 | time_left => undef, | 48 | time_left => undef, |
3235 | @@ -66,8 +53,8 @@ | |||
3236 | 66 | } | 53 | } |
3237 | 67 | 54 | ||
3238 | 68 | # Sub: time_left | 55 | # Sub: time_left |
3241 | 69 | # Return the number of runtime seconds left or undef for forever. | 56 | # Return the number of run time seconds left or undef for forever. |
3242 | 70 | # The return may be less than zero if the runtime has been exceeded. | 57 | # The return may be less than zero if the run time has been exceeded. |
3243 | 71 | # The first call to this subroutine "starts the clock", so to speak, | 58 | # The first call to this subroutine "starts the clock", so to speak, |
3244 | 72 | # if the now callbackup returns a defined value. | 59 | # if the now callbackup returns a defined value. |
3245 | 73 | # | 60 | # |
3246 | @@ -75,7 +62,7 @@ | |||
3247 | 75 | # %args - Arguments passed to now callback. | 62 | # %args - Arguments passed to now callback. |
3248 | 76 | # | 63 | # |
3249 | 77 | # Returns: | 64 | # Returns: |
3251 | 78 | # Number of runtime seconds left, possibly less than zero, or undef | 65 | # Number of run time seconds left, possibly less than zero, or undef |
3252 | 79 | # if running forever. | 66 | # if running forever. |
3253 | 80 | sub time_left { | 67 | sub time_left { |
3254 | 81 | my ( $self, %args ) = @_; | 68 | my ( $self, %args ) = @_; |
3255 | @@ -99,14 +86,14 @@ | |||
3256 | 99 | # we know the current time. | 86 | # we know the current time. |
3257 | 100 | return unless defined $now; | 87 | return unless defined $now; |
3258 | 101 | 88 | ||
3260 | 102 | # If runtime is also defined, then we can determine time left. | 89 | # If run_time is also defined, then we can determine time left. |
3261 | 103 | # If it's not defined, then we're running forever. | 90 | # If it's not defined, then we're running forever. |
3264 | 104 | my $runtime = $self->{runtime}; | 91 | my $run_time = $self->{run_time}; |
3265 | 105 | return unless defined $runtime; | 92 | return unless defined $run_time; |
3266 | 106 | 93 | ||
3267 | 107 | # Set the end time once. | 94 | # Set the end time once. |
3268 | 108 | if ( !$self->{end_time} ) { | 95 | if ( !$self->{end_time} ) { |
3270 | 109 | $self->{end_time} = $now + $runtime; | 96 | $self->{end_time} = $now + $run_time; |
3271 | 110 | PTDEBUG && _d("End time:", $self->{end_time}); | 97 | PTDEBUG && _d("End time:", $self->{end_time}); |
3272 | 111 | } | 98 | } |
3273 | 112 | 99 | ||
3274 | @@ -118,7 +105,7 @@ | |||
3275 | 118 | } | 105 | } |
3276 | 119 | 106 | ||
3277 | 120 | # Sub: have_time | 107 | # Sub: have_time |
3279 | 121 | # Return true or false if there's runtime left. This sub is a simpler | 108 | # Return true or false if there's run time left. This sub is a simpler |
3280 | 122 | # wrapper around <time_left()> which returns true (1) if time left is | 109 | # wrapper around <time_left()> which returns true (1) if time left is |
3281 | 123 | # defined and greater than zero or undef, else returns false. | 110 | # defined and greater than zero or undef, else returns false. |
3282 | 124 | # | 111 | # |
3283 | @@ -131,7 +118,7 @@ | |||
3284 | 131 | my ( $self, %args ) = @_; | 118 | my ( $self, %args ) = @_; |
3285 | 132 | my $time_left = $self->time_left(%args); | 119 | my $time_left = $self->time_left(%args); |
3286 | 133 | return 1 if !defined $time_left; # run forever | 120 | return 1 if !defined $time_left; # run forever |
3288 | 134 | return $time_left <= 0 ? 0 : 1; # <=0s means runtime has elapsed | 121 | return $time_left <= 0 ? 0 : 1; # <=0s means run time has elapsed |
3289 | 135 | } | 122 | } |
3290 | 136 | 123 | ||
3291 | 137 | # Sub: time_elapsed | 124 | # Sub: time_elapsed |
3292 | @@ -173,7 +160,7 @@ | |||
3293 | 173 | $self->{end_time} = undef; | 160 | $self->{end_time} = undef; |
3294 | 174 | $self->{time_left} = undef; | 161 | $self->{time_left} = undef; |
3295 | 175 | $self->{stop} = 0; | 162 | $self->{stop} = 0; |
3297 | 176 | PTDEBUG && _d("Reset runtime"); | 163 | PTDEBUG && _d("Reset run time"); |
3298 | 177 | return; | 164 | return; |
3299 | 178 | } | 165 | } |
3300 | 179 | 166 | ||
3301 | 180 | 167 | ||
3302 | === modified file 't/lib/Cxn.t' | |||
3303 | --- t/lib/Cxn.t 2012-11-08 20:47:00 +0000 | |||
3304 | +++ t/lib/Cxn.t 2013-02-27 23:41:26 +0000 | |||
3305 | @@ -9,7 +9,7 @@ | |||
3306 | 9 | use strict; | 9 | use strict; |
3307 | 10 | use warnings FATAL => 'all'; | 10 | use warnings FATAL => 'all'; |
3308 | 11 | use English qw(-no_match_vars); | 11 | use English qw(-no_match_vars); |
3310 | 12 | use Test::More tests => 19; | 12 | use Test::More; |
3311 | 13 | 13 | ||
3312 | 14 | use Sandbox; | 14 | use Sandbox; |
3313 | 15 | use OptionParser; | 15 | use OptionParser; |
3314 | @@ -252,8 +252,64 @@ | |||
3315 | 252 | $o->get_opts(); | 252 | $o->get_opts(); |
3316 | 253 | 253 | ||
3317 | 254 | # ############################################################################# | 254 | # ############################################################################# |
3318 | 255 | # The parent of a forked Cxn should not disconnect the dbh in DESTORY | ||
3319 | 256 | # because the child still has access to it. | ||
3320 | 257 | # ############################################################################# | ||
3321 | 258 | |||
3322 | 259 | my $sync_file = "/tmp/pt-cxn-sync.$PID"; | ||
3323 | 260 | my $outfile = "/tmp/pt-cxn-outfile.$PID"; | ||
3324 | 261 | |||
3325 | 262 | my $pid; | ||
3326 | 263 | { | ||
3327 | 264 | my $parent_cxn = make_cxn( | ||
3328 | 265 | dsn_string => 'h=127.1,P=12345,u=msandbox,p=msandbox', | ||
3329 | 266 | parent => 1, | ||
3330 | 267 | ); | ||
3331 | 268 | $parent_cxn->connect(); | ||
3332 | 269 | |||
3333 | 270 | $pid = fork(); | ||
3334 | 271 | if ( defined($pid) && $pid == 0 ) { | ||
3335 | 272 | # I am the child. | ||
3336 | 273 | # Wait for the parent to leave this code block which will cause | ||
3337 | 274 | # the $parent_cxn to be destroyed. | ||
3338 | 275 | PerconaTest::wait_for_files($sync_file); | ||
3339 | 276 | $parent_cxn->{parent} = 0; | ||
3340 | 277 | eval { | ||
3341 | 278 | $parent_cxn->dbh->do("SELECT 123 INTO OUTFILE '$outfile'"); | ||
3342 | 279 | $parent_cxn->dbh->disconnect(); | ||
3343 | 280 | }; | ||
3344 | 281 | warn $EVAL_ERROR if $EVAL_ERROR; | ||
3345 | 282 | exit; | ||
3346 | 283 | } | ||
3347 | 284 | } | ||
3348 | 285 | |||
3349 | 286 | # Let the child know that we (the parent) have left that ^ code block, | ||
3350 | 287 | # so our copy of $parent_cxn has been destroyed, but hopefully the child's | ||
3351 | 288 | # copy is still alive, i.e. has an active/not-disconnected dbh. | ||
3352 | 289 | diag(`touch $sync_file`); | ||
3353 | 290 | |||
3354 | 291 | # Wait for the child. | ||
3355 | 292 | waitpid($pid, 0); | ||
3356 | 293 | |||
3357 | 294 | ok( | ||
3358 | 295 | -f $outfile, | ||
3359 | 296 | "Child created outfile" | ||
3360 | 297 | ); | ||
3361 | 298 | |||
3362 | 299 | my $output = `cat $outfile 2>/dev/null`; | ||
3363 | 300 | |||
3364 | 301 | is( | ||
3365 | 302 | $output, | ||
3366 | 303 | "123\n", | ||
3367 | 304 | "Child executed query" | ||
3368 | 305 | ); | ||
3369 | 306 | |||
3370 | 307 | unlink $sync_file if -f $sync_file; | ||
3371 | 308 | unlink $outfile if -f $outfile; | ||
3372 | 309 | |||
3373 | 310 | # ############################################################################# | ||
3374 | 255 | # Done. | 311 | # Done. |
3375 | 256 | # ############################################################################# | 312 | # ############################################################################# |
3376 | 257 | $master_dbh->disconnect() if $master_dbh; | 313 | $master_dbh->disconnect() if $master_dbh; |
3377 | 258 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); | 314 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); |
3379 | 259 | exit; | 315 | done_testing; |
3380 | 260 | 316 | ||
3381 | === modified file 't/pt-deadlock-logger/basics.t' | |||
3382 | --- t/pt-deadlock-logger/basics.t 2012-10-22 21:30:29 +0000 | |||
3383 | +++ t/pt-deadlock-logger/basics.t 2013-02-27 23:41:26 +0000 | |||
3384 | @@ -11,6 +11,8 @@ | |||
3385 | 11 | use English qw(-no_match_vars); | 11 | use English qw(-no_match_vars); |
3386 | 12 | use Test::More; | 12 | use Test::More; |
3387 | 13 | 13 | ||
3388 | 14 | $ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1; | ||
3389 | 15 | |||
3390 | 14 | use PerconaTest; | 16 | use PerconaTest; |
3391 | 15 | use Sandbox; | 17 | use Sandbox; |
3392 | 16 | require "$trunk/bin/pt-deadlock-logger"; | 18 | require "$trunk/bin/pt-deadlock-logger"; |
3393 | @@ -25,8 +27,8 @@ | |||
3394 | 25 | } | 27 | } |
3395 | 26 | 28 | ||
3396 | 27 | my $output; | 29 | my $output; |
3399 | 28 | my $cnf = "/tmp/12345/my.sandbox.cnf"; | 30 | my $dsn = $sb->dsn_for('master'); |
3400 | 29 | my $cmd = "$trunk/bin/pt-deadlock-logger -F $cnf h=127.1"; | 31 | my @args = ($dsn, qw(--iterations 1)); |
3401 | 30 | 32 | ||
3402 | 31 | $dbh1->commit; | 33 | $dbh1->commit; |
3403 | 32 | $dbh2->commit; | 34 | $dbh2->commit; |
3404 | @@ -90,21 +92,30 @@ | |||
3405 | 90 | $output = $dbh1->selectrow_hashref('show /*!40101 engine*/ innodb status')->{status}; | 92 | $output = $dbh1->selectrow_hashref('show /*!40101 engine*/ innodb status')->{status}; |
3406 | 91 | like($output, qr/WE ROLL BACK/, 'There was a deadlock'); | 93 | like($output, qr/WE ROLL BACK/, 'There was a deadlock'); |
3407 | 92 | 94 | ||
3409 | 93 | $output = `$cmd --print`; | 95 | $output = output( |
3410 | 96 | sub { | ||
3411 | 97 | pt_deadlock_logger::main(@args); | ||
3412 | 98 | } | ||
3413 | 99 | ); | ||
3414 | 100 | |||
3415 | 94 | like( | 101 | like( |
3416 | 95 | $output, | 102 | $output, |
3417 | 96 | qr/127\.1.+msandbox.+GEN_CLUST_INDEX/, | 103 | qr/127\.1.+msandbox.+GEN_CLUST_INDEX/, |
3418 | 97 | 'Deadlock logger prints the output' | 104 | 'Deadlock logger prints the output' |
3419 | 98 | ); | 105 | ); |
3420 | 99 | 106 | ||
3423 | 100 | $output = `$cmd`; | 107 | $output = output( |
3424 | 101 | like( | 108 | sub { |
3425 | 109 | pt_deadlock_logger::main(@args, qw(--quiet)); | ||
3426 | 110 | } | ||
3427 | 111 | ); | ||
3428 | 112 | |||
3429 | 113 | is( | ||
3430 | 102 | $output, | 114 | $output, |
3433 | 103 | qr/127\.1.+msandbox.+GEN_CLUST_INDEX/, | 115 | "", |
3434 | 104 | '--print is implicit' | 116 | "No output with --quiet" |
3435 | 105 | ); | 117 | ); |
3436 | 106 | 118 | ||
3437 | 107 | |||
3438 | 108 | # ############################################################################# | 119 | # ############################################################################# |
3439 | 109 | # Issue 943: mk-deadlock-logger reports the same deadlock with --interval | 120 | # Issue 943: mk-deadlock-logger reports the same deadlock with --interval |
3440 | 110 | # ############################################################################# | 121 | # ############################################################################# |
3441 | @@ -112,55 +123,59 @@ | |||
3442 | 112 | # The deadlock from above won't be re-printed so even after running for | 123 | # The deadlock from above won't be re-printed so even after running for |
3443 | 113 | # 3 seconds and checking multiple times only the single, 3 line deadlock | 124 | # 3 seconds and checking multiple times only the single, 3 line deadlock |
3444 | 114 | # should be reported. | 125 | # should be reported. |
3446 | 115 | chomp($output = `$cmd --run-time 3 | wc -l`); | 126 | |
3447 | 127 | $output = output( | ||
3448 | 128 | sub { | ||
3449 | 129 | pt_deadlock_logger::main(@args, qw(--run-time 3)); | ||
3450 | 130 | } | ||
3451 | 131 | ); | ||
3452 | 116 | $output =~ s/^\s+//; | 132 | $output =~ s/^\s+//; |
3453 | 133 | my @lines = split("\n", $output); | ||
3454 | 117 | is( | 134 | is( |
3456 | 118 | $output, | 135 | scalar @lines, |
3457 | 119 | 3, | 136 | 3, |
3458 | 120 | "Doesn't re-print same deadlock (issue 943)" | 137 | "Doesn't re-print same deadlock (issue 943)" |
3460 | 121 | ); | 138 | ) or diag($output); |
3461 | 122 | 139 | ||
3462 | 123 | # ############################################################################# | 140 | # ############################################################################# |
3463 | 124 | # Check that deadlocks from previous test were stored in table. | 141 | # Check that deadlocks from previous test were stored in table. |
3464 | 125 | # ############################################################################# | 142 | # ############################################################################# |
3466 | 126 | `$cmd --dest D=test,t=deadlocks --create-dest-table`; | 143 | $output = output( |
3467 | 144 | sub { | ||
3468 | 145 | pt_deadlock_logger::main(@args, '--dest', 'D=test,t=deadlocks', | ||
3469 | 146 | qw(--create-dest-table)) | ||
3470 | 147 | } | ||
3471 | 148 | ); | ||
3472 | 149 | |||
3473 | 127 | my $res = $dbh1->selectall_arrayref('SELECT * FROM test.deadlocks'); | 150 | my $res = $dbh1->selectall_arrayref('SELECT * FROM test.deadlocks'); |
3474 | 128 | ok( | 151 | ok( |
3475 | 129 | scalar @$res, | 152 | scalar @$res, |
3497 | 130 | 'Deadlocks recorded in --dest table' | 153 | 'Deadlock saved in --dest table' |
3498 | 131 | ); | 154 | ) or diag($output); |
3499 | 132 | 155 | ||
3500 | 133 | # ############################################################################# | 156 | # ############################################################################# |
3501 | 134 | # Check that --dest suppress --print output unless --print is explicit. | 157 | # In 2.1, --dest suppressed output (--print). In 2.2, output is only |
3502 | 135 | # ############################################################################# | 158 | # suppressed by --quiet. |
3503 | 136 | $output = 'foo'; | 159 | # ############################################################################# |
3483 | 137 | $dbh1->do('TRUNCATE TABLE test.deadlocks'); | ||
3484 | 138 | $output = `$cmd --dest D=test,t=deadlocks`; | ||
3485 | 139 | is( | ||
3486 | 140 | $output, | ||
3487 | 141 | '', | ||
3488 | 142 | 'No output with --dest' | ||
3489 | 143 | ); | ||
3490 | 144 | |||
3491 | 145 | $res = $dbh1->selectall_arrayref('SELECT * FROM test.deadlocks'); | ||
3492 | 146 | ok( | ||
3493 | 147 | scalar @$res, | ||
3494 | 148 | 'Deadlocks still recorded in table' | ||
3495 | 149 | ); | ||
3496 | 150 | |||
3504 | 151 | $output = ''; | 160 | $output = ''; |
3505 | 152 | $dbh1->do('TRUNCATE TABLE test.deadlocks'); | 161 | $dbh1->do('TRUNCATE TABLE test.deadlocks'); |
3508 | 153 | $output = `$trunk/bin/pt-deadlock-logger --print --dest D=test,t=deadlocks --host 127.1 --port 12345 --user msandbox --password msandbox`; | 162 | $output = output( |
3509 | 154 | like( | 163 | sub { |
3510 | 164 | pt_deadlock_logger::main(@args, '--dest', 'D=test,t=deadlocks', | ||
3511 | 165 | qw(--quiet)) | ||
3512 | 166 | } | ||
3513 | 167 | ); | ||
3514 | 168 | |||
3515 | 169 | is( | ||
3516 | 155 | $output, | 170 | $output, |
3519 | 156 | qr/127\.1.+msandbox.+GEN_CLUST_INDEX/, | 171 | "", |
3520 | 157 | 'Prints output with --dest and explicit --print' | 172 | "No output with --dest and --quiet" |
3521 | 158 | ); | 173 | ); |
3522 | 159 | 174 | ||
3523 | 160 | $res = $dbh1->selectall_arrayref('SELECT * FROM test.deadlocks'); | 175 | $res = $dbh1->selectall_arrayref('SELECT * FROM test.deadlocks'); |
3524 | 161 | ok( | 176 | ok( |
3525 | 162 | scalar @$res, | 177 | scalar @$res, |
3527 | 163 | 'Deadlocks recorded in table again' | 178 | "... deadlock still saved in the table" |
3528 | 164 | ); | 179 | ); |
3529 | 165 | 180 | ||
3530 | 166 | # ############################################################################# | 181 | # ############################################################################# |
3531 | @@ -180,9 +195,7 @@ | |||
3532 | 180 | make_deadlock(); | 195 | make_deadlock(); |
3533 | 181 | 196 | ||
3534 | 182 | $output = output( | 197 | $output = output( |
3538 | 183 | sub { pt_deadlock_logger::main("F=/tmp/12345/my.sandbox.cnf", | 198 | sub { pt_deadlock_logger::main(@args) } |
3536 | 184 | qw(--print) ); | ||
3537 | 185 | } | ||
3539 | 186 | ); | 199 | ); |
3540 | 187 | 200 | ||
3541 | 188 | like( | 201 | like( |
3542 | @@ -200,4 +213,3 @@ | |||
3543 | 200 | $sb->wipe_clean($dbh1); | 213 | $sb->wipe_clean($dbh1); |
3544 | 201 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); | 214 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); |
3545 | 202 | done_testing; | 215 | done_testing; |
3546 | 203 | exit; | ||
3547 | 204 | 216 | ||
3548 | === modified file 't/pt-deadlock-logger/clear_deadlocks.t' | |||
3549 | --- t/pt-deadlock-logger/clear_deadlocks.t 2012-06-03 19:14:30 +0000 | |||
3550 | +++ t/pt-deadlock-logger/clear_deadlocks.t 2013-02-27 23:41:26 +0000 | |||
3551 | @@ -22,9 +22,6 @@ | |||
3552 | 22 | if ( !$dbh1 ) { | 22 | if ( !$dbh1 ) { |
3553 | 23 | plan skip_all => 'Cannot connect to sandbox master'; | 23 | plan skip_all => 'Cannot connect to sandbox master'; |
3554 | 24 | } | 24 | } |
3555 | 25 | else { | ||
3556 | 26 | plan tests => 4; | ||
3557 | 27 | } | ||
3558 | 28 | 25 | ||
3559 | 29 | my $output; | 26 | my $output; |
3560 | 30 | my $cnf = "/tmp/12345/my.sandbox.cnf"; | 27 | my $cnf = "/tmp/12345/my.sandbox.cnf"; |
3561 | @@ -39,7 +36,7 @@ | |||
3562 | 39 | 36 | ||
3563 | 40 | # The clear-deadlocks table comes and goes quickly so we can really | 37 | # The clear-deadlocks table comes and goes quickly so we can really |
3564 | 41 | # only search the debug output for evidence that it was created. | 38 | # only search the debug output for evidence that it was created. |
3566 | 42 | $output = `PTDEBUG=1 $trunk/bin/pt-deadlock-logger F=$cnf,D=test --clear-deadlocks test.make_deadlock 2>&1`; | 39 | $output = `PTDEBUG=1 $trunk/bin/pt-deadlock-logger F=$cnf,D=test --clear-deadlocks test.make_deadlock --iterations 1 2>&1`; |
3567 | 43 | like( | 40 | like( |
3568 | 44 | $output, | 41 | $output, |
3569 | 45 | qr/INSERT INTO test.make_deadlock/, | 42 | qr/INSERT INTO test.make_deadlock/, |
3570 | @@ -67,4 +64,4 @@ | |||
3571 | 67 | # ############################################################################# | 64 | # ############################################################################# |
3572 | 68 | $sb->wipe_clean($dbh1); | 65 | $sb->wipe_clean($dbh1); |
3573 | 69 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); | 66 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); |
3575 | 70 | exit; | 67 | done_testing; |
3576 | 71 | 68 | ||
3577 | === modified file 't/pt-deadlock-logger/create_dest_table.t' | |||
3578 | --- t/pt-deadlock-logger/create_dest_table.t 2012-06-09 18:43:33 +0000 | |||
3579 | +++ t/pt-deadlock-logger/create_dest_table.t 2013-02-27 23:41:26 +0000 | |||
3580 | @@ -22,15 +22,10 @@ | |||
3581 | 22 | if ( !$dbh1 ) { | 22 | if ( !$dbh1 ) { |
3582 | 23 | plan skip_all => 'Cannot connect to sandbox master'; | 23 | plan skip_all => 'Cannot connect to sandbox master'; |
3583 | 24 | } | 24 | } |
3584 | 25 | else { | ||
3585 | 26 | plan tests => 3; | ||
3586 | 27 | } | ||
3587 | 28 | 25 | ||
3588 | 29 | my $output; | 26 | my $output; |
3591 | 30 | my $cnf = "/tmp/12345/my.sandbox.cnf"; | 27 | my $dsn = $sb->dsn_for('master'); |
3590 | 31 | my $cmd = "$trunk/bin/pt-deadlock-logger -F $cnf h=127.1"; | ||
3592 | 32 | 28 | ||
3593 | 33 | $sb->wipe_clean($dbh1); | ||
3594 | 34 | $sb->create_dbs($dbh1, ['test']); | 29 | $sb->create_dbs($dbh1, ['test']); |
3595 | 35 | 30 | ||
3596 | 36 | # ############################################################################# | 31 | # ############################################################################# |
3597 | @@ -42,17 +37,25 @@ | |||
3598 | 42 | 'Deadlocks table does not exit (issue 386)' | 37 | 'Deadlocks table does not exit (issue 386)' |
3599 | 43 | ); | 38 | ); |
3600 | 44 | 39 | ||
3602 | 45 | `$cmd --dest D=test,t=issue_386 --run-time 1s --interval 1s --create-dest-table`; | 40 | $output = output( |
3603 | 41 | sub { | ||
3604 | 42 | pt_deadlock_logger::main($dsn, | ||
3605 | 43 | '--dest', 'D=test,t=issue_386', | ||
3606 | 44 | qw(--iterations 1 --create-dest-table) | ||
3607 | 45 | ) | ||
3608 | 46 | }, | ||
3609 | 47 | stderr => 1, | ||
3610 | 48 | ); | ||
3611 | 46 | 49 | ||
3612 | 47 | is_deeply( | 50 | is_deeply( |
3613 | 48 | $dbh1->selectall_arrayref(q{show tables from `test` like 'issue_386'}), | 51 | $dbh1->selectall_arrayref(q{show tables from `test` like 'issue_386'}), |
3614 | 49 | [['issue_386']], | 52 | [['issue_386']], |
3615 | 50 | 'Deadlocks table created with --create-dest-table (issue 386)' | 53 | 'Deadlocks table created with --create-dest-table (issue 386)' |
3617 | 51 | ); | 54 | ) or diag($output); |
3618 | 52 | 55 | ||
3619 | 53 | # ############################################################################# | 56 | # ############################################################################# |
3620 | 54 | # Done. | 57 | # Done. |
3621 | 55 | # ############################################################################# | 58 | # ############################################################################# |
3622 | 56 | $sb->wipe_clean($dbh1); | 59 | $sb->wipe_clean($dbh1); |
3623 | 57 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); | 60 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); |
3625 | 58 | exit; | 61 | done_testing; |
3626 | 59 | 62 | ||
3627 | === modified file 't/pt-deadlock-logger/option_sanity.t' | |||
3628 | --- t/pt-deadlock-logger/option_sanity.t 2012-10-22 18:16:42 +0000 | |||
3629 | +++ t/pt-deadlock-logger/option_sanity.t 2013-02-27 23:41:26 +0000 | |||
3630 | @@ -21,7 +21,7 @@ | |||
3631 | 21 | $output = `$trunk/bin/pt-deadlock-logger --dest D=test,t=deadlocks 2>&1`; | 21 | $output = `$trunk/bin/pt-deadlock-logger --dest D=test,t=deadlocks 2>&1`; |
3632 | 22 | like( | 22 | like( |
3633 | 23 | $output, | 23 | $output, |
3635 | 24 | qr/Missing or invalid source host/, | 24 | qr/No DSN was specified/, |
3636 | 25 | 'Requires source host' | 25 | 'Requires source host' |
3637 | 26 | ); | 26 | ); |
3638 | 27 | 27 | ||
3639 | 28 | 28 | ||
3640 | === renamed file 't/pt-deadlock-logger/deadlocks_tbl.sql' => 't/pt-deadlock-logger/samples/deadlocks_tbl.sql' | |||
3641 | === modified file 't/pt-deadlock-logger/standard_options.t' | |||
3642 | --- t/pt-deadlock-logger/standard_options.t 2012-07-23 04:52:41 +0000 | |||
3643 | +++ t/pt-deadlock-logger/standard_options.t 2013-02-27 23:41:26 +0000 | |||
3644 | @@ -17,69 +17,96 @@ | |||
3645 | 17 | 17 | ||
3646 | 18 | my $dp = new DSNParser(opts=>$dsn_opts); | 18 | my $dp = new DSNParser(opts=>$dsn_opts); |
3647 | 19 | my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); | 19 | my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp); |
3649 | 20 | my $dbh1 = $sb->get_dbh_for('master'); | 20 | my $dbh = $sb->get_dbh_for('master'); |
3650 | 21 | 21 | ||
3652 | 22 | if ( !$dbh1 ) { | 22 | if ( !$dbh ) { |
3653 | 23 | plan skip_all => 'Cannot connect to sandbox master'; | 23 | plan skip_all => 'Cannot connect to sandbox master'; |
3654 | 24 | } | 24 | } |
3655 | 25 | else { | ||
3656 | 26 | plan tests => 10; | ||
3657 | 27 | } | ||
3658 | 28 | 25 | ||
3659 | 29 | my $output; | 26 | my $output; |
3662 | 30 | my $cnf = "/tmp/12345/my.sandbox.cnf"; | 27 | my $dsn = $sb->dsn_for('master'); |
3663 | 31 | my $cmd = "$trunk/bin/pt-deadlock-logger -F $cnf h=127.1"; | 28 | my @args = ($dsn, qw(--iterations 1)); |
3664 | 32 | 29 | ||
3667 | 33 | $sb->wipe_clean($dbh1); | 30 | $sb->wipe_clean($dbh); |
3668 | 34 | $sb->create_dbs($dbh1, ['test']); | 31 | $sb->create_dbs($dbh, ['test']); |
3669 | 35 | 32 | ||
3670 | 36 | # ############################################################################# | 33 | # ############################################################################# |
3671 | 37 | # Issue 248: Add --user, --pass, --host, etc to all tools | 34 | # Issue 248: Add --user, --pass, --host, etc to all tools |
3672 | 38 | # ############################################################################# | 35 | # ############################################################################# |
3673 | 39 | 36 | ||
3674 | 40 | # Test that source DSN inherits from --user, etc. | 37 | # Test that source DSN inherits from --user, etc. |
3676 | 41 | $output = `$trunk/bin/pt-deadlock-logger h=127.1,D=test,u=msandbox,p=msandbox --clear-deadlocks test.make_deadlock --port 12345 2>&1`; | 38 | $output = output( |
3677 | 39 | sub { | ||
3678 | 40 | pt_deadlock_logger::main( | ||
3679 | 41 | "h=127.1,D=test,u=msandbox,p=msandbox", | ||
3680 | 42 | qw(--clear-deadlocks test.make_deadlock --port 12345), | ||
3681 | 43 | qw(--iterations 1) | ||
3682 | 44 | ) | ||
3683 | 45 | } | ||
3684 | 46 | ); | ||
3685 | 47 | |||
3686 | 42 | unlike( | 48 | unlike( |
3687 | 43 | $output, | 49 | $output, |
3688 | 44 | qr/failed/, | 50 | qr/failed/, |
3689 | 45 | 'Source DSN inherits from standard connection options (issue 248)' | 51 | 'Source DSN inherits from standard connection options (issue 248)' |
3690 | 46 | ); | 52 | ); |
3691 | 47 | 53 | ||
3693 | 48 | # ######################################################################### | 54 | # ############################################################################# |
3694 | 49 | # Issue 391: Add --pid option to all scripts | 55 | # Issue 391: Add --pid option to all scripts |
3698 | 50 | # ######################################################################### | 56 | # ############################################################################# |
3699 | 51 | `touch /tmp/mk-script.pid`; | 57 | |
3700 | 52 | $output = `$cmd --clear-deadlocks test.make_deadlock --port 12345 --pid /tmp/mk-script.pid 2>&1`; | 58 | my $pid_file = "/tmp/pt-deadlock-logger-test.pid.$PID"; |
3701 | 59 | diag(`touch $pid_file`); | ||
3702 | 60 | |||
3703 | 61 | $output = output( | ||
3704 | 62 | sub { | ||
3705 | 63 | pt_deadlock_logger::main(@args, '--pid', $pid_file) | ||
3706 | 64 | }, | ||
3707 | 65 | stderr => 1, | ||
3708 | 66 | ); | ||
3709 | 67 | |||
3710 | 53 | like( | 68 | like( |
3711 | 54 | $output, | 69 | $output, |
3713 | 55 | qr{PID file /tmp/mk-script.pid already exists}, | 70 | qr{PID file $pid_file already exists}, |
3714 | 56 | 'Dies if PID file already exists (--pid without --daemonize) (issue 391)' | 71 | 'Dies if PID file already exists (--pid without --daemonize) (issue 391)' |
3715 | 57 | ); | 72 | ); |
3717 | 58 | `rm -rf /tmp/mk-script.pid`; | 73 | |
3718 | 74 | unlink $pid_file if -f $pid_file; | ||
3719 | 59 | 75 | ||
3720 | 60 | # ############################################################################# | 76 | # ############################################################################# |
3721 | 61 | # Check daemonization | 77 | # Check daemonization |
3722 | 62 | # ############################################################################# | 78 | # ############################################################################# |
3735 | 63 | my $deadlocks_tbl = load_file('t/pt-deadlock-logger/deadlocks_tbl.sql'); | 79 | $dbh->do('USE test'); |
3736 | 64 | $dbh1->do('USE test'); | 80 | $dbh->do('DROP TABLE IF EXISTS deadlocks'); |
3737 | 65 | $dbh1->do('DROP TABLE IF EXISTS deadlocks'); | 81 | $sb->load_file('master', 't/pt-deadlock-logger/samples/deadlocks_tbl.sql', 'test'); |
3738 | 66 | $dbh1->do("$deadlocks_tbl"); | 82 | |
3739 | 67 | 83 | $output = `$trunk/bin/pt-deadlock-logger $dsn --dest D=test,t=deadlocks --daemonize --run-time 10 --interval 1 --pid $pid_file 1>/dev/null 2>/dev/null`; | |
3728 | 68 | my $pid_file = '/tmp/mk-deadlock-logger.pid'; | ||
3729 | 69 | unlink $pid_file | ||
3730 | 70 | and diag("Unlinked existing $pid_file"); | ||
3731 | 71 | |||
3732 | 72 | `$cmd --dest D=test,t=deadlocks --daemonize --run-time 6s --interval 1s --pid $pid_file 1>/dev/null 2>/dev/null`; | ||
3733 | 73 | $output = `ps -eaf | grep '$cmd \-\-dest '`; | ||
3734 | 74 | like($output, qr/\Q$cmd/, 'It lives daemonized'); | ||
3740 | 75 | 84 | ||
3741 | 76 | PerconaTest::wait_for_files($pid_file); | 85 | PerconaTest::wait_for_files($pid_file); |
3744 | 77 | ok(-f $pid_file, 'PID file created'); | 86 | |
3745 | 78 | my ($pid) = $output =~ /\s+(\d+)\s+/; | 87 | $output = `ps x | grep 'pt-deadlock-logger $dsn' | grep -v grep`; |
3746 | 88 | like( | ||
3747 | 89 | $output, | ||
3748 | 90 | qr/\Qpt-deadlock-logger $dsn/, | ||
3749 | 91 | 'It lives daemonized' | ||
3750 | 92 | ) or diag($output); | ||
3751 | 93 | |||
3752 | 94 | my ($pid) = $output =~ /(\d+)/; | ||
3753 | 95 | |||
3754 | 96 | ok( | ||
3755 | 97 | -f $pid_file, | ||
3756 | 98 | 'PID file created' | ||
3757 | 99 | ) or diag($output); | ||
3758 | 100 | |||
3759 | 79 | chomp($output = slurp_file($pid_file)); | 101 | chomp($output = slurp_file($pid_file)); |
3761 | 80 | is($output, $pid, 'PID file has correct PID'); | 102 | is( |
3762 | 103 | $output, | ||
3763 | 104 | $pid, | ||
3764 | 105 | 'PID file has correct PID' | ||
3765 | 106 | ); | ||
3766 | 81 | 107 | ||
3767 | 82 | # Kill it | 108 | # Kill it |
3768 | 109 | kill 2, $pid; | ||
3769 | 83 | PerconaTest::wait_until(sub { !kill 0, $pid }); | 110 | PerconaTest::wait_until(sub { !kill 0, $pid }); |
3770 | 84 | ok(! -f $pid_file, 'PID file removed'); | 111 | ok(! -f $pid_file, 'PID file removed'); |
3771 | 85 | 112 | ||
3772 | @@ -90,17 +117,25 @@ | |||
3773 | 90 | 'PID file already exists' | 117 | 'PID file already exists' |
3774 | 91 | ); | 118 | ); |
3775 | 92 | 119 | ||
3777 | 93 | $output = `$cmd --dest D=test,t=deadlocks --daemonize --run-time 1s --interval 1s --pid $pid_file 2>&1`; | 120 | $output = output( |
3778 | 121 | sub { | ||
3779 | 122 | pt_deadlock_logger::main(@args, '--pid', $pid_file, | ||
3780 | 123 | qw(--daemonize)) | ||
3781 | 124 | }, | ||
3782 | 125 | stderr => 1, | ||
3783 | 126 | ); | ||
3784 | 127 | |||
3785 | 94 | like( | 128 | like( |
3786 | 95 | $output, | 129 | $output, |
3788 | 96 | qr/PID file .+ already exists/, | 130 | qr/PID file $pid_file already exists/, |
3789 | 97 | 'Does not run if PID file already exists' | 131 | 'Does not run if PID file already exists' |
3790 | 98 | ); | 132 | ); |
3791 | 99 | 133 | ||
3794 | 100 | $output = `ps -eaf | grep 'pt-deadlock-logger \-\-dest '`; | 134 | $output = `ps x | grep 'pt-deadlock-logger $dsn' | grep -v grep`; |
3795 | 101 | unlike( | 135 | |
3796 | 136 | is( | ||
3797 | 102 | $output, | 137 | $output, |
3799 | 103 | qr/$cmd/, | 138 | "", |
3800 | 104 | 'It does not lived daemonized' | 139 | 'It does not lived daemonized' |
3801 | 105 | ); | 140 | ); |
3802 | 106 | 141 | ||
3803 | @@ -109,6 +144,6 @@ | |||
3804 | 109 | # ############################################################################# | 144 | # ############################################################################# |
3805 | 110 | # Done. | 145 | # Done. |
3806 | 111 | # ############################################################################# | 146 | # ############################################################################# |
3808 | 112 | $sb->wipe_clean($dbh1); | 147 | $sb->wipe_clean($dbh); |
3809 | 113 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); | 148 | ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox"); |
3811 | 114 | exit; | 149 | done_testing; |
3812 | 115 | 150 | ||
3813 | === modified file 't/pt-fk-error-logger/basics.t' | |||
3814 | --- t/pt-fk-error-logger/basics.t 2012-11-07 18:38:09 +0000 | |||
3815 | +++ t/pt-fk-error-logger/basics.t 2013-02-27 23:41:26 +0000 | |||
3816 | @@ -27,8 +27,9 @@ | |||
3817 | 27 | $sb->create_dbs($dbh, [qw(test)]); | 27 | $sb->create_dbs($dbh, [qw(test)]); |
3818 | 28 | 28 | ||
3819 | 29 | my $output; | 29 | my $output; |
3822 | 30 | my $cnf = '/tmp/12345/my.sandbox.cnf'; | 30 | my $cnf = '/tmp/12345/my.sandbox.cnf'; |
3823 | 31 | my $cmd = "$trunk/bin/pt-fk-error-logger -F $cnf "; | 31 | my $cmd = "$trunk/bin/pt-fk-error-logger -F $cnf "; |
3824 | 32 | my @args = qw(--iterations 1); | ||
3825 | 32 | 33 | ||
3826 | 33 | $sb->load_file('master', 't/pt-fk-error-logger/samples/fke_tbl.sql', 'test'); | 34 | $sb->load_file('master', 't/pt-fk-error-logger/samples/fke_tbl.sql', 'test'); |
3827 | 34 | 35 | ||
3828 | @@ -39,8 +40,45 @@ | |||
3829 | 39 | # First, create a foreign key error. | 40 | # First, create a foreign key error. |
3830 | 40 | `/tmp/12345/use -D test < $trunk/t/pt-fk-error-logger/samples/fke.sql 1>/dev/null 2>/dev/null`; | 41 | `/tmp/12345/use -D test < $trunk/t/pt-fk-error-logger/samples/fke.sql 1>/dev/null 2>/dev/null`; |
3831 | 41 | 42 | ||
3834 | 42 | # Then get and save that fke. | 43 | $output = output( |
3835 | 43 | output(sub { pt_fk_error_logger::main('h=127.1,P=12345,u=msandbox,p=msandbox', '--dest', 'h=127.1,P=12345,D=test,t=foreign_key_errors'); } ); | 44 | sub { |
3836 | 45 | pt_fk_error_logger::main(@args, 'h=127.1,P=12345,u=msandbox,p=msandbox'), | ||
3837 | 46 | } | ||
3838 | 47 | ); | ||
3839 | 48 | |||
3840 | 49 | like( | ||
3841 | 50 | $output, | ||
3842 | 51 | qr/Foreign key constraint fails/, | ||
3843 | 52 | "Prints fk error by default" | ||
3844 | 53 | ); | ||
3845 | 54 | |||
3846 | 55 | $output = output( | ||
3847 | 56 | sub { | ||
3848 | 57 | pt_fk_error_logger::main(@args, 'h=127.1,P=12345,u=msandbox,p=msandbox', | ||
3849 | 58 | qw(--quiet)) | ||
3850 | 59 | } | ||
3851 | 60 | ); | ||
3852 | 61 | |||
3853 | 62 | is( | ||
3854 | 63 | $output, | ||
3855 | 64 | "", | ||
3856 | 65 | "No output with --quiet" | ||
3857 | 66 | ); | ||
3858 | 67 | |||
3859 | 68 | |||
3860 | 69 | # ############################################################################# | ||
3861 | 70 | # --dest | ||
3862 | 71 | # ############################################################################# | ||
3863 | 72 | |||
3864 | 73 | $output = output( | ||
3865 | 74 | sub { | ||
3866 | 75 | pt_fk_error_logger::main(@args, | ||
3867 | 76 | 'h=127.1,P=12345,u=msandbox,p=msandbox', | ||
3868 | 77 | '--dest', 'h=127.1,P=12345,D=test,t=foreign_key_errors', | ||
3869 | 78 | ) | ||
3870 | 79 | } | ||
3871 | 80 | ); | ||
3872 | 81 | |||
3873 | 44 | sleep 0.1; | 82 | sleep 0.1; |
3874 | 45 | 83 | ||
3875 | 46 | # And then test that it was actually saved. | 84 | # And then test that it was actually saved. |
3876 | @@ -61,7 +99,7 @@ | |||
3877 | 61 | 99 | ||
3878 | 62 | # Check again to make sure that the same fke isn't saved twice. | 100 | # Check again to make sure that the same fke isn't saved twice. |
3879 | 63 | my $first_ts = $fke->[0]->[0]; | 101 | my $first_ts = $fke->[0]->[0]; |
3881 | 64 | output(sub { pt_fk_error_logger::main('h=127.1,P=12345,u=msandbox,p=msandbox', '--dest', 'h=127.1,P=12345,D=test,t=foreign_key_errors'); } ); | 102 | output(sub { pt_fk_error_logger::main(@args, 'h=127.1,P=12345,u=msandbox,p=msandbox', '--dest', 'h=127.1,P=12345,D=test,t=foreign_key_errors'); } ); |
3882 | 65 | sleep 0.1; | 103 | sleep 0.1; |
3883 | 66 | $fke = $dbh->selectall_arrayref('SELECT * FROM test.foreign_key_errors'); | 104 | $fke = $dbh->selectall_arrayref('SELECT * FROM test.foreign_key_errors'); |
3884 | 67 | is( | 105 | is( |
3885 | @@ -82,7 +120,7 @@ | |||
3886 | 82 | eval { | 120 | eval { |
3887 | 83 | $dbh->do('DELETE FROM parent WHERE id = 2'); # Causes foreign key error. | 121 | $dbh->do('DELETE FROM parent WHERE id = 2'); # Causes foreign key error. |
3888 | 84 | }; | 122 | }; |
3890 | 85 | output( sub { pt_fk_error_logger::main('h=127.1,P=12345,u=msandbox,p=msandbox', '--dest', 'h=127.1,P=12345,D=test,t=foreign_key_errors'); } ); | 123 | output( sub { pt_fk_error_logger::main(@args, 'h=127.1,P=12345,u=msandbox,p=msandbox', '--dest', 'h=127.1,P=12345,D=test,t=foreign_key_errors'); } ); |
3891 | 86 | sleep 0.1; | 124 | sleep 0.1; |
3892 | 87 | $fke = $dbh->selectall_arrayref('SELECT * FROM test.foreign_key_errors'); | 125 | $fke = $dbh->selectall_arrayref('SELECT * FROM test.foreign_key_errors'); |
3893 | 88 | like( | 126 | like( |
3894 | @@ -99,11 +137,14 @@ | |||
3895 | 99 | # ########################################################################## | 137 | # ########################################################################## |
3896 | 100 | # Test printing the errors. | 138 | # Test printing the errors. |
3897 | 101 | # ########################################################################## | 139 | # ########################################################################## |
3898 | 140 | |||
3899 | 102 | $dbh->do('USE test'); | 141 | $dbh->do('USE test'); |
3900 | 103 | eval { | 142 | eval { |
3901 | 104 | $dbh->do('DELETE FROM parent WHERE id = 2'); # Causes foreign key error. | 143 | $dbh->do('DELETE FROM parent WHERE id = 2'); # Causes foreign key error. |
3902 | 105 | }; | 144 | }; |
3904 | 106 | $output = output(sub { pt_fk_error_logger::main('h=127.1,P=12345,u=msandbox,p=msandbox'); }); | 145 | |
3905 | 146 | $output = output(sub { pt_fk_error_logger::main(@args, 'h=127.1,P=12345,u=msandbox,p=msandbox'); }); | ||
3906 | 147 | |||
3907 | 107 | like( | 148 | like( |
3908 | 108 | $output, | 149 | $output, |
3909 | 109 | qr/DELETE FROM parent WHERE id = 2/, | 150 | qr/DELETE FROM parent WHERE id = 2/, |
3910 | @@ -127,7 +168,7 @@ | |||
3911 | 127 | 168 | ||
3912 | 128 | $output = output( | 169 | $output = output( |
3913 | 129 | sub { | 170 | sub { |
3915 | 130 | pt_fk_error_logger::main('h=127.1,P=12348,u=msandbox,p=msandbox', | 171 | pt_fk_error_logger::main(@args, 'h=127.1,P=12348,u=msandbox,p=msandbox', |
3916 | 131 | '--dest', 'h=127.1,P=12348,D=test,t=foreign_key_errors') | 172 | '--dest', 'h=127.1,P=12348,D=test,t=foreign_key_errors') |
3917 | 132 | }, | 173 | }, |
3918 | 133 | stderr => 1, | 174 | stderr => 1, |
3919 | @@ -142,6 +183,23 @@ | |||
3920 | 142 | diag(`$trunk/sandbox/stop-sandbox 12348 >/dev/null`); | 183 | diag(`$trunk/sandbox/stop-sandbox 12348 >/dev/null`); |
3921 | 143 | 184 | ||
3922 | 144 | # ############################################################################# | 185 | # ############################################################################# |
3923 | 186 | # Test --pid | ||
3924 | 187 | # ############################################################################# | ||
3925 | 188 | |||
3926 | 189 | my $pid_file = "/tmp/pt-fk-error-log-test-$PID.pid"; | ||
3927 | 190 | diag(`touch $pid_file`); | ||
3928 | 191 | |||
3929 | 192 | $output = `$trunk/bin/pt-fk-error-logger h=127.1,P=12345,u=msandbox,p=msandbox --pid $pid_file --iterations 1 2>&1`; | ||
3930 | 193 | |||
3931 | 194 | like( | ||
3932 | 195 | $output, | ||
3933 | 196 | qr{PID file $pid_file already exists}, | ||
3934 | 197 | 'Dies if PID file already exists (--pid without --daemonize) (issue 391)' | ||
3935 | 198 | ); | ||
3936 | 199 | |||
3937 | 200 | unlink $pid_file; | ||
3938 | 201 | |||
3939 | 202 | # ############################################################################# | ||
3940 | 145 | # Done. | 203 | # Done. |
3941 | 146 | # ############################################################################# | 204 | # ############################################################################# |
3942 | 147 | $sb->wipe_clean($dbh); | 205 | $sb->wipe_clean($dbh); |
3943 | 148 | 206 | ||
3944 | === modified file 't/pt-fk-error-logger/get_fk_error.t' | |||
3945 | --- t/pt-fk-error-logger/get_fk_error.t 2011-07-12 22:56:55 +0000 | |||
3946 | +++ t/pt-fk-error-logger/get_fk_error.t 2013-02-27 23:41:26 +0000 | |||
3947 | @@ -9,7 +9,7 @@ | |||
3948 | 9 | use strict; | 9 | use strict; |
3949 | 10 | use warnings FATAL => 'all'; | 10 | use warnings FATAL => 'all'; |
3950 | 11 | use English qw(-no_match_vars); | 11 | use English qw(-no_match_vars); |
3952 | 12 | use Test::More tests => 10; | 12 | use Test::More; |
3953 | 13 | 13 | ||
3954 | 14 | use PerconaTest; | 14 | use PerconaTest; |
3955 | 15 | require "$trunk/bin/pt-fk-error-logger"; | 15 | require "$trunk/bin/pt-fk-error-logger"; |
3956 | @@ -70,4 +70,4 @@ | |||
3957 | 70 | # ############################################################################# | 70 | # ############################################################################# |
3958 | 71 | # Done. | 71 | # Done. |
3959 | 72 | # ############################################################################# | 72 | # ############################################################################# |
3961 | 73 | exit; | 73 | done_testing; |
3962 | 74 | 74 | ||
3963 | === removed file 't/pt-fk-error-logger/standard_options.t' | |||
3964 | --- t/pt-fk-error-logger/standard_options.t 2011-07-12 22:56:55 +0000 | |||
3965 | +++ t/pt-fk-error-logger/standard_options.t 1970-01-01 00:00:00 +0000 | |||
3966 | @@ -1,32 +0,0 @@ | |||
3967 | 1 | #!/usr/bin/env perl | ||
3968 | 2 | |||
3969 | 3 | BEGIN { | ||
3970 | 4 | die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n" | ||
3971 | 5 | unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH}; | ||
3972 | 6 | unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib"; | ||
3973 | 7 | }; | ||
3974 | 8 | |||
3975 | 9 | use strict; | ||
3976 | 10 | use warnings FATAL => 'all'; | ||
3977 | 11 | use English qw(-no_match_vars); | ||
3978 | 12 | use Test::More tests => 1; | ||
3979 | 13 | |||
3980 | 14 | use PerconaTest; | ||
3981 | 15 | require "$trunk/bin/pt-fk-error-logger"; | ||
3982 | 16 | |||
3983 | 17 | # ######################################################################### | ||
3984 | 18 | # Issue 391: Add --pid option to all scripts | ||
3985 | 19 | # ######################################################################### | ||
3986 | 20 | `touch /tmp/mk-script.pid`; | ||
3987 | 21 | my $output = `$trunk/bin/pt-fk-error-logger h=127.1,P=12345,u=msandbox,p=msandbox --print --pid /tmp/mk-script.pid 2>&1`; | ||
3988 | 22 | like( | ||
3989 | 23 | $output, | ||
3990 | 24 | qr{PID file /tmp/mk-script.pid already exists}, | ||
3991 | 25 | 'Dies if PID file already exists (--pid without --daemonize) (issue 391)' | ||
3992 | 26 | ); | ||
3993 | 27 | `rm -rf /tmp/mk-script.pid`; | ||
3994 | 28 | |||
3995 | 29 | # ############################################################################# | ||
3996 | 30 | # Done. | ||
3997 | 31 | # ############################################################################# | ||
3998 | 32 | exit; |
See my comment #2 in bug 1056838.
All tests pass: https:/ /refute. testnoir. com/percona- toolkit/ jobs/percona- toolkit- all-platforms/ 63