Merge lp:~abychko/percona-server/ps-5.1-bug1032139 into lp:percona-server/5.1
- ps-5.1-bug1032139
- Merge into 5.1
Proposed by
Alexey Bychko
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Alexey Kopytov | ||||||||
Approved revision: | no longer in the source branch. | ||||||||
Merged at revision: | 541 | ||||||||
Proposed branch: | lp:~abychko/percona-server/ps-5.1-bug1032139 | ||||||||
Merge into: | lp:percona-server/5.1 | ||||||||
Diff against target: |
13050 lines (+0/-12986) 8 files modified
build/debian/additions/innotop/InnoDBParser.pm (+0/-1089) build/debian/additions/innotop/changelog.innotop (+0/-318) build/debian/additions/innotop/innotop (+0/-9485) build/debian/additions/innotop/innotop.1 (+0/-2086) build/debian/percona-server-client-5.1.dirs (+0/-1) build/debian/percona-server-client-5.1.docs (+0/-1) build/debian/percona-server-client-5.1.files (+0/-3) build/debian/rules (+0/-3) |
||||||||
To merge this branch: | bzr merge lp:~abychko/percona-server/ps-5.1-bug1032139 | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexey Kopytov (community) | Approve | ||
Ignacio Nin (community) | Approve | ||
Review via email:
|
Commit message
Description of the change
[-] removed innotop and its InnoDBParser perl package from source and debian installation
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alexey Kopytov (akopytov) wrote : | # |
Should also reference bug #1050536 as this fix also fixes that bug. And resubmitted as a proper upmerge for 5.5.
review:
Needs Fixing
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alexey Bychko (abychko) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alexey Kopytov (akopytov) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === removed directory 'build/debian/additions/innotop' |
2 | === removed file 'build/debian/additions/innotop/InnoDBParser.pm' |
3 | --- build/debian/additions/innotop/InnoDBParser.pm 2010-05-31 13:57:21 +0000 |
4 | +++ build/debian/additions/innotop/InnoDBParser.pm 1970-01-01 00:00:00 +0000 |
5 | @@ -1,1089 +0,0 @@ |
6 | -use strict; |
7 | -use warnings FATAL => 'all'; |
8 | - |
9 | -package InnoDBParser; |
10 | - |
11 | -# This program is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com. |
12 | -# Feedback and improvements are gratefully received. |
13 | -# |
14 | -# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
15 | -# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
16 | -# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
17 | -# |
18 | -# This program is free software; you can redistribute it and/or modify it under |
19 | -# the terms of the GNU General Public License as published by the Free Software |
20 | -# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar |
21 | -# systems, you can issue `man perlgpl' or `man perlartistic' to read these |
22 | - |
23 | -# You should have received a copy of the GNU General Public License along with |
24 | -# this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
25 | -# Place, Suite 330, Boston, MA 02111-1307 USA |
26 | - |
27 | -our $VERSION = '1.6.0'; |
28 | - |
29 | -use Data::Dumper; |
30 | -$Data::Dumper::Sortkeys = 1; |
31 | -use English qw(-no_match_vars); |
32 | -use List::Util qw(max); |
33 | - |
34 | -# Some common patterns |
35 | -my $d = qr/(\d+)/; # Digit |
36 | -my $f = qr/(\d+\.\d+)/; # Float |
37 | -my $t = qr/(\d+ \d+)/; # Transaction ID |
38 | -my $i = qr/((?:\d{1,3}\.){3}\d+)/; # IP address |
39 | -my $n = qr/([^`\s]+)/; # MySQL object name |
40 | -my $w = qr/(\w+)/; # Words |
41 | -my $fl = qr/([\w\.\/]+) line $d/; # Filename and line number |
42 | -my $h = qr/((?:0x)?[0-9a-f]*)/; # Hex |
43 | -my $s = qr/(\d{6} .\d:\d\d:\d\d)/; # InnoDB timestamp |
44 | - |
45 | -# If you update this variable, also update the SYNOPSIS in the pod. |
46 | -my %innodb_section_headers = ( |
47 | - "TRANSACTIONS" => "tx", |
48 | - "BUFFER POOL AND MEMORY" => "bp", |
49 | - "SEMAPHORES" => "sm", |
50 | - "LOG" => "lg", |
51 | - "ROW OPERATIONS" => "ro", |
52 | - "INSERT BUFFER AND ADAPTIVE HASH INDEX" => "ib", |
53 | - "FILE I/O" => "io", |
54 | - "LATEST DETECTED DEADLOCK" => "dl", |
55 | - "LATEST FOREIGN KEY ERROR" => "fk", |
56 | -); |
57 | - |
58 | -my %parser_for = ( |
59 | - tx => \&parse_tx_section, |
60 | - bp => \&parse_bp_section, |
61 | - sm => \&parse_sm_section, |
62 | - lg => \&parse_lg_section, |
63 | - ro => \&parse_ro_section, |
64 | - ib => \&parse_ib_section, |
65 | - io => \&parse_io_section, |
66 | - dl => \&parse_dl_section, |
67 | - fk => \&parse_fk_section, |
68 | -); |
69 | - |
70 | -my %fk_parser_for = ( |
71 | - Transaction => \&parse_fk_transaction_error, |
72 | - Error => \&parse_fk_bad_constraint_error, |
73 | - Cannot => \&parse_fk_cant_drop_parent_error, |
74 | -); |
75 | - |
76 | -# A thread's proc_info can be at least 98 different things I've found in the |
77 | -# source. Fortunately, most of them begin with a gerunded verb. These are |
78 | -# the ones that don't. |
79 | -my %is_proc_info = ( |
80 | - 'After create' => 1, |
81 | - 'Execution of init_command' => 1, |
82 | - 'FULLTEXT initialization' => 1, |
83 | - 'Reopen tables' => 1, |
84 | - 'Repair done' => 1, |
85 | - 'Repair with keycache' => 1, |
86 | - 'System lock' => 1, |
87 | - 'Table lock' => 1, |
88 | - 'Thread initialized' => 1, |
89 | - 'User lock' => 1, |
90 | - 'copy to tmp table' => 1, |
91 | - 'discard_or_import_tablespace' => 1, |
92 | - 'end' => 1, |
93 | - 'got handler lock' => 1, |
94 | - 'got old table' => 1, |
95 | - 'init' => 1, |
96 | - 'key cache' => 1, |
97 | - 'locks' => 1, |
98 | - 'malloc' => 1, |
99 | - 'query end' => 1, |
100 | - 'rename result table' => 1, |
101 | - 'rename' => 1, |
102 | - 'setup' => 1, |
103 | - 'statistics' => 1, |
104 | - 'status' => 1, |
105 | - 'table cache' => 1, |
106 | - 'update' => 1, |
107 | -); |
108 | - |
109 | -sub new { |
110 | - bless {}, shift; |
111 | -} |
112 | - |
113 | -# Parse the status and return it. |
114 | -# See srv_printf_innodb_monitor in innobase/srv/srv0srv.c |
115 | -# Pass in the text to parse, whether to be in debugging mode, which sections |
116 | -# to parse (hashref; if empty, parse all), and whether to parse full info from |
117 | -# locks and such (probably shouldn't unless you need to). |
118 | -sub parse_status_text { |
119 | - my ( $self, $fulltext, $debug, $sections, $full ) = @_; |
120 | - |
121 | - die "I can't parse undef" unless defined $fulltext; |
122 | - $fulltext =~ s/[\r\n]+/\n/g; |
123 | - |
124 | - $sections ||= {}; |
125 | - die '$sections must be a hashref' unless ref($sections) eq 'HASH'; |
126 | - |
127 | - my %innodb_data = ( |
128 | - got_all => 0, # Whether I was able to get the whole thing |
129 | - ts => '', # Timestamp the server put on it |
130 | - last_secs => 0, # Num seconds the averages are over |
131 | - sections => {}, # Parsed values from each section |
132 | - ); |
133 | - |
134 | - if ( $debug ) { |
135 | - $innodb_data{'fulltext'} = $fulltext; |
136 | - } |
137 | - |
138 | - # Get the most basic info about the status: beginning and end, and whether |
139 | - # I got the whole thing (if there has been a big deadlock and there are |
140 | - # too many locks to print, the output might be truncated) |
141 | - my ( $time_text ) = $fulltext =~ m/^$s INNODB MONITOR OUTPUT$/m; |
142 | - $innodb_data{'ts'} = [ parse_innodb_timestamp( $time_text ) ]; |
143 | - $innodb_data{'timestring'} = ts_to_string($innodb_data{'ts'}); |
144 | - ( $innodb_data{'last_secs'} ) = $fulltext |
145 | - =~ m/Per second averages calculated from the last $d seconds/; |
146 | - |
147 | - ( my $got_all ) = $fulltext =~ m/END OF INNODB MONITOR OUTPUT/; |
148 | - $innodb_data{'got_all'} = $got_all || 0; |
149 | - |
150 | - # Split it into sections. Each section begins with |
151 | - # ----- |
152 | - # LABEL |
153 | - # ----- |
154 | - my %innodb_sections; |
155 | - my @matches = $fulltext |
156 | - =~ m#\n(---+)\n([A-Z /]+)\n\1\n(.*?)(?=\n(---+)\n[A-Z /]+\n\4\n|$)#gs; |
157 | - while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) { |
158 | - $innodb_sections{$name} = [ $text, $end ? 1 : 0 ]; |
159 | - } |
160 | - # The Row Operations section is a special case, because instead of ending |
161 | - # with the beginning of another section, it ends with the end of the file. |
162 | - # So this section is complete if the entire file is complete. |
163 | - $innodb_sections{'ROW OPERATIONS'}->[1] ||= $innodb_data{'got_all'}; |
164 | - |
165 | - # Just for sanity's sake, make sure I understand what to do with each |
166 | - # section |
167 | - eval { |
168 | - foreach my $section ( keys %innodb_sections ) { |
169 | - my $header = $innodb_section_headers{$section}; |
170 | - die "Unknown section $section in $fulltext\n" |
171 | - unless $header; |
172 | - $innodb_data{'sections'}->{ $header } |
173 | - ->{'fulltext'} = $innodb_sections{$section}->[0]; |
174 | - $innodb_data{'sections'}->{ $header } |
175 | - ->{'complete'} = $innodb_sections{$section}->[1]; |
176 | - } |
177 | - }; |
178 | - if ( $EVAL_ERROR ) { |
179 | - _debug( $debug, $EVAL_ERROR); |
180 | - } |
181 | - |
182 | - # ################################################################ |
183 | - # Parse the detailed data out of the sections. |
184 | - # ################################################################ |
185 | - eval { |
186 | - foreach my $section ( keys %parser_for ) { |
187 | - if ( defined $innodb_data{'sections'}->{$section} |
188 | - && (!%$sections || (defined($sections->{$section} && $sections->{$section})) )) { |
189 | - $parser_for{$section}->( |
190 | - $innodb_data{'sections'}->{$section}, |
191 | - $innodb_data{'sections'}->{$section}->{'complete'}, |
192 | - $debug, |
193 | - $full ) |
194 | - or delete $innodb_data{'sections'}->{$section}; |
195 | - } |
196 | - else { |
197 | - delete $innodb_data{'sections'}->{$section}; |
198 | - } |
199 | - } |
200 | - }; |
201 | - if ( $EVAL_ERROR ) { |
202 | - _debug( $debug, $EVAL_ERROR); |
203 | - } |
204 | - |
205 | - return \%innodb_data; |
206 | -} |
207 | - |
208 | -# Parses the status text and returns it flattened out as a single hash. |
209 | -sub get_status_hash { |
210 | - my ( $self, $fulltext, $debug, $sections, $full ) = @_; |
211 | - |
212 | - # Parse the status text... |
213 | - my $innodb_status |
214 | - = $self->parse_status_text($fulltext, $debug, $sections, $full ); |
215 | - |
216 | - # Flatten the hierarchical structure into a single list by grabbing desired |
217 | - # sections from it. |
218 | - return |
219 | - (map { 'IB_' . $_ => $innodb_status->{$_} } qw(timestring last_secs got_all)), |
220 | - (map { 'IB_bp_' . $_ => $innodb_status->{'sections'}->{'bp'}->{$_} } |
221 | - qw( writes_pending buf_pool_hit_rate total_mem_alloc buf_pool_reads |
222 | - awe_mem_alloc pages_modified writes_pending_lru page_creates_sec |
223 | - reads_pending pages_total buf_pool_hits writes_pending_single_page |
224 | - page_writes_sec pages_read pages_written page_reads_sec |
225 | - writes_pending_flush_list buf_pool_size add_pool_alloc |
226 | - dict_mem_alloc pages_created buf_free complete )), |
227 | - (map { 'IB_tx_' . $_ => $innodb_status->{'sections'}->{'tx'}->{$_} } |
228 | - qw( num_lock_structs history_list_len purge_done_for transactions |
229 | - purge_undo_for is_truncated trx_id_counter complete )), |
230 | - (map { 'IB_ib_' . $_ => $innodb_status->{'sections'}->{'ib'}->{$_} } |
231 | - qw( hash_table_size hash_searches_s non_hash_searches_s |
232 | - bufs_in_node_heap used_cells size free_list_len seg_size inserts |
233 | - merged_recs merges complete )), |
234 | - (map { 'IB_lg_' . $_ => $innodb_status->{'sections'}->{'lg'}->{$_} } |
235 | - qw( log_ios_done pending_chkp_writes last_chkp log_ios_s |
236 | - log_flushed_to log_seq_no pending_log_writes complete )), |
237 | - (map { 'IB_sm_' . $_ => $innodb_status->{'sections'}->{'sm'}->{$_} } |
238 | - qw( wait_array_size rw_shared_spins rw_excl_os_waits mutex_os_waits |
239 | - mutex_spin_rounds mutex_spin_waits rw_excl_spins rw_shared_os_waits |
240 | - waits signal_count reservation_count complete )), |
241 | - (map { 'IB_ro_' . $_ => $innodb_status->{'sections'}->{'ro'}->{$_} } |
242 | - qw( queries_in_queue n_reserved_extents main_thread_state |
243 | - main_thread_proc_no main_thread_id read_sec del_sec upd_sec ins_sec |
244 | - read_views_open num_rows_upd num_rows_ins num_rows_read |
245 | - queries_inside num_rows_del complete )), |
246 | - (map { 'IB_fk_' . $_ => $innodb_status->{'sections'}->{'fk'}->{$_} } |
247 | - qw( trigger parent_table child_index parent_index attempted_op |
248 | - child_db timestring fk_name records col_name reason txn parent_db |
249 | - type child_table parent_col complete )), |
250 | - (map { 'IB_io_' . $_ => $innodb_status->{'sections'}->{'io'}->{$_} } |
251 | - qw( pending_buffer_pool_flushes pending_pwrites pending_preads |
252 | - pending_normal_aio_reads fsyncs_s os_file_writes pending_sync_ios |
253 | - reads_s flush_type avg_bytes_s pending_ibuf_aio_reads writes_s |
254 | - threads os_file_reads pending_aio_writes pending_log_ios os_fsyncs |
255 | - pending_log_flushes complete )), |
256 | - (map { 'IB_dl_' . $_ => $innodb_status->{'sections'}->{'dl'}->{$_} } |
257 | - qw( timestring rolled_back txns complete )); |
258 | - |
259 | -} |
260 | - |
261 | -sub ts_to_string { |
262 | - my $parts = shift; |
263 | - return sprintf('%02d-%02d-%02d %02d:%02d:%02d', @$parts); |
264 | -} |
265 | - |
266 | -sub parse_innodb_timestamp { |
267 | - my $text = shift; |
268 | - my ( $y, $m, $d, $h, $i, $s ) |
269 | - = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/; |
270 | - die("Can't get timestamp from $text\n") unless $y; |
271 | - $y += 2000; |
272 | - return ( $y, $m, $d, $h, $i, $s ); |
273 | -} |
274 | - |
275 | -sub parse_fk_section { |
276 | - my ( $section, $complete, $debug, $full ) = @_; |
277 | - my $fulltext = $section->{'fulltext'}; |
278 | - |
279 | - return 0 unless $fulltext; |
280 | - |
281 | - my ( $ts, $type ) = $fulltext =~ m/^$s\s+(\w+)/m; |
282 | - $section->{'ts'} = [ parse_innodb_timestamp( $ts ) ]; |
283 | - $section->{'timestring'} = ts_to_string($section->{'ts'}); |
284 | - $section->{'type'} = $type; |
285 | - |
286 | - # Decide which type of FK error happened, and dispatch to the right parser. |
287 | - if ( $type && $fk_parser_for{$type} ) { |
288 | - $fk_parser_for{$type}->( $section, $complete, $debug, $fulltext, $full ); |
289 | - } |
290 | - |
291 | - delete $section->{'fulltext'} unless $debug; |
292 | - |
293 | - return 1; |
294 | -} |
295 | - |
296 | -sub parse_fk_cant_drop_parent_error { |
297 | - my ( $section, $complete, $debug, $fulltext, $full ) = @_; |
298 | - |
299 | - # Parse the parent/child table info out |
300 | - @{$section}{ qw(attempted_op parent_db parent_table) } = $fulltext |
301 | - =~ m{Cannot $w table `(.*)/(.*)`}m; |
302 | - @{$section}{ qw(child_db child_table) } = $fulltext |
303 | - =~ m{because it is referenced by `(.*)/(.*)`}m; |
304 | - |
305 | - ( $section->{'reason'} ) = $fulltext =~ m/(Cannot .*)/s; |
306 | - $section->{'reason'} =~ s/\n(?:InnoDB: )?/ /gm |
307 | - if $section->{'reason'}; |
308 | - |
309 | - # Certain data may not be present. Make them '' if not present. |
310 | - map { $section->{$_} ||= "" } |
311 | - qw(child_index fk_name col_name parent_col); |
312 | -} |
313 | - |
314 | -# See dict/dict0dict.c, function dict_foreign_error_report |
315 | -# I don't care much about these. There are lots of different messages, and |
316 | -# they come from someone trying to create a foreign key, or similar |
317 | -# statements. They aren't indicative of some transaction trying to insert, |
318 | -# delete or update data. Sometimes it is possible to parse out a lot of |
319 | -# information about the tables and indexes involved, but often the message |
320 | -# contains the DDL string the user entered, which is way too much for this |
321 | -# module to try to handle. |
322 | -sub parse_fk_bad_constraint_error { |
323 | - my ( $section, $complete, $debug, $fulltext, $full ) = @_; |
324 | - |
325 | - # Parse the parent/child table and index info out |
326 | - @{$section}{ qw(child_db child_table) } = $fulltext |
327 | - =~ m{Error in foreign key constraint of table (.*)/(.*):$}m; |
328 | - $section->{'attempted_op'} = 'DDL'; |
329 | - |
330 | - # FK name, parent info... if possible. |
331 | - @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) } |
332 | - = $fulltext |
333 | - =~ m/CONSTRAINT `?$n`? FOREIGN KEY \(`?$n`?\) REFERENCES (?:`?$n`?\.)?`?$n`? \(`?$n`?\)/; |
334 | - |
335 | - if ( !defined($section->{'fk_name'}) ) { |
336 | - # Try to parse SQL a user might have typed in a CREATE statement or such |
337 | - @{$section}{ qw(col_name parent_db parent_table parent_col) } |
338 | - = $fulltext |
339 | - =~ m/FOREIGN\s+KEY\s*\(`?$n`?\)\s+REFERENCES\s+(?:`?$n`?\.)?`?$n`?\s*\(`?$n`?\)/i; |
340 | - } |
341 | - $section->{'parent_db'} ||= $section->{'child_db'}; |
342 | - |
343 | - # Name of the child index (index in the same table where the FK is, see |
344 | - # definition of dict_foreign_struct in include/dict0mem.h, where it is |
345 | - # called foreign_index, as opposed to referenced_index which is in the |
346 | - # parent table. This may not be possible to find. |
347 | - @{$section}{ qw(child_index) } = $fulltext |
348 | - =~ m/^The index in the foreign key in table is $n$/m; |
349 | - |
350 | - @{$section}{ qw(reason) } = $fulltext =~ m/:\s*([^:]+)(?= Constraint:|$)/ms; |
351 | - $section->{'reason'} =~ s/\s+/ /g |
352 | - if $section->{'reason'}; |
353 | - |
354 | - # Certain data may not be present. Make them '' if not present. |
355 | - map { $section->{$_} ||= "" } |
356 | - qw(child_index fk_name col_name parent_table parent_col); |
357 | -} |
358 | - |
359 | -# see source file row/row0ins.c |
360 | -sub parse_fk_transaction_error { |
361 | - my ( $section, $complete, $debug, $fulltext, $full ) = @_; |
362 | - |
363 | - # Parse the txn info out |
364 | - my ( $txn ) = $fulltext |
365 | - =~ m/Transaction:\n(TRANSACTION.*)\nForeign key constraint fails/s; |
366 | - if ( $txn ) { |
367 | - $section->{'txn'} = parse_tx_text( $txn, $complete, $debug, $full ); |
368 | - } |
369 | - |
370 | - # Parse the parent/child table and index info out. There are two types: an |
371 | - # update or a delete of a parent record leaves a child orphaned |
372 | - # (row_ins_foreign_report_err), and an insert or update of a child record has |
373 | - # no matching parent record (row_ins_foreign_report_add_err). |
374 | - |
375 | - @{$section}{ qw(reason child_db child_table) } |
376 | - = $fulltext =~ m{^(Foreign key constraint fails for table `(.*)/(.*)`:)$}m; |
377 | - |
378 | - @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) } |
379 | - = $fulltext |
380 | - =~ m/CONSTRAINT `$n` FOREIGN KEY \(`$n`\) REFERENCES (?:`$n`\.)?`$n` \(`$n`\)/; |
381 | - $section->{'parent_db'} ||= $section->{'child_db'}; |
382 | - |
383 | - # Special case, which I don't know how to trigger, but see |
384 | - # innobase/row/row0ins.c row_ins_check_foreign_constraint |
385 | - if ( $fulltext =~ m/ibd file does not currently exist!/ ) { |
386 | - my ( $attempted_op, $index, $records ) |
387 | - = $fulltext =~ m/^Trying to (add to index) `$n` tuple:\n(.*))?/sm; |
388 | - $section->{'child_index'} = $index; |
389 | - $section->{'attempted_op'} = $attempted_op || ''; |
390 | - if ( $records && $full ) { |
391 | - ( $section->{'records'} ) |
392 | - = parse_innodb_record_dump( $records, $complete, $debug ); |
393 | - } |
394 | - @{$section}{qw(parent_db parent_table)} |
395 | - =~ m/^But the parent table `$n`\.`$n`$/m; |
396 | - } |
397 | - else { |
398 | - my ( $attempted_op, $which, $index ) |
399 | - = $fulltext =~ m/^Trying to ([\w ]*) in (child|parent) table, in index `$n` tuple:$/m; |
400 | - if ( $which ) { |
401 | - $section->{$which . '_index'} = $index; |
402 | - $section->{'attempted_op'} = $attempted_op || ''; |
403 | - |
404 | - # Parse out the related records in the other table. |
405 | - my ( $search_index, $records ); |
406 | - if ( $which eq 'child' ) { |
407 | - ( $search_index, $records ) = $fulltext |
408 | - =~ m/^But in parent table [^,]*, in index `$n`,\nthe closest match we can find is record:\n(.*)/ms; |
409 | - $section->{'parent_index'} = $search_index; |
410 | - } |
411 | - else { |
412 | - ( $search_index, $records ) = $fulltext |
413 | - =~ m/^But in child table [^,]*, in index `$n`, (?:the record is not available|there is a record:\n(.*))?/ms; |
414 | - $section->{'child_index'} = $search_index; |
415 | - } |
416 | - if ( $records && $full ) { |
417 | - $section->{'records'} |
418 | - = parse_innodb_record_dump( $records, $complete, $debug ); |
419 | - } |
420 | - else { |
421 | - $section->{'records'} = ''; |
422 | - } |
423 | - } |
424 | - } |
425 | - |
426 | - # Parse out the tuple trying to be updated, deleted or inserted. |
427 | - my ( $trigger ) = $fulltext =~ m/^(DATA TUPLE: \d+ fields;\n.*)$/m; |
428 | - if ( $trigger ) { |
429 | - $section->{'trigger'} = parse_innodb_record_dump( $trigger, $complete, $debug ); |
430 | - } |
431 | - |
432 | - # Certain data may not be present. Make them '' if not present. |
433 | - map { $section->{$_} ||= "" } |
434 | - qw(child_index fk_name col_name parent_table parent_col); |
435 | -} |
436 | - |
437 | -# There are new-style and old-style record formats. See rem/rem0rec.c |
438 | -# TODO: write some tests for this |
439 | -sub parse_innodb_record_dump { |
440 | - my ( $dump, $complete, $debug ) = @_; |
441 | - return undef unless $dump; |
442 | - |
443 | - my $result = {}; |
444 | - |
445 | - if ( $dump =~ m/PHYSICAL RECORD/ ) { |
446 | - my $style = $dump =~ m/compact format/ ? 'new' : 'old'; |
447 | - $result->{'style'} = $style; |
448 | - |
449 | - # This is a new-style record. |
450 | - if ( $style eq 'new' ) { |
451 | - @{$result}{qw( heap_no type num_fields info_bits )} |
452 | - = $dump |
453 | - =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; compact format; info bits $d$/m; |
454 | - } |
455 | - |
456 | - # OK, it's old-style. Unfortunately there are variations here too. |
457 | - elsif ( $dump =~ m/-byte offs / ) { |
458 | - # Older-old style. |
459 | - @{$result}{qw( heap_no type num_fields byte_offset info_bits )} |
460 | - = $dump |
461 | - =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offs [A-Z]+; info bits $d$/m; |
462 | - if ( $dump !~ m/-byte offs TRUE/ ) { |
463 | - $result->{'byte_offset'} = 0; |
464 | - } |
465 | - } |
466 | - else { |
467 | - # Newer-old style. |
468 | - @{$result}{qw( heap_no type num_fields byte_offset info_bits )} |
469 | - = $dump |
470 | - =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offsets; info bits $d$/m; |
471 | - } |
472 | - |
473 | - } |
474 | - else { |
475 | - $result->{'style'} = 'tuple'; |
476 | - @{$result}{qw( type num_fields )} |
477 | - = $dump =~ m/^(DATA TUPLE): $d fields;$/m; |
478 | - } |
479 | - |
480 | - # Fill in default values for things that couldn't be parsed. |
481 | - map { $result->{$_} ||= 0 } |
482 | - qw(heap_no num_fields byte_offset info_bits); |
483 | - map { $result->{$_} ||= '' } |
484 | - qw(style type ); |
485 | - |
486 | - my @fields = $dump =~ m/ (\d+:.*?;?);(?=$| \d+:)/gm; |
487 | - $result->{'fields'} = [ map { parse_field($_, $complete, $debug ) } @fields ]; |
488 | - |
489 | - return $result; |
490 | -} |
491 | - |
492 | -# New/old-style applies here. See rem/rem0rec.c |
493 | -# $text should not include the leading space or the second trailing semicolon. |
494 | -sub parse_field { |
495 | - my ( $text, $complete, $debug ) = @_; |
496 | - |
497 | - # Sample fields: |
498 | - # '4: SQL NULL, size 4 ' |
499 | - # '1: len 6; hex 000000005601; asc V ;' |
500 | - # '6: SQL NULL' |
501 | - # '5: len 30; hex 687474703a2f2f7777772e737765657477617465722e636f6d2f73746f72; asc http://www.sweetwater.com/stor;...(truncated)' |
502 | - my ( $id, $nullsize, $len, $hex, $asc, $truncated ); |
503 | - ( $id, $nullsize ) = $text =~ m/^$d: SQL NULL, size $d $/; |
504 | - if ( !defined($id) ) { |
505 | - ( $id ) = $text =~ m/^$d: SQL NULL$/; |
506 | - } |
507 | - if ( !defined($id) ) { |
508 | - ( $id, $len, $hex, $asc, $truncated ) |
509 | - = $text =~ m/^$d: len $d; hex $h; asc (.*);(\.\.\.\(truncated\))?$/; |
510 | - } |
511 | - |
512 | - die "Could not parse this field: '$text'" unless defined $id; |
513 | - return { |
514 | - id => $id, |
515 | - len => defined($len) ? $len : defined($nullsize) ? $nullsize : 0, |
516 | - 'hex' => defined($hex) ? $hex : '', |
517 | - asc => defined($asc) ? $asc : '', |
518 | - trunc => $truncated ? 1 : 0, |
519 | - }; |
520 | - |
521 | -} |
522 | - |
523 | -sub parse_dl_section { |
524 | - my ( $dl, $complete, $debug, $full ) = @_; |
525 | - return unless $dl; |
526 | - my $fulltext = $dl->{'fulltext'}; |
527 | - return 0 unless $fulltext; |
528 | - |
529 | - my ( $ts ) = $fulltext =~ m/^$s$/m; |
530 | - return 0 unless $ts; |
531 | - |
532 | - $dl->{'ts'} = [ parse_innodb_timestamp( $ts ) ]; |
533 | - $dl->{'timestring'} = ts_to_string($dl->{'ts'}); |
534 | - $dl->{'txns'} = {}; |
535 | - |
536 | - my @sections |
537 | - = $fulltext |
538 | - =~ m{ |
539 | - ^\*{3}\s([^\n]*) # *** (1) WAITING FOR THIS... |
540 | - (.*?) # Followed by anything, non-greedy |
541 | - (?=(?:^\*{3})|\z) # Followed by another three stars or EOF |
542 | - }gmsx; |
543 | - |
544 | - |
545 | - # Loop through each section. There are no assumptions about how many |
546 | - # there are, who holds and wants what locks, and who gets rolled back. |
547 | - while ( my ($header, $body) = splice(@sections, 0, 2) ) { |
548 | - my ( $txn_id, $what ) = $header =~ m/^\($d\) (.*):$/; |
549 | - next unless $txn_id; |
550 | - $dl->{'txns'}->{$txn_id} ||= {}; |
551 | - my $txn = $dl->{'txns'}->{$txn_id}; |
552 | - |
553 | - if ( $what eq 'TRANSACTION' ) { |
554 | - $txn->{'tx'} = parse_tx_text( $body, $complete, $debug, $full ); |
555 | - } |
556 | - else { |
557 | - push @{$txn->{'locks'}}, parse_innodb_record_locks( $body, $complete, $debug, $full ); |
558 | - } |
559 | - } |
560 | - |
561 | - @{ $dl }{ qw(rolled_back) } |
562 | - = $fulltext =~ m/^\*\*\* WE ROLL BACK TRANSACTION \($d\)$/m; |
563 | - |
564 | - # Make sure certain values aren't undef |
565 | - map { $dl->{$_} ||= '' } qw(rolled_back); |
566 | - |
567 | - delete $dl->{'fulltext'} unless $debug; |
568 | - return 1; |
569 | -} |
570 | - |
571 | -sub parse_innodb_record_locks { |
572 | - my ( $text, $complete, $debug, $full ) = @_; |
573 | - my @result; |
574 | - |
575 | - foreach my $lock ( $text =~ m/(^(?:RECORD|TABLE) LOCKS?.*$)/gm ) { |
576 | - my $hash = {}; |
577 | - @{$hash}{ qw(lock_type space_id page_no n_bits index db table txn_id lock_mode) } |
578 | - = $lock |
579 | - =~ m{^(RECORD|TABLE) LOCKS? (?:space id $d page no $d n bits $d index `?$n`? of )?table `$n(?:/|`\.`)$n` trx id $t lock.mode (\S+)}m; |
580 | - ( $hash->{'special'} ) |
581 | - = $lock =~ m/^(?:RECORD|TABLE) .*? locks (rec but not gap|gap before rec)/m; |
582 | - $hash->{'insert_intention'} |
583 | - = $lock =~ m/^(?:RECORD|TABLE) .*? insert intention/m ? 1 : 0; |
584 | - $hash->{'waiting'} |
585 | - = $lock =~ m/^(?:RECORD|TABLE) .*? waiting/m ? 1 : 0; |
586 | - |
587 | - # Some things may not be in the text, so make sure they are not |
588 | - # undef. |
589 | - map { $hash->{$_} ||= 0 } qw(n_bits page_no space_id); |
590 | - map { $hash->{$_} ||= "" } qw(index special); |
591 | - push @result, $hash; |
592 | - } |
593 | - |
594 | - return @result; |
595 | -} |
596 | - |
597 | -sub parse_tx_text { |
598 | - my ( $txn, $complete, $debug, $full ) = @_; |
599 | - |
600 | - my ( $txn_id, $txn_status, $active_secs, $proc_no, $os_thread_id ) |
601 | - = $txn |
602 | - =~ m/^(?:---)?TRANSACTION $t, (\D*?)(?: $d sec)?, (?:process no $d, )?OS thread id $d/m; |
603 | - my ( $thread_status, $thread_decl_inside ) |
604 | - = $txn |
605 | - =~ m/OS thread id \d+(?: ([^,]+?))?(?:, thread declared inside InnoDB $d)?$/m; |
606 | - |
607 | - # Parsing the line that begins 'MySQL thread id' is complicated. The only |
608 | - # thing always in the line is the thread and query id. See function |
609 | - # innobase_mysql_print_thd in InnoDB source file sql/ha_innodb.cc. |
610 | - my ( $thread_line ) = $txn =~ m/^(MySQL thread id .*)$/m; |
611 | - my ( $mysql_thread_id, $query_id, $hostname, $ip, $user, $query_status ); |
612 | - |
613 | - if ( $thread_line ) { |
614 | - # These parts can always be gotten. |
615 | - ( $mysql_thread_id, $query_id ) = $thread_line =~ m/^MySQL thread id $d, query id $d/m; |
616 | - |
617 | - # If it's a master/slave thread, "Has (read|sent) all" may be the thread's |
618 | - # proc_info. In these cases, there won't be any host/ip/user info |
619 | - ( $query_status ) = $thread_line =~ m/(Has (?:read|sent) all .*$)/m; |
620 | - if ( defined($query_status) ) { |
621 | - $user = 'system user'; |
622 | - } |
623 | - |
624 | - # It may be the case that the query id is the last thing in the line. |
625 | - elsif ( $thread_line =~ m/query id \d+ / ) { |
626 | - # The IP address is the only non-word thing left, so it's the most |
627 | - # useful marker for where I have to start guessing. |
628 | - ( $hostname, $ip ) = $thread_line =~ m/query id \d+(?: ([A-Za-z]\S+))? $i/m; |
629 | - if ( defined $ip ) { |
630 | - ( $user, $query_status ) = $thread_line =~ m/$ip $w(?: (.*))?$/; |
631 | - } |
632 | - else { # OK, there wasn't an IP address. |
633 | - # There might not be ANYTHING except the query status. |
634 | - ( $query_status ) = $thread_line =~ m/query id \d+ (.*)$/; |
635 | - if ( $query_status !~ m/^\w+ing/ && !exists($is_proc_info{$query_status}) ) { |
636 | - # The remaining tokens are, in order: hostname, user, query_status. |
637 | - # It's basically impossible to know which is which. |
638 | - ( $hostname, $user, $query_status ) = $thread_line |
639 | - =~ m/query id \d+(?: ([A-Za-z]\S+))?(?: $w(?: (.*))?)?$/m; |
640 | - } |
641 | - else { |
642 | - $user = 'system user'; |
643 | - } |
644 | - } |
645 | - } |
646 | - } |
647 | - |
648 | - my ( $lock_wait_status, $lock_structs, $heap_size, $row_locks, $undo_log_entries ) |
649 | - = $txn |
650 | - =~ m/^(?:(\D*) )?$d lock struct\(s\), heap size $d(?:, $d row lock\(s\))?(?:, undo log entries $d)?$/m; |
651 | - my ( $lock_wait_time ) |
652 | - = $txn |
653 | - =~ m/^------- TRX HAS BEEN WAITING $d SEC/m; |
654 | - |
655 | - my $locks; |
656 | - # If the transaction has locks, grab the locks. |
657 | - if ( $txn =~ m/^TABLE LOCK|RECORD LOCKS/ ) { |
658 | - $locks = [parse_innodb_record_locks($txn, $complete, $debug, $full)]; |
659 | - } |
660 | - |
661 | - my ( $tables_in_use, $tables_locked ) |
662 | - = $txn |
663 | - =~ m/^mysql tables in use $d, locked $d$/m; |
664 | - my ( $txn_doesnt_see_ge, $txn_sees_lt ) |
665 | - = $txn |
666 | - =~ m/^Trx read view will not see trx with id >= $t, sees < $t$/m; |
667 | - my $has_read_view = defined($txn_doesnt_see_ge); |
668 | - # Only a certain number of bytes of the query text are included here, at least |
669 | - # under some circumstances. Some versions include 300, some 600. |
670 | - my ( $query_text ) |
671 | - = $txn |
672 | - =~ m{ |
673 | - ^MySQL\sthread\sid\s[^\n]+\n # This comes before the query text |
674 | - (.*?) # The query text |
675 | - (?= # Followed by any of... |
676 | - ^Trx\sread\sview |
677 | - |^-------\sTRX\sHAS\sBEEN\sWAITING |
678 | - |^TABLE\sLOCK |
679 | - |^RECORD\sLOCKS\sspace\sid |
680 | - |^(?:---)?TRANSACTION |
681 | - |^\*\*\*\s\(\d\) |
682 | - |\Z |
683 | - ) |
684 | - }xms; |
685 | - if ( $query_text ) { |
686 | - $query_text =~ s/\s+$//; |
687 | - } |
688 | - else { |
689 | - $query_text = ''; |
690 | - } |
691 | - |
692 | - my %stuff = ( |
693 | - active_secs => $active_secs, |
694 | - has_read_view => $has_read_view, |
695 | - heap_size => $heap_size, |
696 | - hostname => $hostname, |
697 | - ip => $ip, |
698 | - lock_structs => $lock_structs, |
699 | - lock_wait_status => $lock_wait_status, |
700 | - lock_wait_time => $lock_wait_time, |
701 | - mysql_thread_id => $mysql_thread_id, |
702 | - os_thread_id => $os_thread_id, |
703 | - proc_no => $proc_no, |
704 | - query_id => $query_id, |
705 | - query_status => $query_status, |
706 | - query_text => $query_text, |
707 | - row_locks => $row_locks, |
708 | - tables_in_use => $tables_in_use, |
709 | - tables_locked => $tables_locked, |
710 | - thread_decl_inside => $thread_decl_inside, |
711 | - thread_status => $thread_status, |
712 | - txn_doesnt_see_ge => $txn_doesnt_see_ge, |
713 | - txn_id => $txn_id, |
714 | - txn_sees_lt => $txn_sees_lt, |
715 | - txn_status => $txn_status, |
716 | - undo_log_entries => $undo_log_entries, |
717 | - user => $user, |
718 | - ); |
719 | - $stuff{'fulltext'} = $txn if $debug; |
720 | - $stuff{'locks'} = $locks if $locks; |
721 | - |
722 | - # Some things may not be in the txn text, so make sure they are not |
723 | - # undef. |
724 | - map { $stuff{$_} ||= 0 } qw(active_secs heap_size lock_structs |
725 | - tables_in_use undo_log_entries tables_locked has_read_view |
726 | - thread_decl_inside lock_wait_time proc_no row_locks); |
727 | - map { $stuff{$_} ||= "" } qw(thread_status txn_doesnt_see_ge |
728 | - txn_sees_lt query_status ip query_text lock_wait_status user); |
729 | - $stuff{'hostname'} ||= $stuff{'ip'}; |
730 | - |
731 | - return \%stuff; |
732 | -} |
733 | - |
734 | -sub parse_tx_section { |
735 | - my ( $section, $complete, $debug, $full ) = @_; |
736 | - return unless $section && $section->{'fulltext'}; |
737 | - my $fulltext = $section->{'fulltext'}; |
738 | - $section->{'transactions'} = []; |
739 | - |
740 | - # Handle the individual transactions |
741 | - my @transactions = $fulltext =~ m/(---TRANSACTION \d.*?)(?=\n---TRANSACTION|$)/gs; |
742 | - foreach my $txn ( @transactions ) { |
743 | - my $stuff = parse_tx_text( $txn, $complete, $debug, $full ); |
744 | - delete $stuff->{'fulltext'} unless $debug; |
745 | - push @{$section->{'transactions'}}, $stuff; |
746 | - } |
747 | - |
748 | - # Handle the general info |
749 | - @{$section}{ 'trx_id_counter' } |
750 | - = $fulltext =~ m/^Trx id counter $t$/m; |
751 | - @{$section}{ 'purge_done_for', 'purge_undo_for' } |
752 | - = $fulltext =~ m/^Purge done for trx's n:o < $t undo n:o < $t$/m; |
753 | - @{$section}{ 'history_list_len' } # This isn't present in some 4.x versions |
754 | - = $fulltext =~ m/^History list length $d$/m; |
755 | - @{$section}{ 'num_lock_structs' } |
756 | - = $fulltext =~ m/^Total number of lock structs in row lock hash table $d$/m; |
757 | - @{$section}{ 'is_truncated' } |
758 | - = $fulltext =~ m/^\.\.\. truncated\.\.\.$/m ? 1 : 0; |
759 | - |
760 | - # Fill in things that might not be present |
761 | - foreach ( qw(history_list_len) ) { |
762 | - $section->{$_} ||= 0; |
763 | - } |
764 | - |
765 | - delete $section->{'fulltext'} unless $debug; |
766 | - return 1; |
767 | -} |
768 | - |
769 | -# I've read the source for this section. |
770 | -sub parse_ro_section { |
771 | - my ( $section, $complete, $debug, $full ) = @_; |
772 | - return unless $section && $section->{'fulltext'}; |
773 | - my $fulltext = $section->{'fulltext'}; |
774 | - |
775 | - # Grab the info |
776 | - @{$section}{ 'queries_inside', 'queries_in_queue' } |
777 | - = $fulltext =~ m/^$d queries inside InnoDB, $d queries in queue$/m; |
778 | - ( $section->{ 'read_views_open' } ) |
779 | - = $fulltext =~ m/^$d read views open inside InnoDB$/m; |
780 | - ( $section->{ 'n_reserved_extents' } ) |
781 | - = $fulltext =~ m/^$d tablespace extents now reserved for B-tree/m; |
782 | - @{$section}{ 'main_thread_proc_no', 'main_thread_id', 'main_thread_state' } |
783 | - = $fulltext =~ m/^Main thread (?:process no. $d, )?id $d, state: (.*)$/m; |
784 | - @{$section}{ 'num_rows_ins', 'num_rows_upd', 'num_rows_del', 'num_rows_read' } |
785 | - = $fulltext =~ m/^Number of rows inserted $d, updated $d, deleted $d, read $d$/m; |
786 | - @{$section}{ 'ins_sec', 'upd_sec', 'del_sec', 'read_sec' } |
787 | - = $fulltext =~ m#^$f inserts/s, $f updates/s, $f deletes/s, $f reads/s$#m; |
788 | - $section->{'main_thread_proc_no'} ||= 0; |
789 | - |
790 | - map { $section->{$_} ||= 0 } qw(read_views_open n_reserved_extents); |
791 | - delete $section->{'fulltext'} unless $debug; |
792 | - return 1; |
793 | -} |
794 | - |
795 | -sub parse_lg_section { |
796 | - my ( $section, $complete, $debug, $full ) = @_; |
797 | - return unless $section; |
798 | - my $fulltext = $section->{'fulltext'}; |
799 | - |
800 | - # Grab the info |
801 | - ( $section->{ 'log_seq_no' } ) |
802 | - = $fulltext =~ m/Log sequence number \s*(\d.*)$/m; |
803 | - ( $section->{ 'log_flushed_to' } ) |
804 | - = $fulltext =~ m/Log flushed up to \s*(\d.*)$/m; |
805 | - ( $section->{ 'last_chkp' } ) |
806 | - = $fulltext =~ m/Last checkpoint at \s*(\d.*)$/m; |
807 | - @{$section}{ 'pending_log_writes', 'pending_chkp_writes' } |
808 | - = $fulltext =~ m/$d pending log writes, $d pending chkp writes/; |
809 | - @{$section}{ 'log_ios_done', 'log_ios_s' } |
810 | - = $fulltext =~ m#$d log i/o's done, $f log i/o's/second#; |
811 | - |
812 | - delete $section->{'fulltext'} unless $debug; |
813 | - return 1; |
814 | -} |
815 | - |
816 | -sub parse_ib_section { |
817 | - my ( $section, $complete, $debug, $full ) = @_; |
818 | - return unless $section && $section->{'fulltext'}; |
819 | - my $fulltext = $section->{'fulltext'}; |
820 | - |
821 | - # Some servers will output ibuf information for tablespace 0, as though there |
822 | - # might be many tablespaces with insert buffers. (In practice I believe |
823 | - # the source code shows there will only ever be one). I have to parse both |
824 | - # cases here, but I assume there will only be one. |
825 | - @{$section}{ 'size', 'free_list_len', 'seg_size' } |
826 | - = $fulltext =~ m/^Ibuf(?: for space 0)?: size $d, free list len $d, seg size $d,$/m; |
827 | - @{$section}{ 'inserts', 'merged_recs', 'merges' } |
828 | - = $fulltext =~ m/^$d inserts, $d merged recs, $d merges$/m; |
829 | - |
830 | - @{$section}{ 'hash_table_size', 'used_cells', 'bufs_in_node_heap' } |
831 | - = $fulltext =~ m/^Hash table size $d, used cells $d, node heap has $d buffer\(s\)$/m; |
832 | - @{$section}{ 'hash_searches_s', 'non_hash_searches_s' } |
833 | - = $fulltext =~ m{^$f hash searches/s, $f non-hash searches/s$}m; |
834 | - |
835 | - delete $section->{'fulltext'} unless $debug; |
836 | - return 1; |
837 | -} |
838 | - |
839 | -sub parse_wait_array { |
840 | - my ( $text, $complete, $debug, $full ) = @_; |
841 | - my %result; |
842 | - |
843 | - @result{ qw(thread waited_at_filename waited_at_line waited_secs) } |
844 | - = $text =~ m/^--Thread $d has waited at $fl for $f seconds/m; |
845 | - |
846 | - # Depending on whether it's a SYNC_MUTEX,RW_LOCK_EX,RW_LOCK_SHARED, |
847 | - # there will be different text output |
848 | - if ( $text =~ m/^Mutex at/m ) { |
849 | - $result{'request_type'} = 'M'; |
850 | - @result{ qw( lock_mem_addr lock_cfile_name lock_cline lock_var) } |
851 | - = $text =~ m/^Mutex at $h created file $fl, lock var $d$/m; |
852 | - @result{ qw( waiters_flag )} |
853 | - = $text =~ m/^waiters flag $d$/m; |
854 | - } |
855 | - else { |
856 | - @result{ qw( request_type lock_mem_addr lock_cfile_name lock_cline) } |
857 | - = $text =~ m/^(.)-lock on RW-latch at $h created in file $fl$/m; |
858 | - @result{ qw( writer_thread writer_lock_mode ) } |
859 | - = $text =~ m/^a writer \(thread id $d\) has reserved it in mode (.*)$/m; |
860 | - @result{ qw( num_readers waiters_flag )} |
861 | - = $text =~ m/^number of readers $d, waiters flag $d$/m; |
862 | - @result{ qw(last_s_file_name last_s_line ) } |
863 | - = $text =~ m/Last time read locked in file $fl$/m; |
864 | - @result{ qw(last_x_file_name last_x_line ) } |
865 | - = $text =~ m/Last time write locked in file $fl$/m; |
866 | - } |
867 | - |
868 | - $result{'cell_waiting'} = $text =~ m/^wait has ended$/m ? 0 : 1; |
869 | - $result{'cell_event_set'} = $text =~ m/^wait is ending$/m ? 1 : 0; |
870 | - |
871 | - # Because there are two code paths, some things won't get set. |
872 | - map { $result{$_} ||= '' } |
873 | - qw(last_s_file_name last_x_file_name writer_lock_mode); |
874 | - map { $result{$_} ||= 0 } |
875 | - qw(num_readers lock_var last_s_line last_x_line writer_thread); |
876 | - |
877 | - return \%result; |
878 | -} |
879 | - |
880 | -sub parse_sm_section { |
881 | - my ( $section, $complete, $debug, $full ) = @_; |
882 | - return 0 unless $section && $section->{'fulltext'}; |
883 | - my $fulltext = $section->{'fulltext'}; |
884 | - |
885 | - # Grab the info |
886 | - @{$section}{ 'reservation_count', 'signal_count' } |
887 | - = $fulltext =~ m/^OS WAIT ARRAY INFO: reservation count $d, signal count $d$/m; |
888 | - @{$section}{ 'mutex_spin_waits', 'mutex_spin_rounds', 'mutex_os_waits' } |
889 | - = $fulltext =~ m/^Mutex spin waits $d, rounds $d, OS waits $d$/m; |
890 | - @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits', 'rw_excl_spins', 'rw_excl_os_waits' } |
891 | - = $fulltext =~ m/^RW-shared spins $d, OS waits $d; RW-excl spins $d, OS waits $d$/m; |
892 | - |
893 | - # Look for info on waits. |
894 | - my @waits = $fulltext =~ m/^(--Thread.*?)^(?=Mutex spin|--Thread)/gms; |
895 | - $section->{'waits'} = [ map { parse_wait_array($_, $complete, $debug) } @waits ]; |
896 | - $section->{'wait_array_size'} = scalar(@waits); |
897 | - |
898 | - delete $section->{'fulltext'} unless $debug; |
899 | - return 1; |
900 | -} |
901 | - |
902 | -# I've read the source for this section. |
903 | -sub parse_bp_section { |
904 | - my ( $section, $complete, $debug, $full ) = @_; |
905 | - return unless $section && $section->{'fulltext'}; |
906 | - my $fulltext = $section->{'fulltext'}; |
907 | - |
908 | - # Grab the info |
909 | - @{$section}{ 'total_mem_alloc', 'add_pool_alloc' } |
910 | - = $fulltext =~ m/^Total memory allocated $d; in additional pool allocated $d$/m; |
911 | - @{$section}{'dict_mem_alloc'} = $fulltext =~ m/Dictionary memory allocated $d/; |
912 | - @{$section}{'awe_mem_alloc'} = $fulltext =~ m/$d MB of AWE memory/; |
913 | - @{$section}{'buf_pool_size'} = $fulltext =~ m/^Buffer pool size\s*$d$/m; |
914 | - @{$section}{'buf_free'} = $fulltext =~ m/^Free buffers\s*$d$/m; |
915 | - @{$section}{'pages_total'} = $fulltext =~ m/^Database pages\s*$d$/m; |
916 | - @{$section}{'pages_modified'} = $fulltext =~ m/^Modified db pages\s*$d$/m; |
917 | - @{$section}{'pages_read', 'pages_created', 'pages_written'} |
918 | - = $fulltext =~ m/^Pages read $d, created $d, written $d$/m; |
919 | - @{$section}{'page_reads_sec', 'page_creates_sec', 'page_writes_sec'} |
920 | - = $fulltext =~ m{^$f reads/s, $f creates/s, $f writes/s$}m; |
921 | - @{$section}{'buf_pool_hits', 'buf_pool_reads'} |
922 | - = $fulltext =~ m{Buffer pool hit rate $d / $d$}m; |
923 | - if ($fulltext =~ m/^No buffer pool page gets since the last printout$/m) { |
924 | - @{$section}{'buf_pool_hits', 'buf_pool_reads'} = (0, 0); |
925 | - @{$section}{'buf_pool_hit_rate'} = '--'; |
926 | - } |
927 | - else { |
928 | - @{$section}{'buf_pool_hit_rate'} |
929 | - = $fulltext =~ m{Buffer pool hit rate (\d+ / \d+)$}m; |
930 | - } |
931 | - @{$section}{'reads_pending'} = $fulltext =~ m/^Pending reads $d/m; |
932 | - @{$section}{'writes_pending_lru', 'writes_pending_flush_list', 'writes_pending_single_page' } |
933 | - = $fulltext =~ m/^Pending writes: LRU $d, flush list $d, single page $d$/m; |
934 | - |
935 | - map { $section->{$_} ||= 0 } |
936 | - qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page |
937 | - awe_mem_alloc dict_mem_alloc); |
938 | - @{$section}{'writes_pending'} = List::Util::sum( |
939 | - @{$section}{ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page) }); |
940 | - |
941 | - delete $section->{'fulltext'} unless $debug; |
942 | - return 1; |
943 | -} |
944 | - |
945 | -# I've read the source for this. |
946 | -sub parse_io_section { |
947 | - my ( $section, $complete, $debug, $full ) = @_; |
948 | - return unless $section && $section->{'fulltext'}; |
949 | - my $fulltext = $section->{'fulltext'}; |
950 | - $section->{'threads'} = {}; |
951 | - |
952 | - # Grab the I/O thread info |
953 | - my @threads = $fulltext =~ m<^(I/O thread \d+ .*)$>gm; |
954 | - foreach my $thread (@threads) { |
955 | - my ( $tid, $state, $purpose, $event_set ) |
956 | - = $thread =~ m{I/O thread $d state: (.+?) \((.*)\)(?: ev set)?$}m; |
957 | - if ( defined $tid ) { |
958 | - $section->{'threads'}->{$tid} = { |
959 | - thread => $tid, |
960 | - state => $state, |
961 | - purpose => $purpose, |
962 | - event_set => $event_set ? 1 : 0, |
963 | - }; |
964 | - } |
965 | - } |
966 | - |
967 | - # Grab the reads/writes/flushes info |
968 | - @{$section}{ 'pending_normal_aio_reads', 'pending_aio_writes' } |
969 | - = $fulltext =~ m/^Pending normal aio reads: $d, aio writes: $d,$/m; |
970 | - @{$section}{ 'pending_ibuf_aio_reads', 'pending_log_ios', 'pending_sync_ios' } |
971 | - = $fulltext =~ m{^ ibuf aio reads: $d, log i/o's: $d, sync i/o's: $d$}m; |
972 | - @{$section}{ 'flush_type', 'pending_log_flushes', 'pending_buffer_pool_flushes' } |
973 | - = $fulltext =~ m/^Pending flushes \($w\) log: $d; buffer pool: $d$/m; |
974 | - @{$section}{ 'os_file_reads', 'os_file_writes', 'os_fsyncs' } |
975 | - = $fulltext =~ m/^$d OS file reads, $d OS file writes, $d OS fsyncs$/m; |
976 | - @{$section}{ 'reads_s', 'avg_bytes_s', 'writes_s', 'fsyncs_s' } |
977 | - = $fulltext =~ m{^$f reads/s, $d avg bytes/read, $f writes/s, $f fsyncs/s$}m; |
978 | - @{$section}{ 'pending_preads', 'pending_pwrites' } |
979 | - = $fulltext =~ m/$d pending preads, $d pending pwrites$/m; |
980 | - @{$section}{ 'pending_preads', 'pending_pwrites' } = (0, 0) |
981 | - unless defined($section->{'pending_preads'}); |
982 | - |
983 | - delete $section->{'fulltext'} unless $debug; |
984 | - return 1; |
985 | -} |
986 | - |
987 | -sub _debug { |
988 | - my ( $debug, $msg ) = @_; |
989 | - if ( $debug ) { |
990 | - die $msg; |
991 | - } |
992 | - else { |
993 | - warn $msg; |
994 | - } |
995 | - return 1; |
996 | -} |
997 | - |
998 | -1; |
999 | - |
1000 | -# end_of_package |
1001 | -# ############################################################################ |
1002 | -# Perldoc section. I put this last as per the Dog book. |
1003 | -# ############################################################################ |
1004 | -=pod |
1005 | - |
1006 | -=head1 NAME |
1007 | - |
1008 | -InnoDBParser - Parse InnoDB monitor text. |
1009 | - |
1010 | -=head1 DESCRIPTION |
1011 | - |
1012 | -InnoDBParser tries to parse the output of the InnoDB monitor. One way to get |
1013 | -this output is to connect to a MySQL server and issue the command SHOW ENGINE |
1014 | -INNODB STATUS (omit 'ENGINE' on earlier versions of MySQL). The goal is to |
1015 | -turn text into data that something else (e.g. innotop) can use. |
1016 | - |
1017 | -The output comes from all over, but the place to start in the source is |
1018 | -innobase/srv/srv0srv.c. |
1019 | - |
1020 | -=head1 SYNOPSIS |
1021 | - |
1022 | - use InnoDBParser; |
1023 | - use DBI; |
1024 | - |
1025 | - # Get the status text. |
1026 | - my $dbh = DBI->connect( |
1027 | - "DBI::mysql:test;host=localhost", |
1028 | - 'user', |
1029 | - 'password' |
1030 | - ); |
1031 | - my $query = 'SHOW /*!5 ENGINE */ INNODB STATUS'; |
1032 | - my $text = $dbh->selectcol_arrayref($query)->[0]; |
1033 | - |
1034 | - # 1 or 0 |
1035 | - my $debug = 1; |
1036 | - |
1037 | - # Choose sections of the monitor text you want. Possible values: |
1038 | - # TRANSACTIONS => tx |
1039 | - # BUFFER POOL AND MEMORY => bp |
1040 | - # SEMAPHORES => sm |
1041 | - # LOG => lg |
1042 | - # ROW OPERATIONS => ro |
1043 | - # INSERT BUFFER AND ADAPTIVE HASH INDEX => ib |
1044 | - # FILE I/O => io |
1045 | - # LATEST DETECTED DEADLOCK => dl |
1046 | - # LATEST FOREIGN KEY ERROR => fk |
1047 | - |
1048 | - my $required_sections = { |
1049 | - tx => 1, |
1050 | - }; |
1051 | - |
1052 | - # Parse the status text. |
1053 | - my $parser = InnoDBParser->new; |
1054 | - $innodb_status = $parser->parse_status_text( |
1055 | - $text, |
1056 | - $debug, |
1057 | - # Omit the following parameter to get all sections. |
1058 | - $required_sections, |
1059 | - ); |
1060 | - |
1061 | -=head1 COPYRIGHT, LICENSE AND WARRANTY |
1062 | - |
1063 | -This package is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com. |
1064 | -Feedback and improvements are gratefully received. |
1065 | - |
1066 | -THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
1067 | -WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
1068 | -MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
1069 | - |
1070 | -This program is free software; you can redistribute it and/or modify it under |
1071 | -the terms of the GNU General Public License as published by the Free Software |
1072 | -Foundation, version 2; OR the Perl Artistic License. On UNIX and similar |
1073 | -systems, you can issue `man perlgpl' or `man perlartistic' to read these |
1074 | -licenses. |
1075 | - |
1076 | -You should have received a copy of the GNU General Public License along with |
1077 | -this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
1078 | -Place, Suite 330, Boston, MA 02111-1307 USA |
1079 | - |
1080 | -=head1 AUTHOR |
1081 | - |
1082 | -Baron Schwartz, baron at xaprb dot com. |
1083 | - |
1084 | -=head1 BUGS |
1085 | - |
1086 | -None known, but I bet there are some. The InnoDB monitor text wasn't really |
1087 | -designed to be parsable. |
1088 | - |
1089 | -=head1 SEE ALSO |
1090 | - |
1091 | -innotop - a program that can format the parsed status information for humans |
1092 | -to read and enjoy. |
1093 | - |
1094 | -=cut |
1095 | |
1096 | === removed file 'build/debian/additions/innotop/changelog.innotop' |
1097 | --- build/debian/additions/innotop/changelog.innotop 2010-05-31 13:57:21 +0000 |
1098 | +++ build/debian/additions/innotop/changelog.innotop 1970-01-01 00:00:00 +0000 |
1099 | @@ -1,318 +0,0 @@ |
1100 | -Changelog for innotop and InnoDBParser: |
1101 | - |
1102 | -2007-11-09: version 1.6.0 |
1103 | - |
1104 | - * S mode crashed on non-numeric values. |
1105 | - * New user-defined columns crashed upon restart. |
1106 | - * Added --color option to control terminal coloring. |
1107 | - |
1108 | -2007-09-18: version 1.5.2 |
1109 | - |
1110 | - * Added the ability to monitor InnoDB status from a file. |
1111 | - * Changed W mode to L mode; it monitors all locks, not just lock waits. |
1112 | - |
1113 | -2007-09-16: version 1.5.1 |
1114 | - |
1115 | - * Added C (Command Summary) mode. |
1116 | - * Fixed a bug in the 'avg' aggregate function. |
1117 | - |
1118 | -2007-09-10: version 1.5.0 |
1119 | - |
1120 | - Changes: |
1121 | - * Added plugin functionality. |
1122 | - * Added group-by functionality. |
1123 | - * Moved the configuration file to a directory. |
1124 | - * Enhanced filtering and sorting on pivoted tables. |
1125 | - * Many small bug fixes. |
1126 | - |
1127 | -2007-07-16: version 1.4.3 |
1128 | - |
1129 | - Changes: |
1130 | - * Added standard --version command-line option |
1131 | - * Changed colors to cyan instead of blue; more visible on dark terminals. |
1132 | - * Added information to the filter-choosing dialog. |
1133 | - * Added column auto-completion when entering a filter expression. |
1134 | - * Changed Term::ReadKey from optional to mandatory. |
1135 | - * Clarified username in password prompting. |
1136 | - * Ten thousand words of documentation! |
1137 | - |
1138 | - Bugs fixed: |
1139 | - * innotop crashed in W mode when InnoDB status data was truncated. |
1140 | - * innotop didn't display errors in tables if debug was enabled. |
1141 | - * The colored() subroutine wasn't being created in non-interactive mode. |
1142 | - * Don't prompt to save password except the first time. |
1143 | - |
1144 | -2007-05-03: version 1.4.2 |
1145 | - |
1146 | - This version contains all changes to the trunk until revision 239; some |
1147 | - changes in revisions 240:250 are included. |
1148 | - |
1149 | - MAJOR CHANGES: |
1150 | - |
1151 | - * Quick-filters to easily filter any column in any display |
1152 | - * Compatibility with MySQL 3.23 through 6.0 |
1153 | - * Improved error handling when a server is down, permissions denied, etc |
1154 | - * Use additional SHOW INNODB STATUS information in 5.1.x |
1155 | - * Make all modes use tables consistently, so they can all be edited, |
1156 | - filtered, colored and sorted consistently |
1157 | - * Combine V, G and S modes into S mode, with v, g, and s hot-keys |
1158 | - * Let DBD driver read MySQL option files; permit connections without |
1159 | - user/pass/etc |
1160 | - * Compile SQL-like expressions into Perl subroutines; eliminate need to |
1161 | - know Perl |
1162 | - * Do not save all config data to config file, only save user's customizations |
1163 | - * Rewritten and improved command-line option handling |
1164 | - * Added --count, --delay, and other command-line options to support |
1165 | - run-and-exit operation |
1166 | - * Improve built-in variable sets |
1167 | - * Improve help screen with three-part balanced-column layout |
1168 | - * Simplify table-editor and improve hotkey support |
1169 | - * Require Perl to have high-resolution time support (Time::HiRes) |
1170 | - * Help the user choose a query to analyze or kill |
1171 | - * Enable EXPLAIN, show-full-query in T mode just like Q mode |
1172 | - * Let data-extraction access current, previous and incremental data sets |
1173 | - all at once |
1174 | - |
1175 | - MINOR CHANGES: |
1176 | - |
1177 | - * Column stabilizing for Q mode |
1178 | - * New color rules for T, Q, W modes |
1179 | - * Apply slave I/O filter to Q mode |
1180 | - * Improve detection of server version and other meta-data |
1181 | - * Make connection timeout a config variable |
1182 | - * Improve cross-version-compatible SQL syntax |
1183 | - * Get some information from the DBD driver instead of asking MySQL for it |
1184 | - * Improved error messages |
1185 | - * Improve server group creation/editing |
1186 | - * Improve connection/thread killing |
1187 | - * Fix broken key bindings and restore previously mapped hot-keys for |
1188 | - choosing columns |
1189 | - * Some documentation updates (but not nearly enough) |
1190 | - * Allow the user to specify graphing char in S mode (formerly G mode) |
1191 | - * Allow easy switching between variable sets in S mode |
1192 | - * Bind 'n' key globally to choose the 'next' server connection |
1193 | - * Bind '%' key globally to filter displayed tables |
1194 | - * Allow aligning columns on the decimal place for easy readability |
1195 | - * Add hide_hdr config variable to hide column headers in tables |
1196 | - * Add a feature to smartly run PURGE MASTER LOGS in Replication mode |
1197 | - * Enable debug mode as a globally configurable variable |
1198 | - * Improve error messages when an expression or filter doesn't compile or has |
1199 | - a run-time error; die on error when debug is enabled |
1200 | - * Allow user-configurable delays after executing SQL (to let the server |
1201 | - settle down before taking another measurement) |
1202 | - * Add an expression to show how long until a transaction is finished |
1203 | - * Add skip_innodb as a global config variable |
1204 | - * Add '%' after percentages to help disambiguate (user-configurable) |
1205 | - * Add column to M mode to help see how fast slave is catching up to master |
1206 | - |
1207 | - BUG FIXES: |
1208 | - |
1209 | - * T and W modes had wrong value for wait_status column |
1210 | - * Error tracking on connections didn't reset when the connection recovered |
1211 | - * wait_timeout on connections couldn't be set before MySQL 4.0.3 |
1212 | - * There was a crash on 3.23 when wiping deadlocks |
1213 | - * Lettercase changes in some result sets (SHOW MASTER/SLAVE STATUS) between |
1214 | - MySQL versions crashed innotop |
1215 | - * Inactive connections crashed innotop upon access to DBD driver |
1216 | - * set_precision did not respect user defaults for number of digits |
1217 | - * --inc command-line option could not be negated |
1218 | - * InnoDB status parsing was not always parsing all needed information |
1219 | - * S mode (formerly G mode) could crash trying to divide non-numeric data |
1220 | - * M table didn't show Slave_open_temp_tables variable; incorrect lettercase |
1221 | - * DBD drivers with broken AutoCommit would crash innotop |
1222 | - * Some key bindings had incorrect labels |
1223 | - * Some config-file loading routines could load data for things that didn't |
1224 | - exist |
1225 | - * Headers printed too often in S mode |
1226 | - * High-resolution time was not used even when the user had it |
1227 | - * Non-interactive mode printed blank lines sometimes |
1228 | - * Q-mode header and statusbar showed different QPS numbers |
1229 | - * Formulas for key-cache and query-cache hit ratios were wrong |
1230 | - * Mac OS "Darwin" machines were mis-identified as Microsoft Windows |
1231 | - * Some multiplications crashed when given undefined input |
1232 | - * The commify transformation did not check its input and could crash |
1233 | - * Specifying an invalid mode on the command line or config file could crash |
1234 | - innotop |
1235 | - |
1236 | -2007-03-29: version 1.4.1 |
1237 | - |
1238 | - * More tweaks to display of connection errors. |
1239 | - * Fixed a problem with skip-innodb in MySQL 5.1. |
1240 | - * Fix a bug with dead connections in single-connection mode. |
1241 | - * Fix a regex to allow parsing more data from truncated deadlocks. |
1242 | - * Don't load active cxns from the config file if the cxn isn't defined. |
1243 | - |
1244 | -2007-03-03: version 1.4.0 |
1245 | - |
1246 | - * Further tweak error handling and display of connection errors |
1247 | - * More centralization of querying |
1248 | - * Fix forking so it doesn't kill all database connections |
1249 | - * Allow user to run innotop without permissions for GLOBAL variables and status |
1250 | - |
1251 | -2007-02-11: version 1.3.6 |
1252 | - |
1253 | - * Handle some connection failures so innotop doesn't crash because of one server. |
1254 | - * Enable incremental display in more modes. |
1255 | - * Tweaks to colorizing, color editor, and default color rules. |
1256 | - * Tweaks to default sorting rules. |
1257 | - * Use prepared statements for efficiency. |
1258 | - * Bug fixes and code cleanups. |
1259 | - * Data storage is keyed on clock ticks now. |
1260 | - |
1261 | -2007-02-03: version 1.3.5 |
1262 | - |
1263 | - * Bug fixes. |
1264 | - * More tools for editing configuration from within innotop. |
1265 | - * Filters and transformations are constrained to valid values. |
1266 | - * Support for colorizing rows. |
1267 | - * Sorting by multiple columns. |
1268 | - * Compress headers when display is very wide. |
1269 | - * Stabilize and limit column widths. |
1270 | - * Check config file formats when upgrading so upgrades go smoothly. |
1271 | - * Make D mode handle many connections at once. |
1272 | - * Extract simple expressions from data sets in column src property. |
1273 | - This makes innotop more awk-ish. |
1274 | - |
1275 | -2007-01-16: version 1.3 |
1276 | - |
1277 | - * Readline support. |
1278 | - * Can be used unattended, or in a pipe-and-filter mode |
1279 | - where it outputs tab-separated data to standard output. |
1280 | - * You can specify a config file on the command line. |
1281 | - Config files can be marked read-only. |
1282 | - * Monitor multiple servers simultaneously. |
1283 | - * Server groups to help manage many servers conveniently. |
1284 | - * Monitor master/slave status, and control slaves. |
1285 | - * Columns can have user-defined expressions as their data sources. |
1286 | - * Better configuration tools. |
1287 | - * InnoDB status information is merged into SHOW VARIABLES and |
1288 | - SHOW STATUS information, so you can access it all together. |
1289 | - * High-precision time support in more places. |
1290 | - * Lots of tweaks to make things display more readably and compactly. |
1291 | - * Column transformations and filters. |
1292 | - |
1293 | -2007-01-16: version 1.0.1 |
1294 | - * NOTE: innotop is now hosted at Sourceforge, in Subversion not CVS. |
1295 | - The new project homepage is http://sourceforge.net/projects/innotop/ |
1296 | - * Tweak default T/Q mode sort columns to match what people expect. |
1297 | - * Fix broken InnoDBParser.pm documentation (and hence man page). |
1298 | - |
1299 | -2007-01-06: version 1.0 |
1300 | - * NOTE: innotop is now hosted at Sourceforge, in Subversion not CVS. |
1301 | - The new project homepage is http://sourceforge.net/projects/innotop/ |
1302 | - * Prevent control characters from freaking terminal out. |
1303 | - * Set timeout to keep busy servers from closing connection. |
1304 | - * There is only one InnoDB insert buffer. |
1305 | - * Make licenses clear and consistent. |
1306 | - |
1307 | -2006-11-14: innotop 0.1.160, InnoDBParser version 1.69 |
1308 | - * Support for ANSI color on Microsoft Windows (more readable, compact |
1309 | - display; thanks Gisbert W. Selke). |
1310 | - * Better handling of $ENV{HOME} on Windows. |
1311 | - * Added a LICENSE file to the package as per Gentoo bug: |
1312 | - http://bugs.gentoo.org/show_bug.cgi?id=147600 |
1313 | - |
1314 | -2006-11-11: innotop 0.1.157, InnoDBParser version 1.69 |
1315 | - * Add Microsoft Windows support. |
1316 | - |
1317 | -2006-10-19: innotop 0.1.154, InnoDBParser version 1.69 |
1318 | - * Add O (Open Tables) mode |
1319 | - * Add some more checks to handle incomplete InnoDB status information |
1320 | - |
1321 | -2006-09-30: innotop 0.1.152, InnoDBParser version 1.69 |
1322 | - * Figured out what was wrong with package $VERSION variable: it wasn't |
1323 | - after the package declaration! |
1324 | - |
1325 | -2006-09-28: innotop 0.1.152, InnoDBParser version 1.67 |
1326 | - * Make more efforts towards crash-resistance and tolerance of completely |
1327 | - messed-up inputs. If innotop itself is broken, it is now much harder to |
1328 | - tell, because it just keeps on running without complaining. |
1329 | - * Fix a small bug parsing out some information and displaying it. |
1330 | - |
1331 | -2006-09-05: innotop 0.1.149, InnoDBParser version 1.64 |
1332 | - * Try to find and eliminate any parsing code that assumes pattern matches |
1333 | - will succeed. |
1334 | - |
1335 | -2006-09-05: innotop 0.1.149, InnoDBParser version 1.62 |
1336 | - * Make innotop crash-resistant, so I can declare it STABLE finally. |
1337 | - * Instead of using SQL conditional comments, detect MySQL version. |
1338 | - |
1339 | -2006-08-22: innotop 0.1.147, InnoDBParser version 1.60 |
1340 | - * Fix some innotop bugs with undefined values, bad formatting etc. |
1341 | - |
1342 | -2006-08-19: innotop 0.1.146, InnoDBParser version 1.60 |
1343 | - * Make innotop handle some unexpected NULL values in Q mode. |
1344 | - * Add OS wait information to W mode, so it is now "everything that waits." |
1345 | - * Center section captions better. |
1346 | - * Make R mode more readable and compact. |
1347 | - * Make InnoDBParser parse lock waits even when they've been waiting 0 secs. |
1348 | - |
1349 | -2006-08-12: innotop 0.1.139, InnoDBParser version 1.59 |
1350 | - * Add more documentation |
1351 | - * Tweak V mode to show more info in less space. |
1352 | - * Fix a bug in G mode. |
1353 | - |
1354 | -2006-08-10: innotop 0.1.132, InnoDBParser version 1.58 |
1355 | - * Handle yet more types of FK error... it will never end! |
1356 | - * Handle some special cases when DEADLOCK info truncated |
1357 | - * Add a bit more FK info to F mode in innotop |
1358 | - * More tests added to the test suite |
1359 | - |
1360 | -2006-08-07: innotop 0.1.131, InnoDBParser version 1.55 |
1361 | - * Fix another issue with configuration |
1362 | - * Handle another type of FK error |
1363 | - |
1364 | -2006-08-03: innotop 0.1.130, InnoDBParser version 1.54 |
1365 | - * Fix an issue loading config file |
1366 | - * Add heap_no to 'D' (InnoDB Deadlock) mode to ease deadlock debugging. |
1367 | - |
1368 | -2006-08-02: innotop 0.1.128, InnoDBParser version 1.54 |
1369 | - * Parse lock wait information from the TRANSACTION section. |
1370 | - * Even more OS-specific parsing... pain in the butt... |
1371 | - * Add 'W' (InnoDB Lock Wait) mode. |
1372 | - * Fix some minor display issues with statusbar. |
1373 | - |
1374 | -2006-08-02: innotop 0.1.125, InnoDBParser version 1.50 |
1375 | - * Don't try to get references to Perl built-in functions like time() |
1376 | - * Handle more OS-specific variations of InnoDB status text |
1377 | - * Add some more information to various places in innotop |
1378 | - |
1379 | -2006-08-01: innotop 0.1.123, InnoDBParser version 1.47 |
1380 | - |
1381 | - * Enhance S and G modes: clear screen and re-print headers |
1382 | - * Don't crash when deadlock data is truncated |
1383 | - * Make Analyze mode say how to get back to whatever you came from |
1384 | - * Display 'nothing to display' when there is nothing |
1385 | - * Add ability to read InnoDB status text from a file (mostly helps test) |
1386 | - * Add table of Wait Array Information in Row Op/Semaphore mode |
1387 | - * Add table of lock information in InnoDB deadlock mode |
1388 | - * Ensure new features in upgrades don't get masked by existing config files |
1389 | - * Tweak default column choices for T mode |
1390 | - * Enhance foreign key parsing |
1391 | - * Enhance physical record and data tuple parsing |
1392 | - * Enhance lock parsing (handle old-style and new-style formats) |
1393 | - |
1394 | -2006-07-24: innotop 0.1.112, InnoDBParser version 1.36 |
1395 | - |
1396 | - * InnoDBParser enhancements for FK error messages. |
1397 | - * A fix to innotop to prevent it from crashing while trying to display a FK |
1398 | - error message. |
1399 | - * Some minor cosmetic changes to number formatting in innotop. |
1400 | - |
1401 | -2006-07-22: innotop 0.1.106, InnoDBParser version 1.35 |
1402 | - |
1403 | - * InnoDBParser is much more complete and accurate. |
1404 | - * Tons of bug fixes. |
1405 | - * Add partitions to EXPLAIN mode. |
1406 | - * Enhance Q mode header, add T mode header. |
1407 | - * Share some configuration variables across modes. |
1408 | - * Add formatted time columns to Q, T modes. |
1409 | - * Add command-line argument parsing. |
1410 | - * Turn off echo when asking for password. |
1411 | - * Add option to specify port when connecting. |
1412 | - * Let display-optimized-query display multiple notes. |
1413 | - * Lots of small improvements, such as showing more info in statusbar. |
1414 | - |
1415 | -2006-07-02: innotop 0.1.74, InnoDBParser version 1.24 |
1416 | - |
1417 | - * Initial release for public consumption. |
1418 | |
1419 | === removed file 'build/debian/additions/innotop/innotop' |
1420 | --- build/debian/additions/innotop/innotop 2010-05-31 13:57:21 +0000 |
1421 | +++ build/debian/additions/innotop/innotop 1970-01-01 00:00:00 +0000 |
1422 | @@ -1,9485 +0,0 @@ |
1423 | -#!/usr/bin/perl |
1424 | - |
1425 | -# vim: tw=160:nowrap:expandtab:tabstop=3:shiftwidth=3:softtabstop=3 |
1426 | - |
1427 | -use strict; |
1428 | -use warnings FATAL => 'all'; |
1429 | -use sigtrap qw(handler finish untrapped normal-signals); |
1430 | - |
1431 | -use Data::Dumper; |
1432 | -use DBI; |
1433 | -use English qw(-no_match_vars); |
1434 | -use File::Basename qw(dirname); |
1435 | -use Getopt::Long; |
1436 | -use List::Util qw(max min maxstr sum); |
1437 | -use InnoDBParser; |
1438 | -use POSIX qw(ceil); |
1439 | -use Time::HiRes qw(time sleep); |
1440 | -use Term::ReadKey qw(ReadMode ReadKey); |
1441 | - |
1442 | -# Version, license and warranty information. {{{1 |
1443 | -# ########################################################################### |
1444 | -our $VERSION = '1.6.0'; |
1445 | -our $SVN_REV = sprintf("%d", q$Revision: 383 $ =~ m/(\d+)/g); |
1446 | -our $SVN_URL = sprintf("%s", q$URL: https://innotop.svn.sourceforge.net/svnroot/innotop/trunk/innotop $ =~ m$svnroot/innotop/(\S+)$g); |
1447 | - |
1448 | -my $innotop_license = <<"LICENSE"; |
1449 | - |
1450 | -This is innotop version $VERSION, a MySQL and InnoDB monitor. |
1451 | - |
1452 | -This program is copyright (c) 2006 Baron Schwartz. |
1453 | -Feedback and improvements are welcome. |
1454 | - |
1455 | -THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED |
1456 | -WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF |
1457 | -MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
1458 | - |
1459 | -This program is free software; you can redistribute it and/or modify it under |
1460 | -the terms of the GNU General Public License as published by the Free Software |
1461 | -Foundation, version 2; OR the Perl Artistic License. On UNIX and similar |
1462 | -systems, you can issue `man perlgpl' or `man perlartistic' to read these |
1463 | -licenses. |
1464 | - |
1465 | -You should have received a copy of the GNU General Public License along with |
1466 | -this program; if not, write to the Free Software Foundation, Inc., 59 Temple |
1467 | -Place, Suite 330, Boston, MA 02111-1307 USA. |
1468 | -LICENSE |
1469 | - |
1470 | -# Configuration information and global setup {{{1 |
1471 | -# ########################################################################### |
1472 | - |
1473 | -# Really, really, super-global variables. |
1474 | -my @config_versions = ( |
1475 | - "000-000-000", "001-003-000", # config file was one big name-value hash. |
1476 | - "001-003-000", "001-004-002", # config file contained non-user-defined stuff. |
1477 | -); |
1478 | - |
1479 | -my $clear_screen_sub; |
1480 | - |
1481 | -# This defines expected properties and defaults for the column definitions that |
1482 | -# eventually end up in tbl_meta. |
1483 | -my %col_props = ( |
1484 | - hdr => '', |
1485 | - just => '-', |
1486 | - dec => 0, # Whether to align the column on the decimal point |
1487 | - num => 0, |
1488 | - label => '', |
1489 | - user => 0, |
1490 | - src => '', |
1491 | - tbl => '', # Helps when writing/reading custom columns in config files |
1492 | - minw => 0, |
1493 | - maxw => 0, |
1494 | - trans => [], |
1495 | - agg => 'first', # Aggregate function |
1496 | - aggonly => 0, # Whether to show only when tbl_meta->{aggregate} is true |
1497 | -); |
1498 | - |
1499 | -# Actual DBI connections to MySQL servers. |
1500 | -my %dbhs; |
1501 | - |
1502 | -# Command-line parameters {{{2 |
1503 | -# ########################################################################### |
1504 | - |
1505 | -my @opt_spec = ( |
1506 | - { s => 'help', d => 'Show this help message' }, |
1507 | - { s => 'color|C!', d => 'Use terminal coloring (default)', c => 'color' }, |
1508 | - { s => 'config|c=s', d => 'Config file to read' }, |
1509 | - { s => 'nonint|n', d => 'Non-interactive, output tab-separated fields' }, |
1510 | - { s => 'count=i', d => 'Number of updates before exiting' }, |
1511 | - { s => 'delay|d=f', d => 'Delay between updates in seconds', c => 'interval' }, |
1512 | - { s => 'mode|m=s', d => 'Operating mode to start in', c => 'mode' }, |
1513 | - { s => 'inc|i!', d => 'Measure incremental differences', c => 'status_inc' }, |
1514 | - { s => 'version', d => 'Output version information and exit' }, |
1515 | -); |
1516 | - |
1517 | -# This is the container for the command-line options' values to be stored in |
1518 | -# after processing. Initial values are defaults. |
1519 | -my %opts = ( |
1520 | - n => !( -t STDIN && -t STDOUT ), # If in/out aren't to terminals, we're interactive |
1521 | -); |
1522 | -# Post-process... |
1523 | -my %opt_seen; |
1524 | -foreach my $spec ( @opt_spec ) { |
1525 | - my ( $long, $short ) = $spec->{s} =~ m/^(\w+)(?:\|([^!+=]*))?/; |
1526 | - $spec->{k} = $short || $long; |
1527 | - $spec->{l} = $long; |
1528 | - $spec->{t} = $short; |
1529 | - $spec->{n} = $spec->{s} =~ m/!/; |
1530 | - $opts{$spec->{k}} = undef unless defined $opts{$spec->{k}}; |
1531 | - die "Duplicate option $spec->{k}" if $opt_seen{$spec->{k}}++; |
1532 | -} |
1533 | - |
1534 | -Getopt::Long::Configure('no_ignore_case', 'bundling'); |
1535 | -GetOptions( map { $_->{s} => \$opts{$_->{k}} } @opt_spec) or $opts{help} = 1; |
1536 | - |
1537 | -if ( $opts{version} ) { |
1538 | - print "innotop Ver $VERSION Changeset $SVN_REV from $SVN_URL\n"; |
1539 | - exit(0); |
1540 | -} |
1541 | - |
1542 | -if ( $opts{'help'} ) { |
1543 | - print "Usage: innotop <options> <innodb-status-file>\n\n"; |
1544 | - my $maxw = max(map { length($_->{l}) + ($_->{n} ? 4 : 0)} @opt_spec); |
1545 | - foreach my $spec ( sort { $a->{l} cmp $b->{l} } @opt_spec ) { |
1546 | - my $long = $spec->{n} ? "[no]$spec->{l}" : $spec->{l}; |
1547 | - my $short = $spec->{t} ? "-$spec->{t}" : ''; |
1548 | - printf(" --%-${maxw}s %-4s %s\n", $long, $short, $spec->{d}); |
1549 | - } |
1550 | - print <<USAGE; |
1551 | - |
1552 | -innotop is a MySQL and InnoDB transaction/status monitor, like 'top' for |
1553 | -MySQL. It displays queries, InnoDB transactions, lock waits, deadlocks, |
1554 | -foreign key errors, open tables, replication status, buffer information, |
1555 | -row operations, logs, I/O operations, load graph, and more. You can |
1556 | -monitor many servers at once with innotop. |
1557 | - |
1558 | -USAGE |
1559 | - exit(1); |
1560 | -} |
1561 | - |
1562 | -# Meta-data (table definitions etc) {{{2 |
1563 | -# ########################################################################### |
1564 | - |
1565 | -# Expressions {{{3 |
1566 | -# Convenience so I can copy/paste these in several places... |
1567 | -# ########################################################################### |
1568 | -my %exprs = ( |
1569 | - Host => q{my $host = host || hostname || ''; ($host) = $host =~ m/^((?:[\d.]+(?=:))|(?:[a-zA-Z]\w+))/; return $host || ''}, |
1570 | - Port => q{my ($p) = host =~ m/:(.*)$/; return $p || 0}, |
1571 | - OldVersions => q{dulint_to_int(IB_tx_trx_id_counter) - dulint_to_int(IB_tx_purge_done_for)}, |
1572 | - MaxTxnTime => q/max(map{ $_->{active_secs} } @{ IB_tx_transactions }) || 0/, |
1573 | - NumTxns => q{scalar @{ IB_tx_transactions } }, |
1574 | - DirtyBufs => q{ $cur->{IB_bp_pages_modified} / ($cur->{IB_bp_buf_pool_size} || 1) }, |
1575 | - BufPoolFill => q{ $cur->{IB_bp_pages_total} / ($cur->{IB_bp_buf_pool_size} || 1) }, |
1576 | - ServerLoad => q{ $cur->{Threads_connected}/(Questions||1)/Uptime_hires }, |
1577 | - TxnTimeRemain => q{ defined undo_log_entries && defined $pre->{undo_log_entries} && undo_log_entries < $pre->{undo_log_entries} ? undo_log_entries / (($pre->{undo_log_entries} - undo_log_entries)/((active_secs-$pre->{active_secs})||1))||1 : 0}, |
1578 | - SlaveCatchupRate => ' defined $cur->{seconds_behind_master} && defined $pre->{seconds_behind_master} && $cur->{seconds_behind_master} < $pre->{seconds_behind_master} ? ($pre->{seconds_behind_master}-$cur->{seconds_behind_master})/($cur->{Uptime_hires}-$pre->{Uptime_hires}) : 0', |
1579 | - QcacheHitRatio => q{(Qcache_hits||0)/(((Com_select||0)+(Qcache_hits||0))||1)}, |
1580 | -); |
1581 | - |
1582 | -# ########################################################################### |
1583 | -# Column definitions {{{3 |
1584 | -# Defines every column in every table. A named column has the following |
1585 | -# properties: |
1586 | -# * hdr Column header/title |
1587 | -# * label Documentation for humans. |
1588 | -# * num Whether it's numeric (for sorting). |
1589 | -# * just Alignment; generated from num, user-overridable in tbl_meta |
1590 | -# * minw, maxw Auto-generated, user-overridable. |
1591 | -# Values from this hash are just copied to tbl_meta, which is where everything |
1592 | -# else in the program should read from. |
1593 | -# ########################################################################### |
1594 | - |
1595 | -my %columns = ( |
1596 | - active_secs => { hdr => 'SecsActive', num => 1, label => 'Seconds transaction has been active', }, |
1597 | - add_pool_alloc => { hdr => 'Add\'l Pool', num => 1, label => 'Additonal pool allocated' }, |
1598 | - attempted_op => { hdr => 'Action', num => 0, label => 'The action that caused the error' }, |
1599 | - awe_mem_alloc => { hdr => 'AWE Memory', num => 1, label => '[Windows] AWE memory allocated' }, |
1600 | - binlog_cache_overflow => { hdr => 'Binlog Cache', num => 1, label => 'Transactions too big for binlog cache that went to disk' }, |
1601 | - binlog_do_db => { hdr => 'Binlog Do DB', num => 0, label => 'binlog-do-db setting' }, |
1602 | - binlog_ignore_db => { hdr => 'Binlog Ignore DB', num => 0, label => 'binlog-ignore-db setting' }, |
1603 | - bps_in => { hdr => 'BpsIn', num => 1, label => 'Bytes per second received by the server', }, |
1604 | - bps_out => { hdr => 'BpsOut', num => 1, label => 'Bytes per second sent by the server', }, |
1605 | - buf_free => { hdr => 'Free Bufs', num => 1, label => 'Buffers free in the buffer pool' }, |
1606 | - buf_pool_hit_rate => { hdr => 'Hit Rate', num => 0, label => 'Buffer pool hit rate' }, |
1607 | - buf_pool_hits => { hdr => 'Hits', num => 1, label => 'Buffer pool hits' }, |
1608 | - buf_pool_reads => { hdr => 'Reads', num => 1, label => 'Buffer pool reads' }, |
1609 | - buf_pool_size => { hdr => 'Size', num => 1, label => 'Buffer pool size' }, |
1610 | - bufs_in_node_heap => { hdr => 'Node Heap Bufs', num => 1, label => 'Buffers in buffer pool node heap' }, |
1611 | - bytes_behind_master => { hdr => 'ByteLag', num => 1, label => 'Bytes the slave lags the master in binlog' }, |
1612 | - cell_event_set => { hdr => 'Ending?', num => 1, label => 'Whether the cell event is set' }, |
1613 | - cell_waiting => { hdr => 'Waiting?', num => 1, label => 'Whether the cell is waiting' }, |
1614 | - child_db => { hdr => 'Child DB', num => 0, label => 'The database of the child table' }, |
1615 | - child_index => { hdr => 'Child Index', num => 0, label => 'The index in the child table' }, |
1616 | - child_table => { hdr => 'Child Table', num => 0, label => 'The child table' }, |
1617 | - cmd => { hdr => 'Cmd', num => 0, label => 'Type of command being executed', }, |
1618 | - cnt => { hdr => 'Cnt', num => 0, label => 'Count', agg => 'count', aggonly => 1 }, |
1619 | - connect_retry => { hdr => 'Connect Retry', num => 1, label => 'Slave connect-retry timeout' }, |
1620 | - cxn => { hdr => 'CXN', num => 0, label => 'Connection from which the data came', }, |
1621 | - db => { hdr => 'DB', num => 0, label => 'Current database', }, |
1622 | - dict_mem_alloc => { hdr => 'Dict Mem', num => 1, label => 'Dictionary memory allocated' }, |
1623 | - dirty_bufs => { hdr => 'Dirty Buf', num => 1, label => 'Dirty buffer pool pages' }, |
1624 | - dl_txn_num => { hdr => 'Num', num => 0, label => 'Deadlocked transaction number', }, |
1625 | - event_set => { hdr => 'Evt Set?', num => 1, label => '[Win32] if a wait event is set', }, |
1626 | - exec_master_log_pos => { hdr => 'Exec Master Log Pos', num => 1, label => 'Exec Master Log Position' }, |
1627 | - fk_name => { hdr => 'Constraint', num => 0, label => 'The name of the FK constraint' }, |
1628 | - free_list_len => { hdr => 'Free List Len', num => 1, label => 'Length of the free list' }, |
1629 | - has_read_view => { hdr => 'Rd View', num => 1, label => 'Whether the transaction has a read view' }, |
1630 | - hash_searches_s => { hdr => 'Hash/Sec', num => 1, label => 'Number of hash searches/sec' }, |
1631 | - hash_table_size => { hdr => 'Size', num => 1, label => 'Number of non-hash searches/sec' }, |
1632 | - heap_no => { hdr => 'Heap', num => 1, label => 'Heap number' }, |
1633 | - heap_size => { hdr => 'Heap', num => 1, label => 'Heap size' }, |
1634 | - history_list_len => { hdr => 'History', num => 1, label => 'History list length' }, |
1635 | - host_and_domain => { hdr => 'Host', num => 0, label => 'Hostname/IP and domain' }, |
1636 | - host_and_port => { hdr => 'Host/IP', num => 0, label => 'Hostname or IP address, and port number', }, |
1637 | - hostname => { hdr => 'Host', num => 0, label => 'Hostname' }, |
1638 | - index => { hdr => 'Index', num => 0, label => 'The index involved' }, |
1639 | - index_ref => { hdr => 'Index Ref', num => 0, label => 'Index referenced' }, |
1640 | - info => { hdr => 'Query', num => 0, label => 'Info or the current query', }, |
1641 | - insert_intention => { hdr => 'Ins Intent', num => 1, label => 'Whether the thread was trying to insert' }, |
1642 | - inserts => { hdr => 'Inserts', num => 1, label => 'Inserts' }, |
1643 | - io_bytes_s => { hdr => 'Bytes/Sec', num => 1, label => 'Average I/O bytes/sec' }, |
1644 | - io_flush_type => { hdr => 'Flush Type', num => 0, label => 'I/O Flush Type' }, |
1645 | - io_fsyncs_s => { hdr => 'fsyncs/sec', num => 1, label => 'I/O fsyncs/sec' }, |
1646 | - io_reads_s => { hdr => 'Reads/Sec', num => 1, label => 'Average I/O reads/sec' }, |
1647 | - io_writes_s => { hdr => 'Writes/Sec', num => 1, label => 'Average I/O writes/sec' }, |
1648 | - ip => { hdr => 'IP', num => 0, label => 'IP address' }, |
1649 | - is_name_locked => { hdr => 'Locked', num => 1, label => 'Whether table is name locked', }, |
1650 | - key_buffer_hit => { hdr => 'KCacheHit', num => 1, label => 'Key cache hit ratio', }, |
1651 | - key_len => { hdr => 'Key Length', num => 1, label => 'Number of bytes used in the key' }, |
1652 | - last_chkp => { hdr => 'Last Checkpoint', num => 0, label => 'Last log checkpoint' }, |
1653 | - last_errno => { hdr => 'Last Errno', num => 1, label => 'Last error number' }, |
1654 | - last_error => { hdr => 'Last Error', num => 0, label => 'Last error' }, |
1655 | - last_s_file_name => { hdr => 'S-File', num => 0, label => 'Filename where last read locked' }, |
1656 | - last_s_line => { hdr => 'S-Line', num => 1, label => 'Line where last read locked' }, |
1657 | - last_x_file_name => { hdr => 'X-File', num => 0, label => 'Filename where last write locked' }, |
1658 | - last_x_line => { hdr => 'X-Line', num => 1, label => 'Line where last write locked' }, |
1659 | - last_pct => { hdr => 'Pct', num => 1, label => 'Last Percentage' }, |
1660 | - last_total => { hdr => 'Last Total', num => 1, label => 'Last Total' }, |
1661 | - last_value => { hdr => 'Last Incr', num => 1, label => 'Last Value' }, |
1662 | - load => { hdr => 'Load', num => 1, label => 'Server load' }, |
1663 | - lock_cfile_name => { hdr => 'Crtd File', num => 0, label => 'Filename where lock created' }, |
1664 | - lock_cline => { hdr => 'Crtd Line', num => 1, label => 'Line where lock created' }, |
1665 | - lock_mem_addr => { hdr => 'Addr', num => 0, label => 'The lock memory address' }, |
1666 | - lock_mode => { hdr => 'Mode', num => 0, label => 'The lock mode' }, |
1667 | - lock_structs => { hdr => 'LStrcts', num => 1, label => 'Number of lock structs' }, |
1668 | - lock_type => { hdr => 'Type', num => 0, label => 'The lock type' }, |
1669 | - lock_var => { hdr => 'Lck Var', num => 1, label => 'The lock variable' }, |
1670 | - lock_wait_time => { hdr => 'Wait', num => 1, label => 'How long txn has waited for a lock' }, |
1671 | - log_flushed_to => { hdr => 'Flushed To', num => 0, label => 'Log position flushed to' }, |
1672 | - log_ios_done => { hdr => 'IO Done', num => 1, label => 'Log I/Os done' }, |
1673 | - log_ios_s => { hdr => 'IO/Sec', num => 1, label => 'Average log I/Os per sec' }, |
1674 | - log_seq_no => { hdr => 'Sequence No.', num => 0, label => 'Log sequence number' }, |
1675 | - main_thread_id => { hdr => 'Main Thread ID', num => 1, label => 'Main thread ID' }, |
1676 | - main_thread_proc_no => { hdr => 'Main Thread Proc', num => 1, label => 'Main thread process number' }, |
1677 | - main_thread_state => { hdr => 'Main Thread State', num => 0, label => 'Main thread state' }, |
1678 | - master_file => { hdr => 'File', num => 0, label => 'Master file' }, |
1679 | - master_host => { hdr => 'Master', num => 0, label => 'Master server hostname' }, |
1680 | - master_log_file => { hdr => 'Master Log File', num => 0, label => 'Master log file' }, |
1681 | - master_port => { hdr => 'Master Port', num => 1, label => 'Master port' }, |
1682 | - master_pos => { hdr => 'Position', num => 1, label => 'Master position' }, |
1683 | - master_ssl_allowed => { hdr => 'Master SSL Allowed', num => 0, label => 'Master SSL Allowed' }, |
1684 | - master_ssl_ca_file => { hdr => 'Master SSL CA File', num => 0, label => 'Master SSL Cert Auth File' }, |
1685 | - master_ssl_ca_path => { hdr => 'Master SSL CA Path', num => 0, label => 'Master SSL Cert Auth Path' }, |
1686 | - master_ssl_cert => { hdr => 'Master SSL Cert', num => 0, label => 'Master SSL Cert' }, |
1687 | - master_ssl_cipher => { hdr => 'Master SSL Cipher', num => 0, label => 'Master SSL Cipher' }, |
1688 | - master_ssl_key => { hdr => 'Master SSL Key', num => 0, label => 'Master SSL Key' }, |
1689 | - master_user => { hdr => 'Master User', num => 0, label => 'Master username' }, |
1690 | - max_txn => { hdr => 'MaxTxnTime', num => 1, label => 'MaxTxn' }, |
1691 | - merged_recs => { hdr => 'Merged Recs', num => 1, label => 'Merged records' }, |
1692 | - merges => { hdr => 'Merges', num => 1, label => 'Merges' }, |
1693 | - mutex_os_waits => { hdr => 'Waits', num => 1, label => 'Mutex OS Waits' }, |
1694 | - mutex_spin_rounds => { hdr => 'Rounds', num => 1, label => 'Mutex Spin Rounds' }, |
1695 | - mutex_spin_waits => { hdr => 'Spins', num => 1, label => 'Mutex Spin Waits' }, |
1696 | - mysql_thread_id => { hdr => 'ID', num => 1, label => 'MySQL connection (thread) ID', }, |
1697 | - name => { hdr => 'Name', num => 0, label => 'Variable Name' }, |
1698 | - n_bits => { hdr => '# Bits', num => 1, label => 'Number of bits' }, |
1699 | - non_hash_searches_s => { hdr => 'Non-Hash/Sec', num => 1, label => 'Non-hash searches/sec' }, |
1700 | - num_deletes => { hdr => 'Del', num => 1, label => 'Number of deletes' }, |
1701 | - num_deletes_sec => { hdr => 'Del/Sec', num => 1, label => 'Number of deletes' }, |
1702 | - num_inserts => { hdr => 'Ins', num => 1, label => 'Number of inserts' }, |
1703 | - num_inserts_sec => { hdr => 'Ins/Sec', num => 1, label => 'Number of inserts' }, |
1704 | - num_readers => { hdr => 'Readers', num => 1, label => 'Number of readers' }, |
1705 | - num_reads => { hdr => 'Read', num => 1, label => 'Number of reads' }, |
1706 | - num_reads_sec => { hdr => 'Read/Sec', num => 1, label => 'Number of reads' }, |
1707 | - num_res_ext => { hdr => 'BTree Extents', num => 1, label => 'Number of extents reserved for B-Tree' }, |
1708 | - num_rows => { hdr => 'Row Count', num => 1, label => 'Number of rows estimated to examine' }, |
1709 | - num_times_open => { hdr => 'In Use', num => 1, label => '# times table is opened', }, |
1710 | - num_txns => { hdr => 'Txns', num => 1, label => 'Number of transactions' }, |
1711 | - num_updates => { hdr => 'Upd', num => 1, label => 'Number of updates' }, |
1712 | - num_updates_sec => { hdr => 'Upd/Sec', num => 1, label => 'Number of updates' }, |
1713 | - os_file_reads => { hdr => 'OS Reads', num => 1, label => 'OS file reads' }, |
1714 | - os_file_writes => { hdr => 'OS Writes', num => 1, label => 'OS file writes' }, |
1715 | - os_fsyncs => { hdr => 'OS fsyncs', num => 1, label => 'OS fsyncs' }, |
1716 | - os_thread_id => { hdr => 'OS Thread', num => 1, label => 'The operating system thread ID' }, |
1717 | - p_aio_writes => { hdr => 'Async Wrt', num => 1, label => 'Pending asynchronous I/O writes' }, |
1718 | - p_buf_pool_flushes => { hdr => 'Buffer Pool Flushes', num => 1, label => 'Pending buffer pool flushes' }, |
1719 | - p_ibuf_aio_reads => { hdr => 'IBuf Async Rds', num => 1, label => 'Pending insert buffer asynch I/O reads' }, |
1720 | - p_log_flushes => { hdr => 'Log Flushes', num => 1, label => 'Pending log flushes' }, |
1721 | - p_log_ios => { hdr => 'Log I/Os', num => 1, label => 'Pending log I/O operations' }, |
1722 | - p_normal_aio_reads => { hdr => 'Async Rds', num => 1, label => 'Pending asynchronous I/O reads' }, |
1723 | - p_preads => { hdr => 'preads', num => 1, label => 'Pending p-reads' }, |
1724 | - p_pwrites => { hdr => 'pwrites', num => 1, label => 'Pending p-writes' }, |
1725 | - p_sync_ios => { hdr => 'Sync I/Os', num => 1, label => 'Pending synchronous I/O operations' }, |
1726 | - page_creates_sec => { hdr => 'Creates/Sec', num => 1, label => 'Page creates/sec' }, |
1727 | - page_no => { hdr => 'Page', num => 1, label => 'Page number' }, |
1728 | - page_reads_sec => { hdr => 'Reads/Sec', num => 1, label => 'Page reads per second' }, |
1729 | - page_writes_sec => { hdr => 'Writes/Sec', num => 1, label => 'Page writes per second' }, |
1730 | - pages_created => { hdr => 'Created', num => 1, label => 'Pages created' }, |
1731 | - pages_modified => { hdr => 'Dirty Pages', num => 1, label => 'Pages modified (dirty)' }, |
1732 | - pages_read => { hdr => 'Reads', num => 1, label => 'Pages read' }, |
1733 | - pages_total => { hdr => 'Pages', num => 1, label => 'Pages total' }, |
1734 | - pages_written => { hdr => 'Writes', num => 1, label => 'Pages written' }, |
1735 | - parent_col => { hdr => 'Parent Column', num => 0, label => 'The referred column in the parent table', }, |
1736 | - parent_db => { hdr => 'Parent DB', num => 0, label => 'The database of the parent table' }, |
1737 | - parent_index => { hdr => 'Parent Index', num => 0, label => 'The referred index in the parent table' }, |
1738 | - parent_table => { hdr => 'Parent Table', num => 0, label => 'The parent table' }, |
1739 | - part_id => { hdr => 'Part ID', num => 1, label => 'Sub-part ID of the query' }, |
1740 | - partitions => { hdr => 'Partitions', num => 0, label => 'Query partitions used' }, |
1741 | - pct => { hdr => 'Pct', num => 1, label => 'Percentage' }, |
1742 | - pending_chkp_writes => { hdr => 'Chkpt Writes', num => 1, label => 'Pending log checkpoint writes' }, |
1743 | - pending_log_writes => { hdr => 'Log Writes', num => 1, label => 'Pending log writes' }, |
1744 | - port => { hdr => 'Port', num => 1, label => 'Client port number', }, |
1745 | - possible_keys => { hdr => 'Poss. Keys', num => 0, label => 'Possible keys' }, |
1746 | - proc_no => { hdr => 'Proc', num => 1, label => 'Process number' }, |
1747 | - q_cache_hit => { hdr => 'QCacheHit', num => 1, label => 'Query cache hit ratio', }, |
1748 | - qps => { hdr => 'QPS', num => 1, label => 'How many queries/sec', }, |
1749 | - queries_in_queue => { hdr => 'Queries Queued', num => 1, label => 'Queries in queue' }, |
1750 | - queries_inside => { hdr => 'Queries Inside', num => 1, label => 'Queries inside InnoDB' }, |
1751 | - query_id => { hdr => 'Query ID', num => 1, label => 'Query ID' }, |
1752 | - query_status => { hdr => 'Query Status', num => 0, label => 'The query status' }, |
1753 | - query_text => { hdr => 'Query Text', num => 0, label => 'The query text' }, |
1754 | - questions => { hdr => 'Questions', num => 1, label => 'How many queries the server has gotten', }, |
1755 | - read_master_log_pos => { hdr => 'Read Master Pos', num => 1, label => 'Read master log position' }, |
1756 | - read_views_open => { hdr => 'Rd Views', num => 1, label => 'Number of read views open' }, |
1757 | - reads_pending => { hdr => 'Pending Reads', num => 1, label => 'Reads pending' }, |
1758 | - relay_log_file => { hdr => 'Relay File', num => 0, label => 'Relay log file' }, |
1759 | - relay_log_pos => { hdr => 'Relay Pos', num => 1, label => 'Relay log position' }, |
1760 | - relay_log_size => { hdr => 'Relay Size', num => 1, label => 'Relay log size' }, |
1761 | - relay_master_log_file => { hdr => 'Relay Master File', num => 0, label => 'Relay master log file' }, |
1762 | - replicate_do_db => { hdr => 'Do DB', num => 0, label => 'Replicate-do-db setting' }, |
1763 | - replicate_do_table => { hdr => 'Do Table', num => 0, label => 'Replicate-do-table setting' }, |
1764 | - replicate_ignore_db => { hdr => 'Ignore DB', num => 0, label => 'Replicate-ignore-db setting' }, |
1765 | - replicate_ignore_table => { hdr => 'Ignore Table', num => 0, label => 'Replicate-do-table setting' }, |
1766 | - replicate_wild_do_table => { hdr => 'Wild Do Table', num => 0, label => 'Replicate-wild-do-table setting' }, |
1767 | - replicate_wild_ignore_table => { hdr => 'Wild Ignore Table', num => 0, label => 'Replicate-wild-ignore-table setting' }, |
1768 | - request_type => { hdr => 'Type', num => 0, label => 'Type of lock the thread waits for' }, |
1769 | - reservation_count => { hdr => 'ResCnt', num => 1, label => 'Reservation Count' }, |
1770 | - row_locks => { hdr => 'RLocks', num => 1, label => 'Number of row locks' }, |
1771 | - rw_excl_os_waits => { hdr => 'RW Waits', num => 1, label => 'R/W Excl. OS Waits' }, |
1772 | - rw_excl_spins => { hdr => 'RW Spins', num => 1, label => 'R/W Excl. Spins' }, |
1773 | - rw_shared_os_waits => { hdr => 'Sh Waits', num => 1, label => 'R/W Shared OS Waits' }, |
1774 | - rw_shared_spins => { hdr => 'Sh Spins', num => 1, label => 'R/W Shared Spins' }, |
1775 | - scan_type => { hdr => 'Type', num => 0, label => 'Scan type in chosen' }, |
1776 | - seg_size => { hdr => 'Seg. Size', num => 1, label => 'Segment size' }, |
1777 | - select_type => { hdr => 'Select Type', num => 0, label => 'Type of select used' }, |
1778 | - signal_count => { hdr => 'Signals', num => 1, label => 'Signal Count' }, |
1779 | - size => { hdr => 'Size', num => 1, label => 'Size of the tablespace' }, |
1780 | - skip_counter => { hdr => 'Skip Counter', num => 1, label => 'Skip counter' }, |
1781 | - slave_catchup_rate => { hdr => 'Catchup', num => 1, label => 'How fast the slave is catching up in the binlog' }, |
1782 | - slave_io_running => { hdr => 'Slave-IO', num => 0, label => 'Whether the slave I/O thread is running' }, |
1783 | - slave_io_state => { hdr => 'Slave IO State', num => 0, label => 'Slave I/O thread state' }, |
1784 | - slave_open_temp_tables => { hdr => 'Temp', num => 1, label => 'Slave open temp tables' }, |
1785 | - slave_sql_running => { hdr => 'Slave-SQL', num => 0, label => 'Whether the slave SQL thread is running' }, |
1786 | - slow => { hdr => 'Slow', num => 1, label => 'How many slow queries', }, |
1787 | - space_id => { hdr => 'Space', num => 1, label => 'Tablespace ID' }, |
1788 | - special => { hdr => 'Special', num => 0, label => 'Special/Other info' }, |
1789 | - state => { hdr => 'State', num => 0, label => 'Connection state', maxw => 18, }, |
1790 | - tables_in_use => { hdr => 'Tbl Used', num => 1, label => 'Number of tables in use' }, |
1791 | - tables_locked => { hdr => 'Tbl Lck', num => 1, label => 'Number of tables locked' }, |
1792 | - tbl => { hdr => 'Table', num => 0, label => 'Table', }, |
1793 | - thread => { hdr => 'Thread', num => 1, label => 'Thread number' }, |
1794 | - thread_decl_inside => { hdr => 'Thread Inside', num => 0, label => 'What the thread is declared inside' }, |
1795 | - thread_purpose => { hdr => 'Purpose', num => 0, label => "The thread's purpose" }, |
1796 | - thread_status => { hdr => 'Thread Status', num => 0, label => 'The thread status' }, |
1797 | - time => { hdr => 'Time', num => 1, label => 'Time since the last event', }, |
1798 | - time_behind_master => { hdr => 'TimeLag', num => 1, label => 'Time slave lags master' }, |
1799 | - timestring => { hdr => 'Timestring', num => 0, label => 'Time the event occurred' }, |
1800 | - total => { hdr => 'Total', num => 1, label => 'Total' }, |
1801 | - total_mem_alloc => { hdr => 'Memory', num => 1, label => 'Total memory allocated' }, |
1802 | - truncates => { hdr => 'Trunc', num => 0, label => 'Whether the deadlock is truncating InnoDB status' }, |
1803 | - txn_doesnt_see_ge => { hdr => "Txn Won't See", num => 0, label => 'Where txn read view is limited' }, |
1804 | - txn_id => { hdr => 'ID', num => 0, label => 'Transaction ID' }, |
1805 | - txn_sees_lt => { hdr => 'Txn Sees', num => 1, label => 'Where txn read view is limited' }, |
1806 | - txn_status => { hdr => 'Txn Status', num => 0, label => 'Transaction status' }, |
1807 | - txn_time_remain => { hdr => 'Remaining', num => 1, label => 'Time until txn rollback/commit completes' }, |
1808 | - undo_log_entries => { hdr => 'Undo', num => 1, label => 'Number of undo log entries' }, |
1809 | - undo_for => { hdr => 'Undo', num => 0, label => 'Undo for' }, |
1810 | - until_condition => { hdr => 'Until Condition', num => 0, label => 'Slave until condition' }, |
1811 | - until_log_file => { hdr => 'Until Log File', num => 0, label => 'Slave until log file' }, |
1812 | - until_log_pos => { hdr => 'Until Log Pos', num => 1, label => 'Slave until log position' }, |
1813 | - used_cells => { hdr => 'Cells Used', num => 1, label => 'Number of cells used' }, |
1814 | - used_bufs => { hdr => 'Used Bufs', num => 1, label => 'Number of buffer pool pages used' }, |
1815 | - user => { hdr => 'User', num => 0, label => 'Database username', }, |
1816 | - value => { hdr => 'Value', num => 1, label => 'Value' }, |
1817 | - versions => { hdr => 'Versions', num => 1, label => 'Number of InnoDB MVCC versions unpurged' }, |
1818 | - victim => { hdr => 'Victim', num => 0, label => 'Whether this txn was the deadlock victim' }, |
1819 | - wait_array_size => { hdr => 'Wait Array Size', num => 1, label => 'Wait Array Size' }, |
1820 | - wait_status => { hdr => 'Lock Status', num => 0, label => 'Status of txn locks' }, |
1821 | - waited_at_filename => { hdr => 'File', num => 0, label => 'Filename at which thread waits' }, |
1822 | - waited_at_line => { hdr => 'Line', num => 1, label => 'Line at which thread waits' }, |
1823 | - waiters_flag => { hdr => 'Waiters', num => 1, label => 'Waiters Flag' }, |
1824 | - waiting => { hdr => 'Waiting', num => 1, label => 'Whether lock is being waited for' }, |
1825 | - when => { hdr => 'When', num => 0, label => 'Time scale' }, |
1826 | - writer_lock_mode => { hdr => 'Wrtr Lck Mode', num => 0, label => 'Writer lock mode' }, |
1827 | - writer_thread => { hdr => 'Wrtr Thread', num => 1, label => 'Writer thread ID' }, |
1828 | - writes_pending => { hdr => 'Writes', num => 1, label => 'Number of writes pending' }, |
1829 | - writes_pending_flush_list => { hdr => 'Flush List Writes', num => 1, label => 'Number of flush list writes pending' }, |
1830 | - writes_pending_lru => { hdr => 'LRU Writes', num => 1, label => 'Number of LRU writes pending' }, |
1831 | - writes_pending_single_page => { hdr => '1-Page Writes', num => 1, label => 'Number of 1-page writes pending' }, |
1832 | -); |
1833 | - |
1834 | -# Apply a default property or three. By default, columns are not width-constrained, |
1835 | -# aligned left, and sorted alphabetically, not numerically. |
1836 | -foreach my $col ( values %columns ) { |
1837 | - map { $col->{$_} ||= 0 } qw(num minw maxw); |
1838 | - $col->{just} = $col->{num} ? '' : '-'; |
1839 | -} |
1840 | - |
1841 | -# Filters {{{3 |
1842 | -# This hash defines every filter that can be applied to a table. These |
1843 | -# become part of tbl_meta as well. Each filter is just an expression that |
1844 | -# returns true or false. |
1845 | -# Properties of each entry: |
1846 | -# * func: the subroutine |
1847 | -# * name: the name, repeated |
1848 | -# * user: whether it's a user-defined filter (saved in config) |
1849 | -# * text: text of the subroutine |
1850 | -# * note: explanation |
1851 | -my %filters = (); |
1852 | - |
1853 | -# These are pre-processed to live in %filters above, by compiling them. |
1854 | -my %builtin_filters = ( |
1855 | - hide_self => { |
1856 | - text => <<' END', |
1857 | - return ( !$set->{info} || $set->{info} ne 'SHOW FULL PROCESSLIST' ) |
1858 | - && ( !$set->{query_text} || $set->{query_text} !~ m/INNODB STATUS$/ ); |
1859 | - END |
1860 | - note => 'Removes the innotop processes from the list', |
1861 | - tbls => [qw(innodb_transactions processlist)], |
1862 | - }, |
1863 | - hide_inactive => { |
1864 | - text => <<' END', |
1865 | - return ( !defined($set->{txn_status}) || $set->{txn_status} ne 'not started' ) |
1866 | - && ( !defined($set->{cmd}) || $set->{cmd} !~ m/Sleep|Binlog Dump/ ) |
1867 | - && ( !defined($set->{info}) || $set->{info} =~ m/\S/ ); |
1868 | - END |
1869 | - note => 'Removes processes which are not doing anything', |
1870 | - tbls => [qw(innodb_transactions processlist)], |
1871 | - }, |
1872 | - hide_slave_io => { |
1873 | - text => <<' END', |
1874 | - return !$set->{state} || $set->{state} !~ m/^(?:Waiting for master|Has read all relay)/; |
1875 | - END |
1876 | - note => 'Removes slave I/O threads from the list', |
1877 | - tbls => [qw(processlist slave_io_status)], |
1878 | - }, |
1879 | - table_is_open => { |
1880 | - text => <<' END', |
1881 | - return $set->{num_times_open} + $set->{is_name_locked}; |
1882 | - END |
1883 | - note => 'Removes tables that are not in use or locked', |
1884 | - tbls => [qw(open_tables)], |
1885 | - }, |
1886 | - cxn_is_master => { |
1887 | - text => <<' END', |
1888 | - return $set->{master_file} ? 1 : 0; |
1889 | - END |
1890 | - note => 'Removes servers that are not masters', |
1891 | - tbls => [qw(master_status)], |
1892 | - }, |
1893 | - cxn_is_slave => { |
1894 | - text => <<' END', |
1895 | - return $set->{master_host} ? 1 : 0; |
1896 | - END |
1897 | - note => 'Removes servers that are not slaves', |
1898 | - tbls => [qw(slave_io_status slave_sql_status)], |
1899 | - }, |
1900 | - thd_is_not_waiting => { |
1901 | - text => <<' END', |
1902 | - return $set->{thread_status} !~ m#waiting for i/o request#; |
1903 | - END |
1904 | - note => 'Removes idle I/O threads', |
1905 | - tbls => [qw(io_threads)], |
1906 | - }, |
1907 | -); |
1908 | -foreach my $key ( keys %builtin_filters ) { |
1909 | - my ( $sub, $err ) = compile_filter($builtin_filters{$key}->{text}); |
1910 | - $filters{$key} = { |
1911 | - func => $sub, |
1912 | - text => $builtin_filters{$key}->{text}, |
1913 | - user => 0, |
1914 | - name => $key, # useful for later |
1915 | - note => $builtin_filters{$key}->{note}, |
1916 | - tbls => $builtin_filters{$key}->{tbls}, |
1917 | - } |
1918 | -} |
1919 | - |
1920 | -# Variable sets {{{3 |
1921 | -# Sets (arrayrefs) of variables that are used in S mode. They are read/written to |
1922 | -# the config file. |
1923 | -my %var_sets = ( |
1924 | - general => { |
1925 | - text => join( |
1926 | - ', ', |
1927 | - 'set_precision(Questions/Uptime_hires) as QPS', |
1928 | - 'set_precision(Com_commit/Uptime_hires) as Commit_PS', |
1929 | - 'set_precision((Com_rollback||0)/(Com_commit||1)) as Rollback_Commit', |
1930 | - 'set_precision((' |
1931 | - . join('+', map { "($_||0)" } |
1932 | - qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace |
1933 | - Com_replace_select Com_select Com_update Com_update_multi)) |
1934 | - . ')/(Com_commit||1)) as Write_Commit', |
1935 | - 'set_precision((Com_select+(Qcache_hits||0))/((' |
1936 | - . join('+', map { "($_||0)" } |
1937 | - qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace |
1938 | - Com_replace_select Com_select Com_update Com_update_multi)) |
1939 | - . ')||1)) as R_W_Ratio', |
1940 | - 'set_precision(Opened_tables/Uptime_hires) as Opens_PS', |
1941 | - 'percent($cur->{Open_tables}/($cur->{table_cache})) as Table_Cache_Used', |
1942 | - 'set_precision(Threads_created/Uptime_hires) as Threads_PS', |
1943 | - 'percent($cur->{Threads_cached}/($cur->{thread_cache_size}||1)) as Thread_Cache_Used', |
1944 | - 'percent($cur->{Max_used_connections}/($cur->{max_connections}||1)) as CXN_Used_Ever', |
1945 | - 'percent($cur->{Threads_connected}/($cur->{max_connections}||1)) as CXN_Used_Now', |
1946 | - ), |
1947 | - }, |
1948 | - commands => { |
1949 | - text => join( |
1950 | - ', ', |
1951 | - qw(Uptime Questions Com_delete Com_delete_multi Com_insert |
1952 | - Com_insert_select Com_replace Com_replace_select Com_select Com_update |
1953 | - Com_update_multi) |
1954 | - ), |
1955 | - }, |
1956 | - query_status => { |
1957 | - text => join( |
1958 | - ',', |
1959 | - qw( Uptime Select_full_join Select_full_range_join Select_range |
1960 | - Select_range_check Select_scan Slow_queries Sort_merge_passes |
1961 | - Sort_range Sort_rows Sort_scan) |
1962 | - ), |
1963 | - }, |
1964 | - innodb => { |
1965 | - text => join( |
1966 | - ',', |
1967 | - qw( Uptime Innodb_row_lock_current_waits Innodb_row_lock_time |
1968 | - Innodb_row_lock_time_avg Innodb_row_lock_time_max Innodb_row_lock_waits |
1969 | - Innodb_rows_deleted Innodb_rows_inserted Innodb_rows_read |
1970 | - Innodb_rows_updated) |
1971 | - ), |
1972 | - }, |
1973 | - txn => { |
1974 | - text => join( |
1975 | - ',', |
1976 | - qw( Uptime Com_begin Com_commit Com_rollback Com_savepoint |
1977 | - Com_xa_commit Com_xa_end Com_xa_prepare Com_xa_recover Com_xa_rollback |
1978 | - Com_xa_start) |
1979 | - ), |
1980 | - }, |
1981 | - key_cache => { |
1982 | - text => join( |
1983 | - ',', |
1984 | - qw( Uptime Key_blocks_not_flushed Key_blocks_unused Key_blocks_used |
1985 | - Key_read_requests Key_reads Key_write_requests Key_writes ) |
1986 | - ), |
1987 | - }, |
1988 | - query_cache => { |
1989 | - text => join( |
1990 | - ',', |
1991 | - "percent($exprs{QcacheHitRatio}) as Hit_Pct", |
1992 | - 'set_precision((Qcache_hits||0)/(Qcache_inserts||1)) as Hit_Ins', |
1993 | - 'set_precision((Qcache_lowmem_prunes||0)/Uptime_hires) as Lowmem_Prunes_sec', |
1994 | - 'percent(1-((Qcache_free_blocks||0)/(Qcache_total_blocks||1))) as Blocks_used', |
1995 | - qw( Qcache_free_blocks Qcache_free_memory Qcache_not_cached Qcache_queries_in_cache) |
1996 | - ), |
1997 | - }, |
1998 | - handler => { |
1999 | - text => join( |
2000 | - ',', |
2001 | - qw( Uptime Handler_read_key Handler_read_first Handler_read_next |
2002 | - Handler_read_prev Handler_read_rnd Handler_read_rnd_next Handler_delete |
2003 | - Handler_update Handler_write) |
2004 | - ), |
2005 | - }, |
2006 | - cxns_files_threads => { |
2007 | - text => join( |
2008 | - ',', |
2009 | - qw( Uptime Aborted_clients Aborted_connects Bytes_received Bytes_sent |
2010 | - Compression Connections Created_tmp_disk_tables Created_tmp_files |
2011 | - Created_tmp_tables Max_used_connections Open_files Open_streams |
2012 | - Open_tables Opened_tables Table_locks_immediate Table_locks_waited |
2013 | - Threads_cached Threads_connected Threads_created Threads_running) |
2014 | - ), |
2015 | - }, |
2016 | - prep_stmt => { |
2017 | - text => join( |
2018 | - ',', |
2019 | - qw( Uptime Com_dealloc_sql Com_execute_sql Com_prepare_sql Com_reset |
2020 | - Com_stmt_close Com_stmt_execute Com_stmt_fetch Com_stmt_prepare |
2021 | - Com_stmt_reset Com_stmt_send_long_data ) |
2022 | - ), |
2023 | - }, |
2024 | - innodb_health => { |
2025 | - text => join( |
2026 | - ',', |
2027 | - "$exprs{OldVersions} as OldVersions", |
2028 | - qw(IB_sm_mutex_spin_waits IB_sm_mutex_spin_rounds IB_sm_mutex_os_waits), |
2029 | - "$exprs{NumTxns} as NumTxns", |
2030 | - "$exprs{MaxTxnTime} as MaxTxnTime", |
2031 | - qw(IB_ro_queries_inside IB_ro_queries_in_queue), |
2032 | - "set_precision($exprs{DirtyBufs} * 100) as dirty_bufs", |
2033 | - "set_precision($exprs{BufPoolFill} * 100) as buf_fill", |
2034 | - qw(IB_bp_pages_total IB_bp_pages_read IB_bp_pages_written IB_bp_pages_created) |
2035 | - ), |
2036 | - }, |
2037 | - innodb_health2 => { |
2038 | - text => join( |
2039 | - ', ', |
2040 | - 'percent(1-((Innodb_buffer_pool_pages_free||0)/($cur->{Innodb_buffer_pool_pages_total}||1))) as BP_page_cache_usage', |
2041 | - 'percent(1-((Innodb_buffer_pool_reads||0)/(Innodb_buffer_pool_read_requests||1))) as BP_cache_hit_ratio', |
2042 | - 'Innodb_buffer_pool_wait_free', |
2043 | - 'Innodb_log_waits', |
2044 | - ), |
2045 | - }, |
2046 | - slow_queries => { |
2047 | - text => join( |
2048 | - ', ', |
2049 | - 'set_precision(Slow_queries/Uptime_hires) as Slow_PS', |
2050 | - 'set_precision(Select_full_join/Uptime_hires) as Full_Join_PS', |
2051 | - 'percent(Select_full_join/(Com_select||1)) as Full_Join_Ratio', |
2052 | - ), |
2053 | - }, |
2054 | -); |
2055 | - |
2056 | -# Server sets {{{3 |
2057 | -# Defines sets of servers between which the user can quickly switch. |
2058 | -my %server_groups; |
2059 | - |
2060 | -# Connections {{{3 |
2061 | -# This hash defines server connections. Each connection is a string that can be passed to |
2062 | -# the DBI connection. These are saved in the connections section in the config file. |
2063 | -my %connections; |
2064 | -# Defines the parts of connections. |
2065 | -my @conn_parts = qw(user have_user pass have_pass dsn savepass dl_table); |
2066 | - |
2067 | -# Graph widths {{{3 |
2068 | -# This hash defines the max values seen for various status/variable values, for graphing. |
2069 | -# These are stored in their own section in the config file. These are just initial values: |
2070 | -my %mvs = ( |
2071 | - Com_select => 50, |
2072 | - Com_insert => 50, |
2073 | - Com_update => 50, |
2074 | - Com_delete => 50, |
2075 | - Questions => 100, |
2076 | -); |
2077 | - |
2078 | -# ########################################################################### |
2079 | -# Valid Term::ANSIColor color strings. |
2080 | -# ########################################################################### |
2081 | -my %ansicolors = map { $_ => 1 } |
2082 | - qw( black blink blue bold clear concealed cyan dark green magenta on_black |
2083 | - on_blue on_cyan on_green on_magenta on_red on_white on_yellow red reset |
2084 | - reverse underline underscore white yellow); |
2085 | - |
2086 | -# ########################################################################### |
2087 | -# Valid comparison operators for color rules |
2088 | -# ########################################################################### |
2089 | -my %comp_ops = ( |
2090 | - '==' => 'Numeric equality', |
2091 | - '>' => 'Numeric greater-than', |
2092 | - '<' => 'Numeric less-than', |
2093 | - '>=' => 'Numeric greater-than/equal', |
2094 | - '<=' => 'Numeric less-than/equal', |
2095 | - '!=' => 'Numeric not-equal', |
2096 | - 'eq' => 'String equality', |
2097 | - 'gt' => 'String greater-than', |
2098 | - 'lt' => 'String less-than', |
2099 | - 'ge' => 'String greater-than/equal', |
2100 | - 'le' => 'String less-than/equal', |
2101 | - 'ne' => 'String not-equal', |
2102 | - '=~' => 'Pattern match', |
2103 | - '!~' => 'Negated pattern match', |
2104 | -); |
2105 | - |
2106 | -# ########################################################################### |
2107 | -# Valid aggregate functions. |
2108 | -# ########################################################################### |
2109 | -my %agg_funcs = ( |
2110 | - first => sub { |
2111 | - return $_[0] |
2112 | - }, |
2113 | - count => sub { |
2114 | - return 0 + @_; |
2115 | - }, |
2116 | - avg => sub { |
2117 | - my @args = grep { defined $_ } @_; |
2118 | - return (sum(map { m/([\d\.-]+)/g } @args) || 0) / (scalar(@args) || 1); |
2119 | - }, |
2120 | - sum => \&sum, |
2121 | -); |
2122 | - |
2123 | -# ########################################################################### |
2124 | -# Valid functions for transformations. |
2125 | -# ########################################################################### |
2126 | -my %trans_funcs = ( |
2127 | - shorten => \&shorten, |
2128 | - secs_to_time => \&secs_to_time, |
2129 | - no_ctrl_char => \&no_ctrl_char, |
2130 | - percent => \&percent, |
2131 | - commify => \&commify, |
2132 | - dulint_to_int => \&dulint_to_int, |
2133 | - set_precision => \&set_precision, |
2134 | -); |
2135 | - |
2136 | -# Table definitions {{{3 |
2137 | -# This hash defines every table that can get displayed in every mode. Each |
2138 | -# table specifies columns and column data sources. The column is |
2139 | -# defined by the %columns hash. |
2140 | -# |
2141 | -# Example: foo => { src => 'bar' } means the foo column (look at |
2142 | -# $columns{foo} for its definition) gets its data from the 'bar' element of |
2143 | -# the current data set, whatever that is. |
2144 | -# |
2145 | -# These columns are post-processed after being defined, because they get stuff |
2146 | -# from %columns. After all the config is loaded for columns, there's more |
2147 | -# post-processing too; the subroutines compiled from src get added to |
2148 | -# the hash elements for extract_values to use. |
2149 | -# ########################################################################### |
2150 | - |
2151 | -my %tbl_meta = ( |
2152 | - adaptive_hash_index => { |
2153 | - capt => 'Adaptive Hash Index', |
2154 | - cust => {}, |
2155 | - cols => { |
2156 | - cxn => { src => 'cxn' }, |
2157 | - hash_table_size => { src => 'IB_ib_hash_table_size', trans => [qw(shorten)], }, |
2158 | - used_cells => { src => 'IB_ib_used_cells' }, |
2159 | - bufs_in_node_heap => { src => 'IB_ib_bufs_in_node_heap' }, |
2160 | - hash_searches_s => { src => 'IB_ib_hash_searches_s' }, |
2161 | - non_hash_searches_s => { src => 'IB_ib_non_hash_searches_s' }, |
2162 | - }, |
2163 | - visible => [ qw(cxn hash_table_size used_cells bufs_in_node_heap hash_searches_s non_hash_searches_s) ], |
2164 | - filters => [], |
2165 | - sort_cols => 'cxn', |
2166 | - sort_dir => '1', |
2167 | - innodb => 'ib', |
2168 | - group_by => [], |
2169 | - aggregate => 0, |
2170 | - }, |
2171 | - buffer_pool => { |
2172 | - capt => 'Buffer Pool', |
2173 | - cust => {}, |
2174 | - cols => { |
2175 | - cxn => { src => 'cxn' }, |
2176 | - total_mem_alloc => { src => 'IB_bp_total_mem_alloc', trans => [qw(shorten)], }, |
2177 | - awe_mem_alloc => { src => 'IB_bp_awe_mem_alloc', trans => [qw(shorten)], }, |
2178 | - add_pool_alloc => { src => 'IB_bp_add_pool_alloc', trans => [qw(shorten)], }, |
2179 | - buf_pool_size => { src => 'IB_bp_buf_pool_size', trans => [qw(shorten)], }, |
2180 | - buf_free => { src => 'IB_bp_buf_free' }, |
2181 | - buf_pool_hit_rate => { src => 'IB_bp_buf_pool_hit_rate' }, |
2182 | - buf_pool_reads => { src => 'IB_bp_buf_pool_reads' }, |
2183 | - buf_pool_hits => { src => 'IB_bp_buf_pool_hits' }, |
2184 | - dict_mem_alloc => { src => 'IB_bp_dict_mem_alloc' }, |
2185 | - pages_total => { src => 'IB_bp_pages_total' }, |
2186 | - pages_modified => { src => 'IB_bp_pages_modified' }, |
2187 | - reads_pending => { src => 'IB_bp_reads_pending' }, |
2188 | - writes_pending => { src => 'IB_bp_writes_pending' }, |
2189 | - writes_pending_lru => { src => 'IB_bp_writes_pending_lru' }, |
2190 | - writes_pending_flush_list => { src => 'IB_bp_writes_pending_flush_list' }, |
2191 | - writes_pending_single_page => { src => 'IB_bp_writes_pending_single_page' }, |
2192 | - page_creates_sec => { src => 'IB_bp_page_creates_sec' }, |
2193 | - page_reads_sec => { src => 'IB_bp_page_reads_sec' }, |
2194 | - page_writes_sec => { src => 'IB_bp_page_writes_sec' }, |
2195 | - pages_created => { src => 'IB_bp_pages_created' }, |
2196 | - pages_read => { src => 'IB_bp_pages_read' }, |
2197 | - pages_written => { src => 'IB_bp_pages_written' }, |
2198 | - }, |
2199 | - visible => [ qw(cxn buf_pool_size buf_free pages_total pages_modified buf_pool_hit_rate total_mem_alloc add_pool_alloc)], |
2200 | - filters => [], |
2201 | - sort_cols => 'cxn', |
2202 | - sort_dir => '1', |
2203 | - innodb => 'bp', |
2204 | - group_by => [], |
2205 | - aggregate => 0, |
2206 | - }, |
2207 | - # TODO: a new step in set_to_tbl: join result to itself, grouped? |
2208 | - # TODO: this would also enable pulling Q and T data together. |
2209 | - # TODO: using a SQL-ish language would also allow pivots to be easier -- treat the pivoted data as a view and SELECT from it. |
2210 | - cmd_summary => { |
2211 | - capt => 'Command Summary', |
2212 | - cust => {}, |
2213 | - cols => { |
2214 | - name => { src => 'name' }, |
2215 | - total => { src => 'total' }, |
2216 | - value => { src => 'value', agg => 'sum'}, |
2217 | - pct => { src => 'value/total', trans => [qw(percent)] }, |
2218 | - last_total => { src => 'last_total' }, |
2219 | - last_value => { src => 'last_value', agg => 'sum'}, |
2220 | - last_pct => { src => 'last_value/last_total', trans => [qw(percent)] }, |
2221 | - }, |
2222 | - visible => [qw(name value pct last_value last_pct)], |
2223 | - filters => [qw()], |
2224 | - sort_cols => '-value', |
2225 | - sort_dir => '1', |
2226 | - innodb => '', |
2227 | - group_by => [qw(name)], |
2228 | - aggregate => 1, |
2229 | - }, |
2230 | - deadlock_locks => { |
2231 | - capt => 'Deadlock Locks', |
2232 | - cust => {}, |
2233 | - cols => { |
2234 | - cxn => { src => 'cxn' }, |
2235 | - mysql_thread_id => { src => 'mysql_thread_id' }, |
2236 | - dl_txn_num => { src => 'dl_txn_num' }, |
2237 | - lock_type => { src => 'lock_type' }, |
2238 | - space_id => { src => 'space_id' }, |
2239 | - page_no => { src => 'page_no' }, |
2240 | - heap_no => { src => 'heap_no' }, |
2241 | - n_bits => { src => 'n_bits' }, |
2242 | - index => { src => 'index' }, |
2243 | - db => { src => 'db' }, |
2244 | - tbl => { src => 'table' }, |
2245 | - lock_mode => { src => 'lock_mode' }, |
2246 | - special => { src => 'special' }, |
2247 | - insert_intention => { src => 'insert_intention' }, |
2248 | - waiting => { src => 'waiting' }, |
2249 | - }, |
2250 | - visible => [ qw(cxn mysql_thread_id waiting lock_mode db tbl index special insert_intention)], |
2251 | - filters => [], |
2252 | - sort_cols => 'cxn mysql_thread_id', |
2253 | - sort_dir => '1', |
2254 | - innodb => 'dl', |
2255 | - group_by => [], |
2256 | - aggregate => 0, |
2257 | - }, |
2258 | - deadlock_transactions => { |
2259 | - capt => 'Deadlock Transactions', |
2260 | - cust => {}, |
2261 | - cols => { |
2262 | - cxn => { src => 'cxn' }, |
2263 | - active_secs => { src => 'active_secs' }, |
2264 | - dl_txn_num => { src => 'dl_txn_num' }, |
2265 | - has_read_view => { src => 'has_read_view' }, |
2266 | - heap_size => { src => 'heap_size' }, |
2267 | - host_and_domain => { src => 'hostname' }, |
2268 | - hostname => { src => $exprs{Host} }, |
2269 | - ip => { src => 'ip' }, |
2270 | - lock_structs => { src => 'lock_structs' }, |
2271 | - lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, |
2272 | - mysql_thread_id => { src => 'mysql_thread_id' }, |
2273 | - os_thread_id => { src => 'os_thread_id' }, |
2274 | - proc_no => { src => 'proc_no' }, |
2275 | - query_id => { src => 'query_id' }, |
2276 | - query_status => { src => 'query_status' }, |
2277 | - query_text => { src => 'query_text', trans => [ qw(no_ctrl_char) ] }, |
2278 | - row_locks => { src => 'row_locks' }, |
2279 | - tables_in_use => { src => 'tables_in_use' }, |
2280 | - tables_locked => { src => 'tables_locked' }, |
2281 | - thread_decl_inside => { src => 'thread_decl_inside' }, |
2282 | - thread_status => { src => 'thread_status' }, |
2283 | - 'time' => { src => 'active_secs', trans => [ qw(secs_to_time) ] }, |
2284 | - timestring => { src => 'timestring' }, |
2285 | - txn_doesnt_see_ge => { src => 'txn_doesnt_see_ge' }, |
2286 | - txn_id => { src => 'txn_id' }, |
2287 | - txn_sees_lt => { src => 'txn_sees_lt' }, |
2288 | - txn_status => { src => 'txn_status' }, |
2289 | - truncates => { src => 'truncates' }, |
2290 | - undo_log_entries => { src => 'undo_log_entries' }, |
2291 | - user => { src => 'user' }, |
2292 | - victim => { src => 'victim' }, |
2293 | - wait_status => { src => 'lock_wait_status' }, |
2294 | - }, |
2295 | - visible => [ qw(cxn mysql_thread_id timestring user hostname victim time undo_log_entries lock_structs query_text)], |
2296 | - filters => [], |
2297 | - sort_cols => 'cxn mysql_thread_id', |
2298 | - sort_dir => '1', |
2299 | - innodb => 'dl', |
2300 | - group_by => [], |
2301 | - aggregate => 0, |
2302 | - }, |
2303 | - explain => { |
2304 | - capt => 'EXPLAIN Results', |
2305 | - cust => {}, |
2306 | - cols => { |
2307 | - part_id => { src => 'id' }, |
2308 | - select_type => { src => 'select_type' }, |
2309 | - tbl => { src => 'table' }, |
2310 | - partitions => { src => 'partitions' }, |
2311 | - scan_type => { src => 'type' }, |
2312 | - possible_keys => { src => 'possible_keys' }, |
2313 | - index => { src => 'key' }, |
2314 | - key_len => { src => 'key_len' }, |
2315 | - index_ref => { src => 'ref' }, |
2316 | - num_rows => { src => 'rows' }, |
2317 | - special => { src => 'extra' }, |
2318 | - }, |
2319 | - visible => [ qw(select_type tbl partitions scan_type possible_keys index key_len index_ref num_rows special)], |
2320 | - filters => [], |
2321 | - sort_cols => '', |
2322 | - sort_dir => '1', |
2323 | - innodb => '', |
2324 | - group_by => [], |
2325 | - aggregate => 0, |
2326 | - }, |
2327 | - file_io_misc => { |
2328 | - capt => 'File I/O Misc', |
2329 | - cust => {}, |
2330 | - cols => { |
2331 | - cxn => { src => 'cxn' }, |
2332 | - io_bytes_s => { src => 'IB_io_avg_bytes_s' }, |
2333 | - io_flush_type => { src => 'IB_io_flush_type' }, |
2334 | - io_fsyncs_s => { src => 'IB_io_fsyncs_s' }, |
2335 | - io_reads_s => { src => 'IB_io_reads_s' }, |
2336 | - io_writes_s => { src => 'IB_io_writes_s' }, |
2337 | - os_file_reads => { src => 'IB_io_os_file_reads' }, |
2338 | - os_file_writes => { src => 'IB_io_os_file_writes' }, |
2339 | - os_fsyncs => { src => 'IB_io_os_fsyncs' }, |
2340 | - }, |
2341 | - visible => [ qw(cxn os_file_reads os_file_writes os_fsyncs io_reads_s io_writes_s io_bytes_s)], |
2342 | - filters => [], |
2343 | - sort_cols => 'cxn', |
2344 | - sort_dir => '1', |
2345 | - innodb => 'io', |
2346 | - group_by => [], |
2347 | - aggregate => 0, |
2348 | - }, |
2349 | - fk_error => { |
2350 | - capt => 'Foreign Key Error Info', |
2351 | - cust => {}, |
2352 | - cols => { |
2353 | - timestring => { src => 'IB_fk_timestring' }, |
2354 | - child_db => { src => 'IB_fk_child_db' }, |
2355 | - child_table => { src => 'IB_fk_child_table' }, |
2356 | - child_index => { src => 'IB_fk_child_index' }, |
2357 | - fk_name => { src => 'IB_fk_fk_name' }, |
2358 | - parent_db => { src => 'IB_fk_parent_db' }, |
2359 | - parent_table => { src => 'IB_fk_parent_table' }, |
2360 | - parent_col => { src => 'IB_fk_parent_col' }, |
2361 | - parent_index => { src => 'IB_fk_parent_index' }, |
2362 | - attempted_op => { src => 'IB_fk_attempted_op' }, |
2363 | - }, |
2364 | - visible => [ qw(timestring child_db child_table child_index parent_db parent_table parent_col parent_index fk_name attempted_op)], |
2365 | - filters => [], |
2366 | - sort_cols => '', |
2367 | - sort_dir => '1', |
2368 | - innodb => 'fk', |
2369 | - group_by => [], |
2370 | - aggregate => 0, |
2371 | - }, |
2372 | - insert_buffers => { |
2373 | - capt => 'Insert Buffers', |
2374 | - cust => {}, |
2375 | - cols => { |
2376 | - cxn => { src => 'cxn' }, |
2377 | - inserts => { src => 'IB_ib_inserts' }, |
2378 | - merged_recs => { src => 'IB_ib_merged_recs' }, |
2379 | - merges => { src => 'IB_ib_merges' }, |
2380 | - size => { src => 'IB_ib_size' }, |
2381 | - free_list_len => { src => 'IB_ib_free_list_len' }, |
2382 | - seg_size => { src => 'IB_ib_seg_size' }, |
2383 | - }, |
2384 | - visible => [ qw(cxn inserts merged_recs merges size free_list_len seg_size)], |
2385 | - filters => [], |
2386 | - sort_cols => 'cxn', |
2387 | - sort_dir => '1', |
2388 | - innodb => 'ib', |
2389 | - group_by => [], |
2390 | - aggregate => 0, |
2391 | - }, |
2392 | - innodb_locks => { |
2393 | - capt => 'InnoDB Locks', |
2394 | - cust => {}, |
2395 | - cols => { |
2396 | - cxn => { src => 'cxn' }, |
2397 | - db => { src => 'db' }, |
2398 | - index => { src => 'index' }, |
2399 | - insert_intention => { src => 'insert_intention' }, |
2400 | - lock_mode => { src => 'lock_mode' }, |
2401 | - lock_type => { src => 'lock_type' }, |
2402 | - lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, |
2403 | - mysql_thread_id => { src => 'mysql_thread_id' }, |
2404 | - n_bits => { src => 'n_bits' }, |
2405 | - page_no => { src => 'page_no' }, |
2406 | - space_id => { src => 'space_id' }, |
2407 | - special => { src => 'special' }, |
2408 | - tbl => { src => 'table' }, |
2409 | - 'time' => { src => 'active_secs', hdr => 'Active', trans => [ qw(secs_to_time) ] }, |
2410 | - txn_id => { src => 'txn_id' }, |
2411 | - waiting => { src => 'waiting' }, |
2412 | - }, |
2413 | - visible => [ qw(cxn mysql_thread_id lock_type waiting lock_wait_time time lock_mode db tbl index insert_intention special)], |
2414 | - filters => [], |
2415 | - sort_cols => 'cxn -lock_wait_time', |
2416 | - sort_dir => '1', |
2417 | - innodb => 'tx', |
2418 | - colors => [ |
2419 | - { col => 'lock_wait_time', op => '>', arg => 60, color => 'red' }, |
2420 | - { col => 'lock_wait_time', op => '>', arg => 30, color => 'yellow' }, |
2421 | - { col => 'lock_wait_time', op => '>', arg => 10, color => 'green' }, |
2422 | - ], |
2423 | - group_by => [], |
2424 | - aggregate => 0, |
2425 | - }, |
2426 | - innodb_transactions => { |
2427 | - capt => 'InnoDB Transactions', |
2428 | - cust => {}, |
2429 | - cols => { |
2430 | - cxn => { src => 'cxn' }, |
2431 | - active_secs => { src => 'active_secs' }, |
2432 | - has_read_view => { src => 'has_read_view' }, |
2433 | - heap_size => { src => 'heap_size' }, |
2434 | - hostname => { src => $exprs{Host} }, |
2435 | - ip => { src => 'ip' }, |
2436 | - wait_status => { src => 'lock_wait_status' }, |
2437 | - lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, |
2438 | - lock_structs => { src => 'lock_structs' }, |
2439 | - mysql_thread_id => { src => 'mysql_thread_id' }, |
2440 | - os_thread_id => { src => 'os_thread_id' }, |
2441 | - proc_no => { src => 'proc_no' }, |
2442 | - query_id => { src => 'query_id' }, |
2443 | - query_status => { src => 'query_status' }, |
2444 | - query_text => { src => 'query_text', trans => [ qw(no_ctrl_char) ] }, |
2445 | - txn_time_remain => { src => $exprs{TxnTimeRemain}, trans => [ qw(secs_to_time) ] }, |
2446 | - row_locks => { src => 'row_locks' }, |
2447 | - tables_in_use => { src => 'tables_in_use' }, |
2448 | - tables_locked => { src => 'tables_locked' }, |
2449 | - thread_decl_inside => { src => 'thread_decl_inside' }, |
2450 | - thread_status => { src => 'thread_status' }, |
2451 | - 'time' => { src => 'active_secs', trans => [ qw(secs_to_time) ], agg => 'sum' }, |
2452 | - txn_doesnt_see_ge => { src => 'txn_doesnt_see_ge' }, |
2453 | - txn_id => { src => 'txn_id' }, |
2454 | - txn_sees_lt => { src => 'txn_sees_lt' }, |
2455 | - txn_status => { src => 'txn_status', minw => 10, maxw => 10 }, |
2456 | - undo_log_entries => { src => 'undo_log_entries' }, |
2457 | - user => { src => 'user', maxw => 10 }, |
2458 | - cnt => { src => 'mysql_thread_id', minw => 0 }, |
2459 | - }, |
2460 | - visible => [ qw(cxn cnt mysql_thread_id user hostname txn_status time undo_log_entries query_text)], |
2461 | - filters => [ qw( hide_self hide_inactive ) ], |
2462 | - sort_cols => '-active_secs txn_status cxn mysql_thread_id', |
2463 | - sort_dir => '1', |
2464 | - innodb => 'tx', |
2465 | - hide_caption => 1, |
2466 | - colors => [ |
2467 | - { col => 'wait_status', op => 'eq', arg => 'LOCK WAIT', color => 'black on_red' }, |
2468 | - { col => 'time', op => '>', arg => 600, color => 'red' }, |
2469 | - { col => 'time', op => '>', arg => 300, color => 'yellow' }, |
2470 | - { col => 'time', op => '>', arg => 60, color => 'green' }, |
2471 | - { col => 'time', op => '>', arg => 30, color => 'cyan' }, |
2472 | - { col => 'txn_status', op => 'eq', arg => 'not started', color => 'white' }, |
2473 | - ], |
2474 | - group_by => [ qw(cxn txn_status) ], |
2475 | - aggregate => 0, |
2476 | - }, |
2477 | - io_threads => { |
2478 | - capt => 'I/O Threads', |
2479 | - cust => {}, |
2480 | - cols => { |
2481 | - cxn => { src => 'cxn' }, |
2482 | - thread => { src => 'thread' }, |
2483 | - thread_purpose => { src => 'purpose' }, |
2484 | - event_set => { src => 'event_set' }, |
2485 | - thread_status => { src => 'state' }, |
2486 | - }, |
2487 | - visible => [ qw(cxn thread thread_purpose thread_status)], |
2488 | - filters => [ qw() ], |
2489 | - sort_cols => 'cxn thread', |
2490 | - sort_dir => '1', |
2491 | - innodb => 'io', |
2492 | - group_by => [], |
2493 | - aggregate => 0, |
2494 | - }, |
2495 | - log_statistics => { |
2496 | - capt => 'Log Statistics', |
2497 | - cust => {}, |
2498 | - cols => { |
2499 | - cxn => { src => 'cxn' }, |
2500 | - last_chkp => { src => 'IB_lg_last_chkp' }, |
2501 | - log_flushed_to => { src => 'IB_lg_log_flushed_to' }, |
2502 | - log_ios_done => { src => 'IB_lg_log_ios_done' }, |
2503 | - log_ios_s => { src => 'IB_lg_log_ios_s' }, |
2504 | - log_seq_no => { src => 'IB_lg_log_seq_no' }, |
2505 | - pending_chkp_writes => { src => 'IB_lg_pending_chkp_writes' }, |
2506 | - pending_log_writes => { src => 'IB_lg_pending_log_writes' }, |
2507 | - }, |
2508 | - visible => [ qw(cxn log_seq_no log_flushed_to last_chkp log_ios_done log_ios_s)], |
2509 | - filters => [], |
2510 | - sort_cols => 'cxn', |
2511 | - sort_dir => '1', |
2512 | - innodb => 'lg', |
2513 | - group_by => [], |
2514 | - aggregate => 0, |
2515 | - }, |
2516 | - master_status => { |
2517 | - capt => 'Master Status', |
2518 | - cust => {}, |
2519 | - cols => { |
2520 | - cxn => { src => 'cxn' }, |
2521 | - binlog_do_db => { src => 'binlog_do_db' }, |
2522 | - binlog_ignore_db => { src => 'binlog_ignore_db' }, |
2523 | - master_file => { src => 'file' }, |
2524 | - master_pos => { src => 'position' }, |
2525 | - binlog_cache_overflow => { src => '(Binlog_cache_disk_use||0)/(Binlog_cache_use||1)', trans => [ qw(percent) ] }, |
2526 | - }, |
2527 | - visible => [ qw(cxn master_file master_pos binlog_cache_overflow)], |
2528 | - filters => [ qw(cxn_is_master) ], |
2529 | - sort_cols => 'cxn', |
2530 | - sort_dir => '1', |
2531 | - innodb => '', |
2532 | - group_by => [], |
2533 | - aggregate => 0, |
2534 | - }, |
2535 | - pending_io => { |
2536 | - capt => 'Pending I/O', |
2537 | - cust => {}, |
2538 | - cols => { |
2539 | - cxn => { src => 'cxn' }, |
2540 | - p_normal_aio_reads => { src => 'IB_io_pending_normal_aio_reads' }, |
2541 | - p_aio_writes => { src => 'IB_io_pending_aio_writes' }, |
2542 | - p_ibuf_aio_reads => { src => 'IB_io_pending_ibuf_aio_reads' }, |
2543 | - p_sync_ios => { src => 'IB_io_pending_sync_ios' }, |
2544 | - p_buf_pool_flushes => { src => 'IB_io_pending_buffer_pool_flushes' }, |
2545 | - p_log_flushes => { src => 'IB_io_pending_log_flushes' }, |
2546 | - p_log_ios => { src => 'IB_io_pending_log_ios' }, |
2547 | - p_preads => { src => 'IB_io_pending_preads' }, |
2548 | - p_pwrites => { src => 'IB_io_pending_pwrites' }, |
2549 | - }, |
2550 | - visible => [ qw(cxn p_normal_aio_reads p_aio_writes p_ibuf_aio_reads p_sync_ios p_log_flushes p_log_ios)], |
2551 | - filters => [], |
2552 | - sort_cols => 'cxn', |
2553 | - sort_dir => '1', |
2554 | - innodb => 'io', |
2555 | - group_by => [], |
2556 | - aggregate => 0, |
2557 | - }, |
2558 | - open_tables => { |
2559 | - capt => 'Open Tables', |
2560 | - cust => {}, |
2561 | - cols => { |
2562 | - cxn => { src => 'cxn' }, |
2563 | - db => { src => 'database' }, |
2564 | - tbl => { src => 'table' }, |
2565 | - num_times_open => { src => 'in_use' }, |
2566 | - is_name_locked => { src => 'name_locked' }, |
2567 | - }, |
2568 | - visible => [ qw(cxn db tbl num_times_open is_name_locked)], |
2569 | - filters => [ qw(table_is_open) ], |
2570 | - sort_cols => '-num_times_open cxn db tbl', |
2571 | - sort_dir => '1', |
2572 | - innodb => '', |
2573 | - group_by => [], |
2574 | - aggregate => 0, |
2575 | - }, |
2576 | - page_statistics => { |
2577 | - capt => 'Page Statistics', |
2578 | - cust => {}, |
2579 | - cols => { |
2580 | - cxn => { src => 'cxn' }, |
2581 | - pages_read => { src => 'IB_bp_pages_read' }, |
2582 | - pages_written => { src => 'IB_bp_pages_written' }, |
2583 | - pages_created => { src => 'IB_bp_pages_created' }, |
2584 | - page_reads_sec => { src => 'IB_bp_page_reads_sec' }, |
2585 | - page_writes_sec => { src => 'IB_bp_page_writes_sec' }, |
2586 | - page_creates_sec => { src => 'IB_bp_page_creates_sec' }, |
2587 | - }, |
2588 | - visible => [ qw(cxn pages_read pages_written pages_created page_reads_sec page_writes_sec page_creates_sec)], |
2589 | - filters => [], |
2590 | - sort_cols => 'cxn', |
2591 | - sort_dir => '1', |
2592 | - innodb => 'bp', |
2593 | - group_by => [], |
2594 | - aggregate => 0, |
2595 | - }, |
2596 | - processlist => { |
2597 | - capt => 'MySQL Process List', |
2598 | - cust => {}, |
2599 | - cols => { |
2600 | - cxn => { src => 'cxn', minw => 6, maxw => 10 }, |
2601 | - mysql_thread_id => { src => 'id', minw => 6, maxw => 0 }, |
2602 | - user => { src => 'user', minw => 5, maxw => 8 }, |
2603 | - hostname => { src => $exprs{Host}, minw => 13, maxw => 8, }, |
2604 | - port => { src => $exprs{Port}, minw => 0, maxw => 0, }, |
2605 | - host_and_port => { src => 'host', minw => 0, maxw => 0 }, |
2606 | - db => { src => 'db', minw => 6, maxw => 12 }, |
2607 | - cmd => { src => 'command', minw => 5, maxw => 0 }, |
2608 | - time => { src => 'time', minw => 5, maxw => 0, trans => [ qw(secs_to_time) ], agg => 'sum' }, |
2609 | - state => { src => 'state', minw => 0, maxw => 0 }, |
2610 | - info => { src => 'info', minw => 0, maxw => 0, trans => [ qw(no_ctrl_char) ] }, |
2611 | - cnt => { src => 'id', minw => 0, maxw => 0 }, |
2612 | - }, |
2613 | - visible => [ qw(cxn cmd cnt mysql_thread_id user hostname db time info)], |
2614 | - filters => [ qw(hide_self hide_inactive hide_slave_io) ], |
2615 | - sort_cols => '-time cxn hostname mysql_thread_id', |
2616 | - sort_dir => '1', |
2617 | - innodb => '', |
2618 | - hide_caption => 1, |
2619 | - colors => [ |
2620 | - { col => 'state', op => 'eq', arg => 'Locked', color => 'black on_red' }, |
2621 | - { col => 'cmd', op => 'eq', arg => 'Sleep', color => 'white' }, |
2622 | - { col => 'user', op => 'eq', arg => 'system user', color => 'white' }, |
2623 | - { col => 'cmd', op => 'eq', arg => 'Connect', color => 'white' }, |
2624 | - { col => 'cmd', op => 'eq', arg => 'Binlog Dump', color => 'white' }, |
2625 | - { col => 'time', op => '>', arg => 600, color => 'red' }, |
2626 | - { col => 'time', op => '>', arg => 120, color => 'yellow' }, |
2627 | - { col => 'time', op => '>', arg => 60, color => 'green' }, |
2628 | - { col => 'time', op => '>', arg => 30, color => 'cyan' }, |
2629 | - ], |
2630 | - group_by => [qw(cxn cmd)], |
2631 | - aggregate => 0, |
2632 | - }, |
2633 | - |
2634 | - # TODO: some more columns: |
2635 | - # kb_used=hdr='BufUsed' minw='0' num='0' src='percent(1 - ((Key_blocks_unused * key_cache_block_size) / (key_buffer_size||1)))' dec='0' trans='' tbl='q_header' just='-' user='1' maxw='0' label='User-defined' |
2636 | - # retries=hdr='Retries' minw='0' num='0' src='Slave_retried_transactions' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined' |
2637 | - # thd=hdr='Thd' minw='0' num='0' src='Threads_connected' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined' |
2638 | - |
2639 | - q_header => { |
2640 | - capt => 'Q-mode Header', |
2641 | - cust => {}, |
2642 | - cols => { |
2643 | - cxn => { src => 'cxn' }, |
2644 | - questions => { src => 'Questions' }, |
2645 | - qps => { src => 'Questions/Uptime_hires', dec => 1, trans => [qw(shorten)] }, |
2646 | - load => { src => $exprs{ServerLoad}, dec => 1, trans => [qw(shorten)] }, |
2647 | - slow => { src => 'Slow_queries', dec => 1, trans => [qw(shorten)] }, |
2648 | - q_cache_hit => { src => $exprs{QcacheHitRatio}, dec => 1, trans => [qw(percent)] }, |
2649 | - key_buffer_hit => { src => '1-(Key_reads/(Key_read_requests||1))', dec => 1, trans => [qw(percent)] }, |
2650 | - bps_in => { src => 'Bytes_received/Uptime_hires', dec => 1, trans => [qw(shorten)] }, |
2651 | - bps_out => { src => 'Bytes_sent/Uptime_hires', dec => 1, trans => [qw(shorten)] }, |
2652 | - when => { src => 'when' }, |
2653 | - }, |
2654 | - visible => [ qw(cxn when load qps slow q_cache_hit key_buffer_hit bps_in bps_out)], |
2655 | - filters => [], |
2656 | - sort_cols => 'when cxn', |
2657 | - sort_dir => '1', |
2658 | - innodb => '', |
2659 | - hide_caption => 1, |
2660 | - group_by => [], |
2661 | - aggregate => 0, |
2662 | - }, |
2663 | - row_operations => { |
2664 | - capt => 'InnoDB Row Operations', |
2665 | - cust => {}, |
2666 | - cols => { |
2667 | - cxn => { src => 'cxn' }, |
2668 | - num_inserts => { src => 'IB_ro_num_rows_ins' }, |
2669 | - num_updates => { src => 'IB_ro_num_rows_upd' }, |
2670 | - num_reads => { src => 'IB_ro_num_rows_read' }, |
2671 | - num_deletes => { src => 'IB_ro_num_rows_del' }, |
2672 | - num_inserts_sec => { src => 'IB_ro_ins_sec' }, |
2673 | - num_updates_sec => { src => 'IB_ro_upd_sec' }, |
2674 | - num_reads_sec => { src => 'IB_ro_read_sec' }, |
2675 | - num_deletes_sec => { src => 'IB_ro_del_sec' }, |
2676 | - }, |
2677 | - visible => [ qw(cxn num_inserts num_updates num_reads num_deletes num_inserts_sec |
2678 | - num_updates_sec num_reads_sec num_deletes_sec)], |
2679 | - filters => [], |
2680 | - sort_cols => 'cxn', |
2681 | - sort_dir => '1', |
2682 | - innodb => 'ro', |
2683 | - group_by => [], |
2684 | - aggregate => 0, |
2685 | - }, |
2686 | - row_operation_misc => { |
2687 | - capt => 'Row Operation Misc', |
2688 | - cust => {}, |
2689 | - cols => { |
2690 | - cxn => { src => 'cxn' }, |
2691 | - queries_in_queue => { src => 'IB_ro_queries_in_queue' }, |
2692 | - queries_inside => { src => 'IB_ro_queries_inside' }, |
2693 | - read_views_open => { src => 'IB_ro_read_views_open' }, |
2694 | - main_thread_id => { src => 'IB_ro_main_thread_id' }, |
2695 | - main_thread_proc_no => { src => 'IB_ro_main_thread_proc_no' }, |
2696 | - main_thread_state => { src => 'IB_ro_main_thread_state' }, |
2697 | - num_res_ext => { src => 'IB_ro_n_reserved_extents' }, |
2698 | - }, |
2699 | - visible => [ qw(cxn queries_in_queue queries_inside read_views_open main_thread_state)], |
2700 | - filters => [], |
2701 | - sort_cols => 'cxn', |
2702 | - sort_dir => '1', |
2703 | - innodb => 'ro', |
2704 | - group_by => [], |
2705 | - aggregate => 0, |
2706 | - }, |
2707 | - semaphores => { |
2708 | - capt => 'InnoDB Semaphores', |
2709 | - cust => {}, |
2710 | - cols => { |
2711 | - cxn => { src => 'cxn' }, |
2712 | - mutex_os_waits => { src => 'IB_sm_mutex_os_waits' }, |
2713 | - mutex_spin_rounds => { src => 'IB_sm_mutex_spin_rounds' }, |
2714 | - mutex_spin_waits => { src => 'IB_sm_mutex_spin_waits' }, |
2715 | - reservation_count => { src => 'IB_sm_reservation_count' }, |
2716 | - rw_excl_os_waits => { src => 'IB_sm_rw_excl_os_waits' }, |
2717 | - rw_excl_spins => { src => 'IB_sm_rw_excl_spins' }, |
2718 | - rw_shared_os_waits => { src => 'IB_sm_rw_shared_os_waits' }, |
2719 | - rw_shared_spins => { src => 'IB_sm_rw_shared_spins' }, |
2720 | - signal_count => { src => 'IB_sm_signal_count' }, |
2721 | - wait_array_size => { src => 'IB_sm_wait_array_size' }, |
2722 | - }, |
2723 | - visible => [ qw(cxn mutex_os_waits mutex_spin_waits mutex_spin_rounds |
2724 | - rw_excl_os_waits rw_excl_spins rw_shared_os_waits rw_shared_spins |
2725 | - signal_count reservation_count )], |
2726 | - filters => [], |
2727 | - sort_cols => 'cxn', |
2728 | - sort_dir => '1', |
2729 | - innodb => 'sm', |
2730 | - group_by => [], |
2731 | - aggregate => 0, |
2732 | - }, |
2733 | - slave_io_status => { |
2734 | - capt => 'Slave I/O Status', |
2735 | - cust => {}, |
2736 | - cols => { |
2737 | - cxn => { src => 'cxn' }, |
2738 | - connect_retry => { src => 'connect_retry' }, |
2739 | - master_host => { src => 'master_host', hdr => 'Master'}, |
2740 | - master_log_file => { src => 'master_log_file', hdr => 'File' }, |
2741 | - master_port => { src => 'master_port' }, |
2742 | - master_ssl_allowed => { src => 'master_ssl_allowed' }, |
2743 | - master_ssl_ca_file => { src => 'master_ssl_ca_file' }, |
2744 | - master_ssl_ca_path => { src => 'master_ssl_ca_path' }, |
2745 | - master_ssl_cert => { src => 'master_ssl_cert' }, |
2746 | - master_ssl_cipher => { src => 'master_ssl_cipher' }, |
2747 | - master_ssl_key => { src => 'master_ssl_key' }, |
2748 | - master_user => { src => 'master_user' }, |
2749 | - read_master_log_pos => { src => 'read_master_log_pos', hdr => 'Pos' }, |
2750 | - relay_log_size => { src => 'relay_log_space', trans => [qw(shorten)] }, |
2751 | - slave_io_running => { src => 'slave_io_running', hdr => 'On?' }, |
2752 | - slave_io_state => { src => 'slave_io_state', hdr => 'State' }, |
2753 | - }, |
2754 | - visible => [ qw(cxn master_host slave_io_running master_log_file relay_log_size read_master_log_pos slave_io_state)], |
2755 | - filters => [ qw( cxn_is_slave ) ], |
2756 | - sort_cols => 'slave_io_running cxn', |
2757 | - colors => [ |
2758 | - { col => 'slave_io_running', op => 'ne', arg => 'Yes', color => 'black on_red' }, |
2759 | - ], |
2760 | - sort_dir => '1', |
2761 | - innodb => '', |
2762 | - group_by => [], |
2763 | - aggregate => 0, |
2764 | - }, |
2765 | - slave_sql_status => { |
2766 | - capt => 'Slave SQL Status', |
2767 | - cust => {}, |
2768 | - cols => { |
2769 | - cxn => { src => 'cxn' }, |
2770 | - exec_master_log_pos => { src => 'exec_master_log_pos', hdr => 'Master Pos' }, |
2771 | - last_errno => { src => 'last_errno' }, |
2772 | - last_error => { src => 'last_error' }, |
2773 | - master_host => { src => 'master_host', hdr => 'Master' }, |
2774 | - relay_log_file => { src => 'relay_log_file' }, |
2775 | - relay_log_pos => { src => 'relay_log_pos' }, |
2776 | - relay_log_size => { src => 'relay_log_space', trans => [qw(shorten)] }, |
2777 | - relay_master_log_file => { src => 'relay_master_log_file', hdr => 'Master File' }, |
2778 | - replicate_do_db => { src => 'replicate_do_db' }, |
2779 | - replicate_do_table => { src => 'replicate_do_table' }, |
2780 | - replicate_ignore_db => { src => 'replicate_ignore_db' }, |
2781 | - replicate_ignore_table => { src => 'replicate_ignore_table' }, |
2782 | - replicate_wild_do_table => { src => 'replicate_wild_do_table' }, |
2783 | - replicate_wild_ignore_table => { src => 'replicate_wild_ignore_table' }, |
2784 | - skip_counter => { src => 'skip_counter' }, |
2785 | - slave_sql_running => { src => 'slave_sql_running', hdr => 'On?' }, |
2786 | - until_condition => { src => 'until_condition' }, |
2787 | - until_log_file => { src => 'until_log_file' }, |
2788 | - until_log_pos => { src => 'until_log_pos' }, |
2789 | - time_behind_master => { src => 'seconds_behind_master', trans => [ qw(secs_to_time) ] }, |
2790 | - bytes_behind_master => { src => 'master_log_file && master_log_file eq relay_master_log_file ? read_master_log_pos - exec_master_log_pos : 0', trans => [qw(shorten)] }, |
2791 | - slave_catchup_rate => { src => $exprs{SlaveCatchupRate}, trans => [ qw(set_precision) ] }, |
2792 | - slave_open_temp_tables => { src => 'Slave_open_temp_tables' }, |
2793 | - }, |
2794 | - visible => [ qw(cxn master_host slave_sql_running time_behind_master slave_catchup_rate slave_open_temp_tables relay_log_pos last_error)], |
2795 | - filters => [ qw( cxn_is_slave ) ], |
2796 | - sort_cols => 'slave_sql_running cxn', |
2797 | - sort_dir => '1', |
2798 | - innodb => '', |
2799 | - colors => [ |
2800 | - { col => 'slave_sql_running', op => 'ne', arg => 'Yes', color => 'black on_red' }, |
2801 | - { col => 'time_behind_master', op => '>', arg => 600, color => 'red' }, |
2802 | - { col => 'time_behind_master', op => '>', arg => 60, color => 'yellow' }, |
2803 | - { col => 'time_behind_master', op => '==', arg => 0, color => 'white' }, |
2804 | - ], |
2805 | - group_by => [], |
2806 | - aggregate => 0, |
2807 | - }, |
2808 | - t_header => { |
2809 | - capt => 'T-Mode Header', |
2810 | - cust => {}, |
2811 | - cols => { |
2812 | - cxn => { src => 'cxn' }, |
2813 | - dirty_bufs => { src => $exprs{DirtyBufs}, trans => [qw(percent)] }, |
2814 | - history_list_len => { src => 'IB_tx_history_list_len' }, |
2815 | - lock_structs => { src => 'IB_tx_num_lock_structs' }, |
2816 | - num_txns => { src => $exprs{NumTxns} }, |
2817 | - max_txn => { src => $exprs{MaxTxnTime}, trans => [qw(secs_to_time)] }, |
2818 | - undo_for => { src => 'IB_tx_purge_undo_for' }, |
2819 | - used_bufs => { src => $exprs{BufPoolFill}, trans => [qw(percent)]}, |
2820 | - versions => { src => $exprs{OldVersions} }, |
2821 | - }, |
2822 | - visible => [ qw(cxn history_list_len versions undo_for dirty_bufs used_bufs num_txns max_txn lock_structs)], |
2823 | - filters => [ ], |
2824 | - sort_cols => 'cxn', |
2825 | - sort_dir => '1', |
2826 | - innodb => '', |
2827 | - colors => [], |
2828 | - hide_caption => 1, |
2829 | - group_by => [], |
2830 | - aggregate => 0, |
2831 | - }, |
2832 | - var_status => { |
2833 | - capt => 'Variables & Status', |
2834 | - cust => {}, |
2835 | - cols => {}, # Generated from current varset |
2836 | - visible => [], # Generated from current varset |
2837 | - filters => [], |
2838 | - sort_cols => '', |
2839 | - sort_dir => 1, |
2840 | - innodb => '', |
2841 | - temp => 1, # Do not persist to config file. |
2842 | - hide_caption => 1, |
2843 | - pivot => 0, |
2844 | - group_by => [], |
2845 | - aggregate => 0, |
2846 | - }, |
2847 | - wait_array => { |
2848 | - capt => 'InnoDB Wait Array', |
2849 | - cust => {}, |
2850 | - cols => { |
2851 | - cxn => { src => 'cxn' }, |
2852 | - thread => { src => 'thread' }, |
2853 | - waited_at_filename => { src => 'waited_at_filename' }, |
2854 | - waited_at_line => { src => 'waited_at_line' }, |
2855 | - 'time' => { src => 'waited_secs', trans => [ qw(secs_to_time) ] }, |
2856 | - request_type => { src => 'request_type' }, |
2857 | - lock_mem_addr => { src => 'lock_mem_addr' }, |
2858 | - lock_cfile_name => { src => 'lock_cfile_name' }, |
2859 | - lock_cline => { src => 'lock_cline' }, |
2860 | - writer_thread => { src => 'writer_thread' }, |
2861 | - writer_lock_mode => { src => 'writer_lock_mode' }, |
2862 | - num_readers => { src => 'num_readers' }, |
2863 | - lock_var => { src => 'lock_var' }, |
2864 | - waiters_flag => { src => 'waiters_flag' }, |
2865 | - last_s_file_name => { src => 'last_s_file_name' }, |
2866 | - last_s_line => { src => 'last_s_line' }, |
2867 | - last_x_file_name => { src => 'last_x_file_name' }, |
2868 | - last_x_line => { src => 'last_x_line' }, |
2869 | - cell_waiting => { src => 'cell_waiting' }, |
2870 | - cell_event_set => { src => 'cell_event_set' }, |
2871 | - }, |
2872 | - visible => [ qw(cxn thread time waited_at_filename waited_at_line request_type num_readers lock_var waiters_flag cell_waiting cell_event_set)], |
2873 | - filters => [], |
2874 | - sort_cols => 'cxn -time', |
2875 | - sort_dir => '1', |
2876 | - innodb => 'sm', |
2877 | - group_by => [], |
2878 | - aggregate => 0, |
2879 | - }, |
2880 | -); |
2881 | - |
2882 | -# Initialize %tbl_meta from %columns and do some checks. |
2883 | -foreach my $table_name ( keys %tbl_meta ) { |
2884 | - my $table = $tbl_meta{$table_name}; |
2885 | - my $cols = $table->{cols}; |
2886 | - |
2887 | - foreach my $col_name ( keys %$cols ) { |
2888 | - my $col_def = $table->{cols}->{$col_name}; |
2889 | - die "I can't find a column named '$col_name' for '$table_name'" unless $columns{$col_name}; |
2890 | - $columns{$col_name}->{referenced} = 1; |
2891 | - |
2892 | - foreach my $prop ( keys %col_props ) { |
2893 | - # Each column gets non-existing values set from %columns or defaults from %col_props. |
2894 | - if ( !$col_def->{$prop} ) { |
2895 | - $col_def->{$prop} |
2896 | - = defined($columns{$col_name}->{$prop}) |
2897 | - ? $columns{$col_name}->{$prop} |
2898 | - : $col_props{$prop}; |
2899 | - } |
2900 | - } |
2901 | - |
2902 | - # Ensure transformations and aggregate functions are valid |
2903 | - die "Unknown aggregate function '$col_def->{agg}' " |
2904 | - . "for column '$col_name' in table '$table_name'" |
2905 | - unless exists $agg_funcs{$col_def->{agg}}; |
2906 | - foreach my $trans ( @{$col_def->{trans}} ) { |
2907 | - die "Unknown transformation '$trans' " |
2908 | - . "for column '$col_name' in table '$table_name'" |
2909 | - unless exists $trans_funcs{$trans}; |
2910 | - } |
2911 | - } |
2912 | - |
2913 | - # Ensure each column in visible and group_by exists in cols |
2914 | - foreach my $place ( qw(visible group_by) ) { |
2915 | - foreach my $col_name ( @{$table->{$place}} ) { |
2916 | - if ( !exists $cols->{$col_name} ) { |
2917 | - die "Column '$col_name' is listed in '$place' for '$table_name', but doesn't exist"; |
2918 | - } |
2919 | - } |
2920 | - } |
2921 | - |
2922 | - # Compile sort and color subroutines |
2923 | - $table->{sort_func} = make_sort_func($table); |
2924 | - $table->{color_func} = make_color_func($table); |
2925 | -} |
2926 | - |
2927 | -# This is for code cleanup: |
2928 | -{ |
2929 | - my @unused_cols = grep { !$columns{$_}->{referenced} } sort keys %columns; |
2930 | - if ( @unused_cols ) { |
2931 | - die "The following columns are not used: " |
2932 | - . join(' ', @unused_cols); |
2933 | - } |
2934 | -} |
2935 | - |
2936 | -# ########################################################################### |
2937 | -# Operating modes {{{3 |
2938 | -# ########################################################################### |
2939 | -my %modes = ( |
2940 | - B => { |
2941 | - hdr => 'InnoDB Buffers', |
2942 | - cust => {}, |
2943 | - note => 'Shows buffer info from InnoDB', |
2944 | - action_for => { |
2945 | - i => { |
2946 | - action => sub { toggle_config('status_inc') }, |
2947 | - label => 'Toggle incremental status display', |
2948 | - }, |
2949 | - }, |
2950 | - display_sub => \&display_B, |
2951 | - connections => [], |
2952 | - server_group => '', |
2953 | - one_connection => 0, |
2954 | - tables => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)], |
2955 | - visible_tables => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)], |
2956 | - }, |
2957 | - C => { |
2958 | - hdr => 'Command Summary', |
2959 | - cust => {}, |
2960 | - note => 'Shows relative magnitude of variables', |
2961 | - action_for => { |
2962 | - s => { |
2963 | - action => sub { get_config_interactive('cmd_filter') }, |
2964 | - label => 'Choose variable prefix', |
2965 | - }, |
2966 | - }, |
2967 | - display_sub => \&display_C, |
2968 | - connections => [], |
2969 | - server_group => '', |
2970 | - one_connection => 0, |
2971 | - tables => [qw(cmd_summary)], |
2972 | - visible_tables => [qw(cmd_summary)], |
2973 | - }, |
2974 | - D => { |
2975 | - hdr => 'InnoDB Deadlocks', |
2976 | - cust => {}, |
2977 | - note => 'View InnoDB deadlock information', |
2978 | - action_for => { |
2979 | - c => { |
2980 | - action => sub { edit_table('deadlock_transactions') }, |
2981 | - label => 'Choose visible columns', |
2982 | - }, |
2983 | - w => { |
2984 | - action => \&create_deadlock, |
2985 | - label => 'Wipe deadlock status info by creating a deadlock', |
2986 | - }, |
2987 | - }, |
2988 | - display_sub => \&display_D, |
2989 | - connections => [], |
2990 | - server_group => '', |
2991 | - one_connection => 0, |
2992 | - tables => [qw(deadlock_transactions deadlock_locks)], |
2993 | - visible_tables => [qw(deadlock_transactions deadlock_locks)], |
2994 | - }, |
2995 | - F => { |
2996 | - hdr => 'InnoDB FK Err', |
2997 | - cust => {}, |
2998 | - note => 'View the latest InnoDB foreign key error', |
2999 | - action_for => {}, |
3000 | - display_sub => \&display_F, |
3001 | - connections => [], |
3002 | - server_group => '', |
3003 | - one_connection => 1, |
3004 | - tables => [qw(fk_error)], |
3005 | - visible_tables => [qw(fk_error)], |
3006 | - }, |
3007 | - I => { |
3008 | - hdr => 'InnoDB I/O Info', |
3009 | - cust => {}, |
3010 | - note => 'Shows I/O info (i/o, log...) from InnoDB', |
3011 | - action_for => { |
3012 | - i => { |
3013 | - action => sub { toggle_config('status_inc') }, |
3014 | - label => 'Toggle incremental status display', |
3015 | - }, |
3016 | - }, |
3017 | - display_sub => \&display_I, |
3018 | - connections => [], |
3019 | - server_group => '', |
3020 | - one_connection => 0, |
3021 | - tables => [qw(io_threads pending_io file_io_misc log_statistics)], |
3022 | - visible_tables => [qw(io_threads pending_io file_io_misc log_statistics)], |
3023 | - }, |
3024 | - L => { |
3025 | - hdr => 'Locks', |
3026 | - cust => {}, |
3027 | - note => 'Shows transaction locks', |
3028 | - action_for => { |
3029 | - a => { |
3030 | - action => sub { send_cmd_to_servers('CREATE TABLE IF NOT EXISTS test.innodb_lock_monitor(a int) ENGINE=InnoDB', 0, '', []); }, |
3031 | - label => 'Start the InnoDB Lock Monitor', |
3032 | - }, |
3033 | - o => { |
3034 | - action => sub { send_cmd_to_servers('DROP TABLE IF EXISTS test.innodb_lock_monitor', 0, '', []); }, |
3035 | - label => 'Stop the InnoDB Lock Monitor', |
3036 | - }, |
3037 | - }, |
3038 | - display_sub => \&display_L, |
3039 | - connections => [], |
3040 | - server_group => '', |
3041 | - one_connection => 0, |
3042 | - tables => [qw(innodb_locks)], |
3043 | - visible_tables => [qw(innodb_locks)], |
3044 | - }, |
3045 | - M => { |
3046 | - hdr => 'Replication Status', |
3047 | - cust => {}, |
3048 | - note => 'Shows replication (master and slave) status', |
3049 | - action_for => { |
3050 | - a => { |
3051 | - action => sub { send_cmd_to_servers('START SLAVE', 0, 'START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE = ?, MASTER_LOG_POS = ?', []); }, |
3052 | - label => 'Start slave(s)', |
3053 | - }, |
3054 | - i => { |
3055 | - action => sub { toggle_config('status_inc') }, |
3056 | - label => 'Toggle incremental status display', |
3057 | - }, |
3058 | - o => { |
3059 | - action => sub { send_cmd_to_servers('STOP SLAVE', 0, '', []); }, |
3060 | - label => 'Stop slave(s)', |
3061 | - }, |
3062 | - b => { |
3063 | - action => sub { purge_master_logs() }, |
3064 | - label => 'Purge unused master logs', |
3065 | - }, |
3066 | - }, |
3067 | - display_sub => \&display_M, |
3068 | - connections => [], |
3069 | - server_group => '', |
3070 | - one_connection => 0, |
3071 | - tables => [qw(slave_sql_status slave_io_status master_status)], |
3072 | - visible_tables => [qw(slave_sql_status slave_io_status master_status)], |
3073 | - }, |
3074 | - O => { |
3075 | - hdr => 'Open Tables', |
3076 | - cust => {}, |
3077 | - note => 'Shows open tables in MySQL', |
3078 | - action_for => { |
3079 | - r => { |
3080 | - action => sub { reverse_sort('open_tables'); }, |
3081 | - label => 'Reverse sort order', |
3082 | - }, |
3083 | - s => { |
3084 | - action => sub { choose_sort_cols('open_tables'); }, |
3085 | - label => "Choose sort column", |
3086 | - }, |
3087 | - }, |
3088 | - display_sub => \&display_O, |
3089 | - connections => [], |
3090 | - server_group => '', |
3091 | - one_connection => 0, |
3092 | - tables => [qw(open_tables)], |
3093 | - visible_tables => [qw(open_tables)], |
3094 | - }, |
3095 | - Q => { |
3096 | - hdr => 'Query List', |
3097 | - cust => {}, |
3098 | - note => 'Shows queries from SHOW FULL PROCESSLIST', |
3099 | - action_for => { |
3100 | - a => { |
3101 | - action => sub { toggle_filter('processlist', 'hide_self') }, |
3102 | - label => 'Toggle the innotop process', |
3103 | - }, |
3104 | - c => { |
3105 | - action => sub { edit_table('processlist') }, |
3106 | - label => 'Choose visible columns', |
3107 | - }, |
3108 | - e => { |
3109 | - action => sub { analyze_query('e'); }, |
3110 | - label => "Explain a thread's query", |
3111 | - }, |
3112 | - f => { |
3113 | - action => sub { analyze_query('f'); }, |
3114 | - label => "Show a thread's full query", |
3115 | - }, |
3116 | - h => { |
3117 | - action => sub { toggle_visible_table('Q', 'q_header') }, |
3118 | - label => 'Toggle the header on and off', |
3119 | - }, |
3120 | - i => { |
3121 | - action => sub { toggle_filter('processlist', 'hide_inactive') }, |
3122 | - label => 'Toggle idle processes', |
3123 | - }, |
3124 | - k => { |
3125 | - action => sub { kill_query('CONNECTION') }, |
3126 | - label => "Kill a query's connection", |
3127 | - }, |
3128 | - r => { |
3129 | - action => sub { reverse_sort('processlist'); }, |
3130 | - label => 'Reverse sort order', |
3131 | - }, |
3132 | - s => { |
3133 | - action => sub { choose_sort_cols('processlist'); }, |
3134 | - label => "Change the display's sort column", |
3135 | - }, |
3136 | - x => { |
3137 | - action => sub { kill_query('QUERY') }, |
3138 | - label => "Kill a query", |
3139 | - }, |
3140 | - }, |
3141 | - display_sub => \&display_Q, |
3142 | - connections => [], |
3143 | - server_group => '', |
3144 | - one_connection => 0, |
3145 | - tables => [qw(q_header processlist)], |
3146 | - visible_tables => [qw(q_header processlist)], |
3147 | - }, |
3148 | - R => { |
3149 | - hdr => 'InnoDB Row Ops', |
3150 | - cust => {}, |
3151 | - note => 'Shows InnoDB row operation and semaphore info', |
3152 | - action_for => { |
3153 | - i => { |
3154 | - action => sub { toggle_config('status_inc') }, |
3155 | - label => 'Toggle incremental status display', |
3156 | - }, |
3157 | - }, |
3158 | - display_sub => \&display_R, |
3159 | - connections => [], |
3160 | - server_group => '', |
3161 | - one_connection => 0, |
3162 | - tables => [qw(row_operations row_operation_misc semaphores wait_array)], |
3163 | - visible_tables => [qw(row_operations row_operation_misc semaphores wait_array)], |
3164 | - }, |
3165 | - S => { |
3166 | - hdr => 'Variables & Status', |
3167 | - cust => {}, |
3168 | - note => 'Shows query load statistics a la vmstat', |
3169 | - action_for => { |
3170 | - '>' => { |
3171 | - action => sub { switch_var_set('S_set', 1) }, |
3172 | - label => 'Switch to next variable set', |
3173 | - }, |
3174 | - '<' => { |
3175 | - action => sub { switch_var_set('S_set', -1) }, |
3176 | - label => 'Switch to prev variable set', |
3177 | - }, |
3178 | - c => { |
3179 | - action => sub { |
3180 | - choose_var_set('S_set'); |
3181 | - start_S_mode(); |
3182 | - }, |
3183 | - label => "Choose which set to display", |
3184 | - }, |
3185 | - e => { |
3186 | - action => \&edit_current_var_set, |
3187 | - label => 'Edit the current set of variables', |
3188 | - }, |
3189 | - i => { |
3190 | - action => sub { $clear_screen_sub->(); toggle_config('status_inc') }, |
3191 | - label => 'Toggle incremental status display', |
3192 | - }, |
3193 | - '-' => { |
3194 | - action => sub { set_display_precision(-1) }, |
3195 | - label => 'Decrease fractional display precision', |
3196 | - }, |
3197 | - '+' => { |
3198 | - action => sub { set_display_precision(1) }, |
3199 | - label => 'Increase fractional display precision', |
3200 | - }, |
3201 | - g => { |
3202 | - action => sub { set_s_mode('g') }, |
3203 | - label => 'Switch to graph (tload) view', |
3204 | - }, |
3205 | - s => { |
3206 | - action => sub { set_s_mode('s') }, |
3207 | - label => 'Switch to standard (vmstat) view', |
3208 | - }, |
3209 | - v => { |
3210 | - action => sub { set_s_mode('v') }, |
3211 | - label => 'Switch to pivoted view', |
3212 | - }, |
3213 | - }, |
3214 | - display_sub => \&display_S, |
3215 | - no_clear_screen => 1, |
3216 | - connections => [], |
3217 | - server_group => '', |
3218 | - one_connection => 0, |
3219 | - tables => [qw(var_status)], |
3220 | - visible_tables => [qw(var_status)], |
3221 | - }, |
3222 | - T => { |
3223 | - hdr => 'InnoDB Txns', |
3224 | - cust => {}, |
3225 | - note => 'Shows InnoDB transactions in top-like format', |
3226 | - action_for => { |
3227 | - a => { |
3228 | - action => sub { toggle_filter('innodb_transactions', 'hide_self') }, |
3229 | - label => 'Toggle the innotop process', |
3230 | - }, |
3231 | - c => { |
3232 | - action => sub { edit_table('innodb_transactions') }, |
3233 | - label => 'Choose visible columns', |
3234 | - }, |
3235 | - e => { |
3236 | - action => sub { analyze_query('e'); }, |
3237 | - label => "Explain a thread's query", |
3238 | - }, |
3239 | - f => { |
3240 | - action => sub { analyze_query('f'); }, |
3241 | - label => "Show a thread's full query", |
3242 | - }, |
3243 | - h => { |
3244 | - action => sub { toggle_visible_table('T', 't_header') }, |
3245 | - label => 'Toggle the header on and off', |
3246 | - }, |
3247 | - i => { |
3248 | - action => sub { toggle_filter('innodb_transactions', 'hide_inactive') }, |
3249 | - label => 'Toggle inactive transactions', |
3250 | - }, |
3251 | - k => { |
3252 | - action => sub { kill_query('CONNECTION') }, |
3253 | - label => "Kill a transaction's connection", |
3254 | - }, |
3255 | - r => { |
3256 | - action => sub { reverse_sort('innodb_transactions'); }, |
3257 | - label => 'Reverse sort order', |
3258 | - }, |
3259 | - s => { |
3260 | - action => sub { choose_sort_cols('innodb_transactions'); }, |
3261 | - label => "Change the display's sort column", |
3262 | - }, |
3263 | - x => { |
3264 | - action => sub { kill_query('QUERY') }, |
3265 | - label => "Kill a query", |
3266 | - }, |
3267 | - }, |
3268 | - display_sub => \&display_T, |
3269 | - connections => [], |
3270 | - server_group => '', |
3271 | - one_connection => 0, |
3272 | - tables => [qw(t_header innodb_transactions)], |
3273 | - visible_tables => [qw(t_header innodb_transactions)], |
3274 | - }, |
3275 | -); |
3276 | - |
3277 | -# ########################################################################### |
3278 | -# Global key mappings {{{3 |
3279 | -# Keyed on a single character, which is read from the keyboard. Uppercase |
3280 | -# letters switch modes. Lowercase letters access commands when in a mode. |
3281 | -# These can be overridden by action_for in %modes. |
3282 | -# ########################################################################### |
3283 | -my %action_for = ( |
3284 | - '$' => { |
3285 | - action => \&edit_configuration, |
3286 | - label => 'Edit configuration settings', |
3287 | - }, |
3288 | - '?' => { |
3289 | - action => \&display_help, |
3290 | - label => 'Show help', |
3291 | - }, |
3292 | - '!' => { |
3293 | - action => \&display_license, |
3294 | - label => 'Show license and warranty', |
3295 | - }, |
3296 | - '^' => { |
3297 | - action => \&edit_table, |
3298 | - label => "Edit the displayed table(s)", |
3299 | - }, |
3300 | - '#' => { |
3301 | - action => \&choose_server_groups, |
3302 | - label => 'Select/create server groups', |
3303 | - }, |
3304 | - '@' => { |
3305 | - action => \&choose_servers, |
3306 | - label => 'Select/create server connections', |
3307 | - }, |
3308 | - '/' => { |
3309 | - action => \&add_quick_filter, |
3310 | - label => 'Quickly filter what you see', |
3311 | - }, |
3312 | - '\\' => { |
3313 | - action => \&clear_quick_filters, |
3314 | - label => 'Clear quick-filters', |
3315 | - }, |
3316 | - '%' => { |
3317 | - action => \&choose_filters, |
3318 | - label => 'Choose and edit table filters', |
3319 | - }, |
3320 | - "\t" => { |
3321 | - action => \&next_server_group, |
3322 | - label => 'Switch to the next server group', |
3323 | - key => 'TAB', |
3324 | - }, |
3325 | - '=' => { |
3326 | - action => \&toggle_aggregate, |
3327 | - label => 'Toggle aggregation', |
3328 | - }, |
3329 | - # TODO: can these be auto-generated from %modes? |
3330 | - B => { |
3331 | - action => sub { switch_mode('B') }, |
3332 | - label => '', |
3333 | - }, |
3334 | - C => { |
3335 | - action => sub { switch_mode('C') }, |
3336 | - label => '', |
3337 | - }, |
3338 | - D => { |
3339 | - action => sub { switch_mode('D') }, |
3340 | - label => '', |
3341 | - }, |
3342 | - F => { |
3343 | - action => sub { switch_mode('F') }, |
3344 | - label => '', |
3345 | - }, |
3346 | - I => { |
3347 | - action => sub { switch_mode('I') }, |
3348 | - label => '', |
3349 | - }, |
3350 | - L => { |
3351 | - action => sub { switch_mode('L') }, |
3352 | - label => '', |
3353 | - }, |
3354 | - M => { |
3355 | - action => sub { switch_mode('M') }, |
3356 | - label => '', |
3357 | - }, |
3358 | - O => { |
3359 | - action => sub { switch_mode('O') }, |
3360 | - label => '', |
3361 | - }, |
3362 | - Q => { |
3363 | - action => sub { switch_mode('Q') }, |
3364 | - label => '', |
3365 | - }, |
3366 | - R => { |
3367 | - action => sub { switch_mode('R') }, |
3368 | - label => '', |
3369 | - }, |
3370 | - S => { |
3371 | - action => \&start_S_mode, |
3372 | - label => '', |
3373 | - }, |
3374 | - T => { |
3375 | - action => sub { switch_mode('T') }, |
3376 | - label => '', |
3377 | - }, |
3378 | - d => { |
3379 | - action => sub { get_config_interactive('interval') }, |
3380 | - label => 'Change refresh interval', |
3381 | - }, |
3382 | - n => { action => \&next_server, label => 'Switch to the next connection' }, |
3383 | - p => { action => \&pause, label => 'Pause innotop', }, |
3384 | - q => { action => \&finish, label => 'Quit innotop', }, |
3385 | -); |
3386 | - |
3387 | -# ########################################################################### |
3388 | -# Sleep times after certain statements {{{3 |
3389 | -# ########################################################################### |
3390 | -my %stmt_sleep_time_for = (); |
3391 | - |
3392 | -# ########################################################################### |
3393 | -# Config editor key mappings {{{3 |
3394 | -# ########################################################################### |
3395 | -my %cfg_editor_action = ( |
3396 | - c => { |
3397 | - note => 'Edit columns, etc in the displayed table(s)', |
3398 | - func => \&edit_table, |
3399 | - }, |
3400 | - g => { |
3401 | - note => 'Edit general configuration', |
3402 | - func => \&edit_configuration_variables, |
3403 | - }, |
3404 | - k => { |
3405 | - note => 'Edit row-coloring rules', |
3406 | - func => \&edit_color_rules, |
3407 | - }, |
3408 | - p => { |
3409 | - note => 'Manage plugins', |
3410 | - func => \&edit_plugins, |
3411 | - }, |
3412 | - s => { |
3413 | - note => 'Edit server groups', |
3414 | - func => \&edit_server_groups, |
3415 | - }, |
3416 | - S => { |
3417 | - note => 'Edit SQL statement sleep delays', |
3418 | - func => \&edit_stmt_sleep_times, |
3419 | - }, |
3420 | - t => { |
3421 | - note => 'Choose which table(s) to display in this mode', |
3422 | - func => \&choose_mode_tables, |
3423 | - }, |
3424 | -); |
3425 | - |
3426 | -# ########################################################################### |
3427 | -# Color editor key mappings {{{3 |
3428 | -# ########################################################################### |
3429 | -my %color_editor_action = ( |
3430 | - n => { |
3431 | - note => 'Create a new color rule', |
3432 | - func => sub { |
3433 | - my ( $tbl, $idx ) = @_; |
3434 | - my $meta = $tbl_meta{$tbl}; |
3435 | - |
3436 | - $clear_screen_sub->(); |
3437 | - my $col; |
3438 | - do { |
3439 | - $col = prompt_list( |
3440 | - 'Choose the target column for the rule', |
3441 | - '', |
3442 | - sub { return keys %{$meta->{cols}} }, |
3443 | - { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }); |
3444 | - } while ( !$col ); |
3445 | - ( $col ) = grep { $_ } split(/\W+/, $col); |
3446 | - return $idx unless $col && exists $meta->{cols}->{$col}; |
3447 | - |
3448 | - $clear_screen_sub->(); |
3449 | - my $op; |
3450 | - do { |
3451 | - $op = prompt_list( |
3452 | - 'Choose the comparison operator for the rule', |
3453 | - '', |
3454 | - sub { return keys %comp_ops }, |
3455 | - { map { $_ => $comp_ops{$_} } keys %comp_ops } ); |
3456 | - } until ( $op ); |
3457 | - $op =~ s/\s+//g; |
3458 | - return $idx unless $op && exists $comp_ops{$op}; |
3459 | - |
3460 | - my $arg; |
3461 | - do { |
3462 | - $arg = prompt('Specify an argument for the comparison'); |
3463 | - } until defined $arg; |
3464 | - |
3465 | - my $color; |
3466 | - do { |
3467 | - $color = prompt_list( |
3468 | - 'Choose the color(s) the row should be when the rule matches', |
3469 | - '', |
3470 | - sub { return keys %ansicolors }, |
3471 | - { map { $_ => $_ } keys %ansicolors } ); |
3472 | - } until defined $color; |
3473 | - $color = join(' ', unique(grep { exists $ansicolors{$_} } split(/\W+/, $color))); |
3474 | - return $idx unless $color; |
3475 | - |
3476 | - push @{$tbl_meta{$tbl}->{colors}}, { |
3477 | - col => $col, |
3478 | - op => $op, |
3479 | - arg => $arg, |
3480 | - color => $color |
3481 | - }; |
3482 | - $tbl_meta{$tbl}->{cust}->{colors} = 1; |
3483 | - |
3484 | - return $idx; |
3485 | - }, |
3486 | - }, |
3487 | - d => { |
3488 | - note => 'Remove the selected rule', |
3489 | - func => sub { |
3490 | - my ( $tbl, $idx ) = @_; |
3491 | - my @rules = @{ $tbl_meta{$tbl}->{colors} }; |
3492 | - return 0 unless @rules > 0 && $idx < @rules && $idx >= 0; |
3493 | - splice(@{$tbl_meta{$tbl}->{colors}}, $idx, 1); |
3494 | - $tbl_meta{$tbl}->{cust}->{colors} = 1; |
3495 | - return $idx == @rules ? $#rules : $idx; |
3496 | - }, |
3497 | - }, |
3498 | - j => { |
3499 | - note => 'Move highlight down one', |
3500 | - func => sub { |
3501 | - my ( $tbl, $idx ) = @_; |
3502 | - my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}}; |
3503 | - return ($idx + 1) % $num_rules; |
3504 | - }, |
3505 | - }, |
3506 | - k => { |
3507 | - note => 'Move highlight up one', |
3508 | - func => sub { |
3509 | - my ( $tbl, $idx ) = @_; |
3510 | - my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}}; |
3511 | - return ($idx - 1) % $num_rules; |
3512 | - }, |
3513 | - }, |
3514 | - '+' => { |
3515 | - note => 'Move selected rule up one', |
3516 | - func => sub { |
3517 | - my ( $tbl, $idx ) = @_; |
3518 | - my $meta = $tbl_meta{$tbl}; |
3519 | - my $dest = $idx == 0 ? scalar(@{$meta->{colors}} - 1) : $idx - 1; |
3520 | - my $temp = $meta->{colors}->[$idx]; |
3521 | - $meta->{colors}->[$idx] = $meta->{colors}->[$dest]; |
3522 | - $meta->{colors}->[$dest] = $temp; |
3523 | - $meta->{cust}->{colors} = 1; |
3524 | - return $dest; |
3525 | - }, |
3526 | - }, |
3527 | - '-' => { |
3528 | - note => 'Move selected rule down one', |
3529 | - func => sub { |
3530 | - my ( $tbl, $idx ) = @_; |
3531 | - my $meta = $tbl_meta{$tbl}; |
3532 | - my $dest = $idx == scalar(@{$meta->{colors}} - 1) ? 0 : $idx + 1; |
3533 | - my $temp = $meta->{colors}->[$idx]; |
3534 | - $meta->{colors}->[$idx] = $meta->{colors}->[$dest]; |
3535 | - $meta->{colors}->[$dest] = $temp; |
3536 | - $meta->{cust}->{colors} = 1; |
3537 | - return $dest; |
3538 | - }, |
3539 | - }, |
3540 | -); |
3541 | - |
3542 | -# ########################################################################### |
3543 | -# Plugin editor key mappings {{{3 |
3544 | -# ########################################################################### |
3545 | -my %plugin_editor_action = ( |
3546 | - '*' => { |
3547 | - note => 'Toggle selected plugin active/inactive', |
3548 | - func => sub { |
3549 | - my ( $plugins, $idx ) = @_; |
3550 | - my $plugin = $plugins->[$idx]; |
3551 | - $plugin->{active} = $plugin->{active} ? 0 : 1; |
3552 | - return $idx; |
3553 | - }, |
3554 | - }, |
3555 | - j => { |
3556 | - note => 'Move highlight down one', |
3557 | - func => sub { |
3558 | - my ( $plugins, $idx ) = @_; |
3559 | - return ($idx + 1) % scalar(@$plugins); |
3560 | - }, |
3561 | - }, |
3562 | - k => { |
3563 | - note => 'Move highlight up one', |
3564 | - func => sub { |
3565 | - my ( $plugins, $idx ) = @_; |
3566 | - return $idx == 0 ? @$plugins - 1 : $idx - 1; |
3567 | - }, |
3568 | - }, |
3569 | -); |
3570 | - |
3571 | -# ########################################################################### |
3572 | -# Table editor key mappings {{{3 |
3573 | -# ########################################################################### |
3574 | -my %tbl_editor_action = ( |
3575 | - a => { |
3576 | - note => 'Add a column to the table', |
3577 | - func => sub { |
3578 | - my ( $tbl, $col ) = @_; |
3579 | - my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; |
3580 | - my %all_cols = %{ $tbl_meta{$tbl}->{cols} }; |
3581 | - delete @all_cols{@visible_cols}; |
3582 | - my $choice = prompt_list( |
3583 | - 'Choose a column', |
3584 | - '', |
3585 | - sub { return keys %all_cols; }, |
3586 | - { map { $_ => $all_cols{$_}->{label} || $all_cols{$_}->{hdr} } keys %all_cols }); |
3587 | - if ( $all_cols{$choice} ) { |
3588 | - push @{$tbl_meta{$tbl}->{visible}}, $choice; |
3589 | - $tbl_meta{$tbl}->{cust}->{visible} = 1; |
3590 | - return $choice; |
3591 | - } |
3592 | - return $col; |
3593 | - }, |
3594 | - }, |
3595 | - n => { |
3596 | - note => 'Create a new column and add it to the table', |
3597 | - func => sub { |
3598 | - my ( $tbl, $col ) = @_; |
3599 | - |
3600 | - $clear_screen_sub->(); |
3601 | - print word_wrap("Choose a name for the column. This name is not displayed, and is used only " |
3602 | - . "for internal reference. It can contain only lowercase letters, numbers, " |
3603 | - . "and underscores."); |
3604 | - print "\n\n"; |
3605 | - do { |
3606 | - $col = prompt("Enter column name"); |
3607 | - $col = '' if $col =~ m/[^a-z0-9_]/; |
3608 | - } while ( !$col ); |
3609 | - |
3610 | - $clear_screen_sub->(); |
3611 | - my $hdr; |
3612 | - do { |
3613 | - $hdr = prompt("Enter column header"); |
3614 | - } while ( !$hdr ); |
3615 | - |
3616 | - $clear_screen_sub->(); |
3617 | - print "Choose a source for the column's data\n\n"; |
3618 | - my ( $src, $sub, $err ); |
3619 | - do { |
3620 | - if ( $err ) { |
3621 | - print "Error: $err\n\n"; |
3622 | - } |
3623 | - $src = prompt("Enter column source"); |
3624 | - if ( $src ) { |
3625 | - ( $sub, $err ) = compile_expr($src); |
3626 | - } |
3627 | - } until ( !$err); |
3628 | - |
3629 | - # TODO: this duplicates %col_props. |
3630 | - $tbl_meta{$tbl}->{cols}->{$col} = { |
3631 | - hdr => $hdr, |
3632 | - src => $src, |
3633 | - just => '-', |
3634 | - num => 0, |
3635 | - label => 'User-defined', |
3636 | - user => 1, |
3637 | - tbl => $tbl, |
3638 | - minw => 0, |
3639 | - maxw => 0, |
3640 | - trans => [], |
3641 | - func => $sub, |
3642 | - dec => 0, |
3643 | - agg => 0, |
3644 | - aggonly => 0, |
3645 | - }; |
3646 | - |
3647 | - $tbl_meta{$tbl}->{visible} = [ unique(@{$tbl_meta{$tbl}->{visible}}, $col) ]; |
3648 | - $tbl_meta{$tbl}->{cust}->{visible} = 1; |
3649 | - return $col; |
3650 | - }, |
3651 | - }, |
3652 | - d => { |
3653 | - note => 'Remove selected column', |
3654 | - func => sub { |
3655 | - my ( $tbl, $col ) = @_; |
3656 | - my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; |
3657 | - my $idx = 0; |
3658 | - return $col unless @visible_cols > 1; |
3659 | - while ( $visible_cols[$idx] ne $col ) { |
3660 | - $idx++; |
3661 | - } |
3662 | - $tbl_meta{$tbl}->{visible} = [ grep { $_ ne $col } @visible_cols ]; |
3663 | - $tbl_meta{$tbl}->{cust}->{visible} = 1; |
3664 | - return $idx == $#visible_cols ? $visible_cols[$idx - 1] : $visible_cols[$idx + 1]; |
3665 | - }, |
3666 | - }, |
3667 | - e => { |
3668 | - note => 'Edit selected column', |
3669 | - func => sub { |
3670 | - # TODO: make this editor hotkey-driven and give readline support. |
3671 | - my ( $tbl, $col ) = @_; |
3672 | - $clear_screen_sub->(); |
3673 | - my $meta = $tbl_meta{$tbl}->{cols}->{$col}; |
3674 | - my @prop = qw(hdr label src just num minw maxw trans agg); # TODO redundant |
3675 | - |
3676 | - my $answer; |
3677 | - do { |
3678 | - # Do what the user asked... |
3679 | - if ( $answer && grep { $_ eq $answer } @prop ) { |
3680 | - # Some properties are arrays, others scalars. |
3681 | - my $ini = ref $col_props{$answer} ? join(' ', @{$meta->{$answer}}) : $meta->{$answer}; |
3682 | - my $val = prompt("New value for $answer", undef, $ini); |
3683 | - $val = [ split(' ', $val) ] if ref($col_props{$answer}); |
3684 | - if ( $answer eq 'trans' ) { |
3685 | - $val = [ unique(grep{ exists $trans_funcs{$_} } @$val) ]; |
3686 | - } |
3687 | - @{$meta}{$answer, 'user', 'tbl' } = ( $val, 1, $tbl ); |
3688 | - } |
3689 | - |
3690 | - my @display_lines = ( |
3691 | - '', |
3692 | - "You are editing column $tbl.$col.\n", |
3693 | - ); |
3694 | - |
3695 | - push @display_lines, create_table2( |
3696 | - \@prop, |
3697 | - { map { $_ => $_ } @prop }, |
3698 | - { map { $_ => ref $meta->{$_} eq 'ARRAY' ? join(' ', @{$meta->{$_}}) |
3699 | - : ref $meta->{$_} ? '[expression code]' |
3700 | - : $meta->{$_} |
3701 | - } @prop |
3702 | - }, |
3703 | - { sep => ' ' }); |
3704 | - draw_screen(\@display_lines, { raw => 1 }); |
3705 | - print "\n\n"; # One to add space, one to clear readline artifacts |
3706 | - $answer = prompt('Edit what? (q to quit)'); |
3707 | - } while ( $answer ne 'q' ); |
3708 | - |
3709 | - return $col; |
3710 | - }, |
3711 | - }, |
3712 | - j => { |
3713 | - note => 'Move highlight down one', |
3714 | - func => sub { |
3715 | - my ( $tbl, $col ) = @_; |
3716 | - my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; |
3717 | - my $idx = 0; |
3718 | - while ( $visible_cols[$idx] ne $col ) { |
3719 | - $idx++; |
3720 | - } |
3721 | - return $visible_cols[ ($idx + 1) % @visible_cols ]; |
3722 | - }, |
3723 | - }, |
3724 | - k => { |
3725 | - note => 'Move highlight up one', |
3726 | - func => sub { |
3727 | - my ( $tbl, $col ) = @_; |
3728 | - my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; |
3729 | - my $idx = 0; |
3730 | - while ( $visible_cols[$idx] ne $col ) { |
3731 | - $idx++; |
3732 | - } |
3733 | - return $visible_cols[ $idx - 1 ]; |
3734 | - }, |
3735 | - }, |
3736 | - '+' => { |
3737 | - note => 'Move selected column up one', |
3738 | - func => sub { |
3739 | - my ( $tbl, $col ) = @_; |
3740 | - my $meta = $tbl_meta{$tbl}; |
3741 | - my @visible_cols = @{$meta->{visible}}; |
3742 | - my $idx = 0; |
3743 | - while ( $visible_cols[$idx] ne $col ) { |
3744 | - $idx++; |
3745 | - } |
3746 | - if ( $idx ) { |
3747 | - $visible_cols[$idx] = $visible_cols[$idx - 1]; |
3748 | - $visible_cols[$idx - 1] = $col; |
3749 | - $meta->{visible} = \@visible_cols; |
3750 | - } |
3751 | - else { |
3752 | - shift @{$meta->{visible}}; |
3753 | - push @{$meta->{visible}}, $col; |
3754 | - } |
3755 | - $meta->{cust}->{visible} = 1; |
3756 | - return $col; |
3757 | - }, |
3758 | - }, |
3759 | - '-' => { |
3760 | - note => 'Move selected column down one', |
3761 | - func => sub { |
3762 | - my ( $tbl, $col ) = @_; |
3763 | - my $meta = $tbl_meta{$tbl}; |
3764 | - my @visible_cols = @{$meta->{visible}}; |
3765 | - my $idx = 0; |
3766 | - while ( $visible_cols[$idx] ne $col ) { |
3767 | - $idx++; |
3768 | - } |
3769 | - if ( $idx == $#visible_cols ) { |
3770 | - unshift @{$meta->{visible}}, $col; |
3771 | - pop @{$meta->{visible}}; |
3772 | - } |
3773 | - else { |
3774 | - $visible_cols[$idx] = $visible_cols[$idx + 1]; |
3775 | - $visible_cols[$idx + 1] = $col; |
3776 | - $meta->{visible} = \@visible_cols; |
3777 | - } |
3778 | - $meta->{cust}->{visible} = 1; |
3779 | - return $col; |
3780 | - }, |
3781 | - }, |
3782 | - f => { |
3783 | - note => 'Choose filters', |
3784 | - func => sub { |
3785 | - my ( $tbl, $col ) = @_; |
3786 | - choose_filters($tbl); |
3787 | - return $col; |
3788 | - }, |
3789 | - }, |
3790 | - o => { |
3791 | - note => 'Edit color rules', |
3792 | - func => sub { |
3793 | - my ( $tbl, $col ) = @_; |
3794 | - edit_color_rules($tbl); |
3795 | - return $col; |
3796 | - }, |
3797 | - }, |
3798 | - s => { |
3799 | - note => 'Choose sort columns', |
3800 | - func => sub { |
3801 | - my ( $tbl, $col ) = @_; |
3802 | - choose_sort_cols($tbl); |
3803 | - return $col; |
3804 | - }, |
3805 | - }, |
3806 | - g => { |
3807 | - note => 'Choose group-by (aggregate) columns', |
3808 | - func => sub { |
3809 | - my ( $tbl, $col ) = @_; |
3810 | - choose_group_cols($tbl); |
3811 | - return $col; |
3812 | - }, |
3813 | - }, |
3814 | -); |
3815 | - |
3816 | -# ########################################################################### |
3817 | -# Global variables and environment {{{2 |
3818 | -# ########################################################################### |
3819 | - |
3820 | -my @this_term_size; # w_chars, h_chars, w_pix, h_pix |
3821 | -my @last_term_size; # w_chars, h_chars, w_pix, h_pix |
3822 | -my $char; |
3823 | -my $windows = $OSNAME =~ m/MSWin/; |
3824 | -my $have_color = 0; |
3825 | -my $MAX_ULONG = 4294967295; # 2^32-1 |
3826 | -my $num_regex = qr/^[+-]?(?=\d|\.)\d*(?:\.\d+)?(?:E[+-]?\d+|)$/i; |
3827 | -my $int_regex = qr/^\d+$/; |
3828 | -my $bool_regex = qr/^[01]$/; |
3829 | -my $term = undef; |
3830 | -my $file = undef; # File to watch for InnoDB monitor output |
3831 | -my $file_mtime = undef; # Status of watched file |
3832 | -my $file_data = undef; # Last chunk of text read from file |
3833 | -my $innodb_parser = InnoDBParser->new; |
3834 | - |
3835 | -my $nonfatal_errs = join('|', |
3836 | - 'Access denied for user', |
3837 | - 'Unknown MySQL server host', |
3838 | - 'Unknown database', |
3839 | - 'Can\'t connect to local MySQL server through socket', |
3840 | - 'Can\'t connect to MySQL server on', |
3841 | - 'MySQL server has gone away', |
3842 | - 'Cannot call SHOW INNODB STATUS', |
3843 | - 'Access denied', |
3844 | - 'AutoCommit', |
3845 | -); |
3846 | - |
3847 | -if ( !$opts{n} ) { |
3848 | - require Term::ReadLine; |
3849 | - $term = Term::ReadLine->new('innotop'); |
3850 | -} |
3851 | - |
3852 | -# Stores status, variables, innodb status, master/slave status etc. |
3853 | -# Keyed on connection name. Each entry is a hashref of current and past data sets, |
3854 | -# keyed on clock tick. |
3855 | -my %vars; |
3856 | -my %info_gotten = (); # Which things have been retrieved for the current clock tick. |
3857 | - |
3858 | -# Stores info on currently displayed queries: cxn, connection ID, query text. |
3859 | -my @current_queries; |
3860 | - |
3861 | -my $lines_printed = 0; |
3862 | -my $clock = 0; # Incremented with every wake-sleep cycle |
3863 | -my $clearing_deadlocks = 0; |
3864 | - |
3865 | -# Find the home directory; it's different on different OSes. |
3866 | -my $homepath = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; |
3867 | - |
3868 | -# If terminal coloring is available, use it. The only function I want from |
3869 | -# the module is the colored() function. |
3870 | -eval { |
3871 | - if ( !$opts{n} ) { |
3872 | - if ( $windows ) { |
3873 | - require Win32::Console::ANSI; |
3874 | - } |
3875 | - require Term::ANSIColor; |
3876 | - import Term::ANSIColor qw(colored); |
3877 | - $have_color = 1; |
3878 | - } |
3879 | -}; |
3880 | -if ( $EVAL_ERROR || $opts{n} ) { |
3881 | - # If there was an error, manufacture my own colored() function that does no |
3882 | - # coloring. |
3883 | - *colored = sub { pop @_; @_; }; |
3884 | -} |
3885 | - |
3886 | -if ( $opts{n} ) { |
3887 | - $clear_screen_sub = sub {}; |
3888 | -} |
3889 | -elsif ( $windows ) { |
3890 | - $clear_screen_sub = sub { $lines_printed = 0; system("cls") }; |
3891 | -} |
3892 | -else { |
3893 | - my $clear = `clear`; |
3894 | - $clear_screen_sub = sub { $lines_printed = 0; print $clear }; |
3895 | -} |
3896 | - |
3897 | -# ########################################################################### |
3898 | -# Config storage. {{{2 |
3899 | -# ########################################################################### |
3900 | -my %config = ( |
3901 | - color => { |
3902 | - val => $have_color, |
3903 | - note => 'Whether to use terminal coloring', |
3904 | - conf => 'ALL', |
3905 | - pat => $bool_regex, |
3906 | - }, |
3907 | - cmd_filter => { |
3908 | - val => 'Com_', |
3909 | - note => 'Prefix for values in C mode', |
3910 | - conf => [qw(C)], |
3911 | - }, |
3912 | - plugin_dir => { |
3913 | - val => "$homepath/.innotop/plugins", |
3914 | - note => 'Directory where plugins can be found', |
3915 | - conf => 'ALL', |
3916 | - }, |
3917 | - show_percent => { |
3918 | - val => 1, |
3919 | - note => 'Show the % symbol after percentages', |
3920 | - conf => 'ALL', |
3921 | - pat => $bool_regex, |
3922 | - }, |
3923 | - skip_innodb => { |
3924 | - val => 0, |
3925 | - note => 'Disable SHOW INNODB STATUS', |
3926 | - conf => 'ALL', |
3927 | - pat => $bool_regex, |
3928 | - }, |
3929 | - S_func => { |
3930 | - val => 's', |
3931 | - note => 'What to display in S mode: graph, status, pivoted status', |
3932 | - conf => [qw(S)], |
3933 | - pat => qr/^[gsv]$/, |
3934 | - }, |
3935 | - cxn_timeout => { |
3936 | - val => 28800, |
3937 | - note => 'Connection timeout for keeping unused connections alive', |
3938 | - conf => 'ALL', |
3939 | - pat => $int_regex, |
3940 | - }, |
3941 | - graph_char => { |
3942 | - val => '*', |
3943 | - note => 'Character for drawing graphs', |
3944 | - conf => [ qw(S) ], |
3945 | - pat => qr/^.$/, |
3946 | - }, |
3947 | - show_cxn_errors_in_tbl => { |
3948 | - val => 1, |
3949 | - note => 'Whether to display connection errors as rows in the table', |
3950 | - conf => 'ALL', |
3951 | - pat => $bool_regex, |
3952 | - }, |
3953 | - hide_hdr => { |
3954 | - val => 0, |
3955 | - note => 'Whether to show column headers', |
3956 | - conf => 'ALL', |
3957 | - pat => $bool_regex, |
3958 | - }, |
3959 | - show_cxn_errors => { |
3960 | - val => 1, |
3961 | - note => 'Whether to print connection errors to STDOUT', |
3962 | - conf => 'ALL', |
3963 | - pat => $bool_regex, |
3964 | - }, |
3965 | - readonly => { |
3966 | - val => 0, |
3967 | - note => 'Whether the config file is read-only', |
3968 | - conf => [ qw() ], |
3969 | - pat => $bool_regex, |
3970 | - }, |
3971 | - global => { |
3972 | - val => 1, |
3973 | - note => 'Whether to show GLOBAL variables and status', |
3974 | - conf => 'ALL', |
3975 | - pat => $bool_regex, |
3976 | - }, |
3977 | - header_highlight => { |
3978 | - val => 'bold', |
3979 | - note => 'How to highlight table column headers', |
3980 | - conf => 'ALL', |
3981 | - pat => qr/^(?:bold|underline)$/, |
3982 | - }, |
3983 | - display_table_captions => { |
3984 | - val => 1, |
3985 | - note => 'Whether to put captions on tables', |
3986 | - conf => 'ALL', |
3987 | - pat => $bool_regex, |
3988 | - }, |
3989 | - charset => { |
3990 | - val => 'ascii', |
3991 | - note => 'What type of characters should be displayed in queries (ascii, unicode, none)', |
3992 | - conf => 'ALL', |
3993 | - pat => qr/^(?:ascii|unicode|none)$/, |
3994 | - }, |
3995 | - auto_wipe_dl => { |
3996 | - val => 0, |
3997 | - note => 'Whether to auto-wipe InnoDB deadlocks', |
3998 | - conf => 'ALL', |
3999 | - pat => $bool_regex, |
4000 | - }, |
4001 | - max_height => { |
4002 | - val => 30, |
4003 | - note => '[Win32] Max window height', |
4004 | - conf => 'ALL', |
4005 | - }, |
4006 | - debug => { |
4007 | - val => 0, |
4008 | - pat => $bool_regex, |
4009 | - note => 'Debug mode (more verbose errors, uses more memory)', |
4010 | - conf => 'ALL', |
4011 | - }, |
4012 | - num_digits => { |
4013 | - val => 2, |
4014 | - pat => $int_regex, |
4015 | - note => 'How many digits to show in fractional numbers and percents', |
4016 | - conf => 'ALL', |
4017 | - }, |
4018 | - debugfile => { |
4019 | - val => "$homepath/.innotop/core_dump", |
4020 | - note => 'A debug file in case you are interested in error output', |
4021 | - }, |
4022 | - show_statusbar => { |
4023 | - val => 1, |
4024 | - pat => $bool_regex, |
4025 | - note => 'Whether to show the status bar in the display', |
4026 | - conf => 'ALL', |
4027 | - }, |
4028 | - mode => { |
4029 | - val => "T", |
4030 | - note => "Which mode to start in", |
4031 | - cmdline => 1, |
4032 | - }, |
4033 | - status_inc => { |
4034 | - val => 0, |
4035 | - note => 'Whether to show raw or incremental values for status variables', |
4036 | - pat => $bool_regex, |
4037 | - }, |
4038 | - interval => { |
4039 | - val => 10, |
4040 | - pat => qr/^(?:(?:\d*?[1-9]\d*(?:\.\d*)?)|(?:\d*\.\d*?[1-9]\d*))$/, |
4041 | - note => "The interval at which the display will be refreshed. Fractional values allowed.", |
4042 | - }, |
4043 | - num_status_sets => { |
4044 | - val => 9, |
4045 | - pat => $int_regex, |
4046 | - note => 'How many sets of STATUS and VARIABLES values to show', |
4047 | - conf => [ qw(S) ], |
4048 | - }, |
4049 | - S_set => { |
4050 | - val => 'general', |
4051 | - pat => qr/^\w+$/, |
4052 | - note => 'Which set of variables to display in S (Variables & Status) mode', |
4053 | - conf => [ qw(S) ], |
4054 | - }, |
4055 | -); |
4056 | - |
4057 | -# ########################################################################### |
4058 | -# Config file sections {{{2 |
4059 | -# The configuration file is broken up into sections like a .ini file. This |
4060 | -# variable defines those sections and the subroutines responsible for reading |
4061 | -# and writing them. |
4062 | -# ########################################################################### |
4063 | -my %config_file_sections = ( |
4064 | - plugins => { |
4065 | - reader => \&load_config_plugins, |
4066 | - writer => \&save_config_plugins, |
4067 | - }, |
4068 | - group_by => { |
4069 | - reader => \&load_config_group_by, |
4070 | - writer => \&save_config_group_by, |
4071 | - }, |
4072 | - filters => { |
4073 | - reader => \&load_config_filters, |
4074 | - writer => \&save_config_filters, |
4075 | - }, |
4076 | - active_filters => { |
4077 | - reader => \&load_config_active_filters, |
4078 | - writer => \&save_config_active_filters, |
4079 | - }, |
4080 | - visible_tables => { |
4081 | - reader => \&load_config_visible_tables, |
4082 | - writer => \&save_config_visible_tables, |
4083 | - }, |
4084 | - sort_cols => { |
4085 | - reader => \&load_config_sort_cols, |
4086 | - writer => \&save_config_sort_cols, |
4087 | - }, |
4088 | - active_columns => { |
4089 | - reader => \&load_config_active_columns, |
4090 | - writer => \&save_config_active_columns, |
4091 | - }, |
4092 | - tbl_meta => { |
4093 | - reader => \&load_config_tbl_meta, |
4094 | - writer => \&save_config_tbl_meta, |
4095 | - }, |
4096 | - general => { |
4097 | - reader => \&load_config_config, |
4098 | - writer => \&save_config_config, |
4099 | - }, |
4100 | - connections => { |
4101 | - reader => \&load_config_connections, |
4102 | - writer => \&save_config_connections, |
4103 | - }, |
4104 | - active_connections => { |
4105 | - reader => \&load_config_active_connections, |
4106 | - writer => \&save_config_active_connections, |
4107 | - }, |
4108 | - server_groups => { |
4109 | - reader => \&load_config_server_groups, |
4110 | - writer => \&save_config_server_groups, |
4111 | - }, |
4112 | - active_server_groups => { |
4113 | - reader => \&load_config_active_server_groups, |
4114 | - writer => \&save_config_active_server_groups, |
4115 | - }, |
4116 | - max_values_seen => { |
4117 | - reader => \&load_config_mvs, |
4118 | - writer => \&save_config_mvs, |
4119 | - }, |
4120 | - varsets => { |
4121 | - reader => \&load_config_varsets, |
4122 | - writer => \&save_config_varsets, |
4123 | - }, |
4124 | - colors => { |
4125 | - reader => \&load_config_colors, |
4126 | - writer => \&save_config_colors, |
4127 | - }, |
4128 | - stmt_sleep_times => { |
4129 | - reader => \&load_config_stmt_sleep_times, |
4130 | - writer => \&save_config_stmt_sleep_times, |
4131 | - }, |
4132 | -); |
4133 | - |
4134 | -# Config file sections have some dependencies, so they have to be read/written in order. |
4135 | -my @ordered_config_file_sections = qw(general plugins filters active_filters tbl_meta |
4136 | - connections active_connections server_groups active_server_groups max_values_seen |
4137 | - active_columns sort_cols visible_tables varsets colors stmt_sleep_times |
4138 | - group_by); |
4139 | - |
4140 | -# All events for which plugins may register themselves. Entries are arrayrefs. |
4141 | -my %event_listener_for = map { $_ => [] } |
4142 | - qw( |
4143 | - extract_values |
4144 | - set_to_tbl_pre_filter set_to_tbl_pre_sort set_to_tbl_pre_group |
4145 | - set_to_tbl_pre_colorize set_to_tbl_pre_transform set_to_tbl_pre_pivot |
4146 | - set_to_tbl_pre_create set_to_tbl_post_create |
4147 | - draw_screen |
4148 | - ); |
4149 | - |
4150 | -# All variables to which plugins have access. |
4151 | -my %pluggable_vars = ( |
4152 | - action_for => \%action_for, |
4153 | - agg_funcs => \%agg_funcs, |
4154 | - config => \%config, |
4155 | - connections => \%connections, |
4156 | - dbhs => \%dbhs, |
4157 | - filters => \%filters, |
4158 | - modes => \%modes, |
4159 | - server_groups => \%server_groups, |
4160 | - tbl_meta => \%tbl_meta, |
4161 | - trans_funcs => \%trans_funcs, |
4162 | - var_sets => \%var_sets, |
4163 | -); |
4164 | - |
4165 | -# ########################################################################### |
4166 | -# Contains logic to generate prepared statements for a given function for a |
4167 | -# given DB connection. Returns a $sth. |
4168 | -# ########################################################################### |
4169 | -my %stmt_maker_for = ( |
4170 | - INNODB_STATUS => sub { |
4171 | - my ( $dbh ) = @_; |
4172 | - return $dbh->prepare(version_ge( $dbh, '5.0.0' ) |
4173 | - ? 'SHOW ENGINE INNODB STATUS' |
4174 | - : 'SHOW INNODB STATUS'); |
4175 | - }, |
4176 | - SHOW_VARIABLES => sub { |
4177 | - my ( $dbh ) = @_; |
4178 | - return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '4.0.3' ) |
4179 | - ? 'SHOW GLOBAL VARIABLES' |
4180 | - : 'SHOW VARIABLES'); |
4181 | - }, |
4182 | - SHOW_STATUS => sub { |
4183 | - my ( $dbh ) = @_; |
4184 | - return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '5.0.2' ) |
4185 | - ? 'SHOW GLOBAL STATUS' |
4186 | - : 'SHOW STATUS'); |
4187 | - }, |
4188 | - KILL_QUERY => sub { |
4189 | - my ( $dbh ) = @_; |
4190 | - return $dbh->prepare(version_ge( $dbh, '5.0.0' ) |
4191 | - ? 'KILL QUERY ?' |
4192 | - : 'KILL ?'); |
4193 | - }, |
4194 | - SHOW_MASTER_LOGS => sub { |
4195 | - my ( $dbh ) = @_; |
4196 | - return $dbh->prepare('SHOW MASTER LOGS'); |
4197 | - }, |
4198 | - SHOW_MASTER_STATUS => sub { |
4199 | - my ( $dbh ) = @_; |
4200 | - return $dbh->prepare('SHOW MASTER STATUS'); |
4201 | - }, |
4202 | - SHOW_SLAVE_STATUS => sub { |
4203 | - my ( $dbh ) = @_; |
4204 | - return $dbh->prepare('SHOW SLAVE STATUS'); |
4205 | - }, |
4206 | - KILL_CONNECTION => sub { |
4207 | - my ( $dbh ) = @_; |
4208 | - return $dbh->prepare(version_ge( $dbh, '5.0.0' ) |
4209 | - ? 'KILL CONNECTION ?' |
4210 | - : 'KILL ?'); |
4211 | - }, |
4212 | - OPEN_TABLES => sub { |
4213 | - my ( $dbh ) = @_; |
4214 | - return version_ge($dbh, '4.0.0') |
4215 | - ? $dbh->prepare('SHOW OPEN TABLES') |
4216 | - : undef; |
4217 | - }, |
4218 | - PROCESSLIST => sub { |
4219 | - my ( $dbh ) = @_; |
4220 | - return $dbh->prepare('SHOW FULL PROCESSLIST'); |
4221 | - }, |
4222 | -); |
4223 | - |
4224 | -# Plugins! |
4225 | -my %plugins = ( |
4226 | -); |
4227 | - |
4228 | -# ########################################################################### |
4229 | -# Run the program {{{1 |
4230 | -# ########################################################################### |
4231 | - |
4232 | -# This config variable is only useful for MS Windows because its terminal |
4233 | -# can't tell how tall it is. |
4234 | -if ( !$windows ) { |
4235 | - delete $config{max_height}; |
4236 | -} |
4237 | - |
4238 | -# Try to lower my priority. |
4239 | -eval { setpriority(0, 0, getpriority(0, 0) + 10); }; |
4240 | - |
4241 | -# Print stuff to the screen immediately, don't wait for a newline. |
4242 | -$OUTPUT_AUTOFLUSH = 1; |
4243 | - |
4244 | -# Clear the screen and load the configuration. |
4245 | -$clear_screen_sub->(); |
4246 | -load_config(); |
4247 | -post_process_tbl_meta(); |
4248 | - |
4249 | -# Make sure no changes are written to config file in non-interactive mode. |
4250 | -if ( $opts{n} ) { |
4251 | - $config{readonly}->{val} = 1; |
4252 | -} |
4253 | - |
4254 | -eval { |
4255 | - |
4256 | - # Open the file for InnoDB status |
4257 | - if ( @ARGV ) { |
4258 | - my $filename = shift @ARGV; |
4259 | - open $file, "<", $filename |
4260 | - or die "Cannot open '$filename': $OS_ERROR"; |
4261 | - } |
4262 | - |
4263 | - # In certain modes we might have to collect data for two cycles |
4264 | - # before printing anything out, so we need to bump up the count one. |
4265 | - if ( $opts{n} && $opts{count} && $config{status_inc}->{val} |
4266 | - && $config{mode}->{val} =~ m/[S]/ ) |
4267 | - { |
4268 | - $opts{count}++; |
4269 | - } |
4270 | - |
4271 | - while (++$clock) { |
4272 | - |
4273 | - my $mode = $config{mode}->{val} || 'T'; |
4274 | - if ( !$modes{$mode} ) { |
4275 | - die "Mode '$mode' doesn't exist; try one of these:\n" |
4276 | - . join("\n", map { " $_ $modes{$_}->{hdr}" } sort keys %modes) |
4277 | - . "\n"; |
4278 | - } |
4279 | - |
4280 | - if ( !$opts{n} ) { |
4281 | - @last_term_size = @this_term_size; |
4282 | - @this_term_size = Term::ReadKey::GetTerminalSize(\*STDOUT); |
4283 | - if ( $windows ) { |
4284 | - $this_term_size[0]--; |
4285 | - $this_term_size[1] |
4286 | - = min($this_term_size[1], $config{max_height}->{val}); |
4287 | - } |
4288 | - die("Can't read terminal size") unless @this_term_size; |
4289 | - } |
4290 | - |
4291 | - # If there's no connection to a database server, we need to fix that... |
4292 | - if ( !%connections ) { |
4293 | - print "You have not defined any database connections.\n\n"; |
4294 | - add_new_dsn(); |
4295 | - } |
4296 | - |
4297 | - # See whether there are any connections defined for this mode. If there's only one |
4298 | - # connection total, assume the user wants to just use innotop for a single server |
4299 | - # and don't ask which server to connect to. Also, if we're monitoring from a file, |
4300 | - # we just use the first connection. |
4301 | - if ( !get_connections() ) { |
4302 | - if ( $file || 1 == scalar keys %connections ) { |
4303 | - $modes{$config{mode}->{val}}->{connections} = [ keys %connections ]; |
4304 | - } |
4305 | - else { |
4306 | - choose_connections(); |
4307 | - } |
4308 | - } |
4309 | - |
4310 | - # Term::ReadLine might have re-set $OUTPUT_AUTOFLUSH. |
4311 | - $OUTPUT_AUTOFLUSH = 1; |
4312 | - |
4313 | - # Prune old data |
4314 | - my $sets = $config{num_status_sets}->{val}; |
4315 | - foreach my $store ( values %vars ) { |
4316 | - delete @{$store}{ grep { $_ < $clock - $sets } keys %$store }; |
4317 | - } |
4318 | - %info_gotten = (); |
4319 | - |
4320 | - # Call the subroutine to display this mode. |
4321 | - $modes{$mode}->{display_sub}->(); |
4322 | - |
4323 | - # It may be time to quit now. |
4324 | - if ( $opts{count} && $clock >= $opts{count} ) { |
4325 | - finish(); |
4326 | - } |
4327 | - |
4328 | - # Wait for a bit. |
4329 | - if ( $opts{n} ) { |
4330 | - sleep($config{interval}->{val}); |
4331 | - } |
4332 | - else { |
4333 | - ReadMode('cbreak'); |
4334 | - $char = ReadKey($config{interval}->{val}); |
4335 | - ReadMode('normal'); |
4336 | - } |
4337 | - |
4338 | - # Handle whatever action the key indicates. |
4339 | - do_key_action(); |
4340 | - |
4341 | - } |
4342 | -}; |
4343 | -if ( $EVAL_ERROR ) { |
4344 | - core_dump( $EVAL_ERROR ); |
4345 | -} |
4346 | -finish(); |
4347 | - |
4348 | -# Subroutines {{{1 |
4349 | -# Mode functions{{{2 |
4350 | -# switch_mode {{{3 |
4351 | -sub switch_mode { |
4352 | - my $mode = shift; |
4353 | - $config{mode}->{val} = $mode; |
4354 | -} |
4355 | - |
4356 | -# Prompting functions {{{2 |
4357 | -# prompt_list {{{3 |
4358 | -# Prompts the user for a value, given a question, initial value, |
4359 | -# a completion function and a hashref of hints. |
4360 | -sub prompt_list { |
4361 | - die "Can't call in non-interactive mode" if $opts{n}; |
4362 | - my ( $question, $init, $completion, $hints ) = @_; |
4363 | - if ( $hints ) { |
4364 | - # Figure out how wide the table will be |
4365 | - my $max_name = max(map { length($_) } keys %$hints ); |
4366 | - $max_name ||= 0; |
4367 | - $max_name += 3; |
4368 | - my @meta_rows = create_table2( |
4369 | - [ sort keys %$hints ], |
4370 | - { map { $_ => $_ } keys %$hints }, |
4371 | - { map { $_ => trunc($hints->{$_}, $this_term_size[0] - $max_name) } keys %$hints }, |
4372 | - { sep => ' ' }); |
4373 | - if (@meta_rows > 10) { |
4374 | - # Try to split and stack the meta rows next to each other |
4375 | - my $split = int(@meta_rows / 2); |
4376 | - @meta_rows = stack_next( |
4377 | - [@meta_rows[0..$split - 1]], |
4378 | - [@meta_rows[$split..$#meta_rows]], |
4379 | - { pad => ' | '}, |
4380 | - ); |
4381 | - } |
4382 | - print join( "\n", |
4383 | - '', |
4384 | - map { ref $_ ? colored(@$_) : $_ } create_caption('Choose from', @meta_rows), ''), |
4385 | - "\n"; |
4386 | - } |
4387 | - $term->Attribs->{completion_function} = $completion; |
4388 | - my $answer = $term->readline("$question: ", $init); |
4389 | - $OUTPUT_AUTOFLUSH = 1; |
4390 | - $answer = '' if !defined($answer); |
4391 | - $answer =~ s/\s+$//; |
4392 | - return $answer; |
4393 | -} |
4394 | - |
4395 | -# prompt {{{3 |
4396 | -# Prints out a prompt and reads from the keyboard, then validates with the |
4397 | -# validation regex until the input is correct. |
4398 | -sub prompt { |
4399 | - die "Can't call in non-interactive mode" if $opts{n}; |
4400 | - my ( $prompt, $regex, $init, $completion ) = @_; |
4401 | - my $response; |
4402 | - my $success = 0; |
4403 | - do { |
4404 | - if ( $completion ) { |
4405 | - $term->Attribs->{completion_function} = $completion; |
4406 | - } |
4407 | - $response = $term->readline("$prompt: ", $init); |
4408 | - if ( $regex && $response !~ m/$regex/ ) { |
4409 | - print "Invalid response.\n\n"; |
4410 | - } |
4411 | - else { |
4412 | - $success = 1; |
4413 | - } |
4414 | - } while ( !$success ); |
4415 | - $OUTPUT_AUTOFLUSH = 1; |
4416 | - $response =~ s/\s+$//; |
4417 | - return $response; |
4418 | -} |
4419 | - |
4420 | -# prompt_noecho {{{3 |
4421 | -# Unfortunately, suppressing echo with Term::ReadLine isn't reliable; the user might not |
4422 | -# have that library, or it might not support that feature. |
4423 | -sub prompt_noecho { |
4424 | - my ( $prompt ) = @_; |
4425 | - print colored("$prompt: ", 'underline'); |
4426 | - my $response; |
4427 | - ReadMode('noecho'); |
4428 | - $response = <STDIN>; |
4429 | - chomp($response); |
4430 | - ReadMode('normal'); |
4431 | - return $response; |
4432 | -} |
4433 | - |
4434 | -# do_key_action {{{3 |
4435 | -# Depending on whether a key was read, do something. Keys have certain |
4436 | -# actions defined in lookup tables. Each mode may have its own lookup table, |
4437 | -# which trumps the global table -- so keys can be context-sensitive. The key |
4438 | -# may be read and written in a subroutine, so it's a global. |
4439 | -sub do_key_action { |
4440 | - if ( defined $char ) { |
4441 | - my $mode = $config{mode}->{val}; |
4442 | - my $action |
4443 | - = defined($modes{$mode}->{action_for}->{$char}) |
4444 | - ? $modes{$mode}->{action_for}->{$char}->{action} |
4445 | - : defined($action_for{$char}) |
4446 | - ? $action_for{$char}->{action} |
4447 | - : sub{}; |
4448 | - $action->(); |
4449 | - } |
4450 | -} |
4451 | - |
4452 | -# pause {{{3 |
4453 | -sub pause { |
4454 | - die "Can't call in non-interactive mode" if $opts{n}; |
4455 | - my $msg = shift; |
4456 | - print defined($msg) ? "\n$msg" : "\nPress any key to continue"; |
4457 | - ReadMode('cbreak'); |
4458 | - my $char = ReadKey(0); |
4459 | - ReadMode('normal'); |
4460 | - return $char; |
4461 | -} |
4462 | - |
4463 | -# reverse_sort {{{3 |
4464 | -sub reverse_sort { |
4465 | - my $tbl = shift; |
4466 | - $tbl_meta{$tbl}->{sort_dir} *= -1; |
4467 | -} |
4468 | - |
4469 | -# select_cxn {{{3 |
4470 | -# Selects connection(s). If the mode (or argument list) has only one, returns |
4471 | -# it without prompt. |
4472 | -sub select_cxn { |
4473 | - my ( $prompt, @cxns ) = @_; |
4474 | - if ( !@cxns ) { |
4475 | - @cxns = get_connections(); |
4476 | - } |
4477 | - if ( @cxns == 1 ) { |
4478 | - return $cxns[0]; |
4479 | - } |
4480 | - my $choices = prompt_list( |
4481 | - $prompt, |
4482 | - $cxns[0], |
4483 | - sub{ return @cxns }, |
4484 | - { map { $_ => $connections{$_}->{dsn} } @cxns }); |
4485 | - my @result = unique(grep { my $a = $_; grep { $_ eq $a } @cxns } split(/\s+/, $choices)); |
4486 | - return @result; |
4487 | -} |
4488 | - |
4489 | -# kill_query {{{3 |
4490 | -# Kills a connection, or on new versions, optionally a query but not connection. |
4491 | -sub kill_query { |
4492 | - my ( $q_or_c ) = @_; |
4493 | - |
4494 | - my $info = choose_thread( |
4495 | - sub { 1 }, |
4496 | - 'Select a thread to kill the ' . $q_or_c, |
4497 | - ); |
4498 | - return unless $info; |
4499 | - return unless pause("Kill $info->{id}?") =~ m/y/i; |
4500 | - |
4501 | - eval { |
4502 | - do_stmt($info->{cxn}, $q_or_c eq 'QUERY' ? 'KILL_QUERY' : 'KILL_CONNECTION', $info->{id} ); |
4503 | - }; |
4504 | - |
4505 | - if ( $EVAL_ERROR ) { |
4506 | - print "\nError: $EVAL_ERROR"; |
4507 | - pause(); |
4508 | - } |
4509 | -} |
4510 | - |
4511 | -# set_display_precision {{{3 |
4512 | -sub set_display_precision { |
4513 | - my $dir = shift; |
4514 | - $config{num_digits}->{val} = min(9, max(0, $config{num_digits}->{val} + $dir)); |
4515 | -} |
4516 | - |
4517 | -sub toggle_visible_table { |
4518 | - my ( $mode, $table ) = @_; |
4519 | - my $visible = $modes{$mode}->{visible_tables}; |
4520 | - if ( grep { $_ eq $table } @$visible ) { |
4521 | - $modes{$mode}->{visible_tables} = [ grep { $_ ne $table } @$visible ]; |
4522 | - } |
4523 | - else { |
4524 | - unshift @$visible, $table; |
4525 | - } |
4526 | - $modes{$mode}->{cust}->{visible_tables} = 1; |
4527 | -} |
4528 | - |
4529 | -# toggle_filter{{{3 |
4530 | -sub toggle_filter { |
4531 | - my ( $tbl, $filter ) = @_; |
4532 | - my $filters = $tbl_meta{$tbl}->{filters}; |
4533 | - if ( grep { $_ eq $filter } @$filters ) { |
4534 | - $tbl_meta{$tbl}->{filters} = [ grep { $_ ne $filter } @$filters ]; |
4535 | - } |
4536 | - else { |
4537 | - push @$filters, $filter; |
4538 | - } |
4539 | - $tbl_meta{$tbl}->{cust}->{filters} = 1; |
4540 | -} |
4541 | - |
4542 | -# toggle_config {{{3 |
4543 | -sub toggle_config { |
4544 | - my ( $key ) = @_; |
4545 | - $config{$key}->{val} ^= 1; |
4546 | -} |
4547 | - |
4548 | -# create_deadlock {{{3 |
4549 | -sub create_deadlock { |
4550 | - $clear_screen_sub->(); |
4551 | - |
4552 | - print "This function will deliberately cause a small deadlock, " |
4553 | - . "clearing deadlock information from the InnoDB monitor.\n\n"; |
4554 | - |
4555 | - my $answer = prompt("Are you sure you want to proceed? Say 'y' if you do"); |
4556 | - return 0 unless $answer eq 'y'; |
4557 | - |
4558 | - my ( $cxn ) = select_cxn('Clear on which server? '); |
4559 | - return unless $cxn && exists($connections{$cxn}); |
4560 | - |
4561 | - clear_deadlock($cxn); |
4562 | -} |
4563 | - |
4564 | -# deadlock_thread {{{3 |
4565 | -sub deadlock_thread { |
4566 | - my ( $id, $tbl, $cxn ) = @_; |
4567 | - |
4568 | - eval { |
4569 | - my $dbh = get_new_db_connection($cxn, 1); |
4570 | - my @stmts = ( |
4571 | - "set transaction isolation level serializable", |
4572 | - (version_ge($dbh, '4.0.11') ? "start transaction" : 'begin'), |
4573 | - "select * from $tbl where a = $id", |
4574 | - "update $tbl set a = $id where a <> $id", |
4575 | - ); |
4576 | - |
4577 | - foreach my $stmt (@stmts[0..2]) { |
4578 | - $dbh->do($stmt); |
4579 | - } |
4580 | - sleep(1 + $id); |
4581 | - $dbh->do($stmts[-1]); |
4582 | - }; |
4583 | - if ( $EVAL_ERROR ) { |
4584 | - if ( $EVAL_ERROR !~ m/Deadlock found/ ) { |
4585 | - die $EVAL_ERROR; |
4586 | - } |
4587 | - } |
4588 | - exit(0); |
4589 | -} |
4590 | - |
4591 | -# Purges unused binlogs on the master, up to but not including the latest log. |
4592 | -# TODO: guess which connections are slaves of a given master. |
4593 | -sub purge_master_logs { |
4594 | - my @cxns = get_connections(); |
4595 | - |
4596 | - get_master_slave_status(@cxns); |
4597 | - |
4598 | - # Toss out the rows that don't have master/slave status... |
4599 | - my @vars = |
4600 | - grep { $_ && ($_->{file} || $_->{master_host}) } |
4601 | - map { $vars{$_}->{$clock} } @cxns; |
4602 | - @cxns = map { $_->{cxn} } @vars; |
4603 | - |
4604 | - # Figure out which master to purge ons. |
4605 | - my @masters = map { $_->{cxn} } grep { $_->{file} } @vars; |
4606 | - my ( $master ) = select_cxn('Which master?', @masters ); |
4607 | - return unless $master; |
4608 | - my ($master_status) = grep { $_->{cxn} eq $master } @vars; |
4609 | - |
4610 | - # Figure out the result order (not lexical order) of master logs. |
4611 | - my @master_logs = get_master_logs($master); |
4612 | - my $i = 0; |
4613 | - my %master_logs = map { $_->{log_name} => $i++ } @master_logs; |
4614 | - |
4615 | - # Ask which slave(s) are reading from this master. |
4616 | - my @slave_status = grep { $_->{master_host} } @vars; |
4617 | - my @slaves = map { $_->{cxn} } @slave_status; |
4618 | - @slaves = select_cxn("Which slaves are reading from $master?", @slaves); |
4619 | - @slave_status = grep { my $item = $_; grep { $item->{cxn} eq $_ } @slaves } @slave_status; |
4620 | - return unless @slave_status; |
4621 | - |
4622 | - # Find the minimum binary log in use. |
4623 | - my $min_log = min(map { $master_logs{$_->{master_log_file}} } @slave_status); |
4624 | - my $log_name = $master_logs[$min_log]->{log_name}; |
4625 | - |
4626 | - my $stmt = "PURGE MASTER LOGS TO '$log_name'"; |
4627 | - send_cmd_to_servers($stmt, 0, 'PURGE {MASTER | BINARY} LOGS {TO "log_name" | BEFORE "date"}', [$master]); |
4628 | -} |
4629 | - |
4630 | -sub send_cmd_to_servers { |
4631 | - my ( $cmd, $all, $hint, $cxns ) = @_; |
4632 | - if ( $all ) { |
4633 | - @$cxns = get_connections(); |
4634 | - } |
4635 | - elsif ( !@$cxns ) { |
4636 | - @$cxns = select_cxn('Which servers?', @$cxns); |
4637 | - } |
4638 | - if ( $hint ) { |
4639 | - print "\nHint: $hint\n"; |
4640 | - } |
4641 | - $cmd = prompt('Command to send', undef, $cmd); |
4642 | - foreach my $cxn ( @$cxns ) { |
4643 | - eval { |
4644 | - my $sth = do_query($cxn, $cmd); |
4645 | - }; |
4646 | - if ( $EVAL_ERROR ) { |
4647 | - print "Error from $cxn: $EVAL_ERROR\n"; |
4648 | - } |
4649 | - else { |
4650 | - print "Success on $cxn\n"; |
4651 | - } |
4652 | - } |
4653 | - pause(); |
4654 | -} |
4655 | - |
4656 | -# Display functions {{{2 |
4657 | - |
4658 | -sub set_s_mode { |
4659 | - my ( $func ) = @_; |
4660 | - $clear_screen_sub->(); |
4661 | - $config{S_func}->{val} = $func; |
4662 | -} |
4663 | - |
4664 | -# start_S_mode {{{3 |
4665 | -sub start_S_mode { |
4666 | - $clear_screen_sub->(); |
4667 | - switch_mode('S'); |
4668 | -} |
4669 | - |
4670 | -# display_B {{{3 |
4671 | -sub display_B { |
4672 | - my @display_lines; |
4673 | - my @cxns = get_connections(); |
4674 | - get_innodb_status(\@cxns); |
4675 | - |
4676 | - my @buffer_pool; |
4677 | - my @page_statistics; |
4678 | - my @insert_buffers; |
4679 | - my @adaptive_hash_index; |
4680 | - my %rows_for = ( |
4681 | - buffer_pool => \@buffer_pool, |
4682 | - page_statistics => \@page_statistics, |
4683 | - insert_buffers => \@insert_buffers, |
4684 | - adaptive_hash_index => \@adaptive_hash_index, |
4685 | - ); |
4686 | - |
4687 | - my @visible = get_visible_tables(); |
4688 | - my %wanted = map { $_ => 1 } @visible; |
4689 | - |
4690 | - foreach my $cxn ( @cxns ) { |
4691 | - my $set = $vars{$cxn}->{$clock}; |
4692 | - my $pre = $vars{$cxn}->{$clock-1} || $set; |
4693 | - |
4694 | - if ( $set->{IB_bp_complete} ) { |
4695 | - if ( $wanted{buffer_pool} ) { |
4696 | - push @buffer_pool, extract_values($set, $set, $pre, 'buffer_pool'); |
4697 | - } |
4698 | - if ( $wanted{page_statistics} ) { |
4699 | - push @page_statistics, extract_values($set, $set, $pre, 'page_statistics'); |
4700 | - } |
4701 | - } |
4702 | - if ( $set->{IB_ib_complete} ) { |
4703 | - if ( $wanted{insert_buffers} ) { |
4704 | - push @insert_buffers, extract_values( |
4705 | - $config{status_inc}->{val} ? inc(0, $cxn) : $set, $set, $pre, |
4706 | - 'insert_buffers'); |
4707 | - } |
4708 | - if ( $wanted{adaptive_hash_index} ) { |
4709 | - push @adaptive_hash_index, extract_values($set, $set, $pre, 'adaptive_hash_index'); |
4710 | - } |
4711 | - } |
4712 | - } |
4713 | - |
4714 | - my $first_table = 0; |
4715 | - foreach my $tbl ( @visible ) { |
4716 | - push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); |
4717 | - push @display_lines, get_cxn_errors(@cxns) |
4718 | - if ( $config{debug}->{val} || !$first_table++ ); |
4719 | - } |
4720 | - |
4721 | - draw_screen(\@display_lines); |
4722 | -} |
4723 | - |
4724 | -# display_C {{{3 |
4725 | -sub display_C { |
4726 | - my @display_lines; |
4727 | - my @cxns = get_connections(); |
4728 | - get_status_info(@cxns); |
4729 | - |
4730 | - my @cmd_summary; |
4731 | - my %rows_for = ( |
4732 | - cmd_summary => \@cmd_summary, |
4733 | - ); |
4734 | - |
4735 | - my @visible = get_visible_tables(); |
4736 | - my %wanted = map { $_ => 1 } @visible; |
4737 | - |
4738 | - # For now, I'm manually pulling these variables out and pivoting. Eventually a SQL-ish |
4739 | - # dialect should let me join a table to a grouped and pivoted table and do this more easily. |
4740 | - # TODO: make it so. |
4741 | - my $prefix = qr/^$config{cmd_filter}->{val}/; # TODO: this is a total hack |
4742 | - my @values; |
4743 | - my ($total, $last_total) = (0, 0); |
4744 | - foreach my $cxn ( @cxns ) { |
4745 | - my $set = $vars{$cxn}->{$clock}; |
4746 | - my $pre = $vars{$cxn}->{$clock-1} || $set; |
4747 | - foreach my $key ( keys %$set ) { |
4748 | - next unless $key =~ m/$prefix/i; |
4749 | - my $val = $set->{$key}; |
4750 | - next unless defined $val && $val =~ m/^\d+$/; |
4751 | - my $last_val = $val - ($pre->{$key} || 0); |
4752 | - $total += $val; |
4753 | - $last_total += $last_val; |
4754 | - push @values, { |
4755 | - name => $key, |
4756 | - value => $val, |
4757 | - last_value => $last_val, |
4758 | - }; |
4759 | - } |
4760 | - } |
4761 | - |
4762 | - # Add aggregation and turn into a real set TODO: total hack |
4763 | - if ( $wanted{cmd_summary} ) { |
4764 | - foreach my $value ( @values ) { |
4765 | - @{$value}{qw(total last_total)} = ($total, $last_total); |
4766 | - push @cmd_summary, extract_values($value, $value, $value, 'cmd_summary'); |
4767 | - } |
4768 | - } |
4769 | - |
4770 | - my $first_table = 0; |
4771 | - foreach my $tbl ( @visible ) { |
4772 | - push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); |
4773 | - push @display_lines, get_cxn_errors(@cxns) |
4774 | - if ( $config{debug}->{val} || !$first_table++ ); |
4775 | - } |
4776 | - |
4777 | - draw_screen(\@display_lines); |
4778 | -} |
4779 | - |
4780 | -# display_D {{{3 |
4781 | -sub display_D { |
4782 | - my @display_lines; |
4783 | - my @cxns = get_connections(); |
4784 | - get_innodb_status(\@cxns); |
4785 | - |
4786 | - my @deadlock_transactions; |
4787 | - my @deadlock_locks; |
4788 | - my %rows_for = ( |
4789 | - deadlock_transactions => \@deadlock_transactions, |
4790 | - deadlock_locks => \@deadlock_locks, |
4791 | - ); |
4792 | - |
4793 | - my @visible = get_visible_tables(); |
4794 | - my %wanted = map { $_ => 1 } @visible; |
4795 | - |
4796 | - foreach my $cxn ( @cxns ) { |
4797 | - my $innodb_status = $vars{$cxn}->{$clock}; |
4798 | - my $prev_status = $vars{$cxn}->{$clock-1} || $innodb_status; |
4799 | - |
4800 | - if ( $innodb_status->{IB_dl_timestring} ) { |
4801 | - |
4802 | - my $victim = $innodb_status->{IB_dl_rolled_back} || 0; |
4803 | - |
4804 | - if ( %wanted ) { |
4805 | - foreach my $txn_id ( keys %{$innodb_status->{IB_dl_txns}} ) { |
4806 | - my $txn = $innodb_status->{IB_dl_txns}->{$txn_id}; |
4807 | - my $pre = $prev_status->{IB_dl_txns}->{$txn_id} || $txn; |
4808 | - |
4809 | - if ( $wanted{deadlock_transactions} ) { |
4810 | - my $hash = extract_values($txn->{tx}, $txn->{tx}, $pre->{tx}, 'deadlock_transactions'); |
4811 | - $hash->{cxn} = $cxn; |
4812 | - $hash->{dl_txn_num} = $txn_id; |
4813 | - $hash->{victim} = $txn_id == $victim ? 'Yes' : 'No'; |
4814 | - $hash->{timestring} = $innodb_status->{IB_dl_timestring}; |
4815 | - $hash->{truncates} = $innodb_status->{IB_dl_complete} ? 'No' : 'Yes'; |
4816 | - push @deadlock_transactions, $hash; |
4817 | - } |
4818 | - |
4819 | - if ( $wanted{deadlock_locks} ) { |
4820 | - foreach my $lock ( @{$txn->{locks}} ) { |
4821 | - my $hash = extract_values($lock, $lock, $lock, 'deadlock_locks'); |
4822 | - $hash->{dl_txn_num} = $txn_id; |
4823 | - $hash->{cxn} = $cxn; |
4824 | - $hash->{mysql_thread_id} = $txn->{tx}->{mysql_thread_id}; |
4825 | - push @deadlock_locks, $hash; |
4826 | - } |
4827 | - } |
4828 | - |
4829 | - } |
4830 | - } |
4831 | - } |
4832 | - } |
4833 | - |
4834 | - my $first_table = 0; |
4835 | - foreach my $tbl ( @visible ) { |
4836 | - push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); |
4837 | - push @display_lines, get_cxn_errors(@cxns) |
4838 | - if ( $config{debug}->{val} || !$first_table++ ); |
4839 | - } |
4840 | - |
4841 | - draw_screen(\@display_lines); |
4842 | -} |
4843 | - |
4844 | -# display_F {{{3 |
4845 | -sub display_F { |
4846 | - my @display_lines; |
4847 | - my ( $cxn ) = get_connections(); |
4848 | - get_innodb_status([$cxn]); |
4849 | - my $innodb_status = $vars{$cxn}->{$clock}; |
4850 | - |
4851 | - if ( $innodb_status->{IB_fk_timestring} ) { |
4852 | - |
4853 | - push @display_lines, 'Reason: ' . $innodb_status->{IB_fk_reason}; |
4854 | - |
4855 | - # Display FK errors caused by invalid DML. |
4856 | - if ( $innodb_status->{IB_fk_txn} ) { |
4857 | - my $txn = $innodb_status->{IB_fk_txn}; |
4858 | - push @display_lines, |
4859 | - '', |
4860 | - "User $txn->{user} from $txn->{hostname}, thread $txn->{mysql_thread_id} was executing:", |
4861 | - '', no_ctrl_char($txn->{query_text}); |
4862 | - } |
4863 | - |
4864 | - my @fk_table = create_table2( |
4865 | - $tbl_meta{fk_error}->{visible}, |
4866 | - meta_to_hdr('fk_error'), |
4867 | - extract_values($innodb_status, $innodb_status, $innodb_status, 'fk_error'), |
4868 | - { just => '-', sep => ' '}); |
4869 | - push @display_lines, '', @fk_table; |
4870 | - |
4871 | - } |
4872 | - else { |
4873 | - push @display_lines, '', 'No foreign key error data.'; |
4874 | - } |
4875 | - draw_screen(\@display_lines, { raw => 1 } ); |
4876 | -} |
4877 | - |
4878 | -# display_I {{{3 |
4879 | -sub display_I { |
4880 | - my @display_lines; |
4881 | - my @cxns = get_connections(); |
4882 | - get_innodb_status(\@cxns); |
4883 | - |
4884 | - my @io_threads; |
4885 | - my @pending_io; |
4886 | - my @file_io_misc; |
4887 | - my @log_statistics; |
4888 | - my %rows_for = ( |
4889 | - io_threads => \@io_threads, |
4890 | - pending_io => \@pending_io, |
4891 | - file_io_misc => \@file_io_misc, |
4892 | - log_statistics => \@log_statistics, |
4893 | - ); |
4894 | - |
4895 | - my @visible = get_visible_tables(); |
4896 | - my %wanted = map { $_ => 1 } @visible; |
4897 | - |
4898 | - foreach my $cxn ( @cxns ) { |
4899 | - my $set = $vars{$cxn}->{$clock}; |
4900 | - my $pre = $vars{$cxn}->{$clock-1} || $set; |
4901 | - |
4902 | - if ( $set->{IB_io_complete} ) { |
4903 | - if ( $wanted{io_threads} ) { |
4904 | - my $cur_threads = $set->{IB_io_threads}; |
4905 | - my $pre_threads = $pre->{IB_io_threads} || $cur_threads; |
4906 | - foreach my $key ( sort keys %$cur_threads ) { |
4907 | - my $cur_thd = $cur_threads->{$key}; |
4908 | - my $pre_thd = $pre_threads->{$key} || $cur_thd; |
4909 | - my $hash = extract_values($cur_thd, $cur_thd, $pre_thd, 'io_threads'); |
4910 | - $hash->{cxn} = $cxn; |
4911 | - push @io_threads, $hash; |
4912 | - } |
4913 | - } |
4914 | - if ( $wanted{pending_io} ) { |
4915 | - push @pending_io, extract_values($set, $set, $pre, 'pending_io'); |
4916 | - } |
4917 | - if ( $wanted{file_io_misc} ) { |
4918 | - push @file_io_misc, extract_values( |
4919 | - $config{status_inc}->{val} ? inc(0, $cxn) : $set, |
4920 | - $set, $pre, 'file_io_misc'); |
4921 | - } |
4922 | - } |
4923 | - if ( $set->{IB_lg_complete} && $wanted{log_statistics} ) { |
4924 | - push @log_statistics, extract_values($set, $set, $pre, 'log_statistics'); |
4925 | - } |
4926 | - } |
4927 | - |
4928 | - my $first_table = 0; |
4929 | - foreach my $tbl ( @visible ) { |
4930 | - push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); |
4931 | - push @display_lines, get_cxn_errors(@cxns) |
4932 | - if ( $config{debug}->{val} || !$first_table++ ); |
4933 | - } |
4934 | - |
4935 | - draw_screen(\@display_lines); |
4936 | -} |
4937 | - |
4938 | -# display_L {{{3 |
4939 | -sub display_L { |
4940 | - my @display_lines; |
4941 | - my @cxns = get_connections(); |
4942 | - get_innodb_status(\@cxns); |
4943 | - |
4944 | - my @innodb_locks; |
4945 | - my %rows_for = ( |
4946 | - innodb_locks => \@innodb_locks, |
4947 | - ); |
4948 | - |
4949 | - my @visible = get_visible_tables(); |
4950 | - my %wanted = map { $_ => 1 } @visible; |
4951 | - |
4952 | - # Get info on locks |
4953 | - foreach my $cxn ( @cxns ) { |
4954 | - my $set = $vars{$cxn}->{$clock} or next; |
4955 | - my $pre = $vars{$cxn}->{$clock-1} || $set; |
4956 | - |
4957 | - if ( $wanted{innodb_locks} && defined $set->{IB_tx_transactions} && @{$set->{IB_tx_transactions}} ) { |
4958 | - |
4959 | - my $cur_txns = $set->{IB_tx_transactions}; |
4960 | - my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns; |
4961 | - my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns; |
4962 | - my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns; |
4963 | - foreach my $txn ( @$cur_txns ) { |
4964 | - foreach my $lock ( @{$txn->{locks}} ) { |
4965 | - my %hash = map { $_ => $txn->{$_} } qw(txn_id mysql_thread_id lock_wait_time active_secs); |
4966 | - map { $hash{$_} = $lock->{$_} } qw(lock_type space_id page_no n_bits index db table txn_id lock_mode special insert_intention waiting); |
4967 | - $hash{cxn} = $cxn; |
4968 | - push @innodb_locks, extract_values(\%hash, \%hash, \%hash, 'innodb_locks'); |
4969 | - } |
4970 | - } |
4971 | - } |
4972 | - } |
4973 | - |
4974 | - my $first_table = 0; |
4975 | - foreach my $tbl ( @visible ) { |
4976 | - push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); |
4977 | - push @display_lines, get_cxn_errors(@cxns) |
4978 | - if ( $config{debug}->{val} || !$first_table++ ); |
4979 | - } |
4980 | - |
4981 | - draw_screen(\@display_lines); |
4982 | -} |
4983 | - |
4984 | -# display_M {{{3 |
4985 | -sub display_M { |
4986 | - my @display_lines; |
4987 | - my @cxns = get_connections(); |
4988 | - get_master_slave_status(@cxns); |
4989 | - get_status_info(@cxns); |
4990 | - |
4991 | - my @slave_sql_status; |
4992 | - my @slave_io_status; |
4993 | - my @master_status; |
4994 | - my %rows_for = ( |
4995 | - slave_sql_status => \@slave_sql_status, |
4996 | - slave_io_status => \@slave_io_status, |
4997 | - master_status => \@master_status, |
4998 | - ); |
4999 | - |
5000 | - my @visible = get_visible_tables(); |
The diff has been truncated for viewing.
Seems good to me, tested working in squeeze