Merge lp:~abychko/percona-server/bug1032139-5.5 into lp:percona-server/5.5

Proposed by Alexey Bychko
Status: Merged
Approved by: Alexey Kopytov
Approved revision: no longer in the source branch.
Merged at revision: 474
Proposed branch: lp:~abychko/percona-server/bug1032139-5.5
Merge into: lp:percona-server/5.5
Diff against target: 13029 lines (+0/-12985)
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.5.dirs (+0/-1)
build/debian/percona-server-client-5.5.docs (+0/-1)
build/debian/percona-server-client-5.5.install (+0/-3)
build/debian/percona-server-client-5.5.lintian-overrides (+0/-2)
To merge this branch: bzr merge lp:~abychko/percona-server/bug1032139-5.5
Reviewer Review Type Date Requested Status
Alexey Kopytov (community) Approve
Review via email: mp+153073@code.launchpad.net

Description of the change

merge from 5.1
[-] 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
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 2011-02-03 14:34:49 +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 2011-02-03 14:34:49 +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 2011-02-03 14:34:49 +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.

Subscribers

People subscribed via source and target branches