Merge lp:~cafuego/ourdelta/ourdelta-mariadb51-2-cafuego into lp:~ourdelta-core/ourdelta/ourdelta-mariadb51-2

Proposed by Cafuego
Status: Merged
Merged at revision: not available
Proposed branch: lp:~cafuego/ourdelta/ourdelta-mariadb51-2-cafuego
Merge into: lp:~ourdelta-core/ourdelta/ourdelta-mariadb51-2
Diff against target: 17659 lines
97 files modified
.bzrignore (+1/-0)
bakery/autobake-deb.sh (+41/-20)
bakery/debian-5.1/README.Maintainer (+2/-11)
bakery/debian-5.1/additions/debian-start.inc.sh (+12/-10)
bakery/debian-5.1/additions/innotop/InnoDBParser.pm (+0/-1089)
bakery/debian-5.1/additions/innotop/changelog.innotop (+40/-1)
bakery/debian-5.1/additions/innotop/innotop (+1616/-155)
bakery/debian-5.1/additions/innotop/innotop.1 (+192/-194)
bakery/debian-5.1/additions/my.cnf (+11/-20)
bakery/debian-5.1/additions/mysqld_safe_syslog.cnf (+2/-0)
bakery/debian-5.1/additions/mysqlmanager.1 (+0/-49)
bakery/debian-5.1/additions/mysqlreport (+279/-132)
bakery/debian-5.1/additions/ndb_mgmd.cnf (+0/-35)
bakery/debian-5.1/changelog (+5/-3873)
bakery/debian-5.1/compat (+1/-1)
bakery/debian-5.1/control (+0/-146)
bakery/debian-5.1/copyright (+1/-6)
bakery/debian-5.1/dist/Debian/control (+136/-0)
bakery/debian-5.1/dist/Debian/mariadb-server-5.1.README.Debian (+109/-0)
bakery/debian-5.1/dist/Debian/mariadb-server-5.1.dirs (+9/-0)
bakery/debian-5.1/dist/Debian/mariadb-server-5.1.files (+54/-0)
bakery/debian-5.1/dist/Debian/mariadb-server-5.1.postinst (+277/-0)
bakery/debian-5.1/dist/Debian/mariadb-server-5.1.postrm (+83/-0)
bakery/debian-5.1/dist/Debian/rules (+310/-0)
bakery/debian-5.1/dist/Ubuntu/apparmor-profile (+36/-0)
bakery/debian-5.1/dist/Ubuntu/control (+159/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-5.1.README.Debian (+119/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-5.1.dirs (+10/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-5.1.files (+63/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-5.1.postinst (+284/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-5.1.postrm (+86/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-5.1.py (+53/-0)
bakery/debian-5.1/dist/Ubuntu/mariadb-server-core-5.1.files (+26/-0)
bakery/debian-5.1/dist/Ubuntu/rules (+316/-0)
bakery/debian-5.1/libmariadbclient-dev.files (+4/-3)
bakery/debian-5.1/libmariadbd-dev.files (+2/-0)
bakery/debian-5.1/libmysqlclient-dev.lintian-overrides (+0/-2)
bakery/debian-5.1/libndbclient-dev.dirs (+0/-4)
bakery/debian-5.1/libndbclient-dev.files (+0/-4)
bakery/debian-5.1/libndbclient-dev.links (+0/-2)
bakery/debian-5.1/libndbclient3.dirs (+0/-1)
bakery/debian-5.1/libndbclient3.files (+0/-1)
bakery/debian-5.1/mariadb-client-5.1.files (+7/-6)
bakery/debian-5.1/mariadb-client-5.1.links (+3/-0)
bakery/debian-5.1/mariadb-client-5.1.lintian-overrides (+3/-3)
bakery/debian-5.1/mariadb-server-5.1.NEWS (+8/-0)
bakery/debian-5.1/mariadb-server-5.1.config (+28/-4)
bakery/debian-5.1/mariadb-server-5.1.lintian-overrides (+5/-4)
bakery/debian-5.1/mariadb-server-5.1.mysql-server.logrotate (+0/-1)
bakery/debian-5.1/mariadb-server-5.1.mysql.init (+14/-9)
bakery/debian-5.1/mariadb-server-5.1.preinst (+7/-13)
bakery/debian-5.1/mariadb-server-5.1.templates (+26/-21)
bakery/debian-5.1/mysql-common.README.Debian (+0/-20)
bakery/debian-5.1/mysql-common.files (+1/-0)
bakery/debian-5.1/mysql-common.lintian-overrides (+0/-2)
bakery/debian-5.1/mysql-common.postrm (+1/-1)
bakery/debian-5.1/mysql-server-5.1.README.Debian (+0/-118)
bakery/debian-5.1/mysql-server-5.1.dirs (+0/-9)
bakery/debian-5.1/mysql-server-5.1.files (+0/-82)
bakery/debian-5.1/mysql-server-5.1.mysql-ndb-mgm.init (+0/-86)
bakery/debian-5.1/mysql-server-5.1.mysql-ndb.init (+0/-103)
bakery/debian-5.1/mysql-server-5.1.postinst (+0/-289)
bakery/debian-5.1/mysql-server-5.1.postrm (+0/-94)
bakery/debian-5.1/patches/00list (+10/-0)
bakery/debian-5.1/patches/00list.delta (+0/-6)
bakery/debian-5.1/patches/00list.delta-sail (+0/-6)
bakery/debian-5.1/patches/02_no_builtin_ndbcluster_plugin.dpatch (+18/-0)
bakery/debian-5.1/patches/21_init__openquery_configtest.dpatch (+33/-0)
bakery/debian-5.1/patches/33_scripts__mysql_create_system_tables__no_test.dpatch (+11/-4)
bakery/debian-5.1/patches/38_scripts__mysqld_safe.sh__signals.dpatch (+1/-1)
bakery/debian-5.1/patches/44_scripts__mysql_config__libs.dpatch (+8/-8)
bakery/debian-5.1/patches/50_mysql-test__db_test.dpatch (+23/-0)
bakery/debian-5.1/patches/60_zlib_innodb_workaround.dpatch (+31/-0)
bakery/debian-5.1/po/POTFILES.in (+1/-1)
bakery/debian-5.1/po/ar.po (+40/-23)
bakery/debian-5.1/po/ca.po (+38/-23)
bakery/debian-5.1/po/cs.po (+58/-29)
bakery/debian-5.1/po/da.po (+58/-29)
bakery/debian-5.1/po/de.po (+59/-59)
bakery/debian-5.1/po/es.po (+67/-38)
bakery/debian-5.1/po/eu.po (+75/-116)
bakery/debian-5.1/po/fr.po (+66/-51)
bakery/debian-5.1/po/gl.po (+40/-23)
bakery/debian-5.1/po/it.po (+213/-218)
bakery/debian-5.1/po/ja.po (+73/-219)
bakery/debian-5.1/po/nb.po (+40/-23)
bakery/debian-5.1/po/nl.po (+40/-23)
bakery/debian-5.1/po/pt.po (+58/-29)
bakery/debian-5.1/po/pt_BR.po (+40/-23)
bakery/debian-5.1/po/ro.po (+59/-29)
bakery/debian-5.1/po/ru.po (+87/-145)
bakery/debian-5.1/po/sv.po (+162/-302)
bakery/debian-5.1/po/templates.pot (+54/-39)
bakery/debian-5.1/po/tr.po (+39/-24)
bakery/debian-5.1/rules (+0/-359)
bakery/debian-5.1/source.lintian-overrides (+2/-2)
bakery/tarbake51.sh (+7/-1)
To merge this branch: bzr merge lp:~cafuego/ourdelta/ourdelta-mariadb51-2-cafuego
Reviewer Review Type Date Requested Status
OurDelta-core Pending
Review via email: mp+12775@code.launchpad.net
To post a comment you must log in.
71. By Arjen Lentz

Various naming fixups for 5.1 build

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2009-03-19 05:58:44 +0000
3+++ .bzrignore 2009-10-02 06:45:25 +0000
4@@ -0,0 +1,1 @@
5+.mariadb-version
6
7=== modified file 'bakery/autobake-deb.sh'
8--- bakery/autobake-deb.sh 2009-03-25 12:54:42 +0000
9+++ bakery/autobake-deb.sh 2009-10-02 06:45:25 +0000
10@@ -24,7 +24,7 @@
11
12 if [ ! $# -eq 1 ]; then
13 echo "Usage: $0 [tarball]"
14- echo " tarball: ourdelta or ourdelta-sail tarball"
15+ echo " tarball: source tarball"
16 exit 1
17 else
18 TARBALL="$(readlink -f ${1})"
19@@ -39,22 +39,23 @@
20 #
21 SOURCE_DIR=$(basename ${TARBALL} .tar.gz)
22
23-# Find out the bakery version, so we can adjust the changelog file later.
24-#
25-pushd ${BAKERY_BASE_DIR}/..
26-if [ ! -f .bzr-version ]; then
27- echo "No bzr version info. You are not running this script from a"
28- echo "properly exported bakery. Please do so. I will now quit."
29- exit 1
30-else
31- source .bzr-version
32-fi
33-popd
34-
35 # Find major.minor version.
36 #
37 UPSTREAM="$(echo ${SOURCE_DIR} | cut -d- -f 2)"
38 MYVER="$(echo ${SOURCE_DIR} | cut -d- -f 2 | cut -d. -f1,2)"
39+RELEASE_EXTRA="$(echo ${SOURCE_DIR} | cut -d- -f 3-)"
40+
41+pushd ${BAKERY_BASE_DIR}
42+cd ..
43+if [ ! -f .bzr-version ]; then
44+ echo "No bzr version info. You are not running this script from a"
45+ echo "properly exported bakery. Please do so. I will now quit."
46+ popd
47+ exit 1
48+else
49+ source .bzr-version
50+fi
51+popd
52
53 # Whatup?
54 #
55@@ -78,12 +79,32 @@
56
57 # Set version info (again)
58 #
59-source .ourdelta-version
60-
61-# Set symlinks for build files in the debian dir, so we avoid adding AppArmor on Debian.
62+if [ -e .ourdelta-version ]; then
63+ source .ourdelta-version
64+ RELEASE_NAME="${RELEASE_NAME}"
65+ PATCHLEVEL="-d${PATCHLEVEL}"
66+ LOGSTRING="OurDelta patch set ${PATCHLEVEL}"
67+else
68+ PATCHLEVEL=""
69+ RELEASE_NAME=${RELEASE_EXTRA}
70+ RELEASE_EXTRA="ourdelta"
71+ LOGSTRING="${RELEASE_NAME}"
72+fi
73+
74+# Clean up build file symlinks that are distro-specific. First remove all, then set
75+# new links.
76+DISTRODIRS="$(ls ./debian/dist)"
77+for distrodir in ${DISTRODIRS}; do
78+ DISTROFILES="$(ls ./debian/dist/${distrodir})"
79+ for distrofile in ${DISTROFILES}; do
80+ rm -f "./debian/${distrofile}";
81+ done;
82+done;
83+
84+# Set no symlinks for build files in the debian dir, so we avoid adding AppArmor on Debian.
85 DISTRO="$(lsb_release -si)"
86 echo "Copying distribution specific build files for ${DISTRO}"
87-DISTROFILES="control mysql-server-5.0.postinst rules mysql-server-5.0.dirs mysql-server-5.0.postrm mysql-server-5.0.files mysql-server-5.0.preinst"
88+DISTROFILES="$(ls ./debian/dist/${DISTRO})"
89 for distrofile in ${DISTROFILES}; do
90 rm -f "./debian/${distrofile}" && cp -a "./debian/dist/${DISTRO}/${distrofile}" "./debian/${distrofile}";
91 done;
92@@ -91,10 +112,10 @@
93 # Adjust changelog, add new version.
94 #
95 echo "Incrementing changelog and starting build scripts"
96-CODENAME="$(lsb_release -c | cut -d: -f2 | sed 's/\s//g')"
97-dch -b -D ${CODENAME} -v "${UPSTREAM}-d${PATCHLEVEL}-${RELEASE_NAME}${RELEASE_EXTRA:+-${RELEASE_EXTRA}}${REPO_VERSION}" "Automatic build with OurDelta patchset ${PATCHLEVEL} (including Sphinx storage engine)."
98+CODENAME="$(lsb_release -sc)"
99+dch -b -D ${CODENAME} -v "${UPSTREAM}${PATCHLEVEL}-${RELEASE_NAME}${RELEASE_EXTRA:+-${RELEASE_EXTRA}}${REPO_VERSION}" "Automatic build with ${LOGSTRING} (including Sphinx storage engine)."
100
101-echo "Creating package version ${UPSTREAM}-d${PATCHLEVEL}-${RELEASE_NAME}${RELEASE_EXTRA:+-${RELEASE_EXTRA}}${REPO_VERSION} ... "
102+echo "Creating package version ${UPSTREAM}${PATCHLEVEL}-${RELEASE_NAME}${RELEASE_EXTRA:+-${RELEASE_EXTRA}}${REPO_VERSION} ... "
103
104 # Copy in up-to-date gpg keys
105 if [ -d /srv/shared/gnupg ]; then
106
107=== modified file 'bakery/debian-5.1/README.Maintainer'
108--- bakery/debian-5.1/README.Maintainer 2008-10-20 22:54:11 +0000
109+++ bakery/debian-5.1/README.Maintainer 2009-10-02 06:45:25 +0000
110@@ -3,23 +3,14 @@
111 ## FIXME for 5.1 ##
112 ###########################
113
114-# http://dev.mysql.com/doc/refman/5.1/en/upgrading-from-5-0.html
115-* debian-sys-maint is not created properly in postinst
116-* Asking for root passwort has not yet been backported^H^H^H^Htested.
117-* Debconf template translations need testing
118-* Incompatible change: The table_cache system variable has been renamed to table_open_cache.
119- -> sed over /etc/mysql/*
120-* Append --syslog to /etc/mysql/*
121-* call the REPAIR TABLE statement for each table that contains any FULLTEXT indexes.
122-* put this trigger-recreation thing into the init scripts
123+* put this trigger-recreation thing into the init scripts -- what?!
124
125 ###########################################################################
126 # Here are some information that are only of interest for the current and #
127 # following Debian maintainers of MySQL. #
128 ###########################################################################
129
130-The debian/ directory is under SVN control at
131- svn+ssh://svn.debian.org/svn/pkg-mysql/branches/sid-5.1/debian
132+The debian/ directory is under SVN control, see debian/control for URL.
133
134 #
135 # Preparing a new version
136
137=== modified file 'bakery/debian-5.1/additions/debian-start.inc.sh'
138--- bakery/debian-5.1/additions/debian-start.inc.sh 2008-10-20 22:54:11 +0000
139+++ bakery/debian-5.1/additions/debian-start.inc.sh 2009-10-02 06:45:25 +0000
140@@ -11,19 +11,19 @@
141 set -u
142
143 # But do it in the background to not stall the boot process.
144- logger -p daemon.info -i -t$0 "Checking for crashed MySQL tables."
145+ logger -p daemon.info -i -t$0 "Triggering myisam-recover for all MyISAM tables"
146
147 # Checking for $? is unreliable so the size of the output is checked.
148 # Some table handlers like HEAP do not support CHECK TABLE.
149 tempfile=`tempfile`
150- LC_ALL=C $MYCHECK $MYCHECK_PARAMS \
151- 2>&1 \
152- | perl -e "
153- \$_=join('', <>);
154- s/^[^\\n]+\\n(error|note)\s+: You can't use locks with log tables.\\n//simg;
155- s/^[^\\n]+\\n(error|note)\s+: The (handler|storage engine) for the table doesn.t support check\\n//smg;
156- print;" \
157- > $tempfile
158+ # We have to use xargs in this case, because a for loop barfs on the
159+ # spaces in the thing to be looped over.
160+ LC_ALL=C $MYSQL --skip-column-names --batch -e '
161+ select concat('\''select count(*) into @discard from `'\'',
162+ TABLE_SCHEMA, '\''`.`'\'', TABLE_NAME, '\''`'\'')
163+ from information_schema.TABLES where ENGINE='\''MyISAM'\' | \
164+ xargs -i $MYSQL --skip-column-names --silent --batch \
165+ --force -e "{}" >$tempfile
166 if [ -s $tempfile ]; then
167 (
168 /bin/echo -e "\n" \
169@@ -32,7 +32,9 @@
170 $MYADMIN processlist status
171 ) >> $tempfile
172 # Check for presence as a dependency on mailx would require an MTA.
173- if [ -x /usr/bin/mailx ]; then mailx -e -s"$MYCHECK_SUBJECT" $MYCHECK_RCPT < $tempfile; fi
174+ if [ -x /usr/bin/mailx ]; then
175+ mailx -e -s"$MYCHECK_SUBJECT" $MYCHECK_RCPT < $tempfile
176+ fi
177 (echo "$MYCHECK_SUBJECT"; cat $tempfile) | logger -p daemon.warn -i -t$0
178 fi
179 rm $tempfile
180
181=== removed file 'bakery/debian-5.1/additions/innotop/InnoDBParser.pm'
182--- bakery/debian-5.1/additions/innotop/InnoDBParser.pm 2008-10-20 22:54:11 +0000
183+++ bakery/debian-5.1/additions/innotop/InnoDBParser.pm 1970-01-01 00:00:00 +0000
184@@ -1,1089 +0,0 @@
185-use strict;
186-use warnings FATAL => 'all';
187-
188-package InnoDBParser;
189-
190-# This program is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com.
191-# Feedback and improvements are gratefully received.
192-#
193-# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
194-# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
195-# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196-#
197-# This program is free software; you can redistribute it and/or modify it under
198-# the terms of the GNU General Public License as published by the Free Software
199-# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
200-# systems, you can issue `man perlgpl' or `man perlartistic' to read these
201-
202-# You should have received a copy of the GNU General Public License along with
203-# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
204-# Place, Suite 330, Boston, MA 02111-1307 USA
205-
206-our $VERSION = '1.6.0';
207-
208-use Data::Dumper;
209-$Data::Dumper::Sortkeys = 1;
210-use English qw(-no_match_vars);
211-use List::Util qw(max);
212-
213-# Some common patterns
214-my $d = qr/(\d+)/; # Digit
215-my $f = qr/(\d+\.\d+)/; # Float
216-my $t = qr/(\d+ \d+)/; # Transaction ID
217-my $i = qr/((?:\d{1,3}\.){3}\d+)/; # IP address
218-my $n = qr/([^`\s]+)/; # MySQL object name
219-my $w = qr/(\w+)/; # Words
220-my $fl = qr/([\w\.\/]+) line $d/; # Filename and line number
221-my $h = qr/((?:0x)?[0-9a-f]*)/; # Hex
222-my $s = qr/(\d{6} .\d:\d\d:\d\d)/; # InnoDB timestamp
223-
224-# If you update this variable, also update the SYNOPSIS in the pod.
225-my %innodb_section_headers = (
226- "TRANSACTIONS" => "tx",
227- "BUFFER POOL AND MEMORY" => "bp",
228- "SEMAPHORES" => "sm",
229- "LOG" => "lg",
230- "ROW OPERATIONS" => "ro",
231- "INSERT BUFFER AND ADAPTIVE HASH INDEX" => "ib",
232- "FILE I/O" => "io",
233- "LATEST DETECTED DEADLOCK" => "dl",
234- "LATEST FOREIGN KEY ERROR" => "fk",
235-);
236-
237-my %parser_for = (
238- tx => \&parse_tx_section,
239- bp => \&parse_bp_section,
240- sm => \&parse_sm_section,
241- lg => \&parse_lg_section,
242- ro => \&parse_ro_section,
243- ib => \&parse_ib_section,
244- io => \&parse_io_section,
245- dl => \&parse_dl_section,
246- fk => \&parse_fk_section,
247-);
248-
249-my %fk_parser_for = (
250- Transaction => \&parse_fk_transaction_error,
251- Error => \&parse_fk_bad_constraint_error,
252- Cannot => \&parse_fk_cant_drop_parent_error,
253-);
254-
255-# A thread's proc_info can be at least 98 different things I've found in the
256-# source. Fortunately, most of them begin with a gerunded verb. These are
257-# the ones that don't.
258-my %is_proc_info = (
259- 'After create' => 1,
260- 'Execution of init_command' => 1,
261- 'FULLTEXT initialization' => 1,
262- 'Reopen tables' => 1,
263- 'Repair done' => 1,
264- 'Repair with keycache' => 1,
265- 'System lock' => 1,
266- 'Table lock' => 1,
267- 'Thread initialized' => 1,
268- 'User lock' => 1,
269- 'copy to tmp table' => 1,
270- 'discard_or_import_tablespace' => 1,
271- 'end' => 1,
272- 'got handler lock' => 1,
273- 'got old table' => 1,
274- 'init' => 1,
275- 'key cache' => 1,
276- 'locks' => 1,
277- 'malloc' => 1,
278- 'query end' => 1,
279- 'rename result table' => 1,
280- 'rename' => 1,
281- 'setup' => 1,
282- 'statistics' => 1,
283- 'status' => 1,
284- 'table cache' => 1,
285- 'update' => 1,
286-);
287-
288-sub new {
289- bless {}, shift;
290-}
291-
292-# Parse the status and return it.
293-# See srv_printf_innodb_monitor in innobase/srv/srv0srv.c
294-# Pass in the text to parse, whether to be in debugging mode, which sections
295-# to parse (hashref; if empty, parse all), and whether to parse full info from
296-# locks and such (probably shouldn't unless you need to).
297-sub parse_status_text {
298- my ( $self, $fulltext, $debug, $sections, $full ) = @_;
299-
300- die "I can't parse undef" unless defined $fulltext;
301- $fulltext =~ s/[\r\n]+/\n/g;
302-
303- $sections ||= {};
304- die '$sections must be a hashref' unless ref($sections) eq 'HASH';
305-
306- my %innodb_data = (
307- got_all => 0, # Whether I was able to get the whole thing
308- ts => '', # Timestamp the server put on it
309- last_secs => 0, # Num seconds the averages are over
310- sections => {}, # Parsed values from each section
311- );
312-
313- if ( $debug ) {
314- $innodb_data{'fulltext'} = $fulltext;
315- }
316-
317- # Get the most basic info about the status: beginning and end, and whether
318- # I got the whole thing (if there has been a big deadlock and there are
319- # too many locks to print, the output might be truncated)
320- my ( $time_text ) = $fulltext =~ m/^$s INNODB MONITOR OUTPUT$/m;
321- $innodb_data{'ts'} = [ parse_innodb_timestamp( $time_text ) ];
322- $innodb_data{'timestring'} = ts_to_string($innodb_data{'ts'});
323- ( $innodb_data{'last_secs'} ) = $fulltext
324- =~ m/Per second averages calculated from the last $d seconds/;
325-
326- ( my $got_all ) = $fulltext =~ m/END OF INNODB MONITOR OUTPUT/;
327- $innodb_data{'got_all'} = $got_all || 0;
328-
329- # Split it into sections. Each section begins with
330- # -----
331- # LABEL
332- # -----
333- my %innodb_sections;
334- my @matches = $fulltext
335- =~ m#\n(---+)\n([A-Z /]+)\n\1\n(.*?)(?=\n(---+)\n[A-Z /]+\n\4\n|$)#gs;
336- while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) {
337- $innodb_sections{$name} = [ $text, $end ? 1 : 0 ];
338- }
339- # The Row Operations section is a special case, because instead of ending
340- # with the beginning of another section, it ends with the end of the file.
341- # So this section is complete if the entire file is complete.
342- $innodb_sections{'ROW OPERATIONS'}->[1] ||= $innodb_data{'got_all'};
343-
344- # Just for sanity's sake, make sure I understand what to do with each
345- # section
346- eval {
347- foreach my $section ( keys %innodb_sections ) {
348- my $header = $innodb_section_headers{$section};
349- die "Unknown section $section in $fulltext\n"
350- unless $header;
351- $innodb_data{'sections'}->{ $header }
352- ->{'fulltext'} = $innodb_sections{$section}->[0];
353- $innodb_data{'sections'}->{ $header }
354- ->{'complete'} = $innodb_sections{$section}->[1];
355- }
356- };
357- if ( $EVAL_ERROR ) {
358- _debug( $debug, $EVAL_ERROR);
359- }
360-
361- # ################################################################
362- # Parse the detailed data out of the sections.
363- # ################################################################
364- eval {
365- foreach my $section ( keys %parser_for ) {
366- if ( defined $innodb_data{'sections'}->{$section}
367- && (!%$sections || (defined($sections->{$section} && $sections->{$section})) )) {
368- $parser_for{$section}->(
369- $innodb_data{'sections'}->{$section},
370- $innodb_data{'sections'}->{$section}->{'complete'},
371- $debug,
372- $full )
373- or delete $innodb_data{'sections'}->{$section};
374- }
375- else {
376- delete $innodb_data{'sections'}->{$section};
377- }
378- }
379- };
380- if ( $EVAL_ERROR ) {
381- _debug( $debug, $EVAL_ERROR);
382- }
383-
384- return \%innodb_data;
385-}
386-
387-# Parses the status text and returns it flattened out as a single hash.
388-sub get_status_hash {
389- my ( $self, $fulltext, $debug, $sections, $full ) = @_;
390-
391- # Parse the status text...
392- my $innodb_status
393- = $self->parse_status_text($fulltext, $debug, $sections, $full );
394-
395- # Flatten the hierarchical structure into a single list by grabbing desired
396- # sections from it.
397- return
398- (map { 'IB_' . $_ => $innodb_status->{$_} } qw(timestring last_secs got_all)),
399- (map { 'IB_bp_' . $_ => $innodb_status->{'sections'}->{'bp'}->{$_} }
400- qw( writes_pending buf_pool_hit_rate total_mem_alloc buf_pool_reads
401- awe_mem_alloc pages_modified writes_pending_lru page_creates_sec
402- reads_pending pages_total buf_pool_hits writes_pending_single_page
403- page_writes_sec pages_read pages_written page_reads_sec
404- writes_pending_flush_list buf_pool_size add_pool_alloc
405- dict_mem_alloc pages_created buf_free complete )),
406- (map { 'IB_tx_' . $_ => $innodb_status->{'sections'}->{'tx'}->{$_} }
407- qw( num_lock_structs history_list_len purge_done_for transactions
408- purge_undo_for is_truncated trx_id_counter complete )),
409- (map { 'IB_ib_' . $_ => $innodb_status->{'sections'}->{'ib'}->{$_} }
410- qw( hash_table_size hash_searches_s non_hash_searches_s
411- bufs_in_node_heap used_cells size free_list_len seg_size inserts
412- merged_recs merges complete )),
413- (map { 'IB_lg_' . $_ => $innodb_status->{'sections'}->{'lg'}->{$_} }
414- qw( log_ios_done pending_chkp_writes last_chkp log_ios_s
415- log_flushed_to log_seq_no pending_log_writes complete )),
416- (map { 'IB_sm_' . $_ => $innodb_status->{'sections'}->{'sm'}->{$_} }
417- qw( wait_array_size rw_shared_spins rw_excl_os_waits mutex_os_waits
418- mutex_spin_rounds mutex_spin_waits rw_excl_spins rw_shared_os_waits
419- waits signal_count reservation_count complete )),
420- (map { 'IB_ro_' . $_ => $innodb_status->{'sections'}->{'ro'}->{$_} }
421- qw( queries_in_queue n_reserved_extents main_thread_state
422- main_thread_proc_no main_thread_id read_sec del_sec upd_sec ins_sec
423- read_views_open num_rows_upd num_rows_ins num_rows_read
424- queries_inside num_rows_del complete )),
425- (map { 'IB_fk_' . $_ => $innodb_status->{'sections'}->{'fk'}->{$_} }
426- qw( trigger parent_table child_index parent_index attempted_op
427- child_db timestring fk_name records col_name reason txn parent_db
428- type child_table parent_col complete )),
429- (map { 'IB_io_' . $_ => $innodb_status->{'sections'}->{'io'}->{$_} }
430- qw( pending_buffer_pool_flushes pending_pwrites pending_preads
431- pending_normal_aio_reads fsyncs_s os_file_writes pending_sync_ios
432- reads_s flush_type avg_bytes_s pending_ibuf_aio_reads writes_s
433- threads os_file_reads pending_aio_writes pending_log_ios os_fsyncs
434- pending_log_flushes complete )),
435- (map { 'IB_dl_' . $_ => $innodb_status->{'sections'}->{'dl'}->{$_} }
436- qw( timestring rolled_back txns complete ));
437-
438-}
439-
440-sub ts_to_string {
441- my $parts = shift;
442- return sprintf('%02d-%02d-%02d %02d:%02d:%02d', @$parts);
443-}
444-
445-sub parse_innodb_timestamp {
446- my $text = shift;
447- my ( $y, $m, $d, $h, $i, $s )
448- = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
449- die("Can't get timestamp from $text\n") unless $y;
450- $y += 2000;
451- return ( $y, $m, $d, $h, $i, $s );
452-}
453-
454-sub parse_fk_section {
455- my ( $section, $complete, $debug, $full ) = @_;
456- my $fulltext = $section->{'fulltext'};
457-
458- return 0 unless $fulltext;
459-
460- my ( $ts, $type ) = $fulltext =~ m/^$s\s+(\w+)/m;
461- $section->{'ts'} = [ parse_innodb_timestamp( $ts ) ];
462- $section->{'timestring'} = ts_to_string($section->{'ts'});
463- $section->{'type'} = $type;
464-
465- # Decide which type of FK error happened, and dispatch to the right parser.
466- if ( $type && $fk_parser_for{$type} ) {
467- $fk_parser_for{$type}->( $section, $complete, $debug, $fulltext, $full );
468- }
469-
470- delete $section->{'fulltext'} unless $debug;
471-
472- return 1;
473-}
474-
475-sub parse_fk_cant_drop_parent_error {
476- my ( $section, $complete, $debug, $fulltext, $full ) = @_;
477-
478- # Parse the parent/child table info out
479- @{$section}{ qw(attempted_op parent_db parent_table) } = $fulltext
480- =~ m{Cannot $w table `(.*)/(.*)`}m;
481- @{$section}{ qw(child_db child_table) } = $fulltext
482- =~ m{because it is referenced by `(.*)/(.*)`}m;
483-
484- ( $section->{'reason'} ) = $fulltext =~ m/(Cannot .*)/s;
485- $section->{'reason'} =~ s/\n(?:InnoDB: )?/ /gm
486- if $section->{'reason'};
487-
488- # Certain data may not be present. Make them '' if not present.
489- map { $section->{$_} ||= "" }
490- qw(child_index fk_name col_name parent_col);
491-}
492-
493-# See dict/dict0dict.c, function dict_foreign_error_report
494-# I don't care much about these. There are lots of different messages, and
495-# they come from someone trying to create a foreign key, or similar
496-# statements. They aren't indicative of some transaction trying to insert,
497-# delete or update data. Sometimes it is possible to parse out a lot of
498-# information about the tables and indexes involved, but often the message
499-# contains the DDL string the user entered, which is way too much for this
500-# module to try to handle.
501-sub parse_fk_bad_constraint_error {
502- my ( $section, $complete, $debug, $fulltext, $full ) = @_;
503-
504- # Parse the parent/child table and index info out
505- @{$section}{ qw(child_db child_table) } = $fulltext
506- =~ m{Error in foreign key constraint of table (.*)/(.*):$}m;
507- $section->{'attempted_op'} = 'DDL';
508-
509- # FK name, parent info... if possible.
510- @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) }
511- = $fulltext
512- =~ m/CONSTRAINT `?$n`? FOREIGN KEY \(`?$n`?\) REFERENCES (?:`?$n`?\.)?`?$n`? \(`?$n`?\)/;
513-
514- if ( !defined($section->{'fk_name'}) ) {
515- # Try to parse SQL a user might have typed in a CREATE statement or such
516- @{$section}{ qw(col_name parent_db parent_table parent_col) }
517- = $fulltext
518- =~ m/FOREIGN\s+KEY\s*\(`?$n`?\)\s+REFERENCES\s+(?:`?$n`?\.)?`?$n`?\s*\(`?$n`?\)/i;
519- }
520- $section->{'parent_db'} ||= $section->{'child_db'};
521-
522- # Name of the child index (index in the same table where the FK is, see
523- # definition of dict_foreign_struct in include/dict0mem.h, where it is
524- # called foreign_index, as opposed to referenced_index which is in the
525- # parent table. This may not be possible to find.
526- @{$section}{ qw(child_index) } = $fulltext
527- =~ m/^The index in the foreign key in table is $n$/m;
528-
529- @{$section}{ qw(reason) } = $fulltext =~ m/:\s*([^:]+)(?= Constraint:|$)/ms;
530- $section->{'reason'} =~ s/\s+/ /g
531- if $section->{'reason'};
532-
533- # Certain data may not be present. Make them '' if not present.
534- map { $section->{$_} ||= "" }
535- qw(child_index fk_name col_name parent_table parent_col);
536-}
537-
538-# see source file row/row0ins.c
539-sub parse_fk_transaction_error {
540- my ( $section, $complete, $debug, $fulltext, $full ) = @_;
541-
542- # Parse the txn info out
543- my ( $txn ) = $fulltext
544- =~ m/Transaction:\n(TRANSACTION.*)\nForeign key constraint fails/s;
545- if ( $txn ) {
546- $section->{'txn'} = parse_tx_text( $txn, $complete, $debug, $full );
547- }
548-
549- # Parse the parent/child table and index info out. There are two types: an
550- # update or a delete of a parent record leaves a child orphaned
551- # (row_ins_foreign_report_err), and an insert or update of a child record has
552- # no matching parent record (row_ins_foreign_report_add_err).
553-
554- @{$section}{ qw(reason child_db child_table) }
555- = $fulltext =~ m{^(Foreign key constraint fails for table `(.*)/(.*)`:)$}m;
556-
557- @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) }
558- = $fulltext
559- =~ m/CONSTRAINT `$n` FOREIGN KEY \(`$n`\) REFERENCES (?:`$n`\.)?`$n` \(`$n`\)/;
560- $section->{'parent_db'} ||= $section->{'child_db'};
561-
562- # Special case, which I don't know how to trigger, but see
563- # innobase/row/row0ins.c row_ins_check_foreign_constraint
564- if ( $fulltext =~ m/ibd file does not currently exist!/ ) {
565- my ( $attempted_op, $index, $records )
566- = $fulltext =~ m/^Trying to (add to index) `$n` tuple:\n(.*))?/sm;
567- $section->{'child_index'} = $index;
568- $section->{'attempted_op'} = $attempted_op || '';
569- if ( $records && $full ) {
570- ( $section->{'records'} )
571- = parse_innodb_record_dump( $records, $complete, $debug );
572- }
573- @{$section}{qw(parent_db parent_table)}
574- =~ m/^But the parent table `$n`\.`$n`$/m;
575- }
576- else {
577- my ( $attempted_op, $which, $index )
578- = $fulltext =~ m/^Trying to ([\w ]*) in (child|parent) table, in index `$n` tuple:$/m;
579- if ( $which ) {
580- $section->{$which . '_index'} = $index;
581- $section->{'attempted_op'} = $attempted_op || '';
582-
583- # Parse out the related records in the other table.
584- my ( $search_index, $records );
585- if ( $which eq 'child' ) {
586- ( $search_index, $records ) = $fulltext
587- =~ m/^But in parent table [^,]*, in index `$n`,\nthe closest match we can find is record:\n(.*)/ms;
588- $section->{'parent_index'} = $search_index;
589- }
590- else {
591- ( $search_index, $records ) = $fulltext
592- =~ m/^But in child table [^,]*, in index `$n`, (?:the record is not available|there is a record:\n(.*))?/ms;
593- $section->{'child_index'} = $search_index;
594- }
595- if ( $records && $full ) {
596- $section->{'records'}
597- = parse_innodb_record_dump( $records, $complete, $debug );
598- }
599- else {
600- $section->{'records'} = '';
601- }
602- }
603- }
604-
605- # Parse out the tuple trying to be updated, deleted or inserted.
606- my ( $trigger ) = $fulltext =~ m/^(DATA TUPLE: \d+ fields;\n.*)$/m;
607- if ( $trigger ) {
608- $section->{'trigger'} = parse_innodb_record_dump( $trigger, $complete, $debug );
609- }
610-
611- # Certain data may not be present. Make them '' if not present.
612- map { $section->{$_} ||= "" }
613- qw(child_index fk_name col_name parent_table parent_col);
614-}
615-
616-# There are new-style and old-style record formats. See rem/rem0rec.c
617-# TODO: write some tests for this
618-sub parse_innodb_record_dump {
619- my ( $dump, $complete, $debug ) = @_;
620- return undef unless $dump;
621-
622- my $result = {};
623-
624- if ( $dump =~ m/PHYSICAL RECORD/ ) {
625- my $style = $dump =~ m/compact format/ ? 'new' : 'old';
626- $result->{'style'} = $style;
627-
628- # This is a new-style record.
629- if ( $style eq 'new' ) {
630- @{$result}{qw( heap_no type num_fields info_bits )}
631- = $dump
632- =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; compact format; info bits $d$/m;
633- }
634-
635- # OK, it's old-style. Unfortunately there are variations here too.
636- elsif ( $dump =~ m/-byte offs / ) {
637- # Older-old style.
638- @{$result}{qw( heap_no type num_fields byte_offset info_bits )}
639- = $dump
640- =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offs [A-Z]+; info bits $d$/m;
641- if ( $dump !~ m/-byte offs TRUE/ ) {
642- $result->{'byte_offset'} = 0;
643- }
644- }
645- else {
646- # Newer-old style.
647- @{$result}{qw( heap_no type num_fields byte_offset info_bits )}
648- = $dump
649- =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offsets; info bits $d$/m;
650- }
651-
652- }
653- else {
654- $result->{'style'} = 'tuple';
655- @{$result}{qw( type num_fields )}
656- = $dump =~ m/^(DATA TUPLE): $d fields;$/m;
657- }
658-
659- # Fill in default values for things that couldn't be parsed.
660- map { $result->{$_} ||= 0 }
661- qw(heap_no num_fields byte_offset info_bits);
662- map { $result->{$_} ||= '' }
663- qw(style type );
664-
665- my @fields = $dump =~ m/ (\d+:.*?;?);(?=$| \d+:)/gm;
666- $result->{'fields'} = [ map { parse_field($_, $complete, $debug ) } @fields ];
667-
668- return $result;
669-}
670-
671-# New/old-style applies here. See rem/rem0rec.c
672-# $text should not include the leading space or the second trailing semicolon.
673-sub parse_field {
674- my ( $text, $complete, $debug ) = @_;
675-
676- # Sample fields:
677- # '4: SQL NULL, size 4 '
678- # '1: len 6; hex 000000005601; asc V ;'
679- # '6: SQL NULL'
680- # '5: len 30; hex 687474703a2f2f7777772e737765657477617465722e636f6d2f73746f72; asc http://www.sweetwater.com/stor;...(truncated)'
681- my ( $id, $nullsize, $len, $hex, $asc, $truncated );
682- ( $id, $nullsize ) = $text =~ m/^$d: SQL NULL, size $d $/;
683- if ( !defined($id) ) {
684- ( $id ) = $text =~ m/^$d: SQL NULL$/;
685- }
686- if ( !defined($id) ) {
687- ( $id, $len, $hex, $asc, $truncated )
688- = $text =~ m/^$d: len $d; hex $h; asc (.*);(\.\.\.\(truncated\))?$/;
689- }
690-
691- die "Could not parse this field: '$text'" unless defined $id;
692- return {
693- id => $id,
694- len => defined($len) ? $len : defined($nullsize) ? $nullsize : 0,
695- 'hex' => defined($hex) ? $hex : '',
696- asc => defined($asc) ? $asc : '',
697- trunc => $truncated ? 1 : 0,
698- };
699-
700-}
701-
702-sub parse_dl_section {
703- my ( $dl, $complete, $debug, $full ) = @_;
704- return unless $dl;
705- my $fulltext = $dl->{'fulltext'};
706- return 0 unless $fulltext;
707-
708- my ( $ts ) = $fulltext =~ m/^$s$/m;
709- return 0 unless $ts;
710-
711- $dl->{'ts'} = [ parse_innodb_timestamp( $ts ) ];
712- $dl->{'timestring'} = ts_to_string($dl->{'ts'});
713- $dl->{'txns'} = {};
714-
715- my @sections
716- = $fulltext
717- =~ m{
718- ^\*{3}\s([^\n]*) # *** (1) WAITING FOR THIS...
719- (.*?) # Followed by anything, non-greedy
720- (?=(?:^\*{3})|\z) # Followed by another three stars or EOF
721- }gmsx;
722-
723-
724- # Loop through each section. There are no assumptions about how many
725- # there are, who holds and wants what locks, and who gets rolled back.
726- while ( my ($header, $body) = splice(@sections, 0, 2) ) {
727- my ( $txn_id, $what ) = $header =~ m/^\($d\) (.*):$/;
728- next unless $txn_id;
729- $dl->{'txns'}->{$txn_id} ||= {};
730- my $txn = $dl->{'txns'}->{$txn_id};
731-
732- if ( $what eq 'TRANSACTION' ) {
733- $txn->{'tx'} = parse_tx_text( $body, $complete, $debug, $full );
734- }
735- else {
736- push @{$txn->{'locks'}}, parse_innodb_record_locks( $body, $complete, $debug, $full );
737- }
738- }
739-
740- @{ $dl }{ qw(rolled_back) }
741- = $fulltext =~ m/^\*\*\* WE ROLL BACK TRANSACTION \($d\)$/m;
742-
743- # Make sure certain values aren't undef
744- map { $dl->{$_} ||= '' } qw(rolled_back);
745-
746- delete $dl->{'fulltext'} unless $debug;
747- return 1;
748-}
749-
750-sub parse_innodb_record_locks {
751- my ( $text, $complete, $debug, $full ) = @_;
752- my @result;
753-
754- foreach my $lock ( $text =~ m/(^(?:RECORD|TABLE) LOCKS?.*$)/gm ) {
755- my $hash = {};
756- @{$hash}{ qw(lock_type space_id page_no n_bits index db table txn_id lock_mode) }
757- = $lock
758- =~ 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;
759- ( $hash->{'special'} )
760- = $lock =~ m/^(?:RECORD|TABLE) .*? locks (rec but not gap|gap before rec)/m;
761- $hash->{'insert_intention'}
762- = $lock =~ m/^(?:RECORD|TABLE) .*? insert intention/m ? 1 : 0;
763- $hash->{'waiting'}
764- = $lock =~ m/^(?:RECORD|TABLE) .*? waiting/m ? 1 : 0;
765-
766- # Some things may not be in the text, so make sure they are not
767- # undef.
768- map { $hash->{$_} ||= 0 } qw(n_bits page_no space_id);
769- map { $hash->{$_} ||= "" } qw(index special);
770- push @result, $hash;
771- }
772-
773- return @result;
774-}
775-
776-sub parse_tx_text {
777- my ( $txn, $complete, $debug, $full ) = @_;
778-
779- my ( $txn_id, $txn_status, $active_secs, $proc_no, $os_thread_id )
780- = $txn
781- =~ m/^(?:---)?TRANSACTION $t, (\D*?)(?: $d sec)?, (?:process no $d, )?OS thread id $d/m;
782- my ( $thread_status, $thread_decl_inside )
783- = $txn
784- =~ m/OS thread id \d+(?: ([^,]+?))?(?:, thread declared inside InnoDB $d)?$/m;
785-
786- # Parsing the line that begins 'MySQL thread id' is complicated. The only
787- # thing always in the line is the thread and query id. See function
788- # innobase_mysql_print_thd in InnoDB source file sql/ha_innodb.cc.
789- my ( $thread_line ) = $txn =~ m/^(MySQL thread id .*)$/m;
790- my ( $mysql_thread_id, $query_id, $hostname, $ip, $user, $query_status );
791-
792- if ( $thread_line ) {
793- # These parts can always be gotten.
794- ( $mysql_thread_id, $query_id ) = $thread_line =~ m/^MySQL thread id $d, query id $d/m;
795-
796- # If it's a master/slave thread, "Has (read|sent) all" may be the thread's
797- # proc_info. In these cases, there won't be any host/ip/user info
798- ( $query_status ) = $thread_line =~ m/(Has (?:read|sent) all .*$)/m;
799- if ( defined($query_status) ) {
800- $user = 'system user';
801- }
802-
803- # It may be the case that the query id is the last thing in the line.
804- elsif ( $thread_line =~ m/query id \d+ / ) {
805- # The IP address is the only non-word thing left, so it's the most
806- # useful marker for where I have to start guessing.
807- ( $hostname, $ip ) = $thread_line =~ m/query id \d+(?: ([A-Za-z]\S+))? $i/m;
808- if ( defined $ip ) {
809- ( $user, $query_status ) = $thread_line =~ m/$ip $w(?: (.*))?$/;
810- }
811- else { # OK, there wasn't an IP address.
812- # There might not be ANYTHING except the query status.
813- ( $query_status ) = $thread_line =~ m/query id \d+ (.*)$/;
814- if ( $query_status !~ m/^\w+ing/ && !exists($is_proc_info{$query_status}) ) {
815- # The remaining tokens are, in order: hostname, user, query_status.
816- # It's basically impossible to know which is which.
817- ( $hostname, $user, $query_status ) = $thread_line
818- =~ m/query id \d+(?: ([A-Za-z]\S+))?(?: $w(?: (.*))?)?$/m;
819- }
820- else {
821- $user = 'system user';
822- }
823- }
824- }
825- }
826-
827- my ( $lock_wait_status, $lock_structs, $heap_size, $row_locks, $undo_log_entries )
828- = $txn
829- =~ m/^(?:(\D*) )?$d lock struct\(s\), heap size $d(?:, $d row lock\(s\))?(?:, undo log entries $d)?$/m;
830- my ( $lock_wait_time )
831- = $txn
832- =~ m/^------- TRX HAS BEEN WAITING $d SEC/m;
833-
834- my $locks;
835- # If the transaction has locks, grab the locks.
836- if ( $txn =~ m/^TABLE LOCK|RECORD LOCKS/ ) {
837- $locks = [parse_innodb_record_locks($txn, $complete, $debug, $full)];
838- }
839-
840- my ( $tables_in_use, $tables_locked )
841- = $txn
842- =~ m/^mysql tables in use $d, locked $d$/m;
843- my ( $txn_doesnt_see_ge, $txn_sees_lt )
844- = $txn
845- =~ m/^Trx read view will not see trx with id >= $t, sees < $t$/m;
846- my $has_read_view = defined($txn_doesnt_see_ge);
847- # Only a certain number of bytes of the query text are included here, at least
848- # under some circumstances. Some versions include 300, some 600.
849- my ( $query_text )
850- = $txn
851- =~ m{
852- ^MySQL\sthread\sid\s[^\n]+\n # This comes before the query text
853- (.*?) # The query text
854- (?= # Followed by any of...
855- ^Trx\sread\sview
856- |^-------\sTRX\sHAS\sBEEN\sWAITING
857- |^TABLE\sLOCK
858- |^RECORD\sLOCKS\sspace\sid
859- |^(?:---)?TRANSACTION
860- |^\*\*\*\s\(\d\)
861- |\Z
862- )
863- }xms;
864- if ( $query_text ) {
865- $query_text =~ s/\s+$//;
866- }
867- else {
868- $query_text = '';
869- }
870-
871- my %stuff = (
872- active_secs => $active_secs,
873- has_read_view => $has_read_view,
874- heap_size => $heap_size,
875- hostname => $hostname,
876- ip => $ip,
877- lock_structs => $lock_structs,
878- lock_wait_status => $lock_wait_status,
879- lock_wait_time => $lock_wait_time,
880- mysql_thread_id => $mysql_thread_id,
881- os_thread_id => $os_thread_id,
882- proc_no => $proc_no,
883- query_id => $query_id,
884- query_status => $query_status,
885- query_text => $query_text,
886- row_locks => $row_locks,
887- tables_in_use => $tables_in_use,
888- tables_locked => $tables_locked,
889- thread_decl_inside => $thread_decl_inside,
890- thread_status => $thread_status,
891- txn_doesnt_see_ge => $txn_doesnt_see_ge,
892- txn_id => $txn_id,
893- txn_sees_lt => $txn_sees_lt,
894- txn_status => $txn_status,
895- undo_log_entries => $undo_log_entries,
896- user => $user,
897- );
898- $stuff{'fulltext'} = $txn if $debug;
899- $stuff{'locks'} = $locks if $locks;
900-
901- # Some things may not be in the txn text, so make sure they are not
902- # undef.
903- map { $stuff{$_} ||= 0 } qw(active_secs heap_size lock_structs
904- tables_in_use undo_log_entries tables_locked has_read_view
905- thread_decl_inside lock_wait_time proc_no row_locks);
906- map { $stuff{$_} ||= "" } qw(thread_status txn_doesnt_see_ge
907- txn_sees_lt query_status ip query_text lock_wait_status user);
908- $stuff{'hostname'} ||= $stuff{'ip'};
909-
910- return \%stuff;
911-}
912-
913-sub parse_tx_section {
914- my ( $section, $complete, $debug, $full ) = @_;
915- return unless $section && $section->{'fulltext'};
916- my $fulltext = $section->{'fulltext'};
917- $section->{'transactions'} = [];
918-
919- # Handle the individual transactions
920- my @transactions = $fulltext =~ m/(---TRANSACTION \d.*?)(?=\n---TRANSACTION|$)/gs;
921- foreach my $txn ( @transactions ) {
922- my $stuff = parse_tx_text( $txn, $complete, $debug, $full );
923- delete $stuff->{'fulltext'} unless $debug;
924- push @{$section->{'transactions'}}, $stuff;
925- }
926-
927- # Handle the general info
928- @{$section}{ 'trx_id_counter' }
929- = $fulltext =~ m/^Trx id counter $t$/m;
930- @{$section}{ 'purge_done_for', 'purge_undo_for' }
931- = $fulltext =~ m/^Purge done for trx's n:o < $t undo n:o < $t$/m;
932- @{$section}{ 'history_list_len' } # This isn't present in some 4.x versions
933- = $fulltext =~ m/^History list length $d$/m;
934- @{$section}{ 'num_lock_structs' }
935- = $fulltext =~ m/^Total number of lock structs in row lock hash table $d$/m;
936- @{$section}{ 'is_truncated' }
937- = $fulltext =~ m/^\.\.\. truncated\.\.\.$/m ? 1 : 0;
938-
939- # Fill in things that might not be present
940- foreach ( qw(history_list_len) ) {
941- $section->{$_} ||= 0;
942- }
943-
944- delete $section->{'fulltext'} unless $debug;
945- return 1;
946-}
947-
948-# I've read the source for this section.
949-sub parse_ro_section {
950- my ( $section, $complete, $debug, $full ) = @_;
951- return unless $section && $section->{'fulltext'};
952- my $fulltext = $section->{'fulltext'};
953-
954- # Grab the info
955- @{$section}{ 'queries_inside', 'queries_in_queue' }
956- = $fulltext =~ m/^$d queries inside InnoDB, $d queries in queue$/m;
957- ( $section->{ 'read_views_open' } )
958- = $fulltext =~ m/^$d read views open inside InnoDB$/m;
959- ( $section->{ 'n_reserved_extents' } )
960- = $fulltext =~ m/^$d tablespace extents now reserved for B-tree/m;
961- @{$section}{ 'main_thread_proc_no', 'main_thread_id', 'main_thread_state' }
962- = $fulltext =~ m/^Main thread (?:process no. $d, )?id $d, state: (.*)$/m;
963- @{$section}{ 'num_rows_ins', 'num_rows_upd', 'num_rows_del', 'num_rows_read' }
964- = $fulltext =~ m/^Number of rows inserted $d, updated $d, deleted $d, read $d$/m;
965- @{$section}{ 'ins_sec', 'upd_sec', 'del_sec', 'read_sec' }
966- = $fulltext =~ m#^$f inserts/s, $f updates/s, $f deletes/s, $f reads/s$#m;
967- $section->{'main_thread_proc_no'} ||= 0;
968-
969- map { $section->{$_} ||= 0 } qw(read_views_open n_reserved_extents);
970- delete $section->{'fulltext'} unless $debug;
971- return 1;
972-}
973-
974-sub parse_lg_section {
975- my ( $section, $complete, $debug, $full ) = @_;
976- return unless $section;
977- my $fulltext = $section->{'fulltext'};
978-
979- # Grab the info
980- ( $section->{ 'log_seq_no' } )
981- = $fulltext =~ m/Log sequence number \s*(\d.*)$/m;
982- ( $section->{ 'log_flushed_to' } )
983- = $fulltext =~ m/Log flushed up to \s*(\d.*)$/m;
984- ( $section->{ 'last_chkp' } )
985- = $fulltext =~ m/Last checkpoint at \s*(\d.*)$/m;
986- @{$section}{ 'pending_log_writes', 'pending_chkp_writes' }
987- = $fulltext =~ m/$d pending log writes, $d pending chkp writes/;
988- @{$section}{ 'log_ios_done', 'log_ios_s' }
989- = $fulltext =~ m#$d log i/o's done, $f log i/o's/second#;
990-
991- delete $section->{'fulltext'} unless $debug;
992- return 1;
993-}
994-
995-sub parse_ib_section {
996- my ( $section, $complete, $debug, $full ) = @_;
997- return unless $section && $section->{'fulltext'};
998- my $fulltext = $section->{'fulltext'};
999-
1000- # Some servers will output ibuf information for tablespace 0, as though there
1001- # might be many tablespaces with insert buffers. (In practice I believe
1002- # the source code shows there will only ever be one). I have to parse both
1003- # cases here, but I assume there will only be one.
1004- @{$section}{ 'size', 'free_list_len', 'seg_size' }
1005- = $fulltext =~ m/^Ibuf(?: for space 0)?: size $d, free list len $d, seg size $d,$/m;
1006- @{$section}{ 'inserts', 'merged_recs', 'merges' }
1007- = $fulltext =~ m/^$d inserts, $d merged recs, $d merges$/m;
1008-
1009- @{$section}{ 'hash_table_size', 'used_cells', 'bufs_in_node_heap' }
1010- = $fulltext =~ m/^Hash table size $d, used cells $d, node heap has $d buffer\(s\)$/m;
1011- @{$section}{ 'hash_searches_s', 'non_hash_searches_s' }
1012- = $fulltext =~ m{^$f hash searches/s, $f non-hash searches/s$}m;
1013-
1014- delete $section->{'fulltext'} unless $debug;
1015- return 1;
1016-}
1017-
1018-sub parse_wait_array {
1019- my ( $text, $complete, $debug, $full ) = @_;
1020- my %result;
1021-
1022- @result{ qw(thread waited_at_filename waited_at_line waited_secs) }
1023- = $text =~ m/^--Thread $d has waited at $fl for $f seconds/m;
1024-
1025- # Depending on whether it's a SYNC_MUTEX,RW_LOCK_EX,RW_LOCK_SHARED,
1026- # there will be different text output
1027- if ( $text =~ m/^Mutex at/m ) {
1028- $result{'request_type'} = 'M';
1029- @result{ qw( lock_mem_addr lock_cfile_name lock_cline lock_var) }
1030- = $text =~ m/^Mutex at $h created file $fl, lock var $d$/m;
1031- @result{ qw( waiters_flag )}
1032- = $text =~ m/^waiters flag $d$/m;
1033- }
1034- else {
1035- @result{ qw( request_type lock_mem_addr lock_cfile_name lock_cline) }
1036- = $text =~ m/^(.)-lock on RW-latch at $h created in file $fl$/m;
1037- @result{ qw( writer_thread writer_lock_mode ) }
1038- = $text =~ m/^a writer \(thread id $d\) has reserved it in mode (.*)$/m;
1039- @result{ qw( num_readers waiters_flag )}
1040- = $text =~ m/^number of readers $d, waiters flag $d$/m;
1041- @result{ qw(last_s_file_name last_s_line ) }
1042- = $text =~ m/Last time read locked in file $fl$/m;
1043- @result{ qw(last_x_file_name last_x_line ) }
1044- = $text =~ m/Last time write locked in file $fl$/m;
1045- }
1046-
1047- $result{'cell_waiting'} = $text =~ m/^wait has ended$/m ? 0 : 1;
1048- $result{'cell_event_set'} = $text =~ m/^wait is ending$/m ? 1 : 0;
1049-
1050- # Because there are two code paths, some things won't get set.
1051- map { $result{$_} ||= '' }
1052- qw(last_s_file_name last_x_file_name writer_lock_mode);
1053- map { $result{$_} ||= 0 }
1054- qw(num_readers lock_var last_s_line last_x_line writer_thread);
1055-
1056- return \%result;
1057-}
1058-
1059-sub parse_sm_section {
1060- my ( $section, $complete, $debug, $full ) = @_;
1061- return 0 unless $section && $section->{'fulltext'};
1062- my $fulltext = $section->{'fulltext'};
1063-
1064- # Grab the info
1065- @{$section}{ 'reservation_count', 'signal_count' }
1066- = $fulltext =~ m/^OS WAIT ARRAY INFO: reservation count $d, signal count $d$/m;
1067- @{$section}{ 'mutex_spin_waits', 'mutex_spin_rounds', 'mutex_os_waits' }
1068- = $fulltext =~ m/^Mutex spin waits $d, rounds $d, OS waits $d$/m;
1069- @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits', 'rw_excl_spins', 'rw_excl_os_waits' }
1070- = $fulltext =~ m/^RW-shared spins $d, OS waits $d; RW-excl spins $d, OS waits $d$/m;
1071-
1072- # Look for info on waits.
1073- my @waits = $fulltext =~ m/^(--Thread.*?)^(?=Mutex spin|--Thread)/gms;
1074- $section->{'waits'} = [ map { parse_wait_array($_, $complete, $debug) } @waits ];
1075- $section->{'wait_array_size'} = scalar(@waits);
1076-
1077- delete $section->{'fulltext'} unless $debug;
1078- return 1;
1079-}
1080-
1081-# I've read the source for this section.
1082-sub parse_bp_section {
1083- my ( $section, $complete, $debug, $full ) = @_;
1084- return unless $section && $section->{'fulltext'};
1085- my $fulltext = $section->{'fulltext'};
1086-
1087- # Grab the info
1088- @{$section}{ 'total_mem_alloc', 'add_pool_alloc' }
1089- = $fulltext =~ m/^Total memory allocated $d; in additional pool allocated $d$/m;
1090- @{$section}{'dict_mem_alloc'} = $fulltext =~ m/Dictionary memory allocated $d/;
1091- @{$section}{'awe_mem_alloc'} = $fulltext =~ m/$d MB of AWE memory/;
1092- @{$section}{'buf_pool_size'} = $fulltext =~ m/^Buffer pool size\s*$d$/m;
1093- @{$section}{'buf_free'} = $fulltext =~ m/^Free buffers\s*$d$/m;
1094- @{$section}{'pages_total'} = $fulltext =~ m/^Database pages\s*$d$/m;
1095- @{$section}{'pages_modified'} = $fulltext =~ m/^Modified db pages\s*$d$/m;
1096- @{$section}{'pages_read', 'pages_created', 'pages_written'}
1097- = $fulltext =~ m/^Pages read $d, created $d, written $d$/m;
1098- @{$section}{'page_reads_sec', 'page_creates_sec', 'page_writes_sec'}
1099- = $fulltext =~ m{^$f reads/s, $f creates/s, $f writes/s$}m;
1100- @{$section}{'buf_pool_hits', 'buf_pool_reads'}
1101- = $fulltext =~ m{Buffer pool hit rate $d / $d$}m;
1102- if ($fulltext =~ m/^No buffer pool page gets since the last printout$/m) {
1103- @{$section}{'buf_pool_hits', 'buf_pool_reads'} = (0, 0);
1104- @{$section}{'buf_pool_hit_rate'} = '--';
1105- }
1106- else {
1107- @{$section}{'buf_pool_hit_rate'}
1108- = $fulltext =~ m{Buffer pool hit rate (\d+ / \d+)$}m;
1109- }
1110- @{$section}{'reads_pending'} = $fulltext =~ m/^Pending reads $d/m;
1111- @{$section}{'writes_pending_lru', 'writes_pending_flush_list', 'writes_pending_single_page' }
1112- = $fulltext =~ m/^Pending writes: LRU $d, flush list $d, single page $d$/m;
1113-
1114- map { $section->{$_} ||= 0 }
1115- qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page
1116- awe_mem_alloc dict_mem_alloc);
1117- @{$section}{'writes_pending'} = List::Util::sum(
1118- @{$section}{ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page) });
1119-
1120- delete $section->{'fulltext'} unless $debug;
1121- return 1;
1122-}
1123-
1124-# I've read the source for this.
1125-sub parse_io_section {
1126- my ( $section, $complete, $debug, $full ) = @_;
1127- return unless $section && $section->{'fulltext'};
1128- my $fulltext = $section->{'fulltext'};
1129- $section->{'threads'} = {};
1130-
1131- # Grab the I/O thread info
1132- my @threads = $fulltext =~ m<^(I/O thread \d+ .*)$>gm;
1133- foreach my $thread (@threads) {
1134- my ( $tid, $state, $purpose, $event_set )
1135- = $thread =~ m{I/O thread $d state: (.+?) \((.*)\)(?: ev set)?$}m;
1136- if ( defined $tid ) {
1137- $section->{'threads'}->{$tid} = {
1138- thread => $tid,
1139- state => $state,
1140- purpose => $purpose,
1141- event_set => $event_set ? 1 : 0,
1142- };
1143- }
1144- }
1145-
1146- # Grab the reads/writes/flushes info
1147- @{$section}{ 'pending_normal_aio_reads', 'pending_aio_writes' }
1148- = $fulltext =~ m/^Pending normal aio reads: $d, aio writes: $d,$/m;
1149- @{$section}{ 'pending_ibuf_aio_reads', 'pending_log_ios', 'pending_sync_ios' }
1150- = $fulltext =~ m{^ ibuf aio reads: $d, log i/o's: $d, sync i/o's: $d$}m;
1151- @{$section}{ 'flush_type', 'pending_log_flushes', 'pending_buffer_pool_flushes' }
1152- = $fulltext =~ m/^Pending flushes \($w\) log: $d; buffer pool: $d$/m;
1153- @{$section}{ 'os_file_reads', 'os_file_writes', 'os_fsyncs' }
1154- = $fulltext =~ m/^$d OS file reads, $d OS file writes, $d OS fsyncs$/m;
1155- @{$section}{ 'reads_s', 'avg_bytes_s', 'writes_s', 'fsyncs_s' }
1156- = $fulltext =~ m{^$f reads/s, $d avg bytes/read, $f writes/s, $f fsyncs/s$}m;
1157- @{$section}{ 'pending_preads', 'pending_pwrites' }
1158- = $fulltext =~ m/$d pending preads, $d pending pwrites$/m;
1159- @{$section}{ 'pending_preads', 'pending_pwrites' } = (0, 0)
1160- unless defined($section->{'pending_preads'});
1161-
1162- delete $section->{'fulltext'} unless $debug;
1163- return 1;
1164-}
1165-
1166-sub _debug {
1167- my ( $debug, $msg ) = @_;
1168- if ( $debug ) {
1169- die $msg;
1170- }
1171- else {
1172- warn $msg;
1173- }
1174- return 1;
1175-}
1176-
1177-1;
1178-
1179-# end_of_package
1180-# ############################################################################
1181-# Perldoc section. I put this last as per the Dog book.
1182-# ############################################################################
1183-=pod
1184-
1185-=head1 NAME
1186-
1187-InnoDBParser - Parse InnoDB monitor text.
1188-
1189-=head1 DESCRIPTION
1190-
1191-InnoDBParser tries to parse the output of the InnoDB monitor. One way to get
1192-this output is to connect to a MySQL server and issue the command SHOW ENGINE
1193-INNODB STATUS (omit 'ENGINE' on earlier versions of MySQL). The goal is to
1194-turn text into data that something else (e.g. innotop) can use.
1195-
1196-The output comes from all over, but the place to start in the source is
1197-innobase/srv/srv0srv.c.
1198-
1199-=head1 SYNOPSIS
1200-
1201- use InnoDBParser;
1202- use DBI;
1203-
1204- # Get the status text.
1205- my $dbh = DBI->connect(
1206- "DBI::mysql:test;host=localhost",
1207- 'user',
1208- 'password'
1209- );
1210- my $query = 'SHOW /*!5 ENGINE */ INNODB STATUS';
1211- my $text = $dbh->selectcol_arrayref($query)->[0];
1212-
1213- # 1 or 0
1214- my $debug = 1;
1215-
1216- # Choose sections of the monitor text you want. Possible values:
1217- # TRANSACTIONS => tx
1218- # BUFFER POOL AND MEMORY => bp
1219- # SEMAPHORES => sm
1220- # LOG => lg
1221- # ROW OPERATIONS => ro
1222- # INSERT BUFFER AND ADAPTIVE HASH INDEX => ib
1223- # FILE I/O => io
1224- # LATEST DETECTED DEADLOCK => dl
1225- # LATEST FOREIGN KEY ERROR => fk
1226-
1227- my $required_sections = {
1228- tx => 1,
1229- };
1230-
1231- # Parse the status text.
1232- my $parser = InnoDBParser->new;
1233- $innodb_status = $parser->parse_status_text(
1234- $text,
1235- $debug,
1236- # Omit the following parameter to get all sections.
1237- $required_sections,
1238- );
1239-
1240-=head1 COPYRIGHT, LICENSE AND WARRANTY
1241-
1242-This package is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com.
1243-Feedback and improvements are gratefully received.
1244-
1245-THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1246-WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1247-MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1248-
1249-This program is free software; you can redistribute it and/or modify it under
1250-the terms of the GNU General Public License as published by the Free Software
1251-Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1252-systems, you can issue `man perlgpl' or `man perlartistic' to read these
1253-licenses.
1254-
1255-You should have received a copy of the GNU General Public License along with
1256-this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1257-Place, Suite 330, Boston, MA 02111-1307 USA
1258-
1259-=head1 AUTHOR
1260-
1261-Baron Schwartz, baron at xaprb dot com.
1262-
1263-=head1 BUGS
1264-
1265-None known, but I bet there are some. The InnoDB monitor text wasn't really
1266-designed to be parsable.
1267-
1268-=head1 SEE ALSO
1269-
1270-innotop - a program that can format the parsed status information for humans
1271-to read and enjoy.
1272-
1273-=cut
1274
1275=== modified file 'bakery/debian-5.1/additions/innotop/changelog.innotop'
1276--- bakery/debian-5.1/additions/innotop/changelog.innotop 2008-10-20 22:54:11 +0000
1277+++ bakery/debian-5.1/additions/innotop/changelog.innotop 2009-10-02 06:45:25 +0000
1278@@ -1,4 +1,43 @@
1279-Changelog for innotop and InnoDBParser:
1280+Changelog for innotop:
1281+
1282+2009-03-09: version 1.7.1
1283+
1284+ Changes:
1285+ * Don't display the CXN column if only one connection is active in
1286+ the current view
1287+
1288+ Bugs fixed:
1289+ * fixed bug where trying to aggregate the time column would result
1290+ in a crash if the time column had an undef value in it, which is
1291+ the case when a thread is in the 'Connect' state
1292+ * updated innotop.spec file to reflect current version
1293+
1294+2009-02-23: version 1.7.0
1295+
1296+ Changes:
1297+ * supports a central config (/etc/innotop/innotop.conf)
1298+ * changed the default home directory config to ~/.innotop/innotop.conf
1299+ (away from .ini)
1300+ * embedded InnoDBParser.pm into innotop so it can be run with no
1301+ installation
1302+ * no longer writes a new config file by default
1303+ * added --skipcentral (skip reading central config) and --write (write
1304+ a config if none were loaded at start-up)
1305+ * if no config file is loaded, connect to a MySQL database on
1306+ localhost using mysql_read_default_group=client
1307+ * embedded maatkit's DSNParser.pm and added support for --user,
1308+ --password, --host, --port
1309+ * changed default mode from T (InnoDB Transactions) to Q (Query List)
1310+ * in addition to connected threads, now displays running and cached
1311+ threads in statusbar
1312+ * don't load connections from a config file if any DSN information or
1313+ a username or password is specified on the command-line
1314+
1315+ Bugs fixed:
1316+ * fixed bug preventing utilization of command-line options that
1317+ override default config settings if no config file was loaded
1318+ * fixed a bug where migrating from an old version of the config will
1319+ delete ~/innotop.ini, if it exists. Now uses File::Temp::tempfile().
1320
1321 2007-11-09: version 1.6.0
1322
1323
1324=== modified file 'bakery/debian-5.1/additions/innotop/innotop'
1325--- bakery/debian-5.1/additions/innotop/innotop 2008-10-20 22:54:11 +0000
1326+++ bakery/debian-5.1/additions/innotop/innotop 2009-10-02 06:45:25 +0000
1327@@ -2,26 +2,1346 @@
1328
1329 # vim: tw=160:nowrap:expandtab:tabstop=3:shiftwidth=3:softtabstop=3
1330
1331+# This program is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com.
1332+# Feedback and improvements are gratefully received.
1333+#
1334+# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
1335+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1336+# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1337+#
1338+# This program is free software; you can redistribute it and/or modify it under
1339+# the terms of the GNU General Public License as published by the Free Software
1340+# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar
1341+# systems, you can issue `man perlgpl' or `man perlartistic' to read these
1342+
1343+# You should have received a copy of the GNU General Public License along with
1344+# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
1345+# Place, Suite 330, Boston, MA 02111-1307 USA
1346+
1347 use strict;
1348 use warnings FATAL => 'all';
1349+
1350+our $VERSION = '1.7.1';
1351+
1352+# Find the home directory; it's different on different OSes.
1353+our $homepath = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.';
1354+
1355+# Configuration files
1356+our $default_home_conf = "$homepath/.innotop/innotop.conf";
1357+our $default_central_conf = "/etc/innotop/innotop.conf";
1358+our $conf_file = "";
1359+
1360+## Begin packages ##
1361+
1362+package DSNParser;
1363+
1364+use DBI;
1365+use Data::Dumper;
1366+$Data::Dumper::Indent = 0;
1367+$Data::Dumper::Quotekeys = 0;
1368+use English qw(-no_match_vars);
1369+
1370+use constant MKDEBUG => $ENV{MKDEBUG};
1371+
1372+# Defaults are built-in, but you can add/replace items by passing them as
1373+# hashrefs of {key, desc, copy, dsn}. The desc and dsn items are optional.
1374+# You can set properties with the prop() sub. Don't set the 'opts' property.
1375+sub new {
1376+ my ( $class, @opts ) = @_;
1377+ my $self = {
1378+ opts => {
1379+ A => {
1380+ desc => 'Default character set',
1381+ dsn => 'charset',
1382+ copy => 1,
1383+ },
1384+ D => {
1385+ desc => 'Database to use',
1386+ dsn => 'database',
1387+ copy => 1,
1388+ },
1389+ F => {
1390+ desc => 'Only read default options from the given file',
1391+ dsn => 'mysql_read_default_file',
1392+ copy => 1,
1393+ },
1394+ h => {
1395+ desc => 'Connect to host',
1396+ dsn => 'host',
1397+ copy => 1,
1398+ },
1399+ p => {
1400+ desc => 'Password to use when connecting',
1401+ dsn => 'password',
1402+ copy => 1,
1403+ },
1404+ P => {
1405+ desc => 'Port number to use for connection',
1406+ dsn => 'port',
1407+ copy => 1,
1408+ },
1409+ S => {
1410+ desc => 'Socket file to use for connection',
1411+ dsn => 'mysql_socket',
1412+ copy => 1,
1413+ },
1414+ u => {
1415+ desc => 'User for login if not current user',
1416+ dsn => 'user',
1417+ copy => 1,
1418+ },
1419+ },
1420+ };
1421+ foreach my $opt ( @opts ) {
1422+ MKDEBUG && _d('Adding extra property ' . $opt->{key});
1423+ $self->{opts}->{$opt->{key}} = { desc => $opt->{desc}, copy => $opt->{copy} };
1424+ }
1425+ return bless $self, $class;
1426+}
1427+
1428+# Recognized properties:
1429+# * autokey: which key to treat a bareword as (typically h=host).
1430+# * dbidriver: which DBI driver to use; assumes mysql, supports Pg.
1431+# * required: which parts are required (hashref).
1432+# * setvars: a list of variables to set after connecting
1433+sub prop {
1434+ my ( $self, $prop, $value ) = @_;
1435+ if ( @_ > 2 ) {
1436+ MKDEBUG && _d("Setting $prop property");
1437+ $self->{$prop} = $value;
1438+ }
1439+ return $self->{$prop};
1440+}
1441+
1442+sub parse {
1443+ my ( $self, $dsn, $prev, $defaults ) = @_;
1444+ if ( !$dsn ) {
1445+ MKDEBUG && _d('No DSN to parse');
1446+ return;
1447+ }
1448+ MKDEBUG && _d("Parsing $dsn");
1449+ $prev ||= {};
1450+ $defaults ||= {};
1451+ my %given_props;
1452+ my %final_props;
1453+ my %opts = %{$self->{opts}};
1454+ my $prop_autokey = $self->prop('autokey');
1455+
1456+ # Parse given props
1457+ foreach my $dsn_part ( split(/,/, $dsn) ) {
1458+ if ( my ($prop_key, $prop_val) = $dsn_part =~ m/^(.)=(.*)$/ ) {
1459+ # Handle the typical DSN parts like h=host, P=3306, etc.
1460+ $given_props{$prop_key} = $prop_val;
1461+ }
1462+ elsif ( $prop_autokey ) {
1463+ # Handle barewords
1464+ MKDEBUG && _d("Interpreting $dsn_part as $prop_autokey=$dsn_part");
1465+ $given_props{$prop_autokey} = $dsn_part;
1466+ }
1467+ else {
1468+ MKDEBUG && _d("Bad DSN part: $dsn_part");
1469+ }
1470+ }
1471+
1472+ # Fill in final props from given, previous, and/or default props
1473+ foreach my $key ( keys %opts ) {
1474+ MKDEBUG && _d("Finding value for $key");
1475+ $final_props{$key} = $given_props{$key};
1476+ if ( !defined $final_props{$key}
1477+ && defined $prev->{$key} && $opts{$key}->{copy} )
1478+ {
1479+ $final_props{$key} = $prev->{$key};
1480+ MKDEBUG && _d("Copying value for $key from previous DSN");
1481+ }
1482+ if ( !defined $final_props{$key} ) {
1483+ $final_props{$key} = $defaults->{$key};
1484+ MKDEBUG && _d("Copying value for $key from defaults");
1485+ }
1486+ }
1487+
1488+ # Sanity check props
1489+ foreach my $key ( keys %given_props ) {
1490+ die "Unrecognized DSN part '$key' in '$dsn'\n"
1491+ unless exists $opts{$key};
1492+ }
1493+ if ( (my $required = $self->prop('required')) ) {
1494+ foreach my $key ( keys %$required ) {
1495+ die "Missing DSN part '$key' in '$dsn'\n" unless $final_props{$key};
1496+ }
1497+ }
1498+
1499+ return \%final_props;
1500+}
1501+
1502+sub as_string {
1503+ my ( $self, $dsn ) = @_;
1504+ return $dsn unless ref $dsn;
1505+ return join(',',
1506+ map { "$_=" . ($_ eq 'p' ? '...' : $dsn->{$_}) }
1507+ grep { defined $dsn->{$_} && $self->{opts}->{$_} }
1508+ sort keys %$dsn );
1509+}
1510+
1511+sub usage {
1512+ my ( $self ) = @_;
1513+ my $usage
1514+ = "DSN syntax is key=value[,key=value...] Allowable DSN keys:\n"
1515+ . " KEY COPY MEANING\n"
1516+ . " === ==== =============================================\n";
1517+ my %opts = %{$self->{opts}};
1518+ foreach my $key ( sort keys %opts ) {
1519+ $usage .= " $key "
1520+ . ($opts{$key}->{copy} ? 'yes ' : 'no ')
1521+ . ($opts{$key}->{desc} || '[No description]')
1522+ . "\n";
1523+ }
1524+ if ( (my $key = $self->prop('autokey')) ) {
1525+ $usage .= " If the DSN is a bareword, the word is treated as the '$key' key.\n";
1526+ }
1527+ return $usage;
1528+}
1529+
1530+# Supports PostgreSQL via the dbidriver element of $info, but assumes MySQL by
1531+# default.
1532+sub get_cxn_params {
1533+ my ( $self, $info ) = @_;
1534+ my $dsn;
1535+ my %opts = %{$self->{opts}};
1536+ my $driver = $self->prop('dbidriver') || '';
1537+ if ( $driver eq 'Pg' ) {
1538+ $dsn = 'DBI:Pg:dbname=' . ( $info->{D} || '' ) . ';'
1539+ . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" }
1540+ grep { defined $info->{$_} }
1541+ qw(h P));
1542+ }
1543+ else {
1544+ $dsn = 'DBI:mysql:' . ( $info->{D} || '' ) . ';'
1545+ . join(';', map { "$opts{$_}->{dsn}=$info->{$_}" }
1546+ grep { defined $info->{$_} }
1547+ qw(F h P S A))
1548+ . ';mysql_read_default_group=client';
1549+ }
1550+ MKDEBUG && _d($dsn);
1551+ return ($dsn, $info->{u}, $info->{p});
1552+}
1553+
1554+
1555+# Fills in missing info from a DSN after successfully connecting to the server.
1556+sub fill_in_dsn {
1557+ my ( $self, $dbh, $dsn ) = @_;
1558+ my $vars = $dbh->selectall_hashref('SHOW VARIABLES', 'Variable_name');
1559+ my ($user, $db) = $dbh->selectrow_array('SELECT USER(), DATABASE()');
1560+ $user =~ s/@.*//;
1561+ $dsn->{h} ||= $vars->{hostname}->{Value};
1562+ $dsn->{S} ||= $vars->{'socket'}->{Value};
1563+ $dsn->{P} ||= $vars->{port}->{Value};
1564+ $dsn->{u} ||= $user;
1565+ $dsn->{D} ||= $db;
1566+}
1567+
1568+sub get_dbh {
1569+ my ( $self, $cxn_string, $user, $pass, $opts ) = @_;
1570+ $opts ||= {};
1571+ my $defaults = {
1572+ AutoCommit => 0,
1573+ RaiseError => 1,
1574+ PrintError => 0,
1575+ mysql_enable_utf8 => ($cxn_string =~ m/charset=utf8/ ? 1 : 0),
1576+ };
1577+ @{$defaults}{ keys %$opts } = values %$opts;
1578+ my $dbh;
1579+ my $tries = 2;
1580+ while ( !$dbh && $tries-- ) {
1581+ eval {
1582+ MKDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, ' {',
1583+ join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ), '}');
1584+ $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
1585+ # Immediately set character set and binmode on STDOUT.
1586+ if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
1587+ my $sql = "/*!40101 SET NAMES $charset*/";
1588+ MKDEBUG && _d("$dbh: $sql");
1589+ $dbh->do($sql);
1590+ MKDEBUG && _d('Enabling charset for STDOUT');
1591+ if ( $charset eq 'utf8' ) {
1592+ binmode(STDOUT, ':utf8')
1593+ or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
1594+ }
1595+ else {
1596+ binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
1597+ }
1598+ }
1599+ };
1600+ if ( !$dbh && $EVAL_ERROR ) {
1601+ MKDEBUG && _d($EVAL_ERROR);
1602+ if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
1603+ MKDEBUG && _d("Going to try again without utf8 support");
1604+ delete $defaults->{mysql_enable_utf8};
1605+ }
1606+ if ( !$tries ) {
1607+ die $EVAL_ERROR;
1608+ }
1609+ }
1610+ }
1611+ # If setvars exists and it's MySQL connection, set them
1612+ my $setvars = $self->prop('setvars');
1613+ if ( $cxn_string =~ m/mysql/i && $setvars ) {
1614+ my $sql = "SET $setvars";
1615+ MKDEBUG && _d("$dbh: $sql");
1616+ eval {
1617+ $dbh->do($sql);
1618+ };
1619+ if ( $EVAL_ERROR ) {
1620+ MKDEBUG && _d($EVAL_ERROR);
1621+ }
1622+ }
1623+ MKDEBUG && _d('DBH info: ',
1624+ $dbh,
1625+ Dumper($dbh->selectrow_hashref(
1626+ 'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
1627+ ' Connection info: ', ($dbh->{mysql_hostinfo} || 'undef'),
1628+ ' Character set info: ',
1629+ Dumper($dbh->selectall_arrayref(
1630+ 'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
1631+ ' $DBD::mysql::VERSION: ', $DBD::mysql::VERSION,
1632+ ' $DBI::VERSION: ', $DBI::VERSION,
1633+ );
1634+ return $dbh;
1635+}
1636+
1637+# Tries to figure out a hostname for the connection.
1638+sub get_hostname {
1639+ my ( $self, $dbh ) = @_;
1640+ if ( my ($host) = ($dbh->{mysql_hostinfo} || '') =~ m/^(\w+) via/ ) {
1641+ return $host;
1642+ }
1643+ my ( $hostname, $one ) = $dbh->selectrow_array(
1644+ 'SELECT /*!50038 @@hostname, */ 1');
1645+ return $hostname;
1646+}
1647+
1648+# Disconnects a database handle, but complains verbosely if there are any active
1649+# children. These are usually $sth handles that haven't been finish()ed.
1650+sub disconnect {
1651+ my ( $self, $dbh ) = @_;
1652+ MKDEBUG && $self->print_active_handles($dbh);
1653+ $dbh->disconnect;
1654+}
1655+
1656+sub print_active_handles {
1657+ my ( $self, $thing, $level ) = @_;
1658+ $level ||= 0;
1659+ printf("# Active %sh: %s %s %s\n", ($thing->{Type} || 'undef'), "\t" x $level,
1660+ $thing, (($thing->{Type} || '') eq 'st' ? $thing->{Statement} || '' : ''))
1661+ or die "Cannot print: $OS_ERROR";
1662+ foreach my $handle ( grep {defined} @{ $thing->{ChildHandles} } ) {
1663+ $self->print_active_handles( $handle, $level + 1 );
1664+ }
1665+}
1666+
1667+sub _d {
1668+ my ($package, undef, $line) = caller 0;
1669+ @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
1670+ map { defined $_ ? $_ : 'undef' }
1671+ @_;
1672+ # Use $$ instead of $PID in case the package
1673+ # does not use English.
1674+ print "# $package:$line $$ ", @_, "\n";
1675+}
1676+
1677+1;
1678+
1679+package InnoDBParser;
1680+
1681+use Data::Dumper;
1682+$Data::Dumper::Sortkeys = 1;
1683+use English qw(-no_match_vars);
1684+use List::Util qw(max);
1685+
1686+# Some common patterns
1687+my $d = qr/(\d+)/; # Digit
1688+my $f = qr/(\d+\.\d+)/; # Float
1689+my $t = qr/(\d+ \d+)/; # Transaction ID
1690+my $i = qr/((?:\d{1,3}\.){3}\d+)/; # IP address
1691+my $n = qr/([^`\s]+)/; # MySQL object name
1692+my $w = qr/(\w+)/; # Words
1693+my $fl = qr/([\w\.\/]+) line $d/; # Filename and line number
1694+my $h = qr/((?:0x)?[0-9a-f]*)/; # Hex
1695+my $s = qr/(\d{6} .\d:\d\d:\d\d)/; # InnoDB timestamp
1696+
1697+# If you update this variable, also update the SYNOPSIS in the pod.
1698+my %innodb_section_headers = (
1699+ "TRANSACTIONS" => "tx",
1700+ "BUFFER POOL AND MEMORY" => "bp",
1701+ "SEMAPHORES" => "sm",
1702+ "LOG" => "lg",
1703+ "ROW OPERATIONS" => "ro",
1704+ "INSERT BUFFER AND ADAPTIVE HASH INDEX" => "ib",
1705+ "FILE I/O" => "io",
1706+ "LATEST DETECTED DEADLOCK" => "dl",
1707+ "LATEST FOREIGN KEY ERROR" => "fk",
1708+);
1709+
1710+my %parser_for = (
1711+ tx => \&parse_tx_section,
1712+ bp => \&parse_bp_section,
1713+ sm => \&parse_sm_section,
1714+ lg => \&parse_lg_section,
1715+ ro => \&parse_ro_section,
1716+ ib => \&parse_ib_section,
1717+ io => \&parse_io_section,
1718+ dl => \&parse_dl_section,
1719+ fk => \&parse_fk_section,
1720+);
1721+
1722+my %fk_parser_for = (
1723+ Transaction => \&parse_fk_transaction_error,
1724+ Error => \&parse_fk_bad_constraint_error,
1725+ Cannot => \&parse_fk_cant_drop_parent_error,
1726+);
1727+
1728+# A thread's proc_info can be at least 98 different things I've found in the
1729+# source. Fortunately, most of them begin with a gerunded verb. These are
1730+# the ones that don't.
1731+my %is_proc_info = (
1732+ 'After create' => 1,
1733+ 'Execution of init_command' => 1,
1734+ 'FULLTEXT initialization' => 1,
1735+ 'Reopen tables' => 1,
1736+ 'Repair done' => 1,
1737+ 'Repair with keycache' => 1,
1738+ 'System lock' => 1,
1739+ 'Table lock' => 1,
1740+ 'Thread initialized' => 1,
1741+ 'User lock' => 1,
1742+ 'copy to tmp table' => 1,
1743+ 'discard_or_import_tablespace' => 1,
1744+ 'end' => 1,
1745+ 'got handler lock' => 1,
1746+ 'got old table' => 1,
1747+ 'init' => 1,
1748+ 'key cache' => 1,
1749+ 'locks' => 1,
1750+ 'malloc' => 1,
1751+ 'query end' => 1,
1752+ 'rename result table' => 1,
1753+ 'rename' => 1,
1754+ 'setup' => 1,
1755+ 'statistics' => 1,
1756+ 'status' => 1,
1757+ 'table cache' => 1,
1758+ 'update' => 1,
1759+);
1760+
1761+sub new {
1762+ bless {}, shift;
1763+}
1764+
1765+# Parse the status and return it.
1766+# See srv_printf_innodb_monitor in innobase/srv/srv0srv.c
1767+# Pass in the text to parse, whether to be in debugging mode, which sections
1768+# to parse (hashref; if empty, parse all), and whether to parse full info from
1769+# locks and such (probably shouldn't unless you need to).
1770+sub parse_status_text {
1771+ my ( $self, $fulltext, $debug, $sections, $full ) = @_;
1772+
1773+ die "I can't parse undef" unless defined $fulltext;
1774+ $fulltext =~ s/[\r\n]+/\n/g;
1775+
1776+ $sections ||= {};
1777+ die '$sections must be a hashref' unless ref($sections) eq 'HASH';
1778+
1779+ my %innodb_data = (
1780+ got_all => 0, # Whether I was able to get the whole thing
1781+ ts => '', # Timestamp the server put on it
1782+ last_secs => 0, # Num seconds the averages are over
1783+ sections => {}, # Parsed values from each section
1784+ );
1785+
1786+ if ( $debug ) {
1787+ $innodb_data{'fulltext'} = $fulltext;
1788+ }
1789+
1790+ # Get the most basic info about the status: beginning and end, and whether
1791+ # I got the whole thing (if there has been a big deadlock and there are
1792+ # too many locks to print, the output might be truncated)
1793+ my ( $time_text ) = $fulltext =~ m/^$s INNODB MONITOR OUTPUT$/m;
1794+ $innodb_data{'ts'} = [ parse_innodb_timestamp( $time_text ) ];
1795+ $innodb_data{'timestring'} = ts_to_string($innodb_data{'ts'});
1796+ ( $innodb_data{'last_secs'} ) = $fulltext
1797+ =~ m/Per second averages calculated from the last $d seconds/;
1798+
1799+ ( my $got_all ) = $fulltext =~ m/END OF INNODB MONITOR OUTPUT/;
1800+ $innodb_data{'got_all'} = $got_all || 0;
1801+
1802+ # Split it into sections. Each section begins with
1803+ # -----
1804+ # LABEL
1805+ # -----
1806+ my %innodb_sections;
1807+ my @matches = $fulltext
1808+ =~ m#\n(---+)\n([A-Z /]+)\n\1\n(.*?)(?=\n(---+)\n[A-Z /]+\n\4\n|$)#gs;
1809+ while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) {
1810+ $innodb_sections{$name} = [ $text, $end ? 1 : 0 ];
1811+ }
1812+ # The Row Operations section is a special case, because instead of ending
1813+ # with the beginning of another section, it ends with the end of the file.
1814+ # So this section is complete if the entire file is complete.
1815+ $innodb_sections{'ROW OPERATIONS'}->[1] ||= $innodb_data{'got_all'};
1816+
1817+ # Just for sanity's sake, make sure I understand what to do with each
1818+ # section
1819+ eval {
1820+ foreach my $section ( keys %innodb_sections ) {
1821+ my $header = $innodb_section_headers{$section};
1822+ die "Unknown section $section in $fulltext\n"
1823+ unless $header;
1824+ $innodb_data{'sections'}->{ $header }
1825+ ->{'fulltext'} = $innodb_sections{$section}->[0];
1826+ $innodb_data{'sections'}->{ $header }
1827+ ->{'complete'} = $innodb_sections{$section}->[1];
1828+ }
1829+ };
1830+ if ( $EVAL_ERROR ) {
1831+ _debug( $debug, $EVAL_ERROR);
1832+ }
1833+
1834+ # ################################################################
1835+ # Parse the detailed data out of the sections.
1836+ # ################################################################
1837+ eval {
1838+ foreach my $section ( keys %parser_for ) {
1839+ if ( defined $innodb_data{'sections'}->{$section}
1840+ && (!%$sections || (defined($sections->{$section} && $sections->{$section})) )) {
1841+ $parser_for{$section}->(
1842+ $innodb_data{'sections'}->{$section},
1843+ $innodb_data{'sections'}->{$section}->{'complete'},
1844+ $debug,
1845+ $full )
1846+ or delete $innodb_data{'sections'}->{$section};
1847+ }
1848+ else {
1849+ delete $innodb_data{'sections'}->{$section};
1850+ }
1851+ }
1852+ };
1853+ if ( $EVAL_ERROR ) {
1854+ _debug( $debug, $EVAL_ERROR);
1855+ }
1856+
1857+ return \%innodb_data;
1858+}
1859+
1860+# Parses the status text and returns it flattened out as a single hash.
1861+sub get_status_hash {
1862+ my ( $self, $fulltext, $debug, $sections, $full ) = @_;
1863+
1864+ # Parse the status text...
1865+ my $innodb_status
1866+ = $self->parse_status_text($fulltext, $debug, $sections, $full );
1867+
1868+ # Flatten the hierarchical structure into a single list by grabbing desired
1869+ # sections from it.
1870+ return
1871+ (map { 'IB_' . $_ => $innodb_status->{$_} } qw(timestring last_secs got_all)),
1872+ (map { 'IB_bp_' . $_ => $innodb_status->{'sections'}->{'bp'}->{$_} }
1873+ qw( writes_pending buf_pool_hit_rate total_mem_alloc buf_pool_reads
1874+ awe_mem_alloc pages_modified writes_pending_lru page_creates_sec
1875+ reads_pending pages_total buf_pool_hits writes_pending_single_page
1876+ page_writes_sec pages_read pages_written page_reads_sec
1877+ writes_pending_flush_list buf_pool_size add_pool_alloc
1878+ dict_mem_alloc pages_created buf_free complete )),
1879+ (map { 'IB_tx_' . $_ => $innodb_status->{'sections'}->{'tx'}->{$_} }
1880+ qw( num_lock_structs history_list_len purge_done_for transactions
1881+ purge_undo_for is_truncated trx_id_counter complete )),
1882+ (map { 'IB_ib_' . $_ => $innodb_status->{'sections'}->{'ib'}->{$_} }
1883+ qw( hash_table_size hash_searches_s non_hash_searches_s
1884+ bufs_in_node_heap used_cells size free_list_len seg_size inserts
1885+ merged_recs merges complete )),
1886+ (map { 'IB_lg_' . $_ => $innodb_status->{'sections'}->{'lg'}->{$_} }
1887+ qw( log_ios_done pending_chkp_writes last_chkp log_ios_s
1888+ log_flushed_to log_seq_no pending_log_writes complete )),
1889+ (map { 'IB_sm_' . $_ => $innodb_status->{'sections'}->{'sm'}->{$_} }
1890+ qw( wait_array_size rw_shared_spins rw_excl_os_waits mutex_os_waits
1891+ mutex_spin_rounds mutex_spin_waits rw_excl_spins rw_shared_os_waits
1892+ waits signal_count reservation_count complete )),
1893+ (map { 'IB_ro_' . $_ => $innodb_status->{'sections'}->{'ro'}->{$_} }
1894+ qw( queries_in_queue n_reserved_extents main_thread_state
1895+ main_thread_proc_no main_thread_id read_sec del_sec upd_sec ins_sec
1896+ read_views_open num_rows_upd num_rows_ins num_rows_read
1897+ queries_inside num_rows_del complete )),
1898+ (map { 'IB_fk_' . $_ => $innodb_status->{'sections'}->{'fk'}->{$_} }
1899+ qw( trigger parent_table child_index parent_index attempted_op
1900+ child_db timestring fk_name records col_name reason txn parent_db
1901+ type child_table parent_col complete )),
1902+ (map { 'IB_io_' . $_ => $innodb_status->{'sections'}->{'io'}->{$_} }
1903+ qw( pending_buffer_pool_flushes pending_pwrites pending_preads
1904+ pending_normal_aio_reads fsyncs_s os_file_writes pending_sync_ios
1905+ reads_s flush_type avg_bytes_s pending_ibuf_aio_reads writes_s
1906+ threads os_file_reads pending_aio_writes pending_log_ios os_fsyncs
1907+ pending_log_flushes complete )),
1908+ (map { 'IB_dl_' . $_ => $innodb_status->{'sections'}->{'dl'}->{$_} }
1909+ qw( timestring rolled_back txns complete ));
1910+
1911+}
1912+
1913+sub ts_to_string {
1914+ my $parts = shift;
1915+ return sprintf('%02d-%02d-%02d %02d:%02d:%02d', @$parts);
1916+}
1917+
1918+sub parse_innodb_timestamp {
1919+ my $text = shift;
1920+ my ( $y, $m, $d, $h, $i, $s )
1921+ = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
1922+ die("Can't get timestamp from $text\n") unless $y;
1923+ $y += 2000;
1924+ return ( $y, $m, $d, $h, $i, $s );
1925+}
1926+
1927+sub parse_fk_section {
1928+ my ( $section, $complete, $debug, $full ) = @_;
1929+ my $fulltext = $section->{'fulltext'};
1930+
1931+ return 0 unless $fulltext;
1932+
1933+ my ( $ts, $type ) = $fulltext =~ m/^$s\s+(\w+)/m;
1934+ $section->{'ts'} = [ parse_innodb_timestamp( $ts ) ];
1935+ $section->{'timestring'} = ts_to_string($section->{'ts'});
1936+ $section->{'type'} = $type;
1937+
1938+ # Decide which type of FK error happened, and dispatch to the right parser.
1939+ if ( $type && $fk_parser_for{$type} ) {
1940+ $fk_parser_for{$type}->( $section, $complete, $debug, $fulltext, $full );
1941+ }
1942+
1943+ delete $section->{'fulltext'} unless $debug;
1944+
1945+ return 1;
1946+}
1947+
1948+sub parse_fk_cant_drop_parent_error {
1949+ my ( $section, $complete, $debug, $fulltext, $full ) = @_;
1950+
1951+ # Parse the parent/child table info out
1952+ @{$section}{ qw(attempted_op parent_db parent_table) } = $fulltext
1953+ =~ m{Cannot $w table `(.*)/(.*)`}m;
1954+ @{$section}{ qw(child_db child_table) } = $fulltext
1955+ =~ m{because it is referenced by `(.*)/(.*)`}m;
1956+
1957+ ( $section->{'reason'} ) = $fulltext =~ m/(Cannot .*)/s;
1958+ $section->{'reason'} =~ s/\n(?:InnoDB: )?/ /gm
1959+ if $section->{'reason'};
1960+
1961+ # Certain data may not be present. Make them '' if not present.
1962+ map { $section->{$_} ||= "" }
1963+ qw(child_index fk_name col_name parent_col);
1964+}
1965+
1966+# See dict/dict0dict.c, function dict_foreign_error_report
1967+# I don't care much about these. There are lots of different messages, and
1968+# they come from someone trying to create a foreign key, or similar
1969+# statements. They aren't indicative of some transaction trying to insert,
1970+# delete or update data. Sometimes it is possible to parse out a lot of
1971+# information about the tables and indexes involved, but often the message
1972+# contains the DDL string the user entered, which is way too much for this
1973+# module to try to handle.
1974+sub parse_fk_bad_constraint_error {
1975+ my ( $section, $complete, $debug, $fulltext, $full ) = @_;
1976+
1977+ # Parse the parent/child table and index info out
1978+ @{$section}{ qw(child_db child_table) } = $fulltext
1979+ =~ m{Error in foreign key constraint of table (.*)/(.*):$}m;
1980+ $section->{'attempted_op'} = 'DDL';
1981+
1982+ # FK name, parent info... if possible.
1983+ @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) }
1984+ = $fulltext
1985+ =~ m/CONSTRAINT `?$n`? FOREIGN KEY \(`?$n`?\) REFERENCES (?:`?$n`?\.)?`?$n`? \(`?$n`?\)/;
1986+
1987+ if ( !defined($section->{'fk_name'}) ) {
1988+ # Try to parse SQL a user might have typed in a CREATE statement or such
1989+ @{$section}{ qw(col_name parent_db parent_table parent_col) }
1990+ = $fulltext
1991+ =~ m/FOREIGN\s+KEY\s*\(`?$n`?\)\s+REFERENCES\s+(?:`?$n`?\.)?`?$n`?\s*\(`?$n`?\)/i;
1992+ }
1993+ $section->{'parent_db'} ||= $section->{'child_db'};
1994+
1995+ # Name of the child index (index in the same table where the FK is, see
1996+ # definition of dict_foreign_struct in include/dict0mem.h, where it is
1997+ # called foreign_index, as opposed to referenced_index which is in the
1998+ # parent table. This may not be possible to find.
1999+ @{$section}{ qw(child_index) } = $fulltext
2000+ =~ m/^The index in the foreign key in table is $n$/m;
2001+
2002+ @{$section}{ qw(reason) } = $fulltext =~ m/:\s*([^:]+)(?= Constraint:|$)/ms;
2003+ $section->{'reason'} =~ s/\s+/ /g
2004+ if $section->{'reason'};
2005+
2006+ # Certain data may not be present. Make them '' if not present.
2007+ map { $section->{$_} ||= "" }
2008+ qw(child_index fk_name col_name parent_table parent_col);
2009+}
2010+
2011+# see source file row/row0ins.c
2012+sub parse_fk_transaction_error {
2013+ my ( $section, $complete, $debug, $fulltext, $full ) = @_;
2014+
2015+ # Parse the txn info out
2016+ my ( $txn ) = $fulltext
2017+ =~ m/Transaction:\n(TRANSACTION.*)\nForeign key constraint fails/s;
2018+ if ( $txn ) {
2019+ $section->{'txn'} = parse_tx_text( $txn, $complete, $debug, $full );
2020+ }
2021+
2022+ # Parse the parent/child table and index info out. There are two types: an
2023+ # update or a delete of a parent record leaves a child orphaned
2024+ # (row_ins_foreign_report_err), and an insert or update of a child record has
2025+ # no matching parent record (row_ins_foreign_report_add_err).
2026+
2027+ @{$section}{ qw(reason child_db child_table) }
2028+ = $fulltext =~ m{^(Foreign key constraint fails for table `(.*)/(.*)`:)$}m;
2029+
2030+ @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) }
2031+ = $fulltext
2032+ =~ m/CONSTRAINT `$n` FOREIGN KEY \(`$n`\) REFERENCES (?:`$n`\.)?`$n` \(`$n`\)/;
2033+ $section->{'parent_db'} ||= $section->{'child_db'};
2034+
2035+ # Special case, which I don't know how to trigger, but see
2036+ # innobase/row/row0ins.c row_ins_check_foreign_constraint
2037+ if ( $fulltext =~ m/ibd file does not currently exist!/ ) {
2038+ my ( $attempted_op, $index, $records )
2039+ = $fulltext =~ m/^Trying to (add to index) `$n` tuple:\n(.*))?/sm;
2040+ $section->{'child_index'} = $index;
2041+ $section->{'attempted_op'} = $attempted_op || '';
2042+ if ( $records && $full ) {
2043+ ( $section->{'records'} )
2044+ = parse_innodb_record_dump( $records, $complete, $debug );
2045+ }
2046+ @{$section}{qw(parent_db parent_table)}
2047+ =~ m/^But the parent table `$n`\.`$n`$/m;
2048+ }
2049+ else {
2050+ my ( $attempted_op, $which, $index )
2051+ = $fulltext =~ m/^Trying to ([\w ]*) in (child|parent) table, in index `$n` tuple:$/m;
2052+ if ( $which ) {
2053+ $section->{$which . '_index'} = $index;
2054+ $section->{'attempted_op'} = $attempted_op || '';
2055+
2056+ # Parse out the related records in the other table.
2057+ my ( $search_index, $records );
2058+ if ( $which eq 'child' ) {
2059+ ( $search_index, $records ) = $fulltext
2060+ =~ m/^But in parent table [^,]*, in index `$n`,\nthe closest match we can find is record:\n(.*)/ms;
2061+ $section->{'parent_index'} = $search_index;
2062+ }
2063+ else {
2064+ ( $search_index, $records ) = $fulltext
2065+ =~ m/^But in child table [^,]*, in index `$n`, (?:the record is not available|there is a record:\n(.*))?/ms;
2066+ $section->{'child_index'} = $search_index;
2067+ }
2068+ if ( $records && $full ) {
2069+ $section->{'records'}
2070+ = parse_innodb_record_dump( $records, $complete, $debug );
2071+ }
2072+ else {
2073+ $section->{'records'} = '';
2074+ }
2075+ }
2076+ }
2077+
2078+ # Parse out the tuple trying to be updated, deleted or inserted.
2079+ my ( $trigger ) = $fulltext =~ m/^(DATA TUPLE: \d+ fields;\n.*)$/m;
2080+ if ( $trigger ) {
2081+ $section->{'trigger'} = parse_innodb_record_dump( $trigger, $complete, $debug );
2082+ }
2083+
2084+ # Certain data may not be present. Make them '' if not present.
2085+ map { $section->{$_} ||= "" }
2086+ qw(child_index fk_name col_name parent_table parent_col);
2087+}
2088+
2089+# There are new-style and old-style record formats. See rem/rem0rec.c
2090+# TODO: write some tests for this
2091+sub parse_innodb_record_dump {
2092+ my ( $dump, $complete, $debug ) = @_;
2093+ return undef unless $dump;
2094+
2095+ my $result = {};
2096+
2097+ if ( $dump =~ m/PHYSICAL RECORD/ ) {
2098+ my $style = $dump =~ m/compact format/ ? 'new' : 'old';
2099+ $result->{'style'} = $style;
2100+
2101+ # This is a new-style record.
2102+ if ( $style eq 'new' ) {
2103+ @{$result}{qw( heap_no type num_fields info_bits )}
2104+ = $dump
2105+ =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; compact format; info bits $d$/m;
2106+ }
2107+
2108+ # OK, it's old-style. Unfortunately there are variations here too.
2109+ elsif ( $dump =~ m/-byte offs / ) {
2110+ # Older-old style.
2111+ @{$result}{qw( heap_no type num_fields byte_offset info_bits )}
2112+ = $dump
2113+ =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offs [A-Z]+; info bits $d$/m;
2114+ if ( $dump !~ m/-byte offs TRUE/ ) {
2115+ $result->{'byte_offset'} = 0;
2116+ }
2117+ }
2118+ else {
2119+ # Newer-old style.
2120+ @{$result}{qw( heap_no type num_fields byte_offset info_bits )}
2121+ = $dump
2122+ =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offsets; info bits $d$/m;
2123+ }
2124+
2125+ }
2126+ else {
2127+ $result->{'style'} = 'tuple';
2128+ @{$result}{qw( type num_fields )}
2129+ = $dump =~ m/^(DATA TUPLE): $d fields;$/m;
2130+ }
2131+
2132+ # Fill in default values for things that couldn't be parsed.
2133+ map { $result->{$_} ||= 0 }
2134+ qw(heap_no num_fields byte_offset info_bits);
2135+ map { $result->{$_} ||= '' }
2136+ qw(style type );
2137+
2138+ my @fields = $dump =~ m/ (\d+:.*?;?);(?=$| \d+:)/gm;
2139+ $result->{'fields'} = [ map { parse_field($_, $complete, $debug ) } @fields ];
2140+
2141+ return $result;
2142+}
2143+
2144+# New/old-style applies here. See rem/rem0rec.c
2145+# $text should not include the leading space or the second trailing semicolon.
2146+sub parse_field {
2147+ my ( $text, $complete, $debug ) = @_;
2148+
2149+ # Sample fields:
2150+ # '4: SQL NULL, size 4 '
2151+ # '1: len 6; hex 000000005601; asc V ;'
2152+ # '6: SQL NULL'
2153+ # '5: len 30; hex 687474703a2f2f7777772e737765657477617465722e636f6d2f73746f72; asc http://www.sweetwater.com/stor;...(truncated)'
2154+ my ( $id, $nullsize, $len, $hex, $asc, $truncated );
2155+ ( $id, $nullsize ) = $text =~ m/^$d: SQL NULL, size $d $/;
2156+ if ( !defined($id) ) {
2157+ ( $id ) = $text =~ m/^$d: SQL NULL$/;
2158+ }
2159+ if ( !defined($id) ) {
2160+ ( $id, $len, $hex, $asc, $truncated )
2161+ = $text =~ m/^$d: len $d; hex $h; asc (.*);(\.\.\.\(truncated\))?$/;
2162+ }
2163+
2164+ die "Could not parse this field: '$text'" unless defined $id;
2165+ return {
2166+ id => $id,
2167+ len => defined($len) ? $len : defined($nullsize) ? $nullsize : 0,
2168+ 'hex' => defined($hex) ? $hex : '',
2169+ asc => defined($asc) ? $asc : '',
2170+ trunc => $truncated ? 1 : 0,
2171+ };
2172+
2173+}
2174+
2175+sub parse_dl_section {
2176+ my ( $dl, $complete, $debug, $full ) = @_;
2177+ return unless $dl;
2178+ my $fulltext = $dl->{'fulltext'};
2179+ return 0 unless $fulltext;
2180+
2181+ my ( $ts ) = $fulltext =~ m/^$s$/m;
2182+ return 0 unless $ts;
2183+
2184+ $dl->{'ts'} = [ parse_innodb_timestamp( $ts ) ];
2185+ $dl->{'timestring'} = ts_to_string($dl->{'ts'});
2186+ $dl->{'txns'} = {};
2187+
2188+ my @sections
2189+ = $fulltext
2190+ =~ m{
2191+ ^\*{3}\s([^\n]*) # *** (1) WAITING FOR THIS...
2192+ (.*?) # Followed by anything, non-greedy
2193+ (?=(?:^\*{3})|\z) # Followed by another three stars or EOF
2194+ }gmsx;
2195+
2196+
2197+ # Loop through each section. There are no assumptions about how many
2198+ # there are, who holds and wants what locks, and who gets rolled back.
2199+ while ( my ($header, $body) = splice(@sections, 0, 2) ) {
2200+ my ( $txn_id, $what ) = $header =~ m/^\($d\) (.*):$/;
2201+ next unless $txn_id;
2202+ $dl->{'txns'}->{$txn_id} ||= {};
2203+ my $txn = $dl->{'txns'}->{$txn_id};
2204+
2205+ if ( $what eq 'TRANSACTION' ) {
2206+ $txn->{'tx'} = parse_tx_text( $body, $complete, $debug, $full );
2207+ }
2208+ else {
2209+ push @{$txn->{'locks'}}, parse_innodb_record_locks( $body, $complete, $debug, $full );
2210+ }
2211+ }
2212+
2213+ @{ $dl }{ qw(rolled_back) }
2214+ = $fulltext =~ m/^\*\*\* WE ROLL BACK TRANSACTION \($d\)$/m;
2215+
2216+ # Make sure certain values aren't undef
2217+ map { $dl->{$_} ||= '' } qw(rolled_back);
2218+
2219+ delete $dl->{'fulltext'} unless $debug;
2220+ return 1;
2221+}
2222+
2223+sub parse_innodb_record_locks {
2224+ my ( $text, $complete, $debug, $full ) = @_;
2225+ my @result;
2226+
2227+ foreach my $lock ( $text =~ m/(^(?:RECORD|TABLE) LOCKS?.*$)/gm ) {
2228+ my $hash = {};
2229+ @{$hash}{ qw(lock_type space_id page_no n_bits index db table txn_id lock_mode) }
2230+ = $lock
2231+ =~ 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;
2232+ ( $hash->{'special'} )
2233+ = $lock =~ m/^(?:RECORD|TABLE) .*? locks (rec but not gap|gap before rec)/m;
2234+ $hash->{'insert_intention'}
2235+ = $lock =~ m/^(?:RECORD|TABLE) .*? insert intention/m ? 1 : 0;
2236+ $hash->{'waiting'}
2237+ = $lock =~ m/^(?:RECORD|TABLE) .*? waiting/m ? 1 : 0;
2238+
2239+ # Some things may not be in the text, so make sure they are not
2240+ # undef.
2241+ map { $hash->{$_} ||= 0 } qw(n_bits page_no space_id);
2242+ map { $hash->{$_} ||= "" } qw(index special);
2243+ push @result, $hash;
2244+ }
2245+
2246+ return @result;
2247+}
2248+
2249+sub parse_tx_text {
2250+ my ( $txn, $complete, $debug, $full ) = @_;
2251+
2252+ my ( $txn_id, $txn_status, $active_secs, $proc_no, $os_thread_id )
2253+ = $txn
2254+ =~ m/^(?:---)?TRANSACTION $t, (\D*?)(?: $d sec)?, (?:process no $d, )?OS thread id $d/m;
2255+ my ( $thread_status, $thread_decl_inside )
2256+ = $txn
2257+ =~ m/OS thread id \d+(?: ([^,]+?))?(?:, thread declared inside InnoDB $d)?$/m;
2258+
2259+ # Parsing the line that begins 'MySQL thread id' is complicated. The only
2260+ # thing always in the line is the thread and query id. See function
2261+ # innobase_mysql_print_thd in InnoDB source file sql/ha_innodb.cc.
2262+ my ( $thread_line ) = $txn =~ m/^(MySQL thread id .*)$/m;
2263+ my ( $mysql_thread_id, $query_id, $hostname, $ip, $user, $query_status );
2264+
2265+ if ( $thread_line ) {
2266+ # These parts can always be gotten.
2267+ ( $mysql_thread_id, $query_id ) = $thread_line =~ m/^MySQL thread id $d, query id $d/m;
2268+
2269+ # If it's a master/slave thread, "Has (read|sent) all" may be the thread's
2270+ # proc_info. In these cases, there won't be any host/ip/user info
2271+ ( $query_status ) = $thread_line =~ m/(Has (?:read|sent) all .*$)/m;
2272+ if ( defined($query_status) ) {
2273+ $user = 'system user';
2274+ }
2275+
2276+ # It may be the case that the query id is the last thing in the line.
2277+ elsif ( $thread_line =~ m/query id \d+ / ) {
2278+ # The IP address is the only non-word thing left, so it's the most
2279+ # useful marker for where I have to start guessing.
2280+ ( $hostname, $ip ) = $thread_line =~ m/query id \d+(?: ([A-Za-z]\S+))? $i/m;
2281+ if ( defined $ip ) {
2282+ ( $user, $query_status ) = $thread_line =~ m/$ip $w(?: (.*))?$/;
2283+ }
2284+ else { # OK, there wasn't an IP address.
2285+ # There might not be ANYTHING except the query status.
2286+ ( $query_status ) = $thread_line =~ m/query id \d+ (.*)$/;
2287+ if ( $query_status !~ m/^\w+ing/ && !exists($is_proc_info{$query_status}) ) {
2288+ # The remaining tokens are, in order: hostname, user, query_status.
2289+ # It's basically impossible to know which is which.
2290+ ( $hostname, $user, $query_status ) = $thread_line
2291+ =~ m/query id \d+(?: ([A-Za-z]\S+))?(?: $w(?: (.*))?)?$/m;
2292+ }
2293+ else {
2294+ $user = 'system user';
2295+ }
2296+ }
2297+ }
2298+ }
2299+
2300+ my ( $lock_wait_status, $lock_structs, $heap_size, $row_locks, $undo_log_entries )
2301+ = $txn
2302+ =~ m/^(?:(\D*) )?$d lock struct\(s\), heap size $d(?:, $d row lock\(s\))?(?:, undo log entries $d)?$/m;
2303+ my ( $lock_wait_time )
2304+ = $txn
2305+ =~ m/^------- TRX HAS BEEN WAITING $d SEC/m;
2306+
2307+ my $locks;
2308+ # If the transaction has locks, grab the locks.
2309+ if ( $txn =~ m/^TABLE LOCK|RECORD LOCKS/ ) {
2310+ $locks = [parse_innodb_record_locks($txn, $complete, $debug, $full)];
2311+ }
2312+
2313+ my ( $tables_in_use, $tables_locked )
2314+ = $txn
2315+ =~ m/^mysql tables in use $d, locked $d$/m;
2316+ my ( $txn_doesnt_see_ge, $txn_sees_lt )
2317+ = $txn
2318+ =~ m/^Trx read view will not see trx with id >= $t, sees < $t$/m;
2319+ my $has_read_view = defined($txn_doesnt_see_ge);
2320+ # Only a certain number of bytes of the query text are included here, at least
2321+ # under some circumstances. Some versions include 300, some 600.
2322+ my ( $query_text )
2323+ = $txn
2324+ =~ m{
2325+ ^MySQL\sthread\sid\s[^\n]+\n # This comes before the query text
2326+ (.*?) # The query text
2327+ (?= # Followed by any of...
2328+ ^Trx\sread\sview
2329+ |^-------\sTRX\sHAS\sBEEN\sWAITING
2330+ |^TABLE\sLOCK
2331+ |^RECORD\sLOCKS\sspace\sid
2332+ |^(?:---)?TRANSACTION
2333+ |^\*\*\*\s\(\d\)
2334+ |\Z
2335+ )
2336+ }xms;
2337+ if ( $query_text ) {
2338+ $query_text =~ s/\s+$//;
2339+ }
2340+ else {
2341+ $query_text = '';
2342+ }
2343+
2344+ my %stuff = (
2345+ active_secs => $active_secs,
2346+ has_read_view => $has_read_view,
2347+ heap_size => $heap_size,
2348+ hostname => $hostname,
2349+ ip => $ip,
2350+ lock_structs => $lock_structs,
2351+ lock_wait_status => $lock_wait_status,
2352+ lock_wait_time => $lock_wait_time,
2353+ mysql_thread_id => $mysql_thread_id,
2354+ os_thread_id => $os_thread_id,
2355+ proc_no => $proc_no,
2356+ query_id => $query_id,
2357+ query_status => $query_status,
2358+ query_text => $query_text,
2359+ row_locks => $row_locks,
2360+ tables_in_use => $tables_in_use,
2361+ tables_locked => $tables_locked,
2362+ thread_decl_inside => $thread_decl_inside,
2363+ thread_status => $thread_status,
2364+ txn_doesnt_see_ge => $txn_doesnt_see_ge,
2365+ txn_id => $txn_id,
2366+ txn_sees_lt => $txn_sees_lt,
2367+ txn_status => $txn_status,
2368+ undo_log_entries => $undo_log_entries,
2369+ user => $user,
2370+ );
2371+ $stuff{'fulltext'} = $txn if $debug;
2372+ $stuff{'locks'} = $locks if $locks;
2373+
2374+ # Some things may not be in the txn text, so make sure they are not
2375+ # undef.
2376+ map { $stuff{$_} ||= 0 } qw(active_secs heap_size lock_structs
2377+ tables_in_use undo_log_entries tables_locked has_read_view
2378+ thread_decl_inside lock_wait_time proc_no row_locks);
2379+ map { $stuff{$_} ||= "" } qw(thread_status txn_doesnt_see_ge
2380+ txn_sees_lt query_status ip query_text lock_wait_status user);
2381+ $stuff{'hostname'} ||= $stuff{'ip'};
2382+
2383+ return \%stuff;
2384+}
2385+
2386+sub parse_tx_section {
2387+ my ( $section, $complete, $debug, $full ) = @_;
2388+ return unless $section && $section->{'fulltext'};
2389+ my $fulltext = $section->{'fulltext'};
2390+ $section->{'transactions'} = [];
2391+
2392+ # Handle the individual transactions
2393+ my @transactions = $fulltext =~ m/(---TRANSACTION \d.*?)(?=\n---TRANSACTION|$)/gs;
2394+ foreach my $txn ( @transactions ) {
2395+ my $stuff = parse_tx_text( $txn, $complete, $debug, $full );
2396+ delete $stuff->{'fulltext'} unless $debug;
2397+ push @{$section->{'transactions'}}, $stuff;
2398+ }
2399+
2400+ # Handle the general info
2401+ @{$section}{ 'trx_id_counter' }
2402+ = $fulltext =~ m/^Trx id counter $t$/m;
2403+ @{$section}{ 'purge_done_for', 'purge_undo_for' }
2404+ = $fulltext =~ m/^Purge done for trx's n:o < $t undo n:o < $t$/m;
2405+ @{$section}{ 'history_list_len' } # This isn't present in some 4.x versions
2406+ = $fulltext =~ m/^History list length $d$/m;
2407+ @{$section}{ 'num_lock_structs' }
2408+ = $fulltext =~ m/^Total number of lock structs in row lock hash table $d$/m;
2409+ @{$section}{ 'is_truncated' }
2410+ = $fulltext =~ m/^\.\.\. truncated\.\.\.$/m ? 1 : 0;
2411+
2412+ # Fill in things that might not be present
2413+ foreach ( qw(history_list_len) ) {
2414+ $section->{$_} ||= 0;
2415+ }
2416+
2417+ delete $section->{'fulltext'} unless $debug;
2418+ return 1;
2419+}
2420+
2421+# I've read the source for this section.
2422+sub parse_ro_section {
2423+ my ( $section, $complete, $debug, $full ) = @_;
2424+ return unless $section && $section->{'fulltext'};
2425+ my $fulltext = $section->{'fulltext'};
2426+
2427+ # Grab the info
2428+ @{$section}{ 'queries_inside', 'queries_in_queue' }
2429+ = $fulltext =~ m/^$d queries inside InnoDB, $d queries in queue$/m;
2430+ ( $section->{ 'read_views_open' } )
2431+ = $fulltext =~ m/^$d read views open inside InnoDB$/m;
2432+ ( $section->{ 'n_reserved_extents' } )
2433+ = $fulltext =~ m/^$d tablespace extents now reserved for B-tree/m;
2434+ @{$section}{ 'main_thread_proc_no', 'main_thread_id', 'main_thread_state' }
2435+ = $fulltext =~ m/^Main thread (?:process no. $d, )?id $d, state: (.*)$/m;
2436+ @{$section}{ 'num_rows_ins', 'num_rows_upd', 'num_rows_del', 'num_rows_read' }
2437+ = $fulltext =~ m/^Number of rows inserted $d, updated $d, deleted $d, read $d$/m;
2438+ @{$section}{ 'ins_sec', 'upd_sec', 'del_sec', 'read_sec' }
2439+ = $fulltext =~ m#^$f inserts/s, $f updates/s, $f deletes/s, $f reads/s$#m;
2440+ $section->{'main_thread_proc_no'} ||= 0;
2441+
2442+ map { $section->{$_} ||= 0 } qw(read_views_open n_reserved_extents);
2443+ delete $section->{'fulltext'} unless $debug;
2444+ return 1;
2445+}
2446+
2447+sub parse_lg_section {
2448+ my ( $section, $complete, $debug, $full ) = @_;
2449+ return unless $section;
2450+ my $fulltext = $section->{'fulltext'};
2451+
2452+ # Grab the info
2453+ ( $section->{ 'log_seq_no' } )
2454+ = $fulltext =~ m/Log sequence number \s*(\d.*)$/m;
2455+ ( $section->{ 'log_flushed_to' } )
2456+ = $fulltext =~ m/Log flushed up to \s*(\d.*)$/m;
2457+ ( $section->{ 'last_chkp' } )
2458+ = $fulltext =~ m/Last checkpoint at \s*(\d.*)$/m;
2459+ @{$section}{ 'pending_log_writes', 'pending_chkp_writes' }
2460+ = $fulltext =~ m/$d pending log writes, $d pending chkp writes/;
2461+ @{$section}{ 'log_ios_done', 'log_ios_s' }
2462+ = $fulltext =~ m#$d log i/o's done, $f log i/o's/second#;
2463+
2464+ delete $section->{'fulltext'} unless $debug;
2465+ return 1;
2466+}
2467+
2468+sub parse_ib_section {
2469+ my ( $section, $complete, $debug, $full ) = @_;
2470+ return unless $section && $section->{'fulltext'};
2471+ my $fulltext = $section->{'fulltext'};
2472+
2473+ # Some servers will output ibuf information for tablespace 0, as though there
2474+ # might be many tablespaces with insert buffers. (In practice I believe
2475+ # the source code shows there will only ever be one). I have to parse both
2476+ # cases here, but I assume there will only be one.
2477+ @{$section}{ 'size', 'free_list_len', 'seg_size' }
2478+ = $fulltext =~ m/^Ibuf(?: for space 0)?: size $d, free list len $d, seg size $d,$/m;
2479+ @{$section}{ 'inserts', 'merged_recs', 'merges' }
2480+ = $fulltext =~ m/^$d inserts, $d merged recs, $d merges$/m;
2481+
2482+ @{$section}{ 'hash_table_size', 'used_cells', 'bufs_in_node_heap' }
2483+ = $fulltext =~ m/^Hash table size $d, used cells $d, node heap has $d buffer\(s\)$/m;
2484+ @{$section}{ 'hash_searches_s', 'non_hash_searches_s' }
2485+ = $fulltext =~ m{^$f hash searches/s, $f non-hash searches/s$}m;
2486+
2487+ delete $section->{'fulltext'} unless $debug;
2488+ return 1;
2489+}
2490+
2491+sub parse_wait_array {
2492+ my ( $text, $complete, $debug, $full ) = @_;
2493+ my %result;
2494+
2495+ @result{ qw(thread waited_at_filename waited_at_line waited_secs) }
2496+ = $text =~ m/^--Thread $d has waited at $fl for $f seconds/m;
2497+
2498+ # Depending on whether it's a SYNC_MUTEX,RW_LOCK_EX,RW_LOCK_SHARED,
2499+ # there will be different text output
2500+ if ( $text =~ m/^Mutex at/m ) {
2501+ $result{'request_type'} = 'M';
2502+ @result{ qw( lock_mem_addr lock_cfile_name lock_cline lock_var) }
2503+ = $text =~ m/^Mutex at $h created file $fl, lock var $d$/m;
2504+ @result{ qw( waiters_flag )}
2505+ = $text =~ m/^waiters flag $d$/m;
2506+ }
2507+ else {
2508+ @result{ qw( request_type lock_mem_addr lock_cfile_name lock_cline) }
2509+ = $text =~ m/^(.)-lock on RW-latch at $h created in file $fl$/m;
2510+ @result{ qw( writer_thread writer_lock_mode ) }
2511+ = $text =~ m/^a writer \(thread id $d\) has reserved it in mode (.*)$/m;
2512+ @result{ qw( num_readers waiters_flag )}
2513+ = $text =~ m/^number of readers $d, waiters flag $d$/m;
2514+ @result{ qw(last_s_file_name last_s_line ) }
2515+ = $text =~ m/Last time read locked in file $fl$/m;
2516+ @result{ qw(last_x_file_name last_x_line ) }
2517+ = $text =~ m/Last time write locked in file $fl$/m;
2518+ }
2519+
2520+ $result{'cell_waiting'} = $text =~ m/^wait has ended$/m ? 0 : 1;
2521+ $result{'cell_event_set'} = $text =~ m/^wait is ending$/m ? 1 : 0;
2522+
2523+ # Because there are two code paths, some things won't get set.
2524+ map { $result{$_} ||= '' }
2525+ qw(last_s_file_name last_x_file_name writer_lock_mode);
2526+ map { $result{$_} ||= 0 }
2527+ qw(num_readers lock_var last_s_line last_x_line writer_thread);
2528+
2529+ return \%result;
2530+}
2531+
2532+sub parse_sm_section {
2533+ my ( $section, $complete, $debug, $full ) = @_;
2534+ return 0 unless $section && $section->{'fulltext'};
2535+ my $fulltext = $section->{'fulltext'};
2536+
2537+ # Grab the info
2538+ @{$section}{ 'reservation_count', 'signal_count' }
2539+ = $fulltext =~ m/^OS WAIT ARRAY INFO: reservation count $d, signal count $d$/m;
2540+ @{$section}{ 'mutex_spin_waits', 'mutex_spin_rounds', 'mutex_os_waits' }
2541+ = $fulltext =~ m/^Mutex spin waits $d, rounds $d, OS waits $d$/m;
2542+ @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits', 'rw_excl_spins', 'rw_excl_os_waits' }
2543+ = $fulltext =~ m/^RW-shared spins $d, OS waits $d; RW-excl spins $d, OS waits $d$/m;
2544+
2545+ # Look for info on waits.
2546+ my @waits = $fulltext =~ m/^(--Thread.*?)^(?=Mutex spin|--Thread)/gms;
2547+ $section->{'waits'} = [ map { parse_wait_array($_, $complete, $debug) } @waits ];
2548+ $section->{'wait_array_size'} = scalar(@waits);
2549+
2550+ delete $section->{'fulltext'} unless $debug;
2551+ return 1;
2552+}
2553+
2554+# I've read the source for this section.
2555+sub parse_bp_section {
2556+ my ( $section, $complete, $debug, $full ) = @_;
2557+ return unless $section && $section->{'fulltext'};
2558+ my $fulltext = $section->{'fulltext'};
2559+
2560+ # Grab the info
2561+ @{$section}{ 'total_mem_alloc', 'add_pool_alloc' }
2562+ = $fulltext =~ m/^Total memory allocated $d; in additional pool allocated $d$/m;
2563+ @{$section}{'dict_mem_alloc'} = $fulltext =~ m/Dictionary memory allocated $d/;
2564+ @{$section}{'awe_mem_alloc'} = $fulltext =~ m/$d MB of AWE memory/;
2565+ @{$section}{'buf_pool_size'} = $fulltext =~ m/^Buffer pool size\s*$d$/m;
2566+ @{$section}{'buf_free'} = $fulltext =~ m/^Free buffers\s*$d$/m;
2567+ @{$section}{'pages_total'} = $fulltext =~ m/^Database pages\s*$d$/m;
2568+ @{$section}{'pages_modified'} = $fulltext =~ m/^Modified db pages\s*$d$/m;
2569+ @{$section}{'pages_read', 'pages_created', 'pages_written'}
2570+ = $fulltext =~ m/^Pages read $d, created $d, written $d$/m;
2571+ @{$section}{'page_reads_sec', 'page_creates_sec', 'page_writes_sec'}
2572+ = $fulltext =~ m{^$f reads/s, $f creates/s, $f writes/s$}m;
2573+ @{$section}{'buf_pool_hits', 'buf_pool_reads'}
2574+ = $fulltext =~ m{Buffer pool hit rate $d / $d$}m;
2575+ if ($fulltext =~ m/^No buffer pool page gets since the last printout$/m) {
2576+ @{$section}{'buf_pool_hits', 'buf_pool_reads'} = (0, 0);
2577+ @{$section}{'buf_pool_hit_rate'} = '--';
2578+ }
2579+ else {
2580+ @{$section}{'buf_pool_hit_rate'}
2581+ = $fulltext =~ m{Buffer pool hit rate (\d+ / \d+)$}m;
2582+ }
2583+ @{$section}{'reads_pending'} = $fulltext =~ m/^Pending reads $d/m;
2584+ @{$section}{'writes_pending_lru', 'writes_pending_flush_list', 'writes_pending_single_page' }
2585+ = $fulltext =~ m/^Pending writes: LRU $d, flush list $d, single page $d$/m;
2586+
2587+ map { $section->{$_} ||= 0 }
2588+ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page
2589+ awe_mem_alloc dict_mem_alloc);
2590+ @{$section}{'writes_pending'} = List::Util::sum(
2591+ @{$section}{ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page) });
2592+
2593+ delete $section->{'fulltext'} unless $debug;
2594+ return 1;
2595+}
2596+
2597+# I've read the source for this.
2598+sub parse_io_section {
2599+ my ( $section, $complete, $debug, $full ) = @_;
2600+ return unless $section && $section->{'fulltext'};
2601+ my $fulltext = $section->{'fulltext'};
2602+ $section->{'threads'} = {};
2603+
2604+ # Grab the I/O thread info
2605+ my @threads = $fulltext =~ m<^(I/O thread \d+ .*)$>gm;
2606+ foreach my $thread (@threads) {
2607+ my ( $tid, $state, $purpose, $event_set )
2608+ = $thread =~ m{I/O thread $d state: (.+?) \((.*)\)(?: ev set)?$}m;
2609+ if ( defined $tid ) {
2610+ $section->{'threads'}->{$tid} = {
2611+ thread => $tid,
2612+ state => $state,
2613+ purpose => $purpose,
2614+ event_set => $event_set ? 1 : 0,
2615+ };
2616+ }
2617+ }
2618+
2619+ # Grab the reads/writes/flushes info
2620+ @{$section}{ 'pending_normal_aio_reads', 'pending_aio_writes' }
2621+ = $fulltext =~ m/^Pending normal aio reads: $d, aio writes: $d,$/m;
2622+ @{$section}{ 'pending_ibuf_aio_reads', 'pending_log_ios', 'pending_sync_ios' }
2623+ = $fulltext =~ m{^ ibuf aio reads: $d, log i/o's: $d, sync i/o's: $d$}m;
2624+ @{$section}{ 'flush_type', 'pending_log_flushes', 'pending_buffer_pool_flushes' }
2625+ = $fulltext =~ m/^Pending flushes \($w\) log: $d; buffer pool: $d$/m;
2626+ @{$section}{ 'os_file_reads', 'os_file_writes', 'os_fsyncs' }
2627+ = $fulltext =~ m/^$d OS file reads, $d OS file writes, $d OS fsyncs$/m;
2628+ @{$section}{ 'reads_s', 'avg_bytes_s', 'writes_s', 'fsyncs_s' }
2629+ = $fulltext =~ m{^$f reads/s, $d avg bytes/read, $f writes/s, $f fsyncs/s$}m;
2630+ @{$section}{ 'pending_preads', 'pending_pwrites' }
2631+ = $fulltext =~ m/$d pending preads, $d pending pwrites$/m;
2632+ @{$section}{ 'pending_preads', 'pending_pwrites' } = (0, 0)
2633+ unless defined($section->{'pending_preads'});
2634+
2635+ delete $section->{'fulltext'} unless $debug;
2636+ return 1;
2637+}
2638+
2639+sub _debug {
2640+ my ( $debug, $msg ) = @_;
2641+ if ( $debug ) {
2642+ die $msg;
2643+ }
2644+ else {
2645+ warn $msg;
2646+ }
2647+ return 1;
2648+}
2649+
2650+1;
2651+
2652+# end_of_package InnoDBParser
2653+
2654+package main;
2655+
2656 use sigtrap qw(handler finish untrapped normal-signals);
2657
2658 use Data::Dumper;
2659 use DBI;
2660 use English qw(-no_match_vars);
2661 use File::Basename qw(dirname);
2662+use File::Temp;
2663 use Getopt::Long;
2664 use List::Util qw(max min maxstr sum);
2665-use InnoDBParser;
2666 use POSIX qw(ceil);
2667 use Time::HiRes qw(time sleep);
2668 use Term::ReadKey qw(ReadMode ReadKey);
2669
2670-# Version, license and warranty information. {{{1
2671+# License and warranty information. {{{1
2672 # ###########################################################################
2673-our $VERSION = '1.6.0';
2674-our $SVN_REV = sprintf("%d", q$Revision: 383 $ =~ m/(\d+)/g);
2675-our $SVN_URL = sprintf("%s", q$URL: https://innotop.svn.sourceforge.net/svnroot/innotop/trunk/innotop $ =~ m$svnroot/innotop/(\S+)$g);
2676
2677 my $innotop_license = <<"LICENSE";
2678
2679@@ -55,6 +1375,7 @@
2680 );
2681
2682 my $clear_screen_sub;
2683+my $dsn_parser = new DSNParser();
2684
2685 # This defines expected properties and defaults for the column definitions that
2686 # eventually end up in tbl_meta.
2687@@ -89,7 +1410,13 @@
2688 { s => 'delay|d=f', d => 'Delay between updates in seconds', c => 'interval' },
2689 { s => 'mode|m=s', d => 'Operating mode to start in', c => 'mode' },
2690 { s => 'inc|i!', d => 'Measure incremental differences', c => 'status_inc' },
2691+ { s => 'write|w', d => 'Write running configuration into home directory if no config files were loaded' },
2692+ { s => 'skipcentral|s', d => 'Skip reading the central configuration file' },
2693 { s => 'version', d => 'Output version information and exit' },
2694+ { s => 'user|u=s', d => 'User for login if not current user' },
2695+ { s => 'password|p=s', d => 'Password to use for connection' },
2696+ { s => 'host|h=s', d => 'Connect to host' },
2697+ { s => 'port|P=i', d => 'Port number to use for connection' },
2698 );
2699
2700 # This is the container for the command-line options' values to be stored in
2701@@ -113,10 +1440,14 @@
2702 GetOptions( map { $_->{s} => \$opts{$_->{k}} } @opt_spec) or $opts{help} = 1;
2703
2704 if ( $opts{version} ) {
2705- print "innotop Ver $VERSION Changeset $SVN_REV from $SVN_URL\n";
2706+ print "innotop Ver $VERSION\n";
2707 exit(0);
2708 }
2709
2710+if ( $opts{c} and ! -f $opts{c} ) {
2711+ print $opts{c} . " doesn't exist. Exiting.\n";
2712+ exit(1);
2713+}
2714 if ( $opts{'help'} ) {
2715 print "Usage: innotop <options> <innodb-status-file>\n\n";
2716 my $maxw = max(map { length($_->{l}) + ($_->{n} ? 4 : 0)} @opt_spec);
2717@@ -695,7 +2026,10 @@
2718 my @args = grep { defined $_ } @_;
2719 return (sum(map { m/([\d\.-]+)/g } @args) || 0) / (scalar(@args) || 1);
2720 },
2721- sum => \&sum,
2722+ sum => sub {
2723+ my @args = grep { defined $_ } @_;
2724+ return sum(@args);
2725+ }
2726 );
2727
2728 # ###########################################################################
2729@@ -1188,7 +2522,7 @@
2730 info => { src => 'info', minw => 0, maxw => 0, trans => [ qw(no_ctrl_char) ] },
2731 cnt => { src => 'id', minw => 0, maxw => 0 },
2732 },
2733- visible => [ qw(cxn cmd cnt mysql_thread_id user hostname db time info)],
2734+ visible => [ qw(cxn cmd cnt mysql_thread_id state user hostname db time info)],
2735 filters => [ qw(hide_self hide_inactive hide_slave_io) ],
2736 sort_cols => '-time cxn hostname mysql_thread_id',
2737 sort_dir => '1',
2738@@ -2440,9 +3774,6 @@
2739 my $clock = 0; # Incremented with every wake-sleep cycle
2740 my $clearing_deadlocks = 0;
2741
2742-# Find the home directory; it's different on different OSes.
2743-my $homepath = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.';
2744-
2745 # If terminal coloring is available, use it. The only function I want from
2746 # the module is the colored() function.
2747 eval {
2748@@ -2541,7 +3872,7 @@
2749 pat => $bool_regex,
2750 },
2751 readonly => {
2752- val => 0,
2753+ val => 1,
2754 note => 'Whether the config file is read-only',
2755 conf => [ qw() ],
2756 pat => $bool_regex,
2757@@ -2604,7 +3935,7 @@
2758 conf => 'ALL',
2759 },
2760 mode => {
2761- val => "T",
2762+ val => "Q",
2763 note => "Which mode to start in",
2764 cmdline => 1,
2765 },
2766@@ -2822,6 +4153,21 @@
2767 # Clear the screen and load the configuration.
2768 $clear_screen_sub->();
2769 load_config();
2770+
2771+# Override config variables with command-line options
2772+my %cmdline =
2773+ map { $_->{c} => $opts{$_->{k}} }
2774+ grep { exists $_->{c} && exists $opts{$_->{k}} }
2775+ @opt_spec;
2776+
2777+foreach my $name (keys %cmdline) {
2778+ next if not defined $cmdline{$name};
2779+ my $val = $cmdline{$name};
2780+ if ( exists($config{$name}) and (!$config{$name}->{pat} or $val =~ m/$config{$name}->{pat}/ )) {
2781+ $config{$name}->{val} = $val;
2782+ }
2783+}
2784+
2785 post_process_tbl_meta();
2786
2787 # Make sure no changes are written to config file in non-interactive mode.
2788@@ -2848,7 +4194,7 @@
2789
2790 while (++$clock) {
2791
2792- my $mode = $config{mode}->{val} || 'T';
2793+ my $mode = $config{mode}->{val} || 'Q';
2794 if ( !$modes{$mode} ) {
2795 die "Mode '$mode' doesn't exist; try one of these:\n"
2796 . join("\n", map { " $_ $modes{$_}->{hdr}" } sort keys %modes)
2797@@ -4435,6 +5781,16 @@
2798 my ( $rows, $tbl ) = @_;
2799 my $meta = $tbl_meta{$tbl} or die "No such table $tbl in tbl_meta";
2800
2801+ # don't show cxn if there's only one connection being displayed
2802+ my @visible;
2803+ if (scalar @{$modes{$config{mode}->{val}}->{connections}} == 1) {
2804+ map { push @visible, $_ if $_ !~ /^cxn$/ } @{$meta->{visible}};
2805+ delete $$rows[0]{cxn} if defined $$rows[0]{cxn};
2806+ }
2807+ else {
2808+ @visible = @{$meta->{visible}};
2809+ }
2810+
2811 if ( !$meta->{pivot} ) {
2812
2813 # Hook in event listeners
2814@@ -4587,7 +5943,7 @@
2815 # If the table isn't pivoted, just show all columns that are supposed to
2816 # be shown; but eliminate aggonly columns if the table isn't aggregated.
2817 my $aggregated = $meta->{aggregate};
2818- $fmt_cols = [ grep { $aggregated || !$meta->{cols}->{$_}->{aggonly} } @{$meta->{visible}} ];
2819+ $fmt_cols = [ grep { $aggregated || !$meta->{cols}->{$_}->{aggonly} } @visible ];
2820 $fmt_meta = { map { $_ => $meta->{cols}->{$_} } @$fmt_cols };
2821
2822 # If the table is aggregated, re-order the group_by columns to the left of
2823@@ -4988,7 +6344,7 @@
2824 $uptime,
2825 $ibinfo,
2826 shorten($qps) . " QPS",
2827- ($vars->{Threads} || 0) . " thd",
2828+ ($vars->{Threads} || 0) . "/" . ($vars->{Threads_running} || 0) . "/" . ($vars->{Threads_cached} || 0) . " con/run/cac thds",
2829 $cxn)));
2830 }
2831 else {
2832@@ -5003,7 +6359,7 @@
2833
2834 # Database connections {{{3
2835 sub add_new_dsn {
2836- my ( $name ) = @_;
2837+ my ( $name, $dsn, $dl_table, $have_user, $user, $have_pass, $pass, $savepass ) = @_;
2838
2839 if ( defined $name ) {
2840 $name =~ s/[\s:;]//g;
2841@@ -5018,23 +6374,30 @@
2842 } until ( $name );
2843 }
2844
2845- my $dsn;
2846- do {
2847+ if ( !$dsn ) {
2848+ do {
2849+ $clear_screen_sub->();
2850+ print "Typical DSN strings look like\n DBI:mysql:;host=hostname;port=port\n"
2851+ . "The db and port are optional and can usually be omitted.\n"
2852+ . "If you specify 'mysql_read_default_group=mysql' many options can be read\n"
2853+ . "from your mysql options files (~/.my.cnf, /etc/my.cnf).\n\n";
2854+ $dsn = prompt("Enter a DSN string", undef, "DBI:mysql:;mysql_read_default_group=mysql;host=$name");
2855+ } until ( $dsn );
2856+ }
2857+ if ( !$dl_table ) {
2858 $clear_screen_sub->();
2859- print "Typical DSN strings look like\n DBI:mysql:;host=hostname;port=port\n"
2860- . "The db and port are optional and can usually be omitted.\n"
2861- . "If you specify 'mysql_read_default_group=mysql' many options can be read\n"
2862- . "from your mysql options files (~/.my.cnf, /etc/my.cnf).\n\n";
2863- $dsn = prompt("Enter a DSN string", undef, "DBI:mysql:;mysql_read_default_group=mysql;host=$name");
2864- } until ( $dsn );
2865-
2866- $clear_screen_sub->();
2867- my $dl_table = prompt("Optional: enter a table (must not exist) to use when resetting InnoDB deadlock information",
2868- undef, 'test.innotop_dl');
2869+ my $dl_table = prompt("Optional: enter a table (must not exist) to use when resetting InnoDB deadlock information",
2870+ undef, 'test.innotop_dl');
2871+ }
2872
2873 $connections{$name} = {
2874- dsn => $dsn,
2875- dl_table => $dl_table,
2876+ dsn => $dsn,
2877+ dl_table => $dl_table,
2878+ have_user => $have_user,
2879+ user => $user,
2880+ have_pass => $have_pass,
2881+ pass => $pass,
2882+ savepass => $savepass
2883 };
2884 }
2885
2886@@ -5375,12 +6738,14 @@
2887 my $dsn = $connections{$connection}
2888 or die "No connection named '$connection' is defined in your configuration";
2889
2890- if ( !defined $dsn->{have_user} ) {
2891+ # don't ask for a username if mysql_read_default_group=client is in the DSN
2892+ if ( !defined $dsn->{have_user} and $dsn->{dsn} !~ /mysql_read_default_group=client/ ) {
2893 my $answer = prompt("Do you want to specify a username for $connection?", undef, 'n');
2894 $dsn->{have_user} = $answer && $answer =~ m/1|y/i;
2895 }
2896
2897- if ( !defined $dsn->{have_pass} ) {
2898+ # don't ask for a password if mysql_read_default_group=client is in the DSN
2899+ if ( !defined $dsn->{have_pass} and $dsn->{dsn} !~ /mysql_read_default_group=client/ ) {
2900 my $answer = prompt("Do you want to specify a password for $connection?", undef, 'n');
2901 $dsn->{have_pass} = $answer && $answer =~ m/1|y/i;
2902 }
2903@@ -5523,39 +6888,91 @@
2904 print $msg;
2905 }
2906
2907+# migrate_config {{{3
2908+sub migrate_config {
2909+
2910+ my ($old_filename, $new_filename) = @_;
2911+
2912+ # don't proceed if old file doesn't exist
2913+ if ( ! -f $old_filename ) {
2914+ die "Error migrating '$old_filename': file doesn't exist.\n";
2915+ }
2916+ # don't migrate files if new file exists
2917+ elsif ( -f $new_filename ) {
2918+ die "Error migrating '$old_filename' to '$new_filename': new file already exists.\n";
2919+ }
2920+ # if migrating from one file to another in the same directory, just rename them
2921+ if (dirname($old_filename) eq dirname($new_filename)) {
2922+ rename($old_filename, $new_filename)
2923+ or die "Can't rename '$old_filename' to '$new_filename': $OS_ERROR";
2924+ }
2925+ # otherwise, move the existing conf file to a temp file, make the necessary directory structure,
2926+ # and move the temp conf file to its new home
2927+ else {
2928+ my $tmp = File::Temp->new( TEMPLATE => 'innotopXXXXX', DIR => $homepath, SUFFIX => '.conf');
2929+ my $tmp_filename = $tmp->filename;
2930+ my $dirname = dirname($new_filename);
2931+ rename($old_filename, $tmp_filename)
2932+ or die "Can't rename '$old_filename' to '$tmp_filename': $OS_ERROR";
2933+ mkdir($dirname) or die "Can't create directory '$dirname': $OS_ERROR";
2934+ mkdir("$dirname/plugins") or die "Can't create directory '$dirname/plugins': $OS_ERROR";
2935+ rename($tmp_filename, $new_filename)
2936+ or die "Can't rename '$tmp_filename' to '$new_filename': $OS_ERROR";
2937+ }
2938+}
2939+
2940 # load_config {{{3
2941 sub load_config {
2942+
2943+ my ($old_filename, $answer);
2944
2945- my $filename = $opts{c} || "$homepath/.innotop/innotop.ini";
2946- my $dirname = dirname($filename);
2947- if ( -f $dirname && !$opts{c} ) {
2948- # innotop got upgraded and this is the old config file.
2949- my $answer = pause("Innotop's default config location has moved to $filename. Move old config file $dirname there now? y/n");
2950+ if ( $opts{u} or $opts{p} or $opts{h} or $opts{P} ) {
2951+ my @params = $dsn_parser->get_cxn_params(\%opts); # dsn=$params[0]
2952+ add_new_dsn($opts{h} || 'localhost', $params[0], 'test.innotop_dl',
2953+ $opts{u} ? 1 : 0, $opts{u}, $opts{p} ? 1 : 0, $opts{p});
2954+ }
2955+ if ($opts{c}) {
2956+ $conf_file = $opts{c};
2957+ }
2958+ # innotop got upgraded and this is an old config file.
2959+ elsif ( -f "$homepath/.innotop" or -f "$homepath/.innotop/innotop.ini" ) {
2960+ $conf_file = $default_home_conf;
2961+ if ( -f "$homepath/.innotop") {
2962+ $old_filename = "$homepath/.innotop";
2963+ }
2964+ elsif ( -f "$homepath/.innotop/innotop.ini" ) {
2965+ $old_filename = "$homepath/.innotop/innotop.ini";
2966+ }
2967+ $answer = pause("Innotop's default config location has moved to '$conf_file'. Move old config file '$old_filename' there now? y/n");
2968 if ( lc $answer eq 'y' ) {
2969- rename($dirname, "$homepath/innotop.ini")
2970- or die "Can't rename '$dirname': $OS_ERROR";
2971- mkdir($dirname) or die "Can't create directory '$dirname': $OS_ERROR";
2972- mkdir("$dirname/plugins") or die "Can't create directory '$dirname/plugins': $OS_ERROR";
2973- rename("$homepath/innotop.ini", $filename)
2974- or die "Can't rename '$homepath/innotop.ini' to '$filename': $OS_ERROR";
2975+ migrate_config($old_filename, $conf_file);
2976 }
2977 else {
2978 print "\nInnotop will now exit so you can fix the config file.\n";
2979 exit(0);
2980 }
2981 }
2982-
2983- if ( ! -d $dirname ) {
2984- mkdir $dirname
2985- or die "Can't create directory '$dirname': $OS_ERROR";
2986- }
2987- if ( ! -d "$dirname/plugins" ) {
2988- mkdir "$dirname/plugins"
2989- or die "Can't create directory '$dirname/plugins': $OS_ERROR";
2990- }
2991-
2992- if ( -f $filename ) {
2993- open my $file, "<", $filename or die("Can't open '$filename': $OS_ERROR");
2994+ elsif ( -f $default_home_conf ) {
2995+ $conf_file = $default_home_conf;
2996+ }
2997+ elsif ( -f $default_central_conf and not $opts{s} ) {
2998+ $conf_file = $default_central_conf;
2999+ }
3000+ else {
3001+ # If no config file was loaded, set readonly to 0 if the user wants to
3002+ # write a config
3003+ $config{readonly}->{val} = 0 if $opts{w};
3004+ # If no connections have been defined, connect to a MySQL database
3005+ # on localhost using mysql_read_default_group=client
3006+ if (!%connections) {
3007+ add_new_dsn('localhost',
3008+ 'DBI:mysql:;host=localhost;mysql_read_default_group=client',
3009+ 'test.innotop_dl');
3010+ }
3011+ }
3012+
3013+ if ( -f "$conf_file" ) {
3014+ open my $file, "<", $conf_file or die("Can't open '$conf_file': $OS_ERROR");
3015
3016 # Check config file version. Just ignore if either innotop or the file has
3017 # garbage in the version number.
3018@@ -5577,7 +6994,7 @@
3019 # If the config file is between the endpoints and innotop is greater than
3020 # the endpoint, innotop has a newer config file format than the file.
3021 if ( $cfg_ver ge $start && $cfg_ver lt $end && $innotop_ver ge $end ) {
3022- my $msg = "innotop's config file format has changed. Overwrite $filename? y or n";
3023+ my $msg = "innotop's config file format has changed. Overwrite $conf_file? y or n";
3024 if ( pause($msg) eq 'n' ) {
3025 $config{readonly}->{val} = 1;
3026 print "\ninnotop will not save any configuration changes you make.";
3027@@ -5602,7 +7019,7 @@
3028 warn "Unknown config file section '$1'";
3029 }
3030 }
3031- close $file or die("Can't close $filename: $OS_ERROR");
3032+ close $file or die("Can't close $conf_file: $OS_ERROR");
3033 }
3034
3035 }
3036@@ -5999,12 +7416,6 @@
3037 sub load_config_config {
3038 my ( $file ) = @_;
3039
3040- # Look in the command-line parameters for things stored in the same slot.
3041- my %cmdline =
3042- map { $_->{c} => $opts{$_->{k}} }
3043- grep { exists $_->{c} && exists $opts{$_->{k}} }
3044- @opt_spec;
3045-
3046 while ( my $line = <$file> ) {
3047 chomp $line;
3048 next if $line =~ m/^#/;
3049@@ -6013,9 +7424,6 @@
3050 my ( $name, $val ) = $line =~ m/^(.+?)=(.*)$/;
3051 next unless defined $name && defined $val;
3052
3053- # Values might already have been set at the command line.
3054- $val = defined($cmdline{$name}) ? $cmdline{$name} : $val;
3055-
3056 # Validate the incoming values...
3057 if ( $name && exists( $config{$name} ) ) {
3058 if ( !$config{$name}->{pat} || $val =~ m/$config{$name}->{pat}/ ) {
3059@@ -6080,12 +7488,41 @@
3060
3061 # save_config {{{3
3062 sub save_config {
3063+ print "\n";
3064 return if $config{readonly}->{val};
3065+ # return if no config file was loaded and -w wasn't specified
3066+ if (not $conf_file) {
3067+ if (not $opts{w}) {
3068+ return;
3069+ }
3070+ else {
3071+ # if no config was loaded but -w was specified,
3072+ # write to $default_home_conf
3073+ $conf_file = $default_home_conf;
3074+ }
3075+ }
3076+ elsif ($conf_file and $opts{w}) {
3077+ print "Loaded config file on start-up, so ignoring -w (see --help)\n"
3078+ }
3079+
3080+ my $dirname = dirname($conf_file);
3081+
3082+ # if directories don't exist, create them. This could cause errors
3083+ # or warnings if a central config doesn't have readonly=1, but being
3084+ # flexible requires giving the user enough rope to hang themselves with.
3085+ if ( ! -d $dirname ) {
3086+ mkdir $dirname
3087+ or die "Can't create directory '$dirname': $OS_ERROR";
3088+ }
3089+ if ( ! -d "$dirname/plugins" ) {
3090+ mkdir "$dirname/plugins"
3091+ or warn "Can't create directory '$dirname/plugins': $OS_ERROR\n";
3092+ }
3093+
3094 # Save to a temp file first, so a crash doesn't destroy the main config file
3095- my $newname = $opts{c} || "$homepath/.innotop/innotop.ini";
3096- my $filename = $newname . '_tmp';
3097- open my $file, "+>", $filename
3098- or die("Can't write to $filename: $OS_ERROR");
3099+ my $tmpfile = File::Temp->new( TEMPLATE => 'innotopXXXXX', DIR => $dirname, SUFFIX => '.conf.tmp');
3100+ open my $file, "+>", $tmpfile
3101+ or die("Can't write to $tmpfile: $OS_ERROR");
3102 print $file "version=$VERSION\n";
3103
3104 foreach my $section ( @ordered_config_file_sections ) {
3105@@ -6096,12 +7533,13 @@
3106 }
3107
3108 # Now clobber the main config file with the temp.
3109- close $file or die("Can't close $filename: $OS_ERROR");
3110- rename($filename, $newname) or die("Can't rename $filename to $newname: $OS_ERROR");
3111+ close $file or die("Can't close $tmpfile: $OS_ERROR");
3112+ rename($tmpfile, $conf_file) or die("Can't rename $tmpfile to $conf_file: $OS_ERROR");
3113 }
3114
3115 # load_config_connections {{{3
3116 sub load_config_connections {
3117+ return if $opts{u} or $opts{p} or $opts{h} or $opts{P}; # don't load connections if DSN or user/pass options used
3118 my ( $file ) = @_;
3119 while ( my $line = <$file> ) {
3120 chomp $line;
3121@@ -7250,6 +8688,10 @@
3122
3123 innotop --count 5 -d 1 -n
3124
3125+To monitor a database on another system using a particular username and password:
3126+
3127+ innotop -u <username> -p <password> -h <hostname>
3128+
3129 =head1 DESCRIPTION
3130
3131 innotop monitors MySQL servers. Each of its modes shows you a different aspect
3132@@ -7269,42 +8711,30 @@
3133 Enter; otherwise, you will need to change to innotop's directory and type "perl
3134 innotop".
3135
3136-The first thing innotop needs to know is how to connect to a MySQL server. You
3137-can just enter the hostname of the server, for example "localhost" or
3138-"127.0.0.1" if the server is on the same machine as innotop. After this innotop
3139-will prompt you for a DSN (data source name). You should be able to just accept
3140-the defaults by pressing Enter.
3141-
3142-When innotop asks you about a table to use when resetting InnoDB deadlock
3143-information, just accept the default for now. This is an advanced feature you
3144-can configure later (see L<"D: InnoDB Deadlocks"> for more).
3145-
3146-If you have a .my.cnf file with your MySQL connection defaults, innotop can read
3147-it, and you won't need to specify a username and password if it's in that file.
3148-Otherwise, you should answer 'y' to the next couple of prompts.
3149-
3150-After this, you should be connected, and innotop should show you something like
3151-the following:
3152-
3153- InnoDB Txns (? for help) localhost, 01:11:19, InnoDB 10s :-), 50 QPS,
3154-
3155- CXN History Versions Undo Dirty Buf Used Bufs Txns MaxTxn
3156- localhost 7 2035 0 0 0.00% 92.19% 1 07:34
3157-
3158- CXN ID User Host Txn Status Time Undo Query Tex
3159- localhost 98379 user1 webserver ACTIVE 07:34 0 SELECT `c
3160- localhost 98450 user1 webserver ACTIVE 01:06 0 INSERT IN
3161- localhost 97750 user1 webserver not starte 00:00 0
3162- localhost 98375 user1 appserver not starte 00:00 0
3163+With no options specified, innotop will attempt to connect to a MySQL server on
3164+localhost using mysql_read_default_group=client for other connection
3165+parameters. If you need to specify a different username and password, use the
3166+-u and -p options, respectively. To monitor a MySQL database on another
3167+host, use the -h option.
3168+
3169+After you've connected, innotop should show you something like the following:
3170+
3171+ [RO] Query List (? for help) localhost, 01:11:19, 449.44 QPS, 14/7/163 con/run
3172+
3173+ CXN When Load QPS Slow QCacheHit KCacheHit BpsIn BpsOut
3174+ localhost Total 0.00 1.07k 697 0.00% 98.17% 476.83k 242.83k
3175+
3176+ CXN Cmd ID User Host DB Time Query
3177+ localhost Query 766446598 test 10.0.0.1 foo 00:02 INSERT INTO table (
3178+
3179
3180 (This sample is truncated at the right so it will fit on a terminal when running
3181 'man innotop')
3182
3183-This sample comes from a quiet server with few transactions active. If your
3184-server is busy, you'll see more output. Notice the first line on the screen,
3185-which tells you what mode you're in and what server you're connected to. You
3186-can change to other modes with keystrokes; press 'Q' to switch to a list of
3187-currently running queries.
3188+If your server is busy, you'll see more output. Notice the first line on the
3189+screen, which tells you that readonly is set to true ([RO]), what mode you're
3190+in and what server you're connected to. You can change to other modes with
3191+keystrokes; press 'T' to switch to a list of InnoDB transactions, for example.
3192
3193 Press the '?' key to see what keys are active in the current mode. You can
3194 press any of these keys and innotop will either take the requested action or
3195@@ -7325,10 +8755,6 @@
3196
3197 =over
3198
3199-=item --help
3200-
3201-Print a summary of command-line usage and exit.
3202-
3203 =item --color
3204
3205 Enable or disable terminal coloring. Corresponds to the L<"color"> config file
3206@@ -7339,10 +8765,6 @@
3207 Specifies a configuration file to read. This option is non-sticky, that is to
3208 say it does not persist to the configuration file itself.
3209
3210-=item --nonint
3211-
3212-Enable non-interactive operation. See L<"NON-INTERACTIVE OPERATION"> for more.
3213-
3214 =item --count
3215
3216 Refresh only the specified number of times (ticks) before exiting. Each refresh
3217@@ -7354,10 +8776,13 @@
3218 Specifies the amount of time to pause between ticks (refreshes). Corresponds to
3219 the configuration option L<"interval">.
3220
3221-=item --mode
3222-
3223-Specifies the mode in which innotop should start. Corresponds to the
3224-configuration option L<"mode">.
3225+=item --help
3226+
3227+Print a summary of command-line usage and exit.
3228+
3229+=item --host
3230+
3231+Host to connect to.
3232
3233 =item --inc
3234
3235@@ -7365,10 +8790,41 @@
3236 (offsets from their previous values). Corresponds to the configuration option
3237 L<"status_inc">.
3238
3239+=item --mode
3240+
3241+Specifies the mode in which innotop should start. Corresponds to the
3242+configuration option L<"mode">.
3243+
3244+=item --nonint
3245+
3246+Enable non-interactive operation. See L<"NON-INTERACTIVE OPERATION"> for more.
3247+
3248+=item --password
3249+
3250+Password to use for connection.
3251+
3252+=item --port
3253+
3254+Port to use for connection.
3255+
3256+=item --skipcentral
3257+
3258+Don't read the central configuration file.
3259+
3260+=item --user
3261+
3262+User to use for connection.
3263+
3264 =item --version
3265
3266 Output version information and exit.
3267
3268+=item --write
3269+
3270+Sets the configuration option L<"readonly"> to 0, making innotop write the
3271+running configuration to ~/.innotop/innotop.conf on exit, if no configuration
3272+file was loaded at start-up.
3273+
3274 =back
3275
3276 =head1 HOTKEYS
3277@@ -7623,8 +9079,9 @@
3278
3279 The first line innotop displays is a "status bar" of sorts. What it contains
3280 depends on the mode you're in, and what servers you're monitoring. The first
3281-few words are always the innotop mode, such as "InnoDB Txns" for T mode,
3282-followed by a reminder to press '?' for help at any time.
3283+few words are always [RO] (if readonly is set to 1), the innotop mode, such as
3284+"InnoDB Txns" for T mode, followed by a reminder to press '?' for help at any
3285+time.
3286
3287 =head2 ONE SERVER
3288
3289@@ -7701,8 +9158,8 @@
3290
3291 =head1 SERVER CONNECTIONS
3292
3293-When you create a server connection, innotop asks you for a series of inputs, as
3294-follows:
3295+When you create a server connection using '@', innotop asks you for a series of
3296+inputs, as follows:
3297
3298 =over
3299
3300@@ -7755,9 +9212,6 @@
3301 server connections and switch between them by pressing the '@' key. See
3302 L<"SWITCHING BETWEEN CONNECTIONS">.
3303
3304-To create a new connection, press the '@' key and type the name of the new
3305-connection, then follow the steps given above.
3306-
3307 =head1 SERVER GROUPS
3308
3309 If you have multiple MySQL instances, you can put them into named groups, such
3310@@ -7958,20 +9412,23 @@
3311
3312 =head1 CONFIGURATION FILE
3313
3314-innotop's default configuration file location is in $HOME/.innotop, but can be
3315+innotop's default configuration file locations are $HOME/.innotop and
3316+/etc/innotop/innotop.conf, and they are looked for in that order. If the first
3317+configuration file exists, the second will not be processed. Those can be
3318 overridden with the L<"--config"> command-line option. You can edit it by hand
3319-safely. innotop reads the configuration file when it starts, and writes it out
3320-again when it exits, so any changes you make while innotop is running will be
3321-lost.
3322+safely, however innotop reads the configuration file when it starts, and, if
3323+readonly is set to 0, writes it out again when it exits. Thus, if readonly is
3324+set to 0, any changes you make by hand while innotop is running will be lost.
3325
3326 innotop doesn't store its entire configuration in the configuration file. It
3327-has a huge set of default configuration that it holds only in memory, and the
3328-configuration file only overrides these defaults. When you customize a default
3329-setting, innotop notices, and then stores the customizations into the file.
3330-This keeps the file size down, makes it easier to edit, and makes upgrades
3331-easier.
3332+has a huge set of default configuration values that it holds only in memory,
3333+and the configuration file only overrides these defaults. When you customize a
3334+default setting, innotop notices, and then stores the customizations into the
3335+file. This keeps the file size down, makes it easier to edit, and makes
3336+upgrades easier.
3337
3338-A configuration file can be made read-only. See L<"readonly">.
3339+A configuration file is read-only be default. You can override that with
3340+L<"--write">. See L<"readonly">.
3341
3342 The configuration file is arranged into sections like an INI file. Each
3343 section begins with [section-name] and ends with [/section-name]. Each
3344@@ -8119,8 +9576,7 @@
3345
3346 =item readonly
3347
3348-Whether the configuration file is readonly. This cannot be set interactively,
3349-because it would prevent itself from being written to the configuration file.
3350+Whether the configuration file is readonly. This cannot be set interactively.
3351
3352 =item show_cxn_errors
3353
3354@@ -8185,10 +9641,12 @@
3355
3356 =item connections
3357
3358-This section holds the server connections you have defined. Each line is in the
3359-format name=properties, where the properties are a name=value list. The
3360+This section holds the server connections you have defined. Each line is in
3361+the format name=properties, where the properties are a name=value list. The
3362 properties are self-explanatory, and the only one that is treated specially is
3363-'pass' which is only present if 'savepass' is set. See L<"SERVER CONNECTIONS">.
3364+'pass' which is only present if 'savepass' is set. This section of the
3365+configuration file will be skipped if any DSN, username, or password
3366+command-line options are used. See L<"SERVER CONNECTIONS">.
3367
3368 =item active_connections
3369
3370@@ -8646,7 +10104,7 @@
3371
3372 =head2 GROUPING
3373
3374-innotop can group, or aggregate, rows together (I use the terms
3375+innotop can group, or aggregate, rows together (the terms are used
3376 interchangeably). This is quite similar to an SQL GROUP BY clause. You can
3377 specify to group on certain columns, or if you don't specify any, the entire set
3378 of rows is treated as one group. This is quite like SQL so far, but unlike SQL,
3379@@ -9389,15 +10847,16 @@
3380 I don't know for sure. It also runs on Windows under ActivePerl without
3381 problem.
3382
3383-I use innotop on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26, 5.1.15,
3384-and 5.2.3. If it doesn't run correctly for you, that is a bug and I hope you
3385-report it.
3386+innotop has been used on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26,
3387+5.1.15, and 5.2.3. If it doesn't run correctly for you, that is a bug that
3388+should be reported.
3389
3390 =head1 FILES
3391
3392-$HOMEDIR/.innotop is used to store configuration information. Files include the
3393-configuration file innotop.ini, the core_dump file which contains verbose error
3394-messages if L<"debug"> is enabled, and the plugins/ subdirectory.
3395+$HOMEDIR/.innotop and/or /etc/innotop are used to store
3396+configuration information. Files include the configuration file innotop.conf,
3397+the core_dump file which contains verbose error messages if L<"debug"> is
3398+enabled, and the plugins/ subdirectory.
3399
3400 =head1 GLOSSARY OF TERMS
3401
3402@@ -9412,8 +10871,8 @@
3403
3404 =head1 ACKNOWLEDGEMENTS
3405
3406-I'm grateful to the following people for various reasons, and hope I haven't
3407-forgotten to include anyone:
3408+The following people and organizations are acknowledged for various reasons.
3409+Hopefully no one has been forgotten.
3410
3411 Allen K. Smith,
3412 Aurimas Mikalauskas,
3413@@ -9426,6 +10885,7 @@
3414 Dr. Frank Ullrich,
3415 Giuseppe Maxia,
3416 Google.com Site Reliability Engineers,
3417+Google Code,
3418 Jan Pieter Kunst,
3419 Jari Aalto,
3420 Jay Pipes,
3421@@ -9443,9 +10903,9 @@
3422 The Gentoo MySQL Team,
3423 Trevor Price,
3424 Yaar Schnitman,
3425-and probably more people I've neglected to include.
3426+and probably more people that have not been included.
3427
3428-(If I misspelled your name, it's probably because I'm afraid of putting
3429+(If your name has been misspelled, it's probably out of fear of putting
3430 international characters into this documentation; earlier versions of Perl might
3431 not be able to compile it then).
3432
3433@@ -9472,14 +10932,15 @@
3434
3435 =head1 AUTHOR
3436
3437-Baron Schwartz.
3438+Originally written by Baron Schwartz; currently maintained by Aaron Racine.
3439
3440 =head1 BUGS
3441
3442 You can report bugs, ask for improvements, and get other help and support at
3443-L<http://sourceforge.net/projects/innotop>. There are mailing lists, forums,
3444-a bug tracker, etc. Please use these instead of contacting me directly, as it
3445-makes my job easier and benefits others if the discussions are permanent and
3446-public. Of course, if you need to contact me in private, please do.
3447+L<http://code.google.com/p/innotop/>. There are mailing lists, a source code
3448+browser, a bug tracker, etc. Please use these instead of contacting the
3449+maintainer or author directly, as it makes our job easier and benefits others if the
3450+discussions are permanent and public. Of course, if you need to contact us in
3451+private, please do.
3452
3453 =cut
3454
3455=== modified file 'bakery/debian-5.1/additions/innotop/innotop.1'
3456--- bakery/debian-5.1/additions/innotop/innotop.1 2008-10-20 22:54:11 +0000
3457+++ bakery/debian-5.1/additions/innotop/innotop.1 2009-10-02 06:45:25 +0000
3458@@ -1,15 +1,7 @@
3459-.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
3460+.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.07)
3461 .\"
3462 .\" Standard preamble:
3463 .\" ========================================================================
3464-.de Sh \" Subsection heading
3465-.br
3466-.if t .Sp
3467-.ne 5
3468-.PP
3469-\fB\\$1\fR
3470-.PP
3471-..
3472 .de Sp \" Vertical space (when we can't use .PP)
3473 .if t .sp .5v
3474 .if n .sp
3475@@ -48,22 +40,25 @@
3476 . ds R" ''
3477 'br\}
3478 .\"
3479+.\" Escape single quotes in literal strings from groff's Unicode transform.
3480+.ie \n(.g .ds Aq \(aq
3481+.el .ds Aq '
3482+.\"
3483 .\" If the F register is turned on, we'll generate index entries on stderr for
3484-.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
3485+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
3486 .\" entries marked with X<> in POD. Of course, you'll have to process the
3487 .\" output yourself in some meaningful fashion.
3488-.if \nF \{\
3489+.ie \nF \{\
3490 . de IX
3491 . tm Index:\\$1\t\\n%\t"\\$2"
3492 ..
3493 . nr % 0
3494 . rr F
3495 .\}
3496-.\"
3497-.\" For nroff, turn off justification. Always turn off hyphenation; it makes
3498-.\" way too many mistakes in technical documents.
3499-.hy 0
3500-.if n .na
3501+.el \{\
3502+. de IX
3503+..
3504+.\}
3505 .\"
3506 .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
3507 .\" Fear. Run. Save yourself. No user-serviceable parts.
3508@@ -128,8 +123,12 @@
3509 .rm #[ #] #H #V #F C
3510 .\" ========================================================================
3511 .\"
3512-.IX Title "INNOTOP 1p"
3513-.TH INNOTOP 1p "2007-11-09" "perl v5.8.8" "User Contributed Perl Documentation"
3514+.IX Title "INNOTOP 1"
3515+.TH INNOTOP 1 "2009-03-09" "perl v5.10.0" "User Contributed Perl Documentation"
3516+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
3517+.\" way too many mistakes in technical documents.
3518+.if n .ad l
3519+.nh
3520 .SH "NAME"
3521 innotop \- MySQL and InnoDB transaction/status monitor.
3522 .SH "SYNOPSIS"
3523@@ -151,6 +150,12 @@
3524 .Vb 1
3525 \& innotop \-\-count 5 \-d 1 \-n
3526 .Ve
3527+.PP
3528+To monitor a database on another system using a particular username and password:
3529+.PP
3530+.Vb 1
3531+\& innotop \-u <username> \-p <password> \-h <hostname>
3532+.Ve
3533 .SH "DESCRIPTION"
3534 .IX Header "DESCRIPTION"
3535 innotop monitors MySQL servers. Each of its modes shows you a different aspect
3536@@ -160,7 +165,7 @@
3537 .PP
3538 innotop has lots of features for power users, but you can start and run it with
3539 virtually no configuration. If you're just getting started, see
3540-\&\*(L"\s-1QUICK\-START\s0\*(R". Press '?' at any time while running innotop for
3541+\&\*(L"QUICK-START\*(R". Press '?' at any time while running innotop for
3542 context-sensitive help.
3543 .SH "QUICK-START"
3544 .IX Header "QUICK-START"
3545@@ -169,48 +174,31 @@
3546 Enter; otherwise, you will need to change to innotop's directory and type \*(L"perl
3547 innotop\*(R".
3548 .PP
3549-The first thing innotop needs to know is how to connect to a MySQL server. You
3550-can just enter the hostname of the server, for example \*(L"localhost\*(R" or
3551-\&\*(L"127.0.0.1\*(R" if the server is on the same machine as innotop. After this innotop
3552-will prompt you for a \s-1DSN\s0 (data source name). You should be able to just accept
3553-the defaults by pressing Enter.
3554-.PP
3555-When innotop asks you about a table to use when resetting InnoDB deadlock
3556-information, just accept the default for now. This is an advanced feature you
3557-can configure later (see \*(L"D: InnoDB Deadlocks\*(R" for more).
3558-.PP
3559-If you have a .my.cnf file with your MySQL connection defaults, innotop can read
3560-it, and you won't need to specify a username and password if it's in that file.
3561-Otherwise, you should answer 'y' to the next couple of prompts.
3562-.PP
3563-After this, you should be connected, and innotop should show you something like
3564-the following:
3565+With no options specified, innotop will attempt to connect to a MySQL server on
3566+localhost using mysql_read_default_group=client for other connection
3567+parameters. If you need to specify a different username and password, use the
3568+\&\-u and \-p options, respectively. To monitor a MySQL database on another
3569+host, use the \-h option.
3570+.PP
3571+After you've connected, innotop should show you something like the following:
3572 .PP
3573 .Vb 1
3574-\& InnoDB Txns (? for help) localhost, 01:11:19, InnoDB 10s :\-), 50 QPS,
3575-.Ve
3576-.PP
3577-.Vb 2
3578-\& CXN History Versions Undo Dirty Buf Used Bufs Txns MaxTxn
3579-\& localhost 7 2035 0 0 0.00% 92.19% 1 07:34
3580-.Ve
3581-.PP
3582-.Vb 5
3583-\& CXN ID User Host Txn Status Time Undo Query Tex
3584-\& localhost 98379 user1 webserver ACTIVE 07:34 0 SELECT `c
3585-\& localhost 98450 user1 webserver ACTIVE 01:06 0 INSERT IN
3586-\& localhost 97750 user1 webserver not starte 00:00 0
3587-\& localhost 98375 user1 appserver not starte 00:00 0
3588+\& [RO] Query List (? for help) localhost, 01:11:19, 449.44 QPS, 14/7/163 con/run
3589+\&
3590+\& CXN When Load QPS Slow QCacheHit KCacheHit BpsIn BpsOut
3591+\& localhost Total 0.00 1.07k 697 0.00% 98.17% 476.83k 242.83k
3592+\&
3593+\& CXN Cmd ID User Host DB Time Query
3594+\& localhost Query 766446598 test 10.0.0.1 foo 00:02 INSERT INTO table (
3595 .Ve
3596 .PP
3597 (This sample is truncated at the right so it will fit on a terminal when running
3598 \&'man innotop')
3599 .PP
3600-This sample comes from a quiet server with few transactions active. If your
3601-server is busy, you'll see more output. Notice the first line on the screen,
3602-which tells you what mode you're in and what server you're connected to. You
3603-can change to other modes with keystrokes; press 'Q' to switch to a list of
3604-currently running queries.
3605+If your server is busy, you'll see more output. Notice the first line on the
3606+screen, which tells you that readonly is set to true ([\s-1RO\s0]), what mode you're
3607+in and what server you're connected to. You can change to other modes with
3608+keystrokes; press 'T' to switch to a list of InnoDB transactions, for example.
3609 .PP
3610 Press the '?' key to see what keys are active in the current mode. You can
3611 press any of these keys and innotop will either take the requested action or
3612@@ -227,20 +215,14 @@
3613 .PP
3614 You can negate some options by prefixing the option name with \-\-no. For
3615 example, \-\-noinc (or \-\-no\-inc) negates \*(L"\-\-inc\*(R".
3616-.IP "\-\-help" 4
3617-.IX Item "--help"
3618-Print a summary of command-line usage and exit.
3619 .IP "\-\-color" 4
3620 .IX Item "--color"
3621 Enable or disable terminal coloring. Corresponds to the \*(L"color\*(R" config file
3622 setting.
3623 .IP "\-\-config" 4
3624 .IX Item "--config"
3625-Specifies a configuration file to read. This option is non\-sticky, that is to
3626+Specifies a configuration file to read. This option is non-sticky, that is to
3627 say it does not persist to the configuration file itself.
3628-.IP "\-\-nonint" 4
3629-.IX Item "--nonint"
3630-Enable non-interactive operation. See \*(L"\s-1NON\-INTERACTIVE\s0 \s-1OPERATION\s0\*(R" for more.
3631 .IP "\-\-count" 4
3632 .IX Item "--count"
3633 Refresh only the specified number of times (ticks) before exiting. Each refresh
3634@@ -250,21 +232,47 @@
3635 .IX Item "--delay"
3636 Specifies the amount of time to pause between ticks (refreshes). Corresponds to
3637 the configuration option \*(L"interval\*(R".
3638-.IP "\-\-mode" 4
3639-.IX Item "--mode"
3640-Specifies the mode in which innotop should start. Corresponds to the
3641-configuration option \*(L"mode\*(R".
3642+.IP "\-\-help" 4
3643+.IX Item "--help"
3644+Print a summary of command-line usage and exit.
3645+.IP "\-\-host" 4
3646+.IX Item "--host"
3647+Host to connect to.
3648 .IP "\-\-inc" 4
3649 .IX Item "--inc"
3650 Specifies whether innotop should display absolute numbers or relative numbers
3651 (offsets from their previous values). Corresponds to the configuration option
3652 \&\*(L"status_inc\*(R".
3653+.IP "\-\-mode" 4
3654+.IX Item "--mode"
3655+Specifies the mode in which innotop should start. Corresponds to the
3656+configuration option \*(L"mode\*(R".
3657+.IP "\-\-nonint" 4
3658+.IX Item "--nonint"
3659+Enable non-interactive operation. See \*(L"NON-INTERACTIVE \s-1OPERATION\s0\*(R" for more.
3660+.IP "\-\-password" 4
3661+.IX Item "--password"
3662+Password to use for connection.
3663+.IP "\-\-port" 4
3664+.IX Item "--port"
3665+Port to use for connection.
3666+.IP "\-\-skipcentral" 4
3667+.IX Item "--skipcentral"
3668+Don't read the central configuration file.
3669+.IP "\-\-user" 4
3670+.IX Item "--user"
3671+User to use for connection.
3672 .IP "\-\-version" 4
3673 .IX Item "--version"
3674 Output version information and exit.
3675+.IP "\-\-write" 4
3676+.IX Item "--write"
3677+Sets the configuration option \*(L"readonly\*(R" to 0, making innotop write the
3678+running configuration to ~/.innotop/innotop.conf on exit, if no configuration
3679+file was loaded at start-up.
3680 .SH "HOTKEYS"
3681 .IX Header "HOTKEYS"
3682-innotop is interactive, and you control it with key\-presses.
3683+innotop is interactive, and you control it with key-presses.
3684 .IP "\(bu" 4
3685 Uppercase keys switch between modes.
3686 .IP "\(bu" 4
3687@@ -295,7 +303,7 @@
3688 .Sp
3689 .Vb 8
3690 \& Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40
3691-\& _____________________ Command Summary _____________________
3692+\& _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ Command Summary _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_
3693 \& Name Value Pct Last Incr Pct
3694 \& Select_scan 3244858 69.89% 2 100.00%
3695 \& Select_range 1354177 29.17% 0 0.00%
3696@@ -338,7 +346,8 @@
3697 .Sp
3698 If it has, you can create a small deadlock to replace the large one. Use the
3699 \&'w' key to 'wipe' the large deadlock with a small one. This will not work
3700-unless you have defined a deadlock table for the connection (see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R").
3701+unless you have defined a deadlock table for the connection (see \*(L"\s-1SERVER\s0
3702+\&\s-1CONNECTIONS\s0\*(R").
3703 .Sp
3704 You can also configure innotop to automatically detect when a large deadlock
3705 needs to be replaced with a small one (see \*(L"auto_wipe_dl\*(R").
3706@@ -396,7 +405,7 @@
3707 the screen when one connection is waiting for locks another connection holds:
3708 .Sp
3709 .Vb 7
3710-\& _________________________________ InnoDB Locks __________________________
3711+\& _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ InnoDB Locks _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_
3712 \& CXN ID Type Waiting Wait Active Mode DB Table Index
3713 \& localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY
3714 \& localhost 12 TABLE 0 00:10 00:10 IX test t1
3715@@ -440,7 +449,7 @@
3716 You can \s-1EXPLAIN\s0 a query from this mode with the 'e' key. This displays the
3717 query's full text, the results of \s-1EXPLAIN\s0, and in newer MySQL versions, even
3718 the optimized query resulting from \s-1EXPLAIN\s0 \s-1EXTENDED\s0. innotop also tries to
3719-rewrite certain queries to make them EXPLAIN\-able. For example, \s-1INSERT/SELECT\s0
3720+rewrite certain queries to make them EXPLAIN-able. For example, \s-1INSERT/SELECT\s0
3721 statements are rewritable.
3722 .Sp
3723 This mode displays the \*(L"q_header\*(R" and \*(L"processlist\*(R" tables by default.
3724@@ -491,9 +500,10 @@
3725 .IX Header "INNOTOP STATUS"
3726 The first line innotop displays is a \*(L"status bar\*(R" of sorts. What it contains
3727 depends on the mode you're in, and what servers you're monitoring. The first
3728-few words are always the innotop mode, such as \*(L"InnoDB Txns\*(R" for T mode,
3729-followed by a reminder to press '?' for help at any time.
3730-.Sh "\s-1ONE\s0 \s-1SERVER\s0"
3731+few words are always [\s-1RO\s0] (if readonly is set to 1), the innotop mode, such as
3732+\&\*(L"InnoDB Txns\*(R" for T mode, followed by a reminder to press '?' for help at any
3733+time.
3734+.SS "\s-1ONE\s0 \s-1SERVER\s0"
3735 .IX Subsection "ONE SERVER"
3736 The simplest case is when you're monitoring a single server. In this case, the
3737 name of the connection is next on the status line. This is the name you gave
3738@@ -513,7 +523,7 @@
3739 The next two words indicate the server's queries per second (\s-1QPS\s0) and how many
3740 threads (connections) exist. Finally, the server's version number is the last
3741 thing on the line.
3742-.Sh "\s-1MULTIPLE\s0 \s-1SERVERS\s0"
3743+.SS "\s-1MULTIPLE\s0 \s-1SERVERS\s0"
3744 .IX Subsection "MULTIPLE SERVERS"
3745 If you are monitoring multiple servers (see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"), the status
3746 line does not show any details about individual servers. Instead, it shows the
3747@@ -527,7 +537,7 @@
3748 don't have errors.
3749 .PP
3750 See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R" for more details about innotop's error handling.
3751-.Sh "\s-1MONITORING\s0 A \s-1FILE\s0"
3752+.SS "\s-1MONITORING\s0 A \s-1FILE\s0"
3753 .IX Subsection "MONITORING A FILE"
3754 If you give a filename on the command line, innotop will not connect to \s-1ANY\s0
3755 servers at all. It will watch the specified file for InnoDB status output and
3756@@ -549,7 +559,7 @@
3757 innotop pre-selects the longest-running query, or the oldest connection.
3758 Confirm the command with 'y'.
3759 .PP
3760-In \*(L"M: Master/Slave Replication Status\*(R" mode, you can start and stop slaves
3761+In \*(L"Slave Replication Status\*(R"\*(L" in \*(R"M: Master mode, you can start and stop slaves
3762 with the 'a' and 'o' keys, respectively. You can send these commands to many
3763 slaves at once. innotop fills in a default command of \s-1START\s0 \s-1SLAVE\s0 or \s-1STOP\s0 \s-1SLAVE\s0
3764 for you, but you can actually edit the command and send anything you wish, such
3765@@ -564,8 +574,8 @@
3766 these slave connections and suggest it as the argument to \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0.
3767 .SH "SERVER CONNECTIONS"
3768 .IX Header "SERVER CONNECTIONS"
3769-When you create a server connection, innotop asks you for a series of inputs, as
3770-follows:
3771+When you create a server connection using '@', innotop asks you for a series of
3772+inputs, as follows:
3773 .IP "\s-1DSN\s0" 4
3774 .IX Item "DSN"
3775 A \s-1DSN\s0 is a Data Source Name, which is the initial argument passed to the \s-1DBI\s0
3776@@ -576,7 +586,7 @@
3777 .Ve
3778 .Sp
3779 Since this \s-1DSN\s0 is passed to the DBD::mysql driver, you should read the driver's
3780-documentation at \*(L"http://search.cpan.org/dist/DBD\-mysql/lib/DBD/mysql.pm\*(R" for
3781+documentation at \*(L"/search.cpan.org/dist/DBD\-mysql/lib/DBD/mysql.pm\*(R"\*(L" in \*(R"http: for
3782 the exact details on all the options you can pass the driver in the \s-1DSN\s0. You
3783 can read more about \s-1DBI\s0 at <http://dbi.perl.org/docs/>, and especially at
3784 <http://search.cpan.org/~timb/DBI/DBI.pm>.
3785@@ -611,9 +621,6 @@
3786 But innotop isn't limited to monitoring a single server; you can define many
3787 server connections and switch between them by pressing the '@' key. See
3788 \&\*(L"\s-1SWITCHING\s0 \s-1BETWEEN\s0 \s-1CONNECTIONS\s0\*(R".
3789-.PP
3790-To create a new connection, press the '@' key and type the name of the new
3791-connection, then follow the steps given above.
3792 .SH "SERVER GROUPS"
3793 .IX Header "SERVER GROUPS"
3794 If you have multiple MySQL instances, you can put them into named groups, such
3795@@ -629,7 +636,7 @@
3796 .IX Header "SWITCHING BETWEEN CONNECTIONS"
3797 innotop lets you quickly switch which servers you're monitoring. The most basic
3798 way is by pressing the '@' key and typing the name(s) of the connection(s) you
3799-want to use. This setting is per\-mode, so you can monitor different connections
3800+want to use. This setting is per-mode, so you can monitor different connections
3801 in each mode, and innotop remembers which connections you choose.
3802 .PP
3803 You can quickly switch to the 'next' connection in alphabetical order with the
3804@@ -663,7 +670,7 @@
3805 .PP
3806 innotop does not continue to query connections that have errors, because they
3807 may slow innotop and make it hard to use, especially if the error is a problem
3808-connecting and causes a long time\-out. Instead, innotop retries the connection
3809+connecting and causes a long time-out. Instead, innotop retries the connection
3810 occasionally to see if the error still exists. If so, it will wait until some
3811 point in the future. The wait time increases in ticks as the Fibonacci series,
3812 so it tries less frequently as time passes.
3813@@ -704,7 +711,8 @@
3814 .IP "\(bu" 4
3815 innotop only displays the first table in each mode. This is so the output can
3816 be easily processed with other command-line utilities such as awk and sed. To
3817-change which tables display in each mode, see \*(L"\s-1TABLES\s0\*(R". Since \*(L"Q: Query List\*(R" mode is so important, innotop automatically disables the \*(L"q_header\*(R"
3818+change which tables display in each mode, see \*(L"\s-1TABLES\s0\*(R". Since \*(L"Q: Query
3819+List\*(R" mode is so important, innotop automatically disables the \*(L"q_header\*(R"
3820 table. This ensures you'll see the \*(L"processlist\*(R" table, even if you have
3821 innotop configured to show the q_header table during interactive operation.
3822 Similarly, in \*(L"T: InnoDB Transactions\*(R" mode, the \*(L"t_header\*(R" table is
3823@@ -775,20 +783,23 @@
3824 \&\*(L"\s-1TABLES\s0\*(R".
3825 .SH "CONFIGURATION FILE"
3826 .IX Header "CONFIGURATION FILE"
3827-innotop's default configuration file location is in \f(CW$HOME\fR/.innotop, but can be
3828+innotop's default configuration file locations are \f(CW$HOME\fR/.innotop and
3829+/etc/innotop/innotop.conf, and they are looked for in that order. If the first
3830+configuration file exists, the second will not be processed. Those can be
3831 overridden with the \*(L"\-\-config\*(R" command-line option. You can edit it by hand
3832-safely. innotop reads the configuration file when it starts, and writes it out
3833-again when it exits, so any changes you make while innotop is running will be
3834-lost.
3835+safely, however innotop reads the configuration file when it starts, and, if
3836+readonly is set to 0, writes it out again when it exits. Thus, if readonly is
3837+set to 0, any changes you make by hand while innotop is running will be lost.
3838 .PP
3839 innotop doesn't store its entire configuration in the configuration file. It
3840-has a huge set of default configuration that it holds only in memory, and the
3841-configuration file only overrides these defaults. When you customize a default
3842-setting, innotop notices, and then stores the customizations into the file.
3843-This keeps the file size down, makes it easier to edit, and makes upgrades
3844-easier.
3845+has a huge set of default configuration values that it holds only in memory,
3846+and the configuration file only overrides these defaults. When you customize a
3847+default setting, innotop notices, and then stores the customizations into the
3848+file. This keeps the file size down, makes it easier to edit, and makes
3849+upgrades easier.
3850 .PP
3851-A configuration file can be made read\-only. See \*(L"readonly\*(R".
3852+A configuration file is read-only be default. You can override that with
3853+\&\*(L"\-\-write\*(R". See \*(L"readonly\*(R".
3854 .PP
3855 The configuration file is arranged into sections like an \s-1INI\s0 file. Each
3856 section begins with [section\-name] and ends with [/section\-name]. Each
3857@@ -799,7 +810,7 @@
3858 files are still useful, though.
3859 .PP
3860 The first line in the file is innotop's version number. This lets innotop
3861-notice when the file format is not backwards\-compatible, and upgrade smoothly
3862+notice when the file format is not backwards-compatible, and upgrade smoothly
3863 without destroying your customized configuration.
3864 .PP
3865 The following list describes each section of the configuration file and the data
3866@@ -807,7 +818,7 @@
3867 .IP "general" 4
3868 .IX Item "general"
3869 The 'general' section contains global configuration variables and variables that
3870-may be mode\-specific, but don't belong in any other section. The syntax is a
3871+may be mode-specific, but don't belong in any other section. The syntax is a
3872 simple key=value list. innotop writes a comment above each value to help you
3873 edit the file by hand.
3874 .RS 4
3875@@ -902,7 +913,8 @@
3876 \&\*(L"shorten\*(R", and \*(L"percent\*(R" transformations.
3877 .IP "num_status_sets" 4
3878 .IX Item "num_status_sets"
3879-Controls how many sets of status variables to display in pivoted \*(L"S: Variables & Status\*(R" mode. It also controls the number of old sets of variables innotop
3880+Controls how many sets of status variables to display in pivoted \*(L"S: Variables
3881+& Status\*(R" mode. It also controls the number of old sets of variables innotop
3882 keeps in its memory, so the larger this variable is, the more memory innotop
3883 uses.
3884 .IP "plugin_dir" 4
3885@@ -911,8 +923,7 @@
3886 \&'plugins' subdirectory of your innotop configuration directory.
3887 .IP "readonly" 4
3888 .IX Item "readonly"
3889-Whether the configuration file is readonly. This cannot be set interactively,
3890-because it would prevent itself from being written to the configuration file.
3891+Whether the configuration file is readonly. This cannot be set interactively.
3892 .IP "show_cxn_errors" 4
3893 .IX Item "show_cxn_errors"
3894 Makes innotop print connection errors to \s-1STDOUT\s0. See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R".
3895@@ -926,7 +937,8 @@
3896 transformation.
3897 .IP "show_statusbar" 4
3898 .IX Item "show_statusbar"
3899-Controls whether to show the status bar in the display. See \*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R".
3900+Controls whether to show the status bar in the display. See \*(L"\s-1INNOTOP\s0
3901+\&\s-1STATUS\s0\*(R".
3902 .IP "skip_innodb" 4
3903 .IX Item "skip_innodb"
3904 Disables fetching \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, in case your server(s) do not have InnoDB
3905@@ -966,10 +978,12 @@
3906 name=quoted\-value list.
3907 .IP "connections" 4
3908 .IX Item "connections"
3909-This section holds the server connections you have defined. Each line is in the
3910-format name=properties, where the properties are a name=value list. The
3911-properties are self\-explanatory, and the only one that is treated specially is
3912-\&'pass' which is only present if 'savepass' is set. See \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R".
3913+This section holds the server connections you have defined. Each line is in
3914+the format name=properties, where the properties are a name=value list. The
3915+properties are self-explanatory, and the only one that is treated specially is
3916+\&'pass' which is only present if 'savepass' is set. This section of the
3917+configuration file will be skipped if any \s-1DSN\s0, username, or password
3918+command-line options are used. See \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R".
3919 .IP "active_connections" 4
3920 .IX Item "active_connections"
3921 This section holds a list of which connections are active in each mode. Each
3922@@ -1025,7 +1039,7 @@
3923 Choose which columns are in those tables, and create new columns.
3924 .IP "\(bu" 4
3925 Filter which rows display with built-in filters, user-defined filters, and
3926-quick\-filters.
3927+quick-filters.
3928 .IP "\(bu" 4
3929 Sort the rows to put important data first or group together related rows.
3930 .IP "\(bu" 4
3931@@ -1039,7 +1053,7 @@
3932 you unlimited flexibility.
3933 .PP
3934 All these and more are explained in the following sections.
3935-.Sh "\s-1TABLES\s0"
3936+.SS "\s-1TABLES\s0"
3937 .IX Subsection "TABLES"
3938 A table is what you'd expect: a collection of columns. It also has some other
3939 properties, such as a caption. Filters, sorting rules, and colorization rules
3940@@ -1192,7 +1206,7 @@
3941 .IP "wait_array" 4
3942 .IX Item "wait_array"
3943 Displays data about InnoDB's \s-1OS\s0 wait array. Data source: \*(L"\s-1OS_WAIT_ARRAY\s0\*(R".
3944-.Sh "\s-1COLUMNS\s0"
3945+.SS "\s-1COLUMNS\s0"
3946 .IX Subsection "COLUMNS"
3947 Columns belong to tables. You can choose a table's columns by pressing the '^'
3948 key, which starts the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" and lets you choose and edit columns.
3949@@ -1200,7 +1214,7 @@
3950 .IP "\(bu" 4
3951 hdr: a column header. This appears in the first row of the table.
3952 .IP "\(bu" 4
3953-just: justification. '\-' means left-justified and '' means right\-justified,
3954+just: justification. '\-' means left-justified and '' means right-justified,
3955 just as with printf formatting codes (not a coincidence).
3956 .IP "\(bu" 4
3957 dec: whether to further align the column on the decimal point.
3958@@ -1230,12 +1244,12 @@
3959 the table. Several columns are set this way, such as the count column on
3960 \&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R", so you don't see a count when the
3961 grouping isn't enabled, but you do when it is.
3962-.Sh "\s-1FILTERS\s0"
3963+.SS "\s-1FILTERS\s0"
3964 .IX Subsection "FILTERS"
3965 Filters remove rows from the display. They behave much like a \s-1WHERE\s0 clause in
3966 \&\s-1SQL\s0. innotop has several built-in filters, which remove irrelevant information
3967 like inactive queries, but you can define your own as well. innotop also lets
3968-you create quick\-filters, which do not get saved to the configuration file, and
3969+you create quick-filters, which do not get saved to the configuration file, and
3970 are just an easy way to quickly view only some rows.
3971 .PP
3972 You can enable or disable a filter on any table. Press the '%' key (mnemonic: %
3973@@ -1255,7 +1269,7 @@
3974 For example, imagine you want to filter the processlist table so you only see
3975 queries that have been running more than five minutes. Type a new name for your
3976 filter, and when prompted for the subroutine body, press \s-1TAB\s0 to initiate your
3977-terminal's auto\-completion. You'll see the names of the columns in the
3978+terminal's auto-completion. You'll see the names of the columns in the
3979 \&\*(L"processlist\*(R" table (innotop generally tries to help you with auto-completion
3980 lists). You want to filter on the 'time' column. Type the text \*(L"$set\->{time} >
3981 300\*(R" to return true when the query is more than five minutes old. That's all
3982@@ -1279,7 +1293,7 @@
3983 .IX Subsection "QUICK-FILTERS"
3984 .PP
3985 innotop's quick-filters are a shortcut to create a temporary filter that doesn't
3986-persist when you restart innotop. To create a quick\-filter, press the '/' key.
3987+persist when you restart innotop. To create a quick-filter, press the '/' key.
3988 innotop will prompt you for the column name and filter text. Again, you can use
3989 auto-completion on column names. The filter text can be just the text you want
3990 to \*(L"search for.\*(R" For example, to filter the \*(L"processlist\*(R" table on queries
3991@@ -1292,9 +1306,9 @@
3992 filter that is otherwise like any other filter. It just isn't saved to the
3993 configuration file.
3994 .PP
3995-To clear quick\-filters, press the '\e' key and innotop will clear them all at
3996+To clear quick-filters, press the '\e' key and innotop will clear them all at
3997 once.
3998-.Sh "\s-1SORTING\s0"
3999+.SS "\s-1SORTING\s0"
4000 .IX Subsection "SORTING"
4001 innotop has sensible built-in defaults to sort the most important rows to the
4002 top of the table. Like anything else in innotop, you can customize how any
4003@@ -1311,9 +1325,9 @@
4004 .PP
4005 Some modes have keys mapped to open this dialog directly, and to quickly reverse
4006 sort direction. Press '?' as usual to see which keys are mapped in any mode.
4007-.Sh "\s-1GROUPING\s0"
4008+.SS "\s-1GROUPING\s0"
4009 .IX Subsection "GROUPING"
4010-innotop can group, or aggregate, rows together (I use the terms
4011+innotop can group, or aggregate, rows together (the terms are used
4012 interchangeably). This is quite similar to an \s-1SQL\s0 \s-1GROUP\s0 \s-1BY\s0 clause. You can
4013 specify to group on certain columns, or if you don't specify any, the entire set
4014 of rows is treated as one group. This is quite like \s-1SQL\s0 so far, but unlike \s-1SQL\s0,
4015@@ -1365,9 +1379,7 @@
4016 .PP
4017 .Vb 1
4018 \& Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38\-log
4019-.Ve
4020-.PP
4021-.Vb 5
4022+\&
4023 \& CXN Cmd Cnt ID User Host Time Query
4024 \& localhost Query 49 12933 webusr localhost 19:38 SELECT * FROM
4025 \& localhost Sending Da 23 2383 webusr localhost 12:43 SELECT col1,
4026@@ -1383,7 +1395,7 @@
4027 milliseconds to optimize queries. You might not have seen this pattern if you
4028 didn't look at your connections in aggregate. (This is a made-up example, but
4029 it can happen in real life).
4030-.Sh "\s-1PIVOTING\s0"
4031+.SS "\s-1PIVOTING\s0"
4032 .IX Subsection "PIVOTING"
4033 innotop can pivot a table for more compact display, similar to a Pivot Table in
4034 a spreadsheet (also known as a crosstab). Pivoting a table makes columns into
4035@@ -1407,7 +1419,7 @@
4036 .PP
4037 To get reasonable results, you might need to group as well as pivoting.
4038 innotop currently does this for \*(L"S: Variables & Status\*(R" mode.
4039-.Sh "\s-1COLORS\s0"
4040+.SS "\s-1COLORS\s0"
4041 .IX Subsection "COLORS"
4042 By default, innotop highlights rows with color so you can see at a glance which
4043 rows are more important. You can customize the colorization rules and add your
4044@@ -1451,7 +1463,7 @@
4045 for example in the first rule above, you should enter 'Locked' surrounded by
4046 quotes. If you get an error message about a bareword, you probably should have
4047 quoted something.
4048-.Sh "\s-1EXPRESSIONS\s0"
4049+.SS "\s-1EXPRESSIONS\s0"
4050 .IX Subsection "EXPRESSIONS"
4051 Expressions are at the core of how innotop works, and are what enables you to
4052 extend innotop as you wish. Recall the table lifecycle explained in
4053@@ -1486,7 +1498,8 @@
4054 \& }
4055 .Ve
4056 .PP
4057-Here's a concrete example, taken from the header table \*(L"q_header\*(R" in \*(L"Q: Query List\*(R" mode. This expression calculates the qps, or Queries Per Second,
4058+Here's a concrete example, taken from the header table \*(L"q_header\*(R" in \*(L"Q:
4059+Query List\*(R" mode. This expression calculates the qps, or Queries Per Second,
4060 column's values, from the values returned by \s-1SHOW\s0 \s-1STATUS:\s0
4061 .PP
4062 .Vb 1
4063@@ -1511,7 +1524,7 @@
4064 Every column in innotop is computed by subroutines compiled in the same fashion.
4065 There is no difference between innotop's built-in columns and user-defined
4066 columns. This keeps things consistent and predictable.
4067-.Sh "\s-1TRANSFORMATIONS\s0"
4068+.SS "\s-1TRANSFORMATIONS\s0"
4069 .IX Subsection "TRANSFORMATIONS"
4070 Transformations change how a value is rendered. For example, they can take a
4071 number of seconds and display it in H:M:S format. The following transformations
4072@@ -1548,7 +1561,7 @@
4073 .IX Item "shorten"
4074 Formats a number as a unit of 1024 (k/M/G/T) and with \*(L"num_digits\*(R" number of
4075 digits after the decimal point.
4076-.Sh "\s-1TABLE\s0 \s-1EDITOR\s0"
4077+.SS "\s-1TABLE\s0 \s-1EDITOR\s0"
4078 .IX Subsection "TABLE EDITOR"
4079 The innotop table editor lets you customize tables with keystrokes. You start
4080 the table editor with the '^' key. If there's more than one table on the
4081@@ -1557,9 +1570,7 @@
4082 .PP
4083 .Vb 1
4084 \& Editing table definition for Buffer Pool. Press ? for help, q to quit.
4085-.Ve
4086-.PP
4087-.Vb 9
4088+\&
4089 \& name hdr label src
4090 \& cxn CXN Connection from which cxn
4091 \& buf_pool_size Size Buffer pool size IB_bp_buf_poo
4092@@ -1568,7 +1579,7 @@
4093 \& pages_modified Dirty Pages Pages modified (dirty IB_bp_pages_m
4094 \& buf_pool_hit_rate Hit Rate Buffer pool hit rate IB_bp_buf_poo
4095 \& total_mem_alloc Memory Total memory allocate IB_bp_total_m
4096-\& add_pool_alloc Add\(aql Pool Additonal pool alloca IB_bp_add_poo
4097+\& add_pool_alloc Add\*(Aql Pool Additonal pool alloca IB_bp_add_poo
4098 .Ve
4099 .PP
4100 The first line shows which table you're editing, and reminds you again to press
4101@@ -1581,7 +1592,7 @@
4102 with a couple of its properties such as its header and source expression (see
4103 \&\*(L"\s-1EXPRESSIONS\s0\*(R").
4104 .PP
4105-The key mappings are Vim\-style, as in many other places. Pressing 'j' and 'k'
4106+The key mappings are Vim-style, as in many other places. Pressing 'j' and 'k'
4107 moves the highlight up or down. You can then (d)elete or (e)dit the highlighted
4108 column. You can also (a)dd a column to the table. This actually just activates
4109 one of the columns already defined for the table; it prompts you to choose from
4110@@ -1601,7 +1612,7 @@
4111 .IP "\(bu" 4
4112 The column header: this is the label that appears at the top of the column, in
4113 the table header. This can have spaces and funny characters, but be careful not
4114-to make it too wide and waste space on\-screen.
4115+to make it too wide and waste space on-screen.
4116 .IP "\(bu" 4
4117 The column's data source: this is an expression that determines what data from
4118 the source (see \*(L"\s-1TABLES\s0\*(R") innotop will put into the column. This can just be
4119@@ -1680,7 +1691,7 @@
4120 .IX Header "PLUGINS"
4121 innotop has a simple but powerful plugin mechanism by which you can extend
4122 or modify its existing functionality, and add new functionality. innotop's
4123-plugin functionality is event\-based: plugins register themselves to be called
4124+plugin functionality is event-based: plugins register themselves to be called
4125 when events happen. They then have a chance to influence the event.
4126 .PP
4127 An innotop plugin is a Perl module placed in innotop's \*(L"plugin_dir\*(R"
4128@@ -1692,7 +1703,7 @@
4129 The module must conform to innotop's plugin interface. Additionally, the source
4130 code of the module must be written in such a way that innotop can inspect the
4131 file and determine the package name and description.
4132-.Sh "Package Source Convention"
4133+.SS "Package Source Convention"
4134 .IX Subsection "Package Source Convention"
4135 innotop inspects the plugin module's source to determine the Perl package name.
4136 It looks for a line of the form \*(L"package Foo;\*(R" and if found, considers the
4137@@ -1700,10 +1711,10 @@
4138 package name, with double semicolons and so on.
4139 .PP
4140 It also looks for a description in the source code, to make the plugin editor
4141-more human\-friendly. The description is a comment line of the form \*(L"#
4142+more human-friendly. The description is a comment line of the form \*(L"#
4143 description: Foo\*(R", where \*(L"Foo\*(R" is the text innotop will consider to be the
4144 plugin's description.
4145-.Sh "Plugin Interface"
4146+.SS "Plugin Interface"
4147 .IX Subsection "Plugin Interface"
4148 The innotop plugin interface is quite simple: innotop expects the plugin to be
4149 an object-oriented module it can call certain methods on. The methods are
4150@@ -1736,7 +1747,7 @@
4151 \&\fIregister_for_events()\fR, it must have \fIfoo()\fR and \fIbar()\fR methods. These methods are
4152 callbacks for the events. See \*(L"Plugin Events\*(R" for more details about each
4153 event.
4154-.Sh "Plugin Variables"
4155+.SS "Plugin Variables"
4156 .IX Subsection "Plugin Variables"
4157 The plugin's constructor is passed a hash of innotop's variables, which it can
4158 manipulate. It is probably a good idea if the plugin object saves a copy of it
4159@@ -1744,7 +1755,7 @@
4160 \&\f(CW%pluggable_vars\fR, and are as follows:
4161 .IP "action_for" 4
4162 .IX Item "action_for"
4163-A hashref of key mappings. These are innotop's global hot\-keys.
4164+A hashref of key mappings. These are innotop's global hot-keys.
4165 .IP "agg_funcs" 4
4166 .IX Item "agg_funcs"
4167 A hashref of functions that can be used for grouping. See \*(L"\s-1GROUPING\s0\*(R".
4168@@ -1770,7 +1781,7 @@
4169 A hashref of server groups. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R".
4170 .IP "tbl_meta" 4
4171 .IX Item "tbl_meta"
4172-A hashref of innotop's table meta\-data, with one entry per table (see
4173+A hashref of innotop's table meta-data, with one entry per table (see
4174 \&\*(L"\s-1TABLES\s0\*(R" for more information).
4175 .IP "trans_funcs" 4
4176 .IX Item "trans_funcs"
4177@@ -1778,13 +1789,13 @@
4178 .IP "var_sets" 4
4179 .IX Item "var_sets"
4180 A hashref of variable sets. See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R".
4181-.Sh "Plugin Events"
4182+.SS "Plugin Events"
4183 .IX Subsection "Plugin Events"
4184 Each event is defined somewhere in the innotop source code. When innotop runs
4185 that code, it executes the callback function for each plugin that expressed its
4186 interest in the event. innotop passes some data for each event. The events are
4187 defined in the \f(CW%event_listener_for\fR variable, and are as follows:
4188-.ie n .IP "extract_values($set, $cur\fR, \f(CW$pre\fR, \f(CW$tbl)" 4
4189+.ie n .IP "extract_values($set, $cur, $pre, $tbl)" 4
4190 .el .IP "extract_values($set, \f(CW$cur\fR, \f(CW$pre\fR, \f(CW$tbl\fR)" 4
4191 .IX Item "extract_values($set, $cur, $pre, $tbl)"
4192 This event occurs inside the function that extracts values from a data source.
4193@@ -1803,7 +1814,7 @@
4194 .IX Item "draw_screen($lines)"
4195 This event occurs inside the subroutine that prints the lines to the screen.
4196 \&\f(CW$lines\fR is an arrayref of strings.
4197-.Sh "Simple Plugin Example"
4198+.SS "Simple Plugin Example"
4199 .IX Subsection "Simple Plugin Example"
4200 The easiest way to explain the plugin functionality is probably with a simple
4201 example. The following module adds a column to the beginning of every table and
4202@@ -1811,75 +1822,59 @@
4203 .PP
4204 .Vb 2
4205 \& use strict;
4206-\& use warnings FATAL => \(aqall\(aq;
4207-.Ve
4208-.PP
4209-.Vb 2
4210+\& use warnings FATAL => \*(Aqall\*(Aq;
4211+\&
4212 \& package Innotop::Plugin::Example;
4213-\& # description: Adds an \(aqexample\(aq column to every table
4214-.Ve
4215-.PP
4216-.Vb 4
4217+\& # description: Adds an \*(Aqexample\*(Aq column to every table
4218+\&
4219 \& sub new {
4220 \& my ( $class, %vars ) = @_;
4221-\& # Store reference to innotop\(aqs variables in $self
4222+\& # Store reference to innotop\*(Aqs variables in $self
4223 \& my $self = bless { %vars }, $class;
4224-.Ve
4225-.PP
4226-.Vb 11
4227+\&
4228 \& # Design the example column
4229 \& my $col = {
4230-\& hdr => \(aqExample\(aq,
4231-\& just => \(aq\(aq,
4232+\& hdr => \*(AqExample\*(Aq,
4233+\& just => \*(Aq\*(Aq,
4234 \& dec => 0,
4235 \& num => 1,
4236-\& label => \(aqExample\(aq,
4237-\& src => \(aqexample\(aq, # Get data from this column in the data source
4238-\& tbl => \(aq\(aq,
4239+\& label => \*(AqExample\*(Aq,
4240+\& src => \*(Aqexample\*(Aq, # Get data from this column in the data source
4241+\& tbl => \*(Aq\*(Aq,
4242 \& trans => [],
4243 \& };
4244-.Ve
4245-.PP
4246-.Vb 8
4247+\&
4248 \& # Add the column to every table.
4249 \& my $tbl_meta = $vars{tbl_meta};
4250 \& foreach my $tbl ( values %$tbl_meta ) {
4251 \& # Add the column to the list of defined columns
4252 \& $tbl\->{cols}\->{example} = $col;
4253 \& # Add the column to the list of visible columns
4254-\& unshift @{$tbl\->{visible}}, \(aqexample\(aq;
4255+\& unshift @{$tbl\->{visible}}, \*(Aqexample\*(Aq;
4256 \& }
4257-.Ve
4258-.PP
4259-.Vb 3
4260+\&
4261 \& # Be sure to return a reference to the object.
4262 \& return $self;
4263 \& }
4264-.Ve
4265-.PP
4266-.Vb 5
4267-\& # I\(aqd like to be called when a data set is being rendered into a table, please.
4268+\&
4269+\& # I\*(Aqd like to be called when a data set is being rendered into a table, please.
4270 \& sub register_for_events {
4271 \& my ( $self ) = @_;
4272 \& return qw(set_to_tbl_pre_filter);
4273 \& }
4274-.Ve
4275-.PP
4276-.Vb 8
4277+\&
4278 \& # This method will be called when the event fires.
4279 \& sub set_to_tbl_pre_filter {
4280 \& my ( $self, $rows, $tbl ) = @_;
4281-\& # Set the example column\(aqs data source to the value 1.
4282+\& # Set the example column\*(Aqs data source to the value 1.
4283 \& foreach my $row ( @$rows ) {
4284 \& $row\->{example} = 1;
4285 \& }
4286 \& }
4287-.Ve
4288-.PP
4289-.Vb 1
4290+\&
4291 \& 1;
4292 .Ve
4293-.Sh "Plugin Editor"
4294+.SS "Plugin Editor"
4295 .IX Subsection "Plugin Editor"
4296 The plugin editor lets you view the plugins innotop discovered and activate or
4297 deactivate them. Start the editor by pressing $ to start the configuration
4298@@ -1920,7 +1915,7 @@
4299 Whenever innotop fetches data from MySQL, it adds two extra bits to each set:
4300 cxn and Uptime_hires. cxn is the name of the connection from which the data
4301 came. Uptime_hires is a high-resolution version of the server's Uptime status
4302-variable, which is important if your \*(L"interval\*(R" setting is sub\-second.
4303+variable, which is important if your \*(L"interval\*(R" setting is sub-second.
4304 .PP
4305 Here are the kinds of data sources from which data is extracted:
4306 .IP "\s-1STATUS_VARIABLES\s0" 4
4307@@ -2002,14 +1997,15 @@
4308 I don't know for sure. It also runs on Windows under ActivePerl without
4309 problem.
4310 .PP
4311-I use innotop on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26, 5.1.15,
4312-and 5.2.3. If it doesn't run correctly for you, that is a bug and I hope you
4313-report it.
4314+innotop has been used on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26,
4315+5.1.15, and 5.2.3. If it doesn't run correctly for you, that is a bug that
4316+should be reported.
4317 .SH "FILES"
4318 .IX Header "FILES"
4319-$HOMEDIR/.innotop is used to store configuration information. Files include the
4320-configuration file innotop.ini, the core_dump file which contains verbose error
4321-messages if \*(L"debug\*(R" is enabled, and the plugins/ subdirectory.
4322+\&\f(CW$HOMEDIR\fR/.innotop and/or /etc/innotop are used to store
4323+configuration information. Files include the configuration file innotop.conf,
4324+the core_dump file which contains verbose error messages if \*(L"debug\*(R" is
4325+enabled, and the plugins/ subdirectory.
4326 .SH "GLOSSARY OF TERMS"
4327 .IX Header "GLOSSARY OF TERMS"
4328 .IP "tick" 4
4329@@ -2018,8 +2014,8 @@
4330 displays it.
4331 .SH "ACKNOWLEDGEMENTS"
4332 .IX Header "ACKNOWLEDGEMENTS"
4333-I'm grateful to the following people for various reasons, and hope I haven't
4334-forgotten to include anyone:
4335+The following people and organizations are acknowledged for various reasons.
4336+Hopefully no one has been forgotten.
4337 .PP
4338 Allen K. Smith,
4339 Aurimas Mikalauskas,
4340@@ -2032,6 +2028,7 @@
4341 Dr. Frank Ullrich,
4342 Giuseppe Maxia,
4343 Google.com Site Reliability Engineers,
4344+Google Code,
4345 Jan Pieter Kunst,
4346 Jari Aalto,
4347 Jay Pipes,
4348@@ -2049,9 +2046,9 @@
4349 The Gentoo MySQL Team,
4350 Trevor Price,
4351 Yaar Schnitman,
4352-and probably more people I've neglected to include.
4353+and probably more people that have not been included.
4354 .PP
4355-(If I misspelled your name, it's probably because I'm afraid of putting
4356+(If your name has been misspelled, it's probably out of fear of putting
4357 international characters into this documentation; earlier versions of Perl might
4358 not be able to compile it then).
4359 .SH "COPYRIGHT, LICENSE AND WARRANTY"
4360@@ -2076,11 +2073,12 @@
4361 Execute innotop and press '!' to see this information at any time.
4362 .SH "AUTHOR"
4363 .IX Header "AUTHOR"
4364-Baron Schwartz.
4365+Originally written by Baron Schwartz; currently maintained by Aaron Racine.
4366 .SH "BUGS"
4367 .IX Header "BUGS"
4368 You can report bugs, ask for improvements, and get other help and support at
4369-<http://sourceforge.net/projects/innotop>. There are mailing lists, forums,
4370-a bug tracker, etc. Please use these instead of contacting me directly, as it
4371-makes my job easier and benefits others if the discussions are permanent and
4372-public. Of course, if you need to contact me in private, please do.
4373+<http://code.google.com/p/innotop/>. There are mailing lists, a source code
4374+browser, a bug tracker, etc. Please use these instead of contacting the
4375+maintainer or author directly, as it makes our job easier and benefits others if the
4376+discussions are permanent and public. Of course, if you need to contact us in
4377+private, please do.
4378
4379=== modified file 'bakery/debian-5.1/additions/my.cnf'
4380--- bakery/debian-5.1/additions/my.cnf 2008-10-20 22:54:11 +0000
4381+++ bakery/debian-5.1/additions/my.cnf 2009-10-02 06:45:25 +0000
4382@@ -42,10 +42,6 @@
4383 language = /usr/share/mysql/english
4384 skip-external-locking
4385 #
4386-# For compatibility to other Debian packages that still use
4387-# libmysqlclient10 and libmysqlclient12.
4388-old_passwords = 1
4389-#
4390 # Instead of skip-networking the default is now to listen only on
4391 # localhost which is more compatible and is not less secure.
4392 bind-address = 127.0.0.1
4393@@ -56,22 +52,28 @@
4394 max_allowed_packet = 16M
4395 thread_stack = 128K
4396 thread_cache_size = 8
4397+# This replaces the startup script and checks MyISAM tables if needed
4398+# the first time they are touched
4399+myisam-recover = BACKUP
4400 #max_connections = 100
4401 #table_cache = 64
4402 #thread_concurrency = 10
4403 #
4404 # * Query Cache Configuration
4405 #
4406-query_cache_limit = 1M
4407-query_cache_size = 16M
4408+# Cache only tiny result sets, so we can fit more in the query cache.
4409+query_cache_limit = 128K
4410+query_cache_size = 16M
4411 #
4412 # * Logging and Replication
4413 #
4414 # Both location gets rotated by the cronjob.
4415 # Be aware that this log type is a performance killer.
4416-#log = /var/log/mysql/mysql.log
4417+# As of 5.1 you can enable the log at runtime!
4418+#general_log_file = /var/log/mysql/mysql.log
4419+#general_log = 1
4420 #
4421-# Error logging goes to syslog. This is a Debian improvement :)
4422+# Error logging goes to syslog due to /etc/mysql/conf.d/mysqld_safe_syslog.cnf.
4423 #
4424 # Here you can see queries with especially long duration
4425 #log_slow_queries = /var/log/mysql/mysql-slow.log
4426@@ -118,18 +120,7 @@
4427 key_buffer = 16M
4428
4429 #
4430-# * NDB Cluster
4431-#
4432-# See /usr/share/doc/mysql-server-*/README.Debian for more information.
4433-#
4434-# The following configuration is read by the NDB Data Nodes (ndbd processes)
4435-# not from the NDB Management Nodes (ndb_mgmd processes).
4436-#
4437-# [MYSQL_CLUSTER]
4438-# ndb-connectstring=127.0.0.1
4439-
4440-
4441-#
4442 # * IMPORTANT: Additional settings that can override those from this file!
4443+# The files must end with '.cnf', otherwise they'll be ignored.
4444 #
4445 !includedir /etc/mysql/conf.d/
4446
4447=== removed file 'bakery/debian-5.1/additions/mysql_explain_log.1'
4448=== added file 'bakery/debian-5.1/additions/mysqld_safe_syslog.cnf'
4449--- bakery/debian-5.1/additions/mysqld_safe_syslog.cnf 1970-01-01 00:00:00 +0000
4450+++ bakery/debian-5.1/additions/mysqld_safe_syslog.cnf 2009-10-02 06:45:25 +0000
4451@@ -0,0 +1,2 @@
4452+[mysqld_safe]
4453+syslog
4454
4455=== removed file 'bakery/debian-5.1/additions/mysqlmanager.1'
4456--- bakery/debian-5.1/additions/mysqlmanager.1 2008-10-20 22:54:11 +0000
4457+++ bakery/debian-5.1/additions/mysqlmanager.1 1970-01-01 00:00:00 +0000
4458@@ -1,49 +0,0 @@
4459-.TH mysql 1 "March 2005" "MySQL 4.1" "MySQL database"
4460-.SH NAME
4461-mysqlmanager \- Manages instances of MySQL server.
4462-.SH SYNOPSIS
4463-.B mysqlmanager
4464-[\fIOPTIONS\fR]
4465-.SH DESCRIPTION
4466-Manages instances of MySQL server.
4467-.TP
4468-\-?, \fB\-\-help\fR
4469-Display this help and exit.
4470-.TP
4471-\fB\-P\fR, \fB\-\-port=\fR#
4472-Port number to listen on.
4473-.TP
4474-\fB\-l\fR, \fB\-\-log\fR=\fIname\fR
4475-Path to log file.
4476-.TP
4477-\fB\-b\fR, \fB\-\-bind\-address=\fR#
4478-Address to listen on.
4479-.HP
4480-\fB\-B\fR, \fB\-\-tcp\-backlog=\fR# Size of TCP/IP listen queue.
4481-.HP
4482-\fB\-g\fR, \fB\-\-greeting\fR=\fIname\fR Set greeting on connect.
4483-.TP
4484-\fB\-m\fR, \fB\-\-max\-command\-len=\fR#
4485-Maximum command length.
4486-.TP
4487-\fB\-d\fR, \fB\-\-one\-thread\fR
4488-Use one thread ( for debugging).
4489-.TP
4490-\fB\-C\fR, \fB\-\-connect\-retries=\fR#
4491-Number of attempts to establish MySQL connection.
4492-.TP
4493-\fB\-p\fR, \fB\-\-password\-file\fR=\fIname\fR
4494-Password file for manager.
4495-.HP
4496-\fB\-f\fR, \fB\-\-pid\-file\fR=\fIname\fR Pid file to use.
4497-.TP
4498-\fB\-V\fR, \fB\-\-version\fR
4499-Output version information and exit.
4500-.SH "SEE ALSO"
4501-The full documentation for
4502-.B mysqlmanager
4503-is available in the package mysql-doc-4.1 or on the MySQL
4504-homepage www.mysql.com.
4505-.SH AUTHOR
4506-This manpage was created by Christian Hammers <ch@debian.org>
4507-using help2man.
4508
4509=== modified file 'bakery/debian-5.1/additions/mysqlreport'
4510--- bakery/debian-5.1/additions/mysqlreport 2008-10-20 22:54:11 +0000
4511+++ bakery/debian-5.1/additions/mysqlreport 2009-10-02 06:45:25 +0000
4512@@ -1,6 +1,6 @@
4513 #!/usr/bin/perl -w
4514
4515-# mysqlreport v3.4a Jan 23 2008
4516+# mysqlreport v3.5 Apr 16 2008
4517 # http://hackmysql.com/mysqlreport
4518
4519 # mysqlreport makes an easy-to-read report of important MySQL status values.
4520@@ -33,7 +33,7 @@
4521 my %mycnf; # ~/.my.cnf
4522 my ($tmpfile_fh, $tmpfile);
4523 my ($stat_name, $stat_val, $stat_label);
4524-my ($major, $minor, $patch, $x); # MySQL version
4525+my $MySQL_version;
4526 my (%stats, %vars); # SHOW STATUS, SHOW VARIABLES
4527 my (%DMS_vals, %Com_vals, %ib_vals);
4528 my ($dbh, $query);
4529@@ -92,15 +92,18 @@
4530 $op{'com'} ||= 3;
4531 $op{'c'} ||= 1; # Used in collect_reports() if --r given integer value
4532
4533+$relative_live = 0;
4534+$relative_infiles = 0;
4535+
4536 if(defined $op{'r'})
4537 {
4538- if($op{r}) { $relative_live = 1; }
4539+ if($op{r}) { $relative_live = 1; } # if -r was given an integer value
4540 else { $relative_infiles = 1; }
4541 }
4542
4543 # The report is written to a tmp file first.
4544 # Later it will be moved to $op{'outfile'} or emailed $op{'email'} if needed.
4545-($tmpfile_fh, $tmpfile) = tempfile() or die("Cannot open temporary file for writing: $!\n");
4546+($tmpfile_fh, $tmpfile) = tempfile() or die "Cannot open temporary file for writing: $!\n";
4547
4548 if($op{'detach'})
4549 {
4550@@ -122,30 +125,12 @@
4551 select $tmpfile_fh;
4552 $| = 1 if ($op{'detach'} || $relative_live);
4553
4554+print "tmp file: $tmpfile\n" if $op{debug};
4555+
4556 # Connect to MySQL
4557 if(!$op{'infile'} && !$relative_infiles)
4558 {
4559- my $dsn;
4560-
4561- if($mycnf{'socket'} && -S $mycnf{'socket'})
4562- {
4563- $dsn = "DBI:mysql:mysql_socket=$mycnf{socket}";
4564- }
4565- elsif($mycnf{'host'})
4566- {
4567- $dsn = "DBI:mysql:host=$mycnf{host}" . ($mycnf{port} ? ";port=$mycnf{port}" : "");
4568- }
4569- else
4570- {
4571- $dsn = "DBI:mysql:host=localhost";
4572- }
4573-
4574- if($op{debug})
4575- {
4576- print "DBI DSN: $dsn\n";
4577- }
4578-
4579- $dbh = DBI->connect($dsn, $mycnf{'user'}, $mycnf{'pass'}) or die;
4580+ connect_to_MySQL();
4581 }
4582
4583 $have_innodb_vals = 1; # This might be set to 0 later in get_MySQL_version()
4584@@ -192,7 +177,7 @@
4585 sub show_help_and_exit
4586 {
4587 print <<"HELP";
4588-mysqlreport v3.4a Jan 23 2008
4589+mysqlreport v3.5 Apr 16 2008
4590 mysqlreport makes an easy-to-read report of important MySQL status values.
4591
4592 Command line options (abbreviations work):
4593@@ -224,6 +209,8 @@
4594
4595 sub get_user_mycnf
4596 {
4597+ print "get_user_mycnf\n" if $op{debug};
4598+
4599 return if $WIN;
4600 open MYCNF, "$ENV{HOME}/.my.cnf" or return;
4601 while(<MYCNF>)
4602@@ -238,8 +225,34 @@
4603 close MYCNF;
4604 }
4605
4606+sub connect_to_MySQL
4607+{
4608+ print "connect_to_MySQL\n" if $op{debug};
4609+
4610+ my $dsn;
4611+
4612+ if($mycnf{'socket'} && -S $mycnf{'socket'})
4613+ {
4614+ $dsn = "DBI:mysql:mysql_socket=$mycnf{socket}";
4615+ }
4616+ elsif($mycnf{'host'})
4617+ {
4618+ $dsn = "DBI:mysql:host=$mycnf{host}" . ($mycnf{port} ? ";port=$mycnf{port}" : "");
4619+ }
4620+ else
4621+ {
4622+ $dsn = "DBI:mysql:host=localhost";
4623+ }
4624+
4625+ print "connect_to_MySQL: DBI DSN: $dsn\n" if $op{debug};
4626+
4627+ $dbh = DBI->connect($dsn, $mycnf{'user'}, $mycnf{'pass'}) or die;
4628+}
4629+
4630 sub collect_reports
4631 {
4632+ print "collect_reports\n" if $op{debug};
4633+
4634 my $i;
4635
4636 get_vals();
4637@@ -258,8 +271,12 @@
4638
4639 for($i = 0; $i < $op{'c'}; $i++)
4640 {
4641+ $dbh->disconnect();
4642+
4643 sleep($op{'r'});
4644
4645+ connect_to_MySQL();
4646+
4647 print "\n#\n# Interval report " , $i + 1 , ", +", sec_to_dhms(($i + 1) * $op{'r'}), "\n#\n";
4648
4649 get_vals();
4650@@ -270,6 +287,8 @@
4651
4652 sub read_relative_infiles
4653 {
4654+ print "read_relative_infiles\n" if $op{debug};
4655+
4656 my $slurp; # Used to check infiles for multiple sets of status values
4657 my $n_stats; # Number of multiple sets of status values in an infile
4658 my $infile;
4659@@ -309,12 +328,12 @@
4660 for($i = 0; $i < $n_stats; $i++)
4661 {
4662 my ($fh, $name) = tempfile()
4663- or die("read_relative_infiles: cannot open temporary file for writing: $!\n");
4664+ or die "read_relative_infiles: cannot open temporary file for writing: $!\n";
4665
4666 push(@tmpfile_fh, $fh);
4667 push(@tmpfile_name, $name);
4668
4669- print "read_relative_infiles: created tmp file '$name'\n" if $op{debug};
4670+ print "read_relative_infiles: created tmp file '$name' for set $i\n" if $op{debug};
4671 }
4672
4673 $i = 0;
4674@@ -322,31 +341,27 @@
4675
4676 select $tmpfile_fh[$i];
4677
4678- # Read infile again and copy each set of status values
4679- # to seperate tmp files
4680+ # Read infile again and copy each set of status values to seperate tmp files
4681 open INFILE, "< $infile" or warn and next;
4682 while(<INFILE>)
4683 {
4684 next if /^\+/;
4685 next if /^$/;
4686
4687- print;
4688+ # The infile must begin with the system variable values.
4689+ # Therefore, the first occurance of Aborted_clients indicates the beginning
4690+ # of the first set of status values if no sets have occured yet ($stat_n == 0).
4691+ # In this case, the following status values are printed to the current fh,
4692+ # along with the system variable values read thus far, until Aborted_clients
4693+ # occurs again. Then begins the second and subsequent sets of status values.
4694
4695 if(/Aborted_clients/)
4696 {
4697- # The infile should begin with manually inserted system
4698- # var values (like key_buffer_size = 128M). Therefore,
4699- # the first occurance of /Aborted_clients/ indicates
4700- # the first set of status values only if no sets have
4701- # occured yet ($stat_n = 0). In this case, the following
4702- # status values are printed to the current fh along with
4703- # the system var values read so far until /Aborted_clients/
4704- # occurs again. Then begins the second and subsequent sets
4705- # of status values.
4706- next if $stat_n++ == 0;
4707-
4708+ print and next if $stat_n++ == 0;
4709 select $tmpfile_fh[++$i];
4710 }
4711+
4712+ print;
4713 }
4714 close INFILE;
4715
4716@@ -357,13 +372,16 @@
4717 {
4718 close $tmpfile_fh[$i];
4719
4720+ print "read_relative_infiles: reading set $i tmp file '$tmpfile_name[$i]'\n"
4721+ if $op{debug};
4722+
4723 read_infile($tmpfile_name[$i]);
4724 relative_infile_report($report_n++);
4725
4726 if($WIN) { `del $tmpfile_name[$i]`; }
4727 else { `rm -f $tmpfile_name[$i]`; }
4728
4729- print "read_relative_infiles: deleted tmp file '$tmpfile_name[$i]'\n"
4730+ print "read_relative_infiles: deleted set $i tmp file '$tmpfile_name[$i]'\n"
4731 if $op{debug};
4732 }
4733
4734@@ -373,6 +391,8 @@
4735
4736 sub relative_infile_report
4737 {
4738+ print "relative_infile_report\n" if $op{debug};
4739+
4740 my $report_n = shift;
4741
4742 if($report_n == 1)
4743@@ -400,10 +420,12 @@
4744
4745 sub get_vals
4746 {
4747+ print "get_vals\n" if $op{debug};
4748+
4749 my @row;
4750
4751 # Get status values
4752- if($major >= 5 && (($minor == 0 && $patch >= 2) || $minor > 0))
4753+ if($MySQL_version >= 50002)
4754 {
4755 $query = $dbh->prepare("SHOW GLOBAL STATUS;");
4756 }
4757@@ -419,6 +441,8 @@
4758
4759 sub get_vars
4760 {
4761+ print "get_vars\n" if $op{debug};
4762+
4763 my @row;
4764
4765 # Get server system variables
4766@@ -427,7 +451,7 @@
4767 while(@row = $query->fetchrow_array()) { $vars{$row[0]} = $row[1]; }
4768
4769 # table_cache was renamed to table_open_cache in MySQL 5.1.3
4770- if($major >= 5 && (($minor == 1 && $patch >= 3) || $minor > 1))
4771+ if($MySQL_version >= 50103)
4772 {
4773 $vars{'table_cache'} = $vars{'table_open_cache'};
4774 }
4775@@ -435,9 +459,14 @@
4776
4777 sub read_infile
4778 {
4779+ print "read_infile\n" if $op{debug};
4780+
4781 my $infile = shift;
4782
4783- # Default values if not set in INFILE
4784+ # Default required system variable values if not set in INFILE.
4785+ # As of mysqlreport v3.5 the direct output from SHOW VARIABLES;
4786+ # can be put into INFILE instead. See http://hackmysql.com/mysqlreportdoc
4787+ # for details.
4788 $vars{'version'} = "0.0.0" if !exists $vars{'version'};
4789 $vars{'table_cache'} = 64 if !exists $vars{'table_cache'};
4790 $vars{'max_connections'} = 100 if !exists $vars{'max_connections'};
4791@@ -450,34 +479,80 @@
4792 # One should also add:
4793 # key_cache_block_size
4794 # query_cache_size
4795- # to their infile if needed.
4796-
4797- open INFILE, "< $infile" or warn;
4798+ # to INFILE if needed.
4799+
4800+ open INFILE, "< $infile" or die "Cannot open INFILE '$infile': $!\n";
4801+
4802 while(<INFILE>)
4803 {
4804- next if /^\+\-/;
4805- next if /^$/;
4806-
4807- chomp;
4808-
4809- if(/([A-Za-z_]+)[\s\t|]+(\d+)/)
4810- {
4811- $stats{$1} = $2;
4812- next;
4813- }
4814-
4815- # Explicit var = val (e.g. key_buffer_size = 128M)
4816- if( /^\s*(\w+)\s*=\s*([0-9.]+)(M*)\s*$/ )
4817- {
4818- $vars{$1} = ($3 ? $2 * 1024 * 1024 : $2);
4819- print "read_infile: read '$_' as $1 = $vars{$1}\n" if $op{debug};
4820- next;
4821+ last if !defined $_;
4822+
4823+ next if /^\+/; # skip divider lines
4824+ next if /^$/; # skip blank lines
4825+
4826+ next until /(Aborted_clients|back_log|=)/;
4827+
4828+ if($1 eq 'Aborted_clients') # status values
4829+ {
4830+ print "read_infile: start stats\n" if $op{debug};
4831+
4832+ while($_)
4833+ {
4834+ chomp;
4835+ if(/([A-Za-z_]+)[\s\t|]+(\d+)/)
4836+ {
4837+ $stats{$1} = $2;
4838+ print "read_infile: save $1 = $2\n" if $op{debug};
4839+ }
4840+ else { print "read_infile: ignore '$_'\n" if $op{debug}; }
4841+
4842+ last if $1 eq 'Uptime'; # exit while() if end of status values
4843+ $_ = <INFILE>; # otherwise, read next line of status values
4844+ }
4845+ }
4846+ elsif($1 eq 'back_log') # system variable values
4847+ {
4848+ print "read_infile: start vars\n" if $op{debug};
4849+
4850+ while($_)
4851+ {
4852+ chomp;
4853+ if(/([A-Za-z_]+)[\s\t|]+([\w\.\-]+)/) # This will exclude some vars
4854+ { # like pid_file which we don't need
4855+ $vars{$1} = $2;
4856+ print "read_infile: save $1 = $2\n" if $op{debug};
4857+ }
4858+ else { print "read_infile: ignore '$_'\n" if $op{debug}; }
4859+
4860+ last if $1 eq 'wait_timeout'; # exit while() if end of vars
4861+ $_ = <INFILE>; # otherwise, read next line of vars
4862+ }
4863+ }
4864+ elsif($1 eq '=') # old style, manually added system variable values
4865+ {
4866+ print "read_infile: start old vars\n" if $op{debug};
4867+
4868+ while($_ && $_ =~ /=/)
4869+ {
4870+ chomp;
4871+ if(/^\s*(\w+)\s*=\s*([0-9.]+)(M*)\s*$/) # e.g.: key_buffer_size = 128M
4872+ {
4873+ $vars{$1} = ($3 ? $2 * 1024 * 1024 : $2);
4874+ print "read_infile: read '$_' as $1 = $vars{$1}\n" if $op{debug};
4875+ }
4876+ else { print "read_infile: ignore '$_'\n" if $op{debug}; }
4877+
4878+ $_ = <INFILE>; # otherwise, read next line of old vars
4879+ }
4880+
4881+ redo;
4882 }
4883 else
4884 {
4885 print "read_infile: unrecognized line: '$_'\n" if $op{debug};
4886 }
4887 }
4888+
4889 close INFILE;
4890
4891 $real_uptime = $stats{'Uptime'};
4892@@ -489,7 +564,11 @@
4893
4894 sub get_MySQL_version
4895 {
4896- return if $major;
4897+ print "get_MySQL_version\n" if $op{debug};
4898+
4899+ return if $MySQL_version;
4900+
4901+ my ($major, $minor, $patch);
4902
4903 if($op{'infile'} || $relative_infiles)
4904 {
4905@@ -505,8 +584,10 @@
4906 ($major, $minor, $patch) = ($row[1] =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/);
4907 }
4908
4909+ $MySQL_version = sprintf("%d%02d%02d", $major, $minor, $patch);
4910+
4911 # Innodb_ status values were added in 5.0.2
4912- if($major <= 4 || $patch < 2)
4913+ if($MySQL_version < 50002)
4914 {
4915 $have_innodb_vals = 0;
4916 print "get_MySQL_version: no InnoDB reports because MySQL version is older than 5.0.2\n" if $op{debug};
4917@@ -515,6 +596,8 @@
4918
4919 sub set_myisam_vals
4920 {
4921+ print "set_myisam_vals\n" if $op{debug};
4922+
4923 $questions = $stats{'Questions'};
4924
4925 $key_read_ratio = sprintf "%.2f",
4926@@ -554,12 +637,14 @@
4927
4928 $dms = $DMS_vals{SELECT} + $DMS_vals{INSERT} + $DMS_vals{REPLACE} + $DMS_vals{UPDATE} + $DMS_vals{DELETE};
4929
4930- $slow_query_t = "($vars{long_query_time})";
4931+ $slow_query_t = format_u_time($vars{long_query_time});
4932
4933 }
4934
4935 sub set_ib_vals
4936 {
4937+ print "set_ib_vals\n" if $op{debug};
4938+
4939 $ib_bp_used = ($stats{'Innodb_buffer_pool_pages_total'} -
4940 $stats{'Innodb_buffer_pool_pages_free'}) *
4941 $stats{'Innodb_page_size'};
4942@@ -575,65 +660,69 @@
4943
4944 sub write_relative_report
4945 {
4946- %stats_present = %stats;
4947-
4948- for(keys %stats)
4949- {
4950- if($stats_past{$_} =~ /\d+/)
4951- {
4952- if($stats_present{$_} >= $stats_past{$_}) # Avoid negative values
4953- {
4954- $stats{$_} = $stats_present{$_} - $stats_past{$_};
4955- }
4956- }
4957- }
4958-
4959- # These values are either "at present" or "high water marks".
4960- # Therefore, it is more logical to not relativize these values.
4961- # Doing otherwise causes strange and misleading values.
4962- $stats{'Key_blocks_used'} = $stats_present{'Key_blocks_used'};
4963- $stats{'Open_tables'} = $stats_present{'Open_tables'};
4964- $stats{'Max_used_connections'} = $stats_present{'Max_used_connections'};
4965- $stats{'Threads_running'} = $stats_present{'Threads_running'};
4966- $stats{'Threads_connected'} = $stats_present{'Threads_connected'};
4967- $stats{'Threads_cached'} = $stats_present{'Threads_cached'};
4968- $stats{'Qcache_free_blocks'} = $stats_present{'Qcache_free_blocks'};
4969- $stats{'Qcache_total_blocks'} = $stats_present{'Qcache_total_blocks'};
4970- $stats{'Qcache_free_memory'} = $stats_present{'Qcache_free_memory'};
4971- if($have_innodb_vals)
4972- {
4973- $stats{'Innodb_page_size'} = $stats_present{'Innodb_page_size'};
4974- $stats{'Innodb_buffer_pool_pages_data'} = $stats_present{'Innodb_buffer_pool_pages_data'};
4975- $stats{'Innodb_buffer_pool_pages_dirty'} = $stats_present{'Innodb_buffer_pool_pages_dirty'};
4976- $stats{'Innodb_buffer_pool_pages_free'} = $stats_present{'Innodb_buffer_pool_pages_free'};
4977- $stats{'Innodb_buffer_pool_pages_latched'} = $stats_present{'Innodb_buffer_pool_pages_latched'};
4978- $stats{'Innodb_buffer_pool_pages_misc'} = $stats_present{'Innodb_buffer_pool_pages_misc'};
4979- $stats{'Innodb_buffer_pool_pages_total'} = $stats_present{'Innodb_buffer_pool_pages_total'};
4980- $stats{'Innodb_data_pending_fsyncs'} = $stats_present{'Innodb_data_pending_fsyncs'};
4981- $stats{'Innodb_data_pending_reads'} = $stats_present{'Innodb_data_pending_reads'};
4982- $stats{'Innodb_data_pending_writes'} = $stats_present{'Innodb_data_pending_writes'};
4983-
4984- # Innodb_row_lock_ values were added in MySQL 5.0.3
4985- if((($minor == 0 && $patch >= 3) || $minor > 0))
4986- {
4987- $stats{'Innodb_row_lock_current_waits'} = $stats_present{'Innodb_row_lock_current_waits'};
4988- $stats{'Innodb_row_lock_time_avg'} = $stats_present{'Innodb_row_lock_time_avg'};
4989- $stats{'Innodb_row_lock_time_max'} = $stats_present{'Innodb_row_lock_time_max'};
4990- }
4991- }
4992-
4993- get_Com_values();
4994-
4995- %stats_past = %stats_present;
4996-
4997- set_myisam_vals();
4998- set_ib_vals() if $have_innodb_vals;
4999-
5000- write_report();
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches