Merge lp:~percona-toolkit-dev/percona-toolkit/summary-tools-2.1 into lp:percona-toolkit/2.1

Proposed by Daniel Nichter
Status: Merged
Approved by: Daniel Nichter
Approved revision: 239
Merged at revision: 231
Proposed branch: lp:~percona-toolkit-dev/percona-toolkit/summary-tools-2.1
Merge into: lp:percona-toolkit/2.1
Diff against target: 35981 lines (+30662/-3529)
203 files modified
bin/pt-mysql-summary (+2083/-683)
bin/pt-summary (+2022/-839)
lib/bash/alt_cmds.sh (+25/-1)
lib/bash/collect_mysql_info.sh (+263/-0)
lib/bash/collect_system_info.sh (+574/-0)
lib/bash/log_warn_die.sh (+6/-0)
lib/bash/report_formatting.sh (+117/-0)
lib/bash/report_mysql_info.sh (+1391/-0)
lib/bash/report_system_info.sh (+1050/-0)
lib/bash/summary_common.sh (+155/-0)
t/lib/bash/collect_mysql_info.sh (+197/-0)
t/lib/bash/collect_system_info.sh (+307/-0)
t/lib/bash/parse_options.sh.~1~ (+241/-0)
t/lib/bash/report_formatting.sh (+109/-0)
t/lib/bash/report_mysql_info.sh (+734/-0)
t/lib/bash/report_system_info.sh (+1569/-0)
t/lib/bash/report_system_info.t (+212/-0)
t/lib/bash/summary_common.sh (+79/-0)
t/pt-deadlock-logger/basics.t (+1/-1)
t/pt-mysql-summary/find_my_cnf_file.sh (+0/-20)
t/pt-mysql-summary/format_binlog_filters.sh (+0/-12)
t/pt-mysql-summary/format_innodb_status.sh (+0/-147)
t/pt-mysql-summary/format_overall_db_stats.sh (+0/-61)
t/pt-mysql-summary/format_status_variables.sh (+0/-97)
t/pt-mysql-summary/fuzz.sh (+0/-7)
t/pt-mysql-summary/get_mysql_info.sh (+0/-26)
t/pt-mysql-summary/parse_mysqld_instances.sh (+0/-47)
t/pt-mysql-summary/pretty_print_cnf_file.sh (+0/-40)
t/pt-mysql-summary/pt-mysql-summary.t (+54/-2)
t/pt-mysql-summary/samples/expected_output_temp002.txt (+276/-0)
t/pt-mysql-summary/samples/expected_output_temp003.txt (+219/-0)
t/pt-mysql-summary/samples/expected_output_temp004.txt (+218/-0)
t/pt-mysql-summary/samples/expected_output_temp005.txt (+291/-0)
t/pt-mysql-summary/samples/expected_result_report_summary.txt (+257/-0)
t/pt-mysql-summary/samples/mysql-variables-with-semisync.txt (+326/-0)
t/pt-mysql-summary/samples/temp001/mysql-status (+304/-0)
t/pt-mysql-summary/samples/temp001/mysql-variables (+356/-0)
t/pt-mysql-summary/samples/temp002/innodb-status (+118/-0)
t/pt-mysql-summary/samples/temp002/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp002/mysql-databases (+6/-0)
t/pt-mysql-summary/samples/temp002/mysql-plugins (+35/-0)
t/pt-mysql-summary/samples/temp002/mysql-processlist (+12/-0)
t/pt-mysql-summary/samples/temp002/mysql-status (+370/-0)
t/pt-mysql-summary/samples/temp002/mysql-status-defer (+370/-0)
t/pt-mysql-summary/samples/temp002/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp002/mysql-variables (+372/-0)
t/pt-mysql-summary/samples/temp002/mysqld-instances (+4/-0)
t/pt-mysql-summary/samples/temp002/mysqldump (+396/-0)
t/pt-mysql-summary/samples/temp003/innodb-status (+77/-0)
t/pt-mysql-summary/samples/temp003/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp003/mysql-databases (+2/-0)
t/pt-mysql-summary/samples/temp003/mysql-master-logs (+1/-0)
t/pt-mysql-summary/samples/temp003/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/temp003/mysql-plugins (+10/-0)
t/pt-mysql-summary/samples/temp003/mysql-processlist (+9/-0)
t/pt-mysql-summary/samples/temp003/mysql-status (+291/-0)
t/pt-mysql-summary/samples/temp003/mysql-status-defer (+291/-0)
t/pt-mysql-summary/samples/temp003/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp003/mysql-variables (+285/-0)
t/pt-mysql-summary/samples/temp003/mysqld-instances (+2/-0)
t/pt-mysql-summary/samples/temp004/innodb-status (+77/-0)
t/pt-mysql-summary/samples/temp004/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp004/mysql-databases (+3/-0)
t/pt-mysql-summary/samples/temp004/mysql-master-logs (+2/-0)
t/pt-mysql-summary/samples/temp004/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/temp004/mysql-plugins (+10/-0)
t/pt-mysql-summary/samples/temp004/mysql-processlist (+9/-0)
t/pt-mysql-summary/samples/temp004/mysql-status (+291/-0)
t/pt-mysql-summary/samples/temp004/mysql-status-defer (+291/-0)
t/pt-mysql-summary/samples/temp004/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp004/mysql-variables (+285/-0)
t/pt-mysql-summary/samples/temp004/mysqld-instances (+2/-0)
t/pt-mysql-summary/samples/temp005/innodb-status (+108/-0)
t/pt-mysql-summary/samples/temp005/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/temp005/mysql-databases (+3/-0)
t/pt-mysql-summary/samples/temp005/mysql-master-logs (+1/-0)
t/pt-mysql-summary/samples/temp005/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/temp005/mysql-plugins (+28/-0)
t/pt-mysql-summary/samples/temp005/mysql-processlist (+18/-0)
t/pt-mysql-summary/samples/temp005/mysql-status (+304/-0)
t/pt-mysql-summary/samples/temp005/mysql-status-defer (+304/-0)
t/pt-mysql-summary/samples/temp005/mysql-users (+1/-0)
t/pt-mysql-summary/samples/temp005/mysql-variables (+363/-0)
t/pt-mysql-summary/samples/temp005/mysqld-executables (+1/-0)
t/pt-mysql-summary/samples/temp005/mysqld-instances (+4/-0)
t/pt-mysql-summary/samples/temp005/mysqldump (+1084/-0)
t/pt-mysql-summary/samples/tempdir/innodb-status (+77/-0)
t/pt-mysql-summary/samples/tempdir/mysql-config-file (+26/-0)
t/pt-mysql-summary/samples/tempdir/mysql-databases (+3/-0)
t/pt-mysql-summary/samples/tempdir/mysql-master-logs (+3/-0)
t/pt-mysql-summary/samples/tempdir/mysql-master-status (+1/-0)
t/pt-mysql-summary/samples/tempdir/mysql-plugins (+10/-0)
t/pt-mysql-summary/samples/tempdir/mysql-processlist (+9/-0)
t/pt-mysql-summary/samples/tempdir/mysql-status (+291/-0)
t/pt-mysql-summary/samples/tempdir/mysql-status-defer (+291/-0)
t/pt-mysql-summary/samples/tempdir/mysql-users (+5/-0)
t/pt-mysql-summary/samples/tempdir/mysql-variables (+283/-0)
t/pt-mysql-summary/samples/tempdir/mysqld-instances (+4/-0)
t/pt-mysql-summary/samples/tempdir/mysqldump (+328/-0)
t/pt-mysql-summary/samples/tempdir/tempfile (+130/-0)
t/pt-mysql-summary/summarize_binlogs.sh (+0/-13)
t/pt-mysql-summary/summarize_processlist.sh (+0/-64)
t/pt-summary/format_vmstat.sh (+0/-37)
t/pt-summary/parse_arcconf.sh (+0/-176)
t/pt-summary/parse_dmidecode_mem_devices.sh (+0/-104)
t/pt-summary/parse_ethernet_controller_lspci.sh (+0/-11)
t/pt-summary/parse_fdisk.sh (+0/-16)
t/pt-summary/parse_filesystems.sh (+0/-52)
t/pt-summary/parse_free_minus_b.sh (+0/-67)
t/pt-summary/parse_fusionmpt_lsiutil.sh (+0/-50)
t/pt-summary/parse_hpacucli.sh (+0/-26)
t/pt-summary/parse_ip_s_link.sh (+0/-28)
t/pt-summary/parse_lsi_megaraid.sh (+0/-696)
t/pt-summary/parse_netstat.sh (+0/-49)
t/pt-summary/parse_proc_cpuinfo.sh (+0/-74)
t/pt-summary/parse_raid_controller_dmesg.sh (+0/-32)
t/pt-summary/parse_raid_controller_lspci.sh (+0/-39)
t/pt-summary/parse_virtualization_dmesg.sh (+0/-10)
t/pt-summary/pt-summary.t (+12/-2)
t/pt-summary/samples/BSD/freebsd_001/mounted_fs (+7/-0)
t/pt-summary/samples/BSD/freebsd_001/notable_procs (+2/-0)
t/pt-summary/samples/BSD/freebsd_001/processes (+10/-0)
t/pt-summary/samples/BSD/freebsd_001/summary (+10/-0)
t/pt-summary/samples/BSD/freebsd_001/sysctl (+1481/-0)
t/pt-summary/samples/BSD/freebsd_001/uptime (+1/-0)
t/pt-summary/samples/BSD/freebsd_001/vmstat (+7/-0)
t/pt-summary/samples/BSD/netbsd_001/mounted_fs (+5/-0)
t/pt-summary/samples/BSD/netbsd_001/notable_procs (+2/-0)
t/pt-summary/samples/BSD/netbsd_001/proc_cpuinfo_copy (+14/-0)
t/pt-summary/samples/BSD/netbsd_001/processes (+10/-0)
t/pt-summary/samples/BSD/netbsd_001/summary (+10/-0)
t/pt-summary/samples/BSD/netbsd_001/swapctl (+1/-0)
t/pt-summary/samples/BSD/netbsd_001/sysctl (+511/-0)
t/pt-summary/samples/BSD/netbsd_001/uptime (+1/-0)
t/pt-summary/samples/BSD/netbsd_001/vmstat (+7/-0)
t/pt-summary/samples/BSD/openbsd_001/mounted_fs (+4/-0)
t/pt-summary/samples/BSD/openbsd_001/notable_procs (+2/-0)
t/pt-summary/samples/BSD/openbsd_001/processes (+10/-0)
t/pt-summary/samples/BSD/openbsd_001/summary (+10/-0)
t/pt-summary/samples/BSD/openbsd_001/swapctl (+1/-0)
t/pt-summary/samples/BSD/openbsd_001/sysctl (+423/-0)
t/pt-summary/samples/BSD/openbsd_001/uptime (+1/-0)
t/pt-summary/samples/BSD/openbsd_001/vmstat (+7/-0)
t/pt-summary/samples/Linux/001/dmesg_file (+786/-0)
t/pt-summary/samples/Linux/001/dmidecode (+412/-0)
t/pt-summary/samples/Linux/001/ip (+24/-0)
t/pt-summary/samples/Linux/001/lspci_file (+17/-0)
t/pt-summary/samples/Linux/001/lvs (+1/-0)
t/pt-summary/samples/Linux/001/memory (+50/-0)
t/pt-summary/samples/Linux/001/mounted_fs (+12/-0)
t/pt-summary/samples/Linux/001/netstat (+6/-0)
t/pt-summary/samples/Linux/001/notable_procs (+5/-0)
t/pt-summary/samples/Linux/001/partitioning (+30/-0)
t/pt-summary/samples/Linux/001/proc_cpuinfo_copy (+58/-0)
t/pt-summary/samples/Linux/001/proc_cpuinfo_copy.unq (+1/-0)
t/pt-summary/samples/Linux/001/processes (+10/-0)
t/pt-summary/samples/Linux/001/summary (+23/-0)
t/pt-summary/samples/Linux/001/sysctl (+905/-0)
t/pt-summary/samples/Linux/001/uptime (+1/-0)
t/pt-summary/samples/Linux/001/vmstat (+7/-0)
t/pt-summary/samples/Linux/002/dmesg_file (+283/-0)
t/pt-summary/samples/Linux/002/memory (+34/-0)
t/pt-summary/samples/Linux/002/mounted_fs (+3/-0)
t/pt-summary/samples/Linux/002/netstat (+6/-0)
t/pt-summary/samples/Linux/002/notable_procs (+2/-0)
t/pt-summary/samples/Linux/002/partitioning (+9/-0)
t/pt-summary/samples/Linux/002/proc_cpuinfo_copy (+19/-0)
t/pt-summary/samples/Linux/002/processes (+10/-0)
t/pt-summary/samples/Linux/002/summary (+19/-0)
t/pt-summary/samples/Linux/002/uptime (+1/-0)
t/pt-summary/samples/Linux/002/vmstat (+7/-0)
t/pt-summary/samples/Linux/003/dmesg_file (+283/-0)
t/pt-summary/samples/Linux/003/memory (+34/-0)
t/pt-summary/samples/Linux/003/mounted_fs (+3/-0)
t/pt-summary/samples/Linux/003/netstat (+6/-0)
t/pt-summary/samples/Linux/003/notable_procs (+2/-0)
t/pt-summary/samples/Linux/003/partitioning (+1/-0)
t/pt-summary/samples/Linux/003/proc_cpuinfo_copy (+19/-0)
t/pt-summary/samples/Linux/003/processes (+10/-0)
t/pt-summary/samples/Linux/003/summary (+19/-0)
t/pt-summary/samples/Linux/003/uptime (+1/-0)
t/pt-summary/samples/Linux/003/vmstat (+7/-0)
t/pt-summary/samples/Linux/output_002.txt (+82/-0)
t/pt-summary/samples/Linux/output_003.txt (+79/-0)
t/pt-summary/samples/MegaCli64_AdpAllInfo_aALL001.txt (+227/-0)
t/pt-summary/samples/MegaCli64_LdPdInfo_aALL_886223 (+214/-0)
t/pt-summary/samples/arcconf-001.txt (+133/-0)
t/pt-summary/samples/arcconf-003_900285.txt (+228/-0)
t/pt-summary/samples/arcconf-004_917781.txt (+162/-0)
t/pt-summary/samples/arcconf-004_917781.txt.bak.~1~ (+162/-0)
t/pt-summary/samples/dmesg-005.txt (+787/-0)
t/pt-summary/samples/dmesg-007.txt (+136/-0)
t/pt-summary/samples/hpaculi-001.txt (+11/-0)
t/pt-summary/samples/hpaculi-002.txt (+354/-0)
t/pt-summary/samples/hpaculi-003.txt (+11/-0)
t/pt-summary/samples/ip-s-link-003.txt (+24/-0)
t/pt-summary/samples/lspci-005.txt (+38/-0)
t/pt-summary/samples/netstat-002.txt (+1328/-0)
t/pt-summary/samples/proc_cpuinfo001.txt (+57/-0)
t/pt-summary/samples/proc_cpuinfo001.txt.unq (+1/-0)
t/pt-summary/samples/proc_cpuinfo002.txt (+57/-0)
t/pt-summary/samples/proc_cpuinfo002.txt.unq (+1/-0)
util/test-bash-functions (+48/-0)
To merge this branch: bzr merge lp:~percona-toolkit-dev/percona-toolkit/summary-tools-2.1
Reviewer Review Type Date Requested Status
Daniel Nichter Approve
Review via email: mp+100545@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Daniel Nichter (daniel-nichter) wrote :

pt-summary and pt-mysql-summary integration tests fail on Debian 6.

review: Needs Fixing
236. By Brian Fraser <email address hidden>

Fix a section() bug.

Turns out that awk's indexes are documented to start from 1;
So what happens if you use 0? Apparently it's undefined behavior, so
substr(var, 0, 5);
and
substr(var, 1, 5);
May or may not actually do the same thing. In Debian 6, the former
doesn't quite work, and actually returns something like substr(var, 1, 4),
which broke section()'s output.

237. By Brian Fraser <email address hidden>

section(): Less printf, more awk

238. By Brian Fraser <email address hidden>

Other instances of the substr(var, 0, n) bug

239. By Brian Fraser <email address hidden>

Fix for a bug in 32-bit Debian.

Namely, awk's printf("%d") doing what it's supposed to do, cast
it's operand to (int), which screws up large numbers.
The fix is simple, although it mostly just pushes the problem
under the rug; using %.0f instead of %d.

Revision history for this message
Daniel Nichter (daniel-nichter) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/pt-mysql-summary'
2--- bin/pt-mysql-summary 2012-03-07 23:41:54 +0000
3+++ bin/pt-mysql-summary 2012-04-03 15:57:31 +0000
4@@ -4,14 +4,421 @@
5 # See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
6 # notices and disclaimers.
7
8+set -u
9+
10+# ###########################################################################
11+# log_warn_die package
12+# This package is a copy without comments from the original. The original
13+# with comments and its test file can be found in the Bazaar repository at,
14+# lib/bash/log_warn_die.sh
15+# t/lib/bash/log_warn_die.sh
16+# See https://launchpad.net/percona-toolkit for more information.
17+# ###########################################################################
18+
19+
20+set -u
21+
22+PTFUNCNAME=""
23+PTDEBUG="${PTDEBUG:-""}"
24+EXIT_STATUS=0
25+
26+log() {
27+ TS=$(date +%F-%T | tr :- _);
28+ echo "$TS $*"
29+}
30+
31+warn() {
32+ log "$*" >&2
33+ EXIT_STATUS=1
34+}
35+
36+die() {
37+ warn "$*"
38+ exit 1
39+}
40+
41+_d () {
42+ [ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
43+}
44+
45+# ###########################################################################
46+# End log_warn_die package
47+# ###########################################################################
48+
49+# ###########################################################################
50+# parse_options package
51+# This package is a copy without comments from the original. The original
52+# with comments and its test file can be found in the Bazaar repository at,
53+# lib/bash/parse_options.sh
54+# t/lib/bash/parse_options.sh
55+# See https://launchpad.net/percona-toolkit for more information.
56+# ###########################################################################
57+
58+
59+
60+
61+
62+set -u
63+
64+ARGV="" # Non-option args (probably input files)
65+EXT_ARGV="" # Everything after -- (args for an external command)
66+HAVE_EXT_ARGV="" # Got --, everything else is put into EXT_ARGV
67+OPT_ERRS=0 # How many command line option errors
68+OPT_VERSION="" # If --version was specified
69+OPT_HELP="" # If --help was specified
70+PO_DIR="" # Directory with program option spec files
71+
72 usage() {
73- if [ "${OPT_ERR}" ]; then
74- echo "${OPT_ERR}" >&2
75- fi
76- echo "Usage: pt-mysql-summary [MYSQL-OPTIONS]" >&2
77- echo "For more information, 'man pt-mysql-summary' or 'perldoc $0'" >&2
78- exit 1
79-}
80+ local file="$1"
81+
82+ local usage=$(grep '^Usage: ' "$file")
83+ echo $usage
84+ echo
85+ echo "For more information, 'man $TOOL' or 'perldoc $file'."
86+}
87+
88+usage_or_errors() {
89+ local file="$1"
90+
91+ if [ "$OPT_VERSION" ]; then
92+ local version=$(grep '^pt-[^ ]\+ [0-9]' "$file")
93+ echo "$version"
94+ return 1
95+ fi
96+
97+ if [ "$OPT_HELP" ]; then
98+ usage "$file"
99+ echo
100+ echo "Command line options:"
101+ echo
102+ perl -e '
103+ use strict;
104+ use warnings FATAL => qw(all);
105+ my $lcol = 20; # Allow this much space for option names.
106+ my $rcol = 80 - $lcol; # The terminal is assumed to be 80 chars wide.
107+ my $name;
108+ while ( <> ) {
109+ my $line = $_;
110+ chomp $line;
111+ if ( $line =~ s/^long:/ --/ ) {
112+ $name = $line;
113+ }
114+ elsif ( $line =~ s/^desc:// ) {
115+ $line =~ s/ +$//mg;
116+ my @lines = grep { $_ }
117+ $line =~ m/(.{0,$rcol})(?:\s+|\Z)/g;
118+ if ( length($name) >= $lcol ) {
119+ print $name, "\n", (q{ } x $lcol);
120+ }
121+ else {
122+ printf "%-${lcol}s", $name;
123+ }
124+ print join("\n" . (q{ } x $lcol), @lines);
125+ print "\n";
126+ }
127+ }
128+ ' "$PO_DIR"/*
129+ echo
130+ echo "Options and values after processing arguments:"
131+ echo
132+ for opt in $(ls "$PO_DIR"); do
133+ local varname="OPT_$(echo "$opt" | tr a-z- A-Z_)"
134+ local varvalue="${!varname}"
135+ printf -- " --%-30s %s" "$opt" "${varvalue:-(No value)}"
136+ echo
137+ done
138+ return 1
139+ fi
140+
141+ if [ $OPT_ERRS -gt 0 ]; then
142+ echo
143+ usage "$file"
144+ return 1
145+ fi
146+
147+ return 0
148+}
149+
150+option_error() {
151+ local err="$1"
152+ OPT_ERRS=$(($OPT_ERRS + 1))
153+ echo "$err" >&2
154+}
155+
156+parse_options() {
157+ local file="$1"
158+ shift
159+
160+ ARGV=""
161+ EXT_ARGV=""
162+ HAVE_EXT_ARGV=""
163+ OPT_ERRS=0
164+ OPT_VERSION=""
165+ OPT_HELP=""
166+ PO_DIR="$TMPDIR/po"
167+
168+ if [ ! -d "$PO_DIR" ]; then
169+ mkdir "$PO_DIR"
170+ if [ $? -ne 0 ]; then
171+ echo "Cannot mkdir $PO_DIR" >&2
172+ exit 1
173+ fi
174+ fi
175+
176+ rm -rf "$PO_DIR"/*
177+ if [ $? -ne 0 ]; then
178+ echo "Cannot rm -rf $PO_DIR/*" >&2
179+ exit 1
180+ fi
181+
182+ _parse_pod "$file" # Parse POD into program option (po) spec files
183+ _eval_po # Eval po into existence with default values
184+
185+ if [ $# -ge 2 ] && [ "$1" = "--config" ]; then
186+ shift # --config
187+ local user_config_files="$1"
188+ shift # that ^
189+ local IFS=","
190+ for user_config_file in $user_config_files; do
191+ _parse_config_files "$user_config_file"
192+ done
193+ else
194+ _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf"
195+ fi
196+
197+ _parse_command_line "$@"
198+}
199+
200+_parse_pod() {
201+ local file="$1"
202+
203+ cat "$file" | PO_DIR="$PO_DIR" perl -ne '
204+ BEGIN { $/ = ""; }
205+ next unless $_ =~ m/^=head1 OPTIONS/;
206+ while ( defined(my $para = <>) ) {
207+ last if $para =~ m/^=head1/;
208+ chomp;
209+ if ( $para =~ m/^=item --(\S+)/ ) {
210+ my $opt = $1;
211+ my $file = "$ENV{PO_DIR}/$opt";
212+ open my $opt_fh, ">", $file or die "Cannot open $file: $!";
213+ print $opt_fh "long:$opt\n";
214+ $para = <>;
215+ chomp;
216+ if ( $para =~ m/^[a-z ]+:/ ) {
217+ map {
218+ chomp;
219+ my ($attrib, $val) = split(/: /, $_);
220+ print $opt_fh "$attrib:$val\n";
221+ } split(/; /, $para);
222+ $para = <>;
223+ chomp;
224+ }
225+ my ($desc) = $para =~ m/^([^?.]+)/;
226+ print $opt_fh "desc:$desc.\n";
227+ close $opt_fh;
228+ }
229+ }
230+ last;
231+ '
232+}
233+
234+_eval_po() {
235+ local IFS=":"
236+ for opt_spec in "$PO_DIR"/*; do
237+ local opt=""
238+ local default_val=""
239+ local neg=0
240+ local size=0
241+ while read key val; do
242+ case "$key" in
243+ long)
244+ opt=$(echo $val | sed 's/-/_/g' | tr [:lower:] [:upper:])
245+ ;;
246+ default)
247+ default_val="$val"
248+ ;;
249+ "short form")
250+ ;;
251+ type)
252+ [ "$val" = "size" ] && size=1
253+ ;;
254+ desc)
255+ ;;
256+ negatable)
257+ if [ "$val" = "yes" ]; then
258+ neg=1
259+ fi
260+ ;;
261+ *)
262+ echo "Invalid attribute in $opt_spec: $line" >&2
263+ exit 1
264+ esac
265+ done < "$opt_spec"
266+
267+ if [ -z "$opt" ]; then
268+ echo "No long attribute in option spec $opt_spec" >&2
269+ exit 1
270+ fi
271+
272+ if [ $neg -eq 1 ]; then
273+ if [ -z "$default_val" ] || [ "$default_val" != "yes" ]; then
274+ echo "Option $opt_spec is negatable but not default: yes" >&2
275+ exit 1
276+ fi
277+ fi
278+
279+ if [ $size -eq 1 -a -n "$default_val" ]; then
280+ default_val=$(size_to_bytes $default_val)
281+ fi
282+
283+ eval "OPT_${opt}"="$default_val"
284+ done
285+}
286+
287+_parse_config_files() {
288+
289+ for config_file in "$@"; do
290+ test -f "$config_file" || continue
291+
292+ while read config_opt; do
293+
294+ echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue
295+
296+ config_opt="$(echo "$config_opt" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/[ ]*=[ ]*/=/' -e 's/[ ]*#.*$//')"
297+
298+ [ "$config_opt" = "" ] && continue
299+
300+ if ! [ "$HAVE_EXT_ARGV" ]; then
301+ config_opt="--$config_opt"
302+ fi
303+
304+ _parse_command_line "$config_opt"
305+
306+ done < "$config_file"
307+
308+ HAVE_EXT_ARGV="" # reset for each file
309+
310+ done
311+}
312+
313+_parse_command_line() {
314+ local opt=""
315+ local val=""
316+ local next_opt_is_val=""
317+ local opt_is_ok=""
318+ local opt_is_negated=""
319+ local real_opt=""
320+ local required_arg=""
321+ local spec=""
322+
323+ for opt in "$@"; do
324+ if [ "$opt" = "--" -o "$opt" = "----" ]; then
325+ HAVE_EXT_ARGV=1
326+ continue
327+ fi
328+ if [ "$HAVE_EXT_ARGV" ]; then
329+ if [ "$EXT_ARGV" ]; then
330+ EXT_ARGV="$EXT_ARGV $opt"
331+ else
332+ EXT_ARGV="$opt"
333+ fi
334+ continue
335+ fi
336+
337+ if [ "$next_opt_is_val" ]; then
338+ next_opt_is_val=""
339+ if [ $# -eq 0 ] || [ $(expr "$opt" : "-") -eq 1 ]; then
340+ option_error "$real_opt requires a $required_arg argument"
341+ continue
342+ fi
343+ val="$opt"
344+ opt_is_ok=1
345+ else
346+ if [ $(expr "$opt" : "-") -eq 0 ]; then
347+ if [ -z "$ARGV" ]; then
348+ ARGV="$opt"
349+ else
350+ ARGV="$ARGV $opt"
351+ fi
352+ continue
353+ fi
354+
355+ real_opt="$opt"
356+
357+ if $(echo $opt | grep '^--no-' >/dev/null); then
358+ opt_is_negated=1
359+ opt=$(echo $opt | sed 's/^--no-//')
360+ else
361+ opt_is_negated=""
362+ opt=$(echo $opt | sed 's/^-*//')
363+ fi
364+
365+ if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
366+ val="$(echo $opt | awk -F= '{print $2}')"
367+ opt="$(echo $opt | awk -F= '{print $1}')"
368+ fi
369+
370+ if [ -f "$TMPDIR/po/$opt" ]; then
371+ spec="$TMPDIR/po/$opt"
372+ else
373+ spec=$(grep "^short form:-$opt\$" "$TMPDIR"/po/* | cut -d ':' -f 1)
374+ if [ -z "$spec" ]; then
375+ option_error "Unknown option: $real_opt"
376+ continue
377+ fi
378+ fi
379+
380+ required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}')
381+ if [ "$required_arg" ]; then
382+ if [ "$val" ]; then
383+ opt_is_ok=1
384+ else
385+ next_opt_is_val=1
386+ fi
387+ else
388+ if [ "$val" ]; then
389+ option_error "Option $real_opt does not take a value"
390+ continue
391+ fi
392+ if [ "$opt_is_negated" ]; then
393+ val=""
394+ else
395+ val="yes"
396+ fi
397+ opt_is_ok=1
398+ fi
399+ fi
400+
401+ if [ "$opt_is_ok" ]; then
402+ opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr [:lower:] [:upper:])
403+
404+ if grep "^type:size" "$spec" >/dev/null; then
405+ val=$(size_to_bytes $val)
406+ fi
407+
408+ eval "OPT_$opt"="'$val'"
409+
410+ opt=""
411+ val=""
412+ next_opt_is_val=""
413+ opt_is_ok=""
414+ opt_is_negated=""
415+ real_opt=""
416+ required_arg=""
417+ spec=""
418+ fi
419+ done
420+}
421+
422+size_to_bytes() {
423+ local size="$1"
424+ echo $size | perl -ne '%f=(B=>1, K=>1_024, M=>1_048_576, G=>1_073_741_824, T=>1_099_511_627_776); m/^(\d+)([kMGT])?/i; print $1 * $f{uc($2 || "B")};'
425+}
426+
427+# ###########################################################################
428+# End parse_options package
429+# ###########################################################################
430
431 # ###########################################################################
432 # tmpdir package
433@@ -22,18 +429,21 @@
434 # See https://launchpad.net/percona-toolkit for more information.
435 # ###########################################################################
436
437+
438+set -u
439+
440 TMPDIR=""
441
442 mk_tmpdir() {
443- local dir=${1:-""}
444+ local dir="${1:-""}"
445
446 if [ -n "$dir" ]; then
447 if [ ! -d "$dir" ]; then
448- mkdir $dir || die "Cannot make tmpdir $dir"
449+ mkdir "$dir" || die "Cannot make tmpdir $dir"
450 fi
451 TMPDIR="$dir"
452 else
453- local tool=`basename $0`
454+ local tool="${0##*/}"
455 local pid="$$"
456 TMPDIR=`mktemp -d /tmp/${tool}.${pid}.XXXXX` \
457 || die "Cannot make secure tmpdir"
458@@ -42,7 +452,7 @@
459
460 rm_tmpdir() {
461 if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then
462- rm -rf $TMPDIR
463+ rm -rf "$TMPDIR"
464 fi
465 TMPDIR=""
466 }
467@@ -51,27 +461,68 @@
468 # End tmpdir package
469 # ###########################################################################
470
471-# ########################################################################
472-# Some global setup is necessary for cross-platform compatibility, even
473-# when sourcing this script for testing purposes.
474-# ########################################################################
475-AP_AWK="$(which awk)"
476-which gawk >/dev/null 2>&1 && AP_AWK="$(which gawk)"
477-AP_SED="$(which sed)"
478-which gsed >/dev/null 2>&1 && AP_SED="$(which gsed)"
479-AP_GREP="$(which grep)"
480-which ggrep >/dev/null 2>&1 && AP_GREP="$(which ggrep)"
481-
482-# ########################################################################
483-# Globals, helper functions
484-# ########################################################################
485-
486-# The awk code for fuzzy rounding. (It's used in a few places, so makes sense
487-# not to duplicate). It fuzzy-rounds the variable named fuzzy_var. It goes in
488-# steps of 5, 10, 25, then repeats by a factor of 10 larger (50, 100, 250), and
489-# so on, until it finds a number that's large enough. The pattern is slightly
490-# broken between the initial 1 and 50, because rounding to the nearest 2.5
491-# doesn't seem right to me.
492+# ###########################################################################
493+# alt_cmds package
494+# This package is a copy without comments from the original. The original
495+# with comments and its test file can be found in the Bazaar repository at,
496+# lib/bash/alt_cmds.sh
497+# t/lib/bash/alt_cmds.sh
498+# See https://launchpad.net/percona-toolkit for more information.
499+# ###########################################################################
500+
501+
502+set -u
503+
504+_seq() {
505+ local i="$1"
506+ awk "BEGIN { for(i=1; i<=$i; i++) print i; }"
507+}
508+
509+_pidof() {
510+ local cmd="$1"
511+ if ! pidof "$cmd" 2>/dev/null; then
512+ ps -eo pid,ucomm | awk -v comm="$cmd" '$2 == comm { print $1 }'
513+ fi
514+}
515+
516+_lsof() {
517+ local pid="$1"
518+ if ! lsof -p $pid 2>/dev/null; then
519+ /bin/ls -l /proc/$pid/fd 2>/dev/null
520+ fi
521+}
522+
523+
524+
525+_which() {
526+ if [ -x /usr/bin/which ]; then
527+ /usr/bin/which "$1" 2>/dev/null | awk '{print $1}'
528+ elif which which 1>/dev/null 2>&1; then
529+ which "$1" 2>/dev/null | awk '{print $1}'
530+ else
531+ echo "$1"
532+ fi
533+}
534+
535+# ###########################################################################
536+# End alt_cmds package
537+# ###########################################################################
538+
539+# ###########################################################################
540+# report_formatting package
541+# This package is a copy without comments from the original. The original
542+# with comments and its test file can be found in the Bazaar repository at,
543+# lib/bash/report_formatting.sh
544+# t/lib/bash/report_formatting.sh
545+# See https://launchpad.net/percona-toolkit for more information.
546+# ###########################################################################
547+
548+
549+set -u
550+
551+POSIXLY_CORRECT=1
552+export POSIXLY_CORRECT
553+
554 fuzzy_formula='
555 rounded = 0;
556 if (fuzzy_var <= 10 ) {
557@@ -94,108 +545,461 @@
558 factor = factor * 10;
559 }'
560
561-# The temp files are for storing working results so we don't call commands many
562-# times (gives inconsistent results, maybe adds load on things I don't want to
563-# such as RAID controllers). They must not exist -- if they did, someone would
564-# symlink them to /etc/passwd and then run this program as root. Call this
565-# function with "rm" or "touch" as an argument.
566-temp_files() {
567- for file in $TMPDIR/percona-toolkit{,-mysql-variables,-mysql-status,-innodb-status} \
568- $TMPDIR/percona-toolkit{2,-mysql-databases,-mysql-processlist,-noncounters} \
569- $TMPDIR/percona-toolkit-mysql{dump,-slave};
570- do
571- case "$1" in
572- touch)
573- if ! touch "${file}"; then
574- echo "I can't make my temp file ${file}";
575- exit 1;
576- fi
577- ;;
578- rm)
579- rm -f "${file}"
580- ;;
581- esac
582- done
583-}
584-
585-# Print a space-padded string into $line. Then translate spaces to hashes, and
586-# underscores to spaces. End result is a line of hashes with words at the
587-# start.
588+fuzz () {
589+ awk -v fuzzy_var="$1" "BEGIN { ${fuzzy_formula} print fuzzy_var;}"
590+}
591+
592+fuzzy_pct () {
593+ local pct="$(awk -v one="$1" -v two="$2" 'BEGIN{ if (two > 0) { printf "%d", one/two*100; } else {print 0} }')";
594+ echo "$(fuzz "${pct}")%"
595+}
596+
597 section () {
598- line="$(printf '#_%-60s' "$1_")"
599- line="${line// /#}"
600- printf "%s\n" "${line//_/ }"
601-}
602-
603-# Print a "name | value" line.
604-name_val() {
605- printf "%20s | %s\n" "$1" "$2"
606-}
607-
608-# Converts a value to units of power of 2. Optional precision is $2.
609+ local str="$1"
610+ awk -v var="${str} _" 'BEGIN {
611+ line = sprintf("# %-60s", var);
612+ i = index(line, "_");
613+ x = substr(line, i);
614+ gsub(/[_ \t]/, "#", x);
615+ printf("%s%s\n", substr(line, 1, i-1), x);
616+ }'
617+}
618+
619+NAME_VAL_LEN=12
620+name_val () {
621+ printf "%+*s | %s\n" "${NAME_VAL_LEN}" "$1" "$2"
622+}
623+
624 shorten() {
625- unit=k
626- size=1024
627- if [ $1 -ge 1099511627776 ] ; then
628- size=1099511627776
629- unit=T
630- elif [ $1 -ge 1073741824 ] ; then
631- size=1073741824
632- unit=G
633- elif [ $1 -ge 1048576 ] ; then
634- size=1048576
635- unit=M
636- fi
637- result=$(echo "$1 $size ${2:-0}" | $AP_AWK '{printf "%." $3 "f", $1 / $2}')
638- echo "${result}${unit}"
639+ local num="$1"
640+ local prec="${2:-2}"
641+ local div="${3:-1024}"
642+
643+ echo "$num" | awk -v prec="$prec" -v div="$div" '
644+ {
645+ size = 4;
646+ val = $1;
647+
648+ unit = val >= 1099511627776 ? "T" : val >= 1073741824 ? "G" : val >= 1048576 ? "M" : val >= 1024 ? "k" : "";
649+
650+ while ( int(val) && !(val % 1024) ) {
651+ val /= 1024;
652+ }
653+
654+ while ( val > 1000 ) {
655+ val /= div;
656+ }
657+
658+ printf "%.*f%s", prec, val, unit;
659+ }
660+ '
661 }
662
663-# Collapse a file into an aggregated list; file must be created with 'sort |
664-# uniq -c'. This function is copy-pasted from 'summary' so see there for full
665-# docs and tests.
666-# ##############################################################################
667 group_concat () {
668- sed -e '{H; $!d}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' ${1}
669-}
670-
671-# Accepts a number of seconds, and outputs a d+h:m:s formatted string
672+ sed -e '{H; $!d;}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' "${1}"
673+}
674+
675+# ###########################################################################
676+# End report_formatting package
677+# ###########################################################################
678+
679+# ###########################################################################
680+# summary_common package
681+# This package is a copy without comments from the original. The original
682+# with comments and its test file can be found in the Bazaar repository at,
683+# lib/bash/summary_common.sh
684+# t/lib/bash/summary_common.sh
685+# See https://launchpad.net/percona-toolkit for more information.
686+# ###########################################################################
687+
688+
689+set -u
690+
691+CMD_FILE="$( _which file 2>/dev/null )"
692+CMD_NM="$( _which nm 2>/dev/null )"
693+CMD_OBJDUMP="$( _which objdump 2>/dev/null )"
694+
695+get_nice_of_pid () {
696+ local pid="$1"
697+ local niceness="$(ps -p $pid -o nice | awk '$1 !~ /[^0-9]/ {print $1; exit}')"
698+
699+ if [ -n "${niceness}" ]; then
700+ echo $niceness
701+ else
702+ local tmpfile="$TMPDIR/nice_through_c.tmp.c"
703+ _d "Getting the niceness from ps failed, somehow. We are about to try this:"
704+ cat <<EOC > "$tmpfile"
705+
706+int main(void) {
707+ int priority = getpriority(PRIO_PROCESS, $pid);
708+ if ( priority == -1 && errno == ESRCH ) {
709+ return 1;
710+ }
711+ else {
712+ printf("%d\\n", priority);
713+ return 0;
714+ }
715+}
716+
717+EOC
718+ local c_comp=$(_which gcc)
719+ if [ -z "${c_comp}" ]; then
720+ c_comp=$(_which cc)
721+ fi
722+ _d "$tmpfile: $( cat "$tmpfile" )"
723+ _d "$c_comp -xc \"$tmpfile\" -o \"$tmpfile\" && eval \"$tmpfile\""
724+ $c_comp -xc "$tmpfile" -o "$tmpfile" 2>/dev/null && eval "$tmpfile" 2>/dev/null
725+ if [ $? -ne 0 ]; then
726+ echo "?"
727+ _d "Failed to get a niceness value for $pid"
728+ fi
729+ fi
730+}
731+
732+get_oom_of_pid () {
733+ local pid="$1"
734+ local oom_adj=""
735+
736+ if [ -n "${pid}" -a -e /proc/cpuinfo ]; then
737+ if [ -s "/proc/$pid/oom_score_adj" ]; then
738+ oom_adj=$(cat "/proc/$pid/oom_score_adj" 2>/dev/null)
739+ _d "For $pid, the oom value is $oom_adj, retreived from oom_score_adj"
740+ else
741+ oom_adj=$(cat "/proc/$pid/oom_adj" 2>/dev/null)
742+ _d "For $pid, the oom value is $oom_adj, retreived from oom_adj"
743+ fi
744+ fi
745+
746+ if [ -n "${oom_adj}" ]; then
747+ echo "${oom_adj}"
748+ else
749+ echo "?"
750+ _d "Can't find the oom value for $pid"
751+ fi
752+}
753+
754+has_symbols () {
755+ local executable="$(_which "$1")"
756+ local has_symbols=""
757+
758+ if [ "${CMD_FILE}" ] \
759+ && [ "$($CMD_FILE "${executable}" | grep 'not stripped' )" ]; then
760+ has_symbols=1
761+ elif [ "${CMD_NM}" ] \
762+ || [ "${CMD_OBJDMP}" ]; then
763+ if [ "${CMD_NM}" ] \
764+ && [ !"$("${CMD_NM}" -- "${executable}" 2>&1 | grep 'File format not recognized' )" ]; then
765+ if [ -z "$( $CMD_NM -- "${executable}" 2>&1 | grep ': no symbols' )" ]; then
766+ has_symbols=1
767+ fi
768+ elif [ -z "$("${CMD_OBJDUMP}" -t -- "${executable}" | grep '^no symbols$' )" ]; then
769+ has_symbols=1
770+ fi
771+ fi
772+
773+ if [ "${has_symbols}" ]; then
774+ echo "Yes"
775+ else
776+ echo "No"
777+ fi
778+}
779+
780+setup_data_dir () {
781+ local existing_dir="$1"
782+ local data_dir=""
783+ if [ -z "$existing_dir" ]; then
784+ mkdir "$TMPDIR/data" || die "Cannot mkdir $TMPDIR/data"
785+ data_dir="$TMPDIR/data"
786+ else
787+ if [ ! -d "$existing_dir" ]; then
788+ mkdir "$existing_dir" || die "Cannot mkdir $existing_dir"
789+ elif [ "$( ls -A "$existing_dir" )" ]; then
790+ die "--save-samples directory isn't empty, halting."
791+ fi
792+ touch "$existing_dir/test" || die "Cannot write to $existing_dir"
793+ rm "$existing_dir/test" || die "Cannot rm $existing_dir/test"
794+ data_dir="$existing_dir"
795+ fi
796+ echo "$data_dir"
797+}
798+
799+get_var () {
800+ local varname="$1"
801+ local file="$2"
802+ awk -v pattern="${varname}" '$1 == pattern { if (length($2)) { len = length($1); print substr($0, len+index(substr($0, len+1), $2)) } }' "${file}"
803+}
804+
805+# ###########################################################################
806+# End summary_common package
807+# ###########################################################################
808+
809+# ###########################################################################
810+# collect_mysql_info package
811+# This package is a copy without comments from the original. The original
812+# with comments and its test file can be found in the Bazaar repository at,
813+# lib/bash/collect_mysql_info.sh
814+# t/lib/bash/collect_mysql_info.sh
815+# See https://launchpad.net/percona-toolkit for more information.
816+# ###########################################################################
817+
818+
819+
820+CMD_MYSQL="${CMD_MYSQL:-""}"
821+CMD_MYSQLDUMP="${CMD_MYSQLDUMP:-""}"
822+
823+collect_mysqld_instances () {
824+ local variables_file="$1"
825+
826+ local pids="$(_pidof mysqld)"
827+
828+ if [ -n "$pids" ]; then
829+
830+ for pid in $pids; do
831+ local nice="$( get_nice_of_pid $pid )"
832+ local oom="$( get_oom_of_pid $pid )"
833+ echo "internal::nice_of_$pid $nice" >> "$variables_file"
834+ echo "internal::oom_of_$pid $oom" >> "$variables_file"
835+ done
836+
837+ pids="$(echo $pids | sed -e 's/ /,/g')"
838+ ps ww -p "$pids" 2>/dev/null
839+ else
840+ echo "mysqld doesn't appear to be running"
841+ fi
842+
843+}
844+
845+find_my_cnf_file() {
846+ local file="$1"
847+ local port="${2:-""}"
848+
849+ local cnf_file=""
850+ if test -n "$port" && grep -- "/mysqld.*--port=$port" "${file}" >/dev/null 2>&1 ; then
851+ cnf_file="$(grep -- "/mysqld.*--port=$port" "${file}" \
852+ | awk 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
853+ | head -n1)"
854+ else
855+ cnf_file="$(grep '/mysqld' "${file}" \
856+ | awk 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
857+ | head -n1)"
858+ fi
859+
860+ if [ ! -n "${cnf_file}" ]; then
861+ cnf_file="/etc/my.cnf";
862+ if [ ! -e "${cnf_file}" ]; then
863+ cnf_file="/etc/mysql/my.cnf";
864+ fi
865+ if [ ! -e "${cnf_file}" ]; then
866+ cnf_file="/var/db/mysql/my.cnf";
867+ fi
868+ fi
869+
870+ echo "$cnf_file"
871+}
872+
873+collect_mysql_variables () {
874+ $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW /*!40100 GLOBAL*/ VARIABLES'
875+}
876+
877+collect_mysql_status () {
878+ $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW /*!50000 GLOBAL*/ STATUS'
879+}
880+
881+collect_mysql_databases () {
882+ $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW DATABASES' 2>/dev/null
883+}
884+
885+collect_mysql_plugins () {
886+ $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW PLUGINS' 2>/dev/null
887+}
888+
889+collect_mysql_slave_status () {
890+ $CMD_MYSQL $EXT_ARGV -ssE -e 'SHOW SLAVE STATUS' 2>/dev/null
891+}
892+
893+collect_mysql_innodb_status () {
894+ $CMD_MYSQL $EXT_ARGV -ssE -e 'SHOW /*!50000 ENGINE*/ INNODB STATUS' 2>/dev/null
895+}
896+
897+collect_mysql_processlist () {
898+ $CMD_MYSQL $EXT_ARGV -ssE -e 'SHOW FULL PROCESSLIST' 2>/dev/null
899+}
900+
901+collect_mysql_users () {
902+ $CMD_MYSQL $EXT_ARGV -ss -e 'SELECT COUNT(*), SUM(user=""), SUM(password=""), SUM(password NOT LIKE "*%") FROM mysql.user' 2>/dev/null
903+}
904+
905+collect_master_logs_status () {
906+ local master_logs_file="$1"
907+ local master_status_file="$2"
908+ $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW MASTER LOGS' > "$master_logs_file" 2>/dev/null
909+ $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW MASTER STATUS' > "$master_status_file" 2>/dev/null
910+}
911+
912+collect_mysql_deferred_status () {
913+ local status_file="$1"
914+ collect_mysql_status > "$TMPDIR/defer_gatherer"
915+ join "$status_file" "$TMPDIR/defer_gatherer"
916+}
917+
918+collect_internal_vars () {
919+ local mysqld_executables="${1:-""}"
920+
921+ local FNV_64=""
922+ if $CMD_MYSQL $EXT_ARGV -e 'SELECT FNV_64("a")' >/dev/null 2>&1; then
923+ FNV_64="Enabled";
924+ else
925+ FNV_64="Unknown";
926+ fi
927+
928+ local now="$($CMD_MYSQL $EXT_ARGV -ss -e 'SELECT NOW()')"
929+ local user="$($CMD_MYSQL $EXT_ARGV -ss -e 'SELECT CURRENT_USER()')"
930+ local trigger_count=$($CMD_MYSQL $EXT_ARGV -ss -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TRIGGERS" 2>/dev/null)
931+
932+ echo "pt-summary-internal-mysql_executable $CMD_MYSQL"
933+ echo "pt-summary-internal-now $now"
934+ echo "pt-summary-internal-user $user"
935+ echo "pt-summary-internal-FNV_64 $FNV_64"
936+ echo "pt-summary-internal-trigger_count $trigger_count"
937+
938+ if [ -e "$mysqld_executables" ]; then
939+ local i=1
940+ while read executable; do
941+ echo "pt-summary-internal-mysqld_executable_${i} $(has_symbols "$executable")"
942+ i=$(($i + 1))
943+ done < "$mysqld_executables"
944+ fi
945+}
946+
947+get_mysqldump_for () {
948+ local args="$1"
949+ local dbtodump="${2:-"--all-databases"}"
950+
951+ $CMD_MYSQLDUMP $EXT_ARGV --no-data --skip-comments \
952+ --skip-add-locks --skip-add-drop-table --compact \
953+ --skip-lock-all-tables --skip-lock-tables --skip-set-charset \
954+ ${args} --databases $( local IFS=,; echo ${dbtodump})
955+}
956+
957+get_mysqldump_args () {
958+ local file="$1"
959+ local trg_arg=""
960+
961+ if $CMD_MYSQLDUMP --help --verbose 2>&1 | grep triggers >/dev/null; then
962+ trg_arg="--routines"
963+ fi
964+
965+ if [ "${trg_arg}" ]; then
966+ local triggers="--skip-triggers"
967+ local trg=$(get_var "pt-summary-internal-trigger_count" "$file" )
968+ if [ -n "${trg}" ] && [ "${trg}" -gt 0 ]; then
969+ triggers="--triggers"
970+ fi
971+ trg_arg="${trg_arg} ${triggers}";
972+ fi
973+ echo "${trg_arg}"
974+}
975+
976+collect_mysqld_executables () {
977+ local mysqld_instances="$1"
978+
979+ for pid in $( grep '/mysqld' "$mysqld_instances" | awk '/^ .*[0-9]/{print $1}' ); do
980+ ps -o cmd -p $pid | sed -e 's/^\(.*mysqld\) .*/\1/' | grep -v '^CMD$'
981+ done | sort -u
982+}
983+
984+collect_mysql_info () {
985+ local dir="$1"
986+
987+ collect_mysql_variables > "$dir/mysql-variables"
988+ collect_mysql_status > "$dir/mysql-status"
989+ collect_mysql_databases > "$dir/mysql-databases"
990+ collect_mysql_plugins > "$dir/mysql-plugins"
991+ collect_mysql_slave_status > "$dir/mysql-slave"
992+ collect_mysql_innodb_status > "$dir/innodb-status"
993+ collect_mysql_processlist > "$dir/mysql-processlist"
994+ collect_mysql_users > "$dir/mysql-users"
995+
996+ collect_mysqld_instances "$dir/mysql-variables" > "$dir/mysqld-instances"
997+ collect_mysqld_executables "$dir/mysqld-instances" > "$dir/mysqld-executables"
998+
999+ local binlog="$(get_var log_bin "$dir/mysql-variables")"
1000+ if [ "${binlog}" ]; then
1001+ collect_master_logs_status "$dir/mysql-master-logs" "$dir/mysql-master-status"
1002+ fi
1003+
1004+ local uptime="$(get_var Uptime "$dir/mysql-status")"
1005+ local current_time="$($CMD_MYSQL $EXT_ARGV -ss -e \
1006+ "SELECT LEFT(NOW() - INTERVAL ${uptime} SECOND, 16)")"
1007+
1008+ local port="$(get_var port "$dir/mysql-variables")"
1009+ local cnf_file="$(find_my_cnf_file "$dir/mysqld-instances" ${port})"
1010+
1011+ cat "$cnf_file" > "$dir/mysql-config-file"
1012+
1013+ local pid_file="$(get_var "pid_file" "$dir/mysql-variables")"
1014+ local pid_file_exists=""
1015+ [ -e "${pid_file}" ] && pid_file_exists=1
1016+ echo "pt-summary-internal-pid_file_exists $pid_file_exists" >> "$dir/mysql-variables"
1017+
1018+ echo "pt-summary-internal-current_time $current_time" >> "$dir/mysql-variables"
1019+ echo "pt-summary-internal-Config_File_path $cnf_file" >> "$dir/mysql-variables"
1020+ collect_internal_vars "$dir/mysqld-executables" >> "$dir/mysql-variables"
1021+
1022+ if [ -n "${OPT_DATABASES}" ]; then
1023+ local trg_arg="$( get_mysqldump_args "$dir/mysql-variables" )"
1024+ get_mysqldump_for "${trg_arg}" "${OPT_DATABASES}" > "$dir/mysqldump"
1025+ fi
1026+
1027+ (
1028+ sleep $OPT_SLEEP
1029+ collect_mysql_deferred_status "$dir/mysql-status" > "$dir/mysql-status-defer"
1030+ ) &
1031+ _d "Forked child is $!"
1032+}
1033+
1034+# ###########################################################################
1035+# End collect_mysql_info package
1036+# ###########################################################################
1037+
1038+# ###########################################################################
1039+# report_mysql_info package
1040+# This package is a copy without comments from the original. The original
1041+# with comments and its test file can be found in the Bazaar repository at,
1042+# lib/bash/report_mysql_info.sh
1043+# t/lib/bash/report_mysql_info.sh
1044+# See https://launchpad.net/percona-toolkit for more information.
1045+# ###########################################################################
1046+
1047+
1048+set -u
1049+POSIXLY_CORRECT=1
1050+
1051 secs_to_time () {
1052- echo "$1" | $AP_AWK '{
1053- printf( "%d+%02d:%02d:%02d", $1 / 86400, ($1 % 86400) / 3600, ($1 % 3600) / 60, $1 % 60);
1054+ awk -v sec="$1" 'BEGIN {
1055+ printf( "%d+%02d:%02d:%02d", sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
1056 }'
1057 }
1058
1059-# gets a value from $TMPDIR/percona-toolkit-mysql-variables. Returns zero if it doesn't
1060-# exist.
1061-get_var () {
1062- v="$($AP_AWK "\$1 ~ /^$1$/ { print \$2 }" $TMPDIR/percona-toolkit-mysql-variables)"
1063- echo "${v:-0}"
1064-}
1065-
1066-# Returns true if a variable exists
1067-var_exists () {
1068- $AP_GREP "$1" $TMPDIR/percona-toolkit-mysql-variables >/dev/null 2>&1;
1069-}
1070-
1071-# Returns "Enabled", "Disabled", or "Not Supported" depending on whether the
1072-# variable exists and is ON or enabled. You can pass 2nd and 3rd variables to
1073-# control whether the variable should be 'gt' (numeric greater than) or 'eq'
1074-# (string equal) to some value.
1075 feat_on() {
1076- if var_exists $1 ; then
1077- var="$($AP_AWK "\$1 ~ /^$1$/ { print \$2 }" $TMPDIR/percona-toolkit-mysql-variables)"
1078+ local file="$1"
1079+ local varname="$2"
1080+ [ -e "$file" ] || return
1081+
1082+ if [ "$( get_var "$varname" "${file}" )" ]; then
1083+ local var="$(awk "\$1 ~ /^$2$/ { print \$2 }" $file)"
1084 if [ "${var}" = "ON" ]; then
1085 echo "Enabled"
1086 elif [ "${var}" = "OFF" -o "${var}" = "0" -o -z "${var}" ]; then
1087 echo "Disabled"
1088- elif [ "$2" = "ne" ]; then
1089- if [ "${var}" != "$3" ]; then
1090+ elif [ "$3" = "ne" ]; then
1091+ if [ "${var}" != "$4" ]; then
1092 echo "Enabled"
1093 else
1094 echo "Disabled"
1095 fi
1096- elif [ "$2" = "gt" ]; then
1097- if [ "${var}" -gt "$3" ]; then
1098+ elif [ "$3" = "gt" ]; then
1099+ if [ "${var}" -gt "$4" ]; then
1100 echo "Enabled"
1101 else
1102 echo "Disabled"
1103@@ -210,128 +1014,124 @@
1104 fi
1105 }
1106
1107-# gets a value from $TMPDIR/percona-toolkit-mysql-status. Returns zero if it doesn't
1108-# exist.
1109-get_stat () {
1110- v="$($AP_AWK "\$1 ~ /^$1$/ { print \$2 }" $TMPDIR/percona-toolkit-mysql-status)"
1111- echo "${v:-0}"
1112-}
1113-
1114-# Does fuzzy rounding: rounds to nearest interval, but the interval gets larger
1115-# as the number gets larger. This is to make things easier to diff.
1116-fuzz () {
1117- echo $1 | $AP_AWK "{fuzzy_var=\$1; ${fuzzy_formula} print fuzzy_var;}"
1118-}
1119-
1120-# Fuzzy computes the percent that $1 is of $2
1121-fuzzy_pct () {
1122- pct=$(echo $1 $2 | $AP_AWK '{ if ($2 > 0) { printf "%d", $1/$2*100; } else {print 0} }');
1123- echo "$(fuzz ${pct})%"
1124-}
1125-
1126-# ##############################################################################
1127-# Functions for parsing specific files and getting desired info from them.
1128-# These are called from within main() and are separated so they can be tested
1129-# easily. The calling convention is that the data they need to run is prepared
1130-# first by putting it into $TMPDIR/percona-toolkit. Then code that's testing
1131-# just needs to put sample data into $TMPDIR/percona-toolkit and call it.
1132-# ##############################################################################
1133-
1134-# Parses the output of 'ps -e -o args | $AP_GREP mysqld' or 'ps auxww...'
1135-# which should be in $TMPDIR/percona-toolkit.
1136+get_table_cache () {
1137+ local file="$1"
1138+
1139+ [ -e "$file" ] || return
1140+
1141+ local table_cache=""
1142+ if [ "$( get_var table_open_cache "${file}" )" ]; then
1143+ table_cache="$(get_var table_open_cache "${file}")"
1144+ else
1145+ table_cache="$(get_var table_cache "${file}")"
1146+ fi
1147+ echo ${table_cache:-0}
1148+}
1149+
1150+get_plugin_status () {
1151+ local file="$1"
1152+ local plugin="$2"
1153+
1154+ local status="$(grep -w "$plugin" "$file" | awk '{ print $2 }')"
1155+
1156+ echo ${status:-"Not found"}
1157+}
1158+
1159+
1160+_NO_FALSE_NEGATIVES=""
1161 parse_mysqld_instances () {
1162- local file=$1
1163+ local file="$1"
1164+ local variables_file="$2"
1165+
1166 local socket=${socket:-""}
1167 local port=${port:-""}
1168- local datadir=${datadir:-""}
1169- echo " Port Data Directory Socket"
1170- echo " ===== ========================== ======"
1171- $AP_GREP '/mysqld ' $file | while read line; do
1172+ local datadir="${datadir:-""}"
1173+
1174+ [ -e "$file" ] || return
1175+
1176+ echo " Port Data Directory Nice OOM Socket"
1177+ echo " ===== ========================== ==== === ======"
1178+
1179+ grep '/mysqld ' "$file" | while read line; do
1180+ local pid=$(echo "$line" | awk '{print $1;}')
1181 for word in ${line}; do
1182- # Some grep doesn't have -o, so I have to pull out the words I want by
1183- # looking at each word
1184- if echo "${word}" | $AP_GREP -- "--socket=" > /dev/null; then
1185+ if echo "${word}" | grep -- "--socket=" > /dev/null; then
1186 socket="$(echo "${word}" | cut -d= -f2)"
1187 fi
1188- if echo "${word}" | $AP_GREP -- "--port=" > /dev/null; then
1189+ if echo "${word}" | grep -- "--port=" > /dev/null; then
1190 port="$(echo "${word}" | cut -d= -f2)"
1191 fi
1192- if echo "${word}" | $AP_GREP -- "--datadir=" > /dev/null; then
1193+ if echo "${word}" | grep -- "--datadir=" > /dev/null; then
1194 datadir="$(echo "${word}" | cut -d= -f2)"
1195 fi
1196 done
1197- printf " %5s %-26s %s\n" "${port}" "${datadir}" "${socket}"
1198+ local nice="$(get_var "internal::nice_of_$pid" "$variables_file")"
1199+ local oom="$(get_var "internal::oom_of_$pid" "$variables_file")"
1200+ if [ -n "${_NO_FALSE_NEGATIVES}" ]; then
1201+ nice="?"
1202+ oom="?"
1203+ fi
1204+ printf " %5s %-26s %-4s %-3s %s\n" "${port}" "${datadir}" "${nice:-"?"}" "${oom:-"?"}" "${socket}"
1205 done
1206 }
1207
1208-# Tries to find the my.cnf file by examining 'ps' output, which should be in
1209-# $TMPDIR/percona-toolkit. You have to specify the port for the instance you are
1210-# interested in, in case there are multiple instances.
1211-find_my_cnf_file() {
1212- local file=$1
1213- local port=${2:-""}
1214- if test -n "$port" && $AP_GREP -- "/mysqld.*--port=$port" $file >/dev/null 2>&1 ; then
1215- $AP_GREP -- "/mysqld.*--port=$port" $file \
1216- | $AP_AWK 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
1217- | head -n1
1218- else
1219- $AP_GREP '/mysqld' $file \
1220- | $AP_AWK 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
1221- | head -n1
1222- fi
1223-}
1224-
1225-# Gets the MySQL system time. Uses input from $TMPDIR/percona-toolkit-mysql-variables.
1226 get_mysql_timezone () {
1227- tz="$(get_var time_zone)"
1228+ local file="$1"
1229+
1230+ [ -e "$file" ] || return
1231+
1232+ local tz="$(get_var time_zone "${file}")"
1233 if [ "${tz}" = "SYSTEM" ]; then
1234- tz="$(get_var system_time_zone)"
1235+ tz="$(get_var system_time_zone "${file}")"
1236 fi
1237 echo "${tz}"
1238 }
1239
1240-# Gets the MySQL system version. Uses input from $TMPDIR/percona-toolkit-mysql-variables.
1241 get_mysql_version () {
1242- name_val Version "$(get_var version) $(get_var version_comment)"
1243- name_val "Built On" "$(get_var version_compile_os) $(get_var version_compile_machine)"
1244+ local file="$1"
1245+
1246+ name_val Version "$(get_var version "${file}") $(get_var version_comment "${file}")"
1247+ name_val "Built On" "$(get_var version_compile_os "${file}") $(get_var version_compile_machine "${file}")"
1248 }
1249
1250-# Gets the system start and uptime in human readable format. Last restart date
1251-# should be in $TMPDIR/percona-toolkit.
1252 get_mysql_uptime () {
1253- local file=$1
1254- restart="$(cat $file)"
1255- uptime="$(get_stat Uptime)"
1256+ local uptime="$1"
1257+ local restart="$2"
1258 uptime="$(secs_to_time ${uptime})"
1259 echo "${restart} (up ${uptime})"
1260 }
1261
1262-# Summarizes the output of SHOW MASTER LOGS, which is in $TMPDIR/percona-toolkit
1263 summarize_binlogs () {
1264- local file=$1
1265- name_val "Binlogs" $(wc -l $file)
1266- name_val "Zero-Sized" $($AP_GREP -c '\<0$' $file)
1267- size=$($AP_AWK '{t += $2} END{printf "%0.f\n", t}' $file)
1268+ local file="$1"
1269+
1270+ [ -e "$file" ] || return
1271+
1272+ local size="$(awk '{t += $2} END{printf "%0.f\n", t}' "$file")"
1273+ name_val "Binlogs" $(wc -l "$file")
1274+ name_val "Zero-Sized" $(grep -c '\<0$' "$file")
1275 name_val "Total Size" $(shorten ${size} 1)
1276 }
1277
1278-# Print out binlog_do_db and binlog_ignore_db
1279+format_users () {
1280+ local file="$1"
1281+ [ -e "$file" ] || return
1282+ awk '{printf "%d users, %d anon, %d w/o pw, %d old pw\n", $1, $2, $3, $4}' "${file}"
1283+}
1284+
1285 format_binlog_filters () {
1286- local file=$1
1287- name_val "binlog_do_db" $(cut -f3 $file)
1288- name_val "binlog_ignore_db" $(cut -f4 $file)
1289+ local file="$1"
1290+ [ -e "$file" ] || return
1291+ name_val "binlog_do_db" "$(cut -f3 "$file")"
1292+ name_val "binlog_ignore_db" "$(cut -f4 "$file")"
1293 }
1294
1295-# Takes as input a file that has two samples of SHOW STATUS, columnized next to
1296-# each other. These should be in $TMPDIR/percona-toolkit. Outputs fuzzy-ed numbers:
1297-# absolute, all-time per second, and per-second over the interval between the
1298-# samples. Omits any rows that are all zeroes.
1299 format_status_variables () {
1300- local file=$1
1301- # First, figure out the intervals.
1302- utime1=$($AP_AWK '/Uptime /{print $2}' $file);
1303- utime2=$($AP_AWK '/Uptime /{print $3}' $file);
1304- ${AP_AWK} "
1305+ local file="$1"
1306+ [ -e "$file" ] || return
1307+
1308+ utime1="$(awk '/Uptime /{print $2}' "$file")";
1309+ utime2="$(awk '/Uptime /{print $3}' "$file")";
1310+ awk "
1311 BEGIN {
1312 utime1 = ${utime1};
1313 utime2 = ${utime2};
1314@@ -367,28 +1167,22 @@
1315 printf(format, \$1, perday, persec, nowsec);
1316 }
1317 }
1318- }" $file
1319+ }" "$file"
1320 }
1321
1322-# Slices the processlist a bunch of different ways. The processlist should be
1323-# created with the \G flag so it's vertical.
1324-# The parsing is a bit awkward because different
1325-# versions of awk have limitations like "too many fields on line xyz". So we
1326-# use 'cut' to shorten the lines. We count all things into temporary variables
1327-# for each process in the processlist, and when we hit the Info: line which
1328-# ought to be the last line in the process, we decide what to do with the temp
1329-# variables. If we're summarizing Command, we count everything; otherwise, only
1330-# non-Sleep processes get counted towards the sum and max of Time.
1331 summarize_processlist () {
1332- local file=$1
1333+ local file="$1"
1334+
1335+ [ -e "$file" ] || return
1336+
1337 for param in Command User Host db State; do
1338 echo
1339 printf ' %-30s %8s %7s %9s %9s\n' \
1340 "${param}" "COUNT(*)" Working "SUM(Time)" "MAX(Time)"
1341 echo " ------------------------------" \
1342 "-------- ------- --------- ---------"
1343- cut -c1-80 $file \
1344- | $AP_AWK "
1345+ cut -c1-80 "$file" \
1346+ | awk "
1347 \$1 == \"${param}:\" {
1348 p = substr(\$0, index(\$0, \":\") + 2);
1349 if ( index(p, \":\") > 0 ) {
1350@@ -428,22 +1222,21 @@
1351 echo
1352 }
1353
1354-# Pretty-prints the my.cnf file, which should be in $TMPDIR/percona-toolkit. It's super
1355-# annoying, but some *modern* versions of awk don't support POSIX character
1356-# sets in regular expressions, like [[:space:]] (looking at you, Debian). So
1357-# the below patterns contain [<space><tab>] and must remain that way.
1358 pretty_print_cnf_file () {
1359- local file=$1
1360- $AP_AWK '
1361+ local file="$1"
1362+
1363+ [ -e "$file" ] || return
1364+
1365+ awk '
1366 BEGIN {
1367 FS="="
1368 }
1369- /^ *[a-zA-Z[]/ {
1370- if ($2) {
1371- gsub(/^[ ]*/, "", $1);
1372- gsub(/^[ ]*/, "", $2);
1373- gsub(/[ ]*$/, "", $1);
1374- gsub(/[ ]*$/, "", $2);
1375+ /^[ \t]*[a-zA-Z[]/ {
1376+ if (length($2)) {
1377+ gsub(/^[ \t]*/, "", $1);
1378+ gsub(/^[ \t]*/, "", $2);
1379+ gsub(/[ \t]*$/, "", $1);
1380+ gsub(/[ \t]*$/, "", $2);
1381 printf("%-35s = %s\n", $1, $2);
1382 }
1383 else if ( $0 ~ /\[/ ) {
1384@@ -453,11 +1246,12 @@
1385 else {
1386 print $1;
1387 }
1388- }' $file
1389+ }' "$file"
1390 }
1391
1392 find_checkpoint_age() {
1393- $AP_AWK '
1394+ local file="$1"
1395+ awk '
1396 /Log sequence number/{
1397 if ( $5 ) {
1398 lsn = $5 + ($4 * 4294967296);
1399@@ -474,11 +1268,15 @@
1400 print lsn - $4;
1401 }
1402 }
1403- ' "$@"
1404+ ' "$file"
1405 }
1406
1407 find_pending_io_reads() {
1408- $AP_AWK '
1409+ local file="$1"
1410+
1411+ [ -e "$file" ] || return
1412+
1413+ awk '
1414 /Pending normal aio reads/ {
1415 normal_aio_reads = substr($5, 1, index($5, ","));
1416 }
1417@@ -495,11 +1293,15 @@
1418 printf "%d buf pool reads, %d normal AIO", reads, normal_aio_reads;
1419 printf ", %d ibuf AIO, %d preads", ibuf_aio_reads, preads;
1420 }
1421- ' "${1}"
1422+ ' "${file}"
1423 }
1424
1425 find_pending_io_writes() {
1426- $AP_AWK '
1427+ local file="$1"
1428+
1429+ [ -e "$file" ] || return
1430+
1431+ awk '
1432 /aio writes/ {
1433 aio_writes = substr($NF, 1, index($NF, ","));
1434 }
1435@@ -522,11 +1324,15 @@
1436 END {
1437 printf "%d buf pool (%d LRU, %d flush list, %d page); %d AIO, %d sync, %d log IO (%d log, %d chkp); %d pwrites", lru + flush_list + single_page, lru, flush_list, single_page, aio_writes, sync_ios, log_ios, log_writes, chkp_writes, pwrites;
1438 }
1439- ' "${1}"
1440+ ' "${file}"
1441 }
1442
1443 find_pending_io_flushes() {
1444- $AP_AWK '
1445+ local file="$1"
1446+
1447+ [ -e "$file" ] || return
1448+
1449+ awk '
1450 /Pending flushes/ {
1451 log_flushes = substr($5, 1, index($5, ";"));
1452 buf_pool = $NF;
1453@@ -534,13 +1340,17 @@
1454 END {
1455 printf "%d buf pool, %d log", buf_pool, log_flushes;
1456 }
1457- ' "${1}"
1458+ ' "${file}"
1459 }
1460
1461 summarize_undo_log_entries() {
1462- $AP_GREP 'undo log entries' "$1" \
1463- | $AP_SED -e 's/^.*undo log entries \([0-9]*\)/\1/' \
1464- | $AP_AWK '
1465+ local file="$1"
1466+
1467+ [ -e "$file" ] || return
1468+
1469+ grep 'undo log entries' "${file}" \
1470+ | sed -e 's/^.*undo log entries \([0-9]*\)/\1/' \
1471+ | awk '
1472 {
1473 count++;
1474 sum += $1;
1475@@ -554,7 +1364,11 @@
1476 }
1477
1478 find_max_trx_time() {
1479- $AP_AWK '
1480+ local file="$1"
1481+
1482+ [ -e "$file" ] || return
1483+
1484+ awk '
1485 BEGIN {
1486 max = 0;
1487 }
1488@@ -570,59 +1384,69 @@
1489 }
1490 END {
1491 print max;
1492- }' "$@"
1493-}
1494-
1495-# Summarizes various things about InnoDB status that are not easy to see by eye.
1496+ }' "${file}"
1497+}
1498+
1499+find_transation_states () {
1500+ local file="$1"
1501+ local tmpfile="$TMPDIR/find_transation_states.tmp"
1502+
1503+ [ -e "$file" ] || return
1504+
1505+ awk -F, '/^---TRANSACTION/{print $2}' "${file}" \
1506+ | sed -e 's/ [0-9]* sec.*//' \
1507+ | sort \
1508+ | uniq -c > "${tmpfile}"
1509+ group_concat "${tmpfile}"
1510+}
1511+
1512 format_innodb_status () {
1513 local file=$1
1514- name_val "Checkpoint Age" $(shorten $(find_checkpoint_age "${file}"))
1515+
1516+ [ -e "$file" ] || return
1517+
1518+ name_val "Checkpoint Age" "$(shorten $(find_checkpoint_age "${file}") 0)"
1519 name_val "InnoDB Queue" "$(awk '/queries inside/{print}' "${file}")"
1520 name_val "Oldest Transaction" "$(find_max_trx_time "${file}") Seconds";
1521- name_val "History List Len" $(awk '/History list length/{print $4}' "${file}")
1522- name_val "Read Views" $(awk '/read views open inside/{print $1}' "${file}")
1523+ name_val "History List Len" "$(awk '/History list length/{print $4}' "${file}")"
1524+ name_val "Read Views" "$(awk '/read views open inside/{print $1}' "${file}")"
1525 name_val "Undo Log Entries" "$(summarize_undo_log_entries "${file}")"
1526 name_val "Pending I/O Reads" "$(find_pending_io_reads "${file}")"
1527 name_val "Pending I/O Writes" "$(find_pending_io_writes "${file}")"
1528 name_val "Pending I/O Flushes" "$(find_pending_io_flushes "${file}")"
1529- $AP_AWK -F, '/^---TRANSACTION/{print $2}' "${file}" \
1530- | $AP_SED -e 's/ [0-9]* sec.*//' | sort | uniq -c > $TMPDIR/percona-toolkit2
1531- name_val "Transaction States" "$(group_concat $TMPDIR/percona-toolkit2)"
1532- if $AP_GREP 'TABLE LOCK table' "${file}" >/dev/null ; then
1533+ name_val "Transaction States" "$(find_transation_states "${file}" )"
1534+ if grep 'TABLE LOCK table' "${file}" >/dev/null ; then
1535 echo "Tables Locked"
1536- $AP_AWK '/^TABLE LOCK table/{print $4}' "${file}" \
1537+ awk '/^TABLE LOCK table/{print $4}' "${file}" \
1538 | sort | uniq -c | sort -rn
1539 fi
1540- if $AP_GREP 'has waited at' "${file}" > /dev/null ; then
1541+ if grep 'has waited at' "${file}" > /dev/null ; then
1542 echo "Semaphore Waits"
1543- $AP_GREP 'has waited at' "${file}" | cut -d' ' -f6-8 \
1544+ grep 'has waited at' "${file}" | cut -d' ' -f6-8 \
1545 | sort | uniq -c | sort -rn
1546 fi
1547- if $AP_GREP 'reserved it in mode' "${file}" > /dev/null; then
1548+ if grep 'reserved it in mode' "${file}" > /dev/null; then
1549 echo "Semaphore Holders"
1550- $AP_AWK '/has reserved it in mode/{
1551+ awk '/has reserved it in mode/{
1552 print substr($0, 1 + index($0, "("), index($0, ")") - index($0, "(") - 1);
1553 }' "${file}" | sort | uniq -c | sort -rn
1554 fi
1555- if $AP_GREP -e 'Mutex at' -e 'lock on' "${file}" >/dev/null 2>&1; then
1556+ if grep -e 'Mutex at' -e 'lock on' "${file}" >/dev/null 2>&1; then
1557 echo "Mutexes/Locks Waited For"
1558- $AP_GREP -e 'Mutex at' -e 'lock on' "${file}" | $AP_SED -e 's/^[XS]-//' -e 's/,.*$//' \
1559+ grep -e 'Mutex at' -e 'lock on' "${file}" | sed -e 's/^[XS]-//' -e 's/,.*$//' \
1560 | sort | uniq -c | sort -rn
1561 fi
1562 }
1563
1564-# Summarizes per-database statistics for a bunch of different things: count of
1565-# tables, views, etc. $1 is the file name. $2 is the database name; if none,
1566-# then there should be multiple databases.
1567 format_overall_db_stats () {
1568- local file=$1
1569+ local file="$1"
1570+ local tmpfile="$TMPDIR/format_overall_db_stats.tmp"
1571+
1572+ [ -e "$file" ] || return
1573+
1574 echo
1575- # We keep counts of everything in an associative array keyed by db name, and
1576- # what it is. The num_dbs counter is to ensure sort order is consistent when
1577- # we run the awk commands following this one.
1578- $AP_AWK '
1579+ awk '
1580 BEGIN {
1581- # In case there is no USE statement in the file.
1582 db = "{chosen}";
1583 num_dbs = 0;
1584 }
1585@@ -634,7 +1458,6 @@
1586 }
1587 }
1588 /^CREATE TABLE/ {
1589- # Handle single-DB dumps, where there is no USE statement.
1590 if (num_dbs == 0) {
1591 num_dbs = 1;
1592 db_seen[db] = 1;
1593@@ -674,15 +1497,13 @@
1594 printf fmt, db, counts[db ",tables"], counts[db ",views"], counts[db ",sps"], counts[db ",trg"], counts[db ",func"], counts[db ",fk"], counts[db ",partn"];
1595 }
1596 }
1597- ' $file > $TMPDIR/percona-toolkit
1598- head -n2 $TMPDIR/percona-toolkit
1599- tail -n +3 $TMPDIR/percona-toolkit | sort
1600+ ' "$file" > "$tmpfile"
1601+ head -n2 "$tmpfile"
1602+ tail -n +3 "$tmpfile" | sort
1603
1604 echo
1605- # Now do the summary of engines per DB
1606- $AP_AWK '
1607+ awk '
1608 BEGIN {
1609- # In case there is no USE statement in the file.
1610 db = "{chosen}";
1611 num_dbs = 0;
1612 num_engines = 0;
1613@@ -695,7 +1516,6 @@
1614 }
1615 }
1616 /^\) ENGINE=/ {
1617- # Handle single-DB dumps, where there is no USE statement.
1618 if (num_dbs == 0) {
1619 num_dbs = 1;
1620 db_seen[db] = 1;
1621@@ -734,16 +1554,13 @@
1622 print "";
1623 }
1624 }
1625- ' $file > $TMPDIR/percona-toolkit
1626- head -n1 $TMPDIR/percona-toolkit
1627- tail -n +2 $TMPDIR/percona-toolkit | sort
1628+ ' "$file" > "$tmpfile"
1629+ head -n1 "$tmpfile"
1630+ tail -n +2 "$tmpfile" | sort
1631
1632 echo
1633- # Now do the summary of index types per DB. Careful -- index is a reserved
1634- # word in awk.
1635- $AP_AWK '
1636+ awk '
1637 BEGIN {
1638- # In case there is no USE statement in the file.
1639 db = "{chosen}";
1640 num_dbs = 0;
1641 num_idxes = 0;
1642@@ -756,7 +1573,6 @@
1643 }
1644 }
1645 /KEY/ {
1646- # Handle single-DB dumps, where there is no USE statement.
1647 if (num_dbs == 0) {
1648 num_dbs = 1;
1649 db_seen[db] = 1;
1650@@ -807,15 +1623,13 @@
1651 print "";
1652 }
1653 }
1654- ' $file > $TMPDIR/percona-toolkit
1655- head -n1 $TMPDIR/percona-toolkit
1656- tail -n +2 $TMPDIR/percona-toolkit | sort
1657+ ' "$file" > "$tmpfile"
1658+ head -n1 "$tmpfile"
1659+ tail -n +2 "$tmpfile" | sort
1660
1661 echo
1662- # Now do the summary of datatypes per DB
1663- $AP_AWK '
1664+ awk '
1665 BEGIN {
1666- # In case there is no USE statement in the file.
1667 db = "{chosen}";
1668 num_dbs = 0;
1669 num_types = 0;
1670@@ -828,7 +1642,6 @@
1671 }
1672 }
1673 /^ `/ {
1674- # Handle single-DB dumps, where there is no USE statement.
1675 if (num_dbs == 0) {
1676 num_dbs = 1;
1677 db_seen[db] = 1;
1678@@ -898,106 +1711,195 @@
1679 print "";
1680 }
1681 }
1682- ' $file > $TMPDIR/percona-toolkit
1683- hdr=$($AP_GREP -n Database $TMPDIR/percona-toolkit | cut -d: -f1);
1684- head -n${hdr} $TMPDIR/percona-toolkit
1685- tail -n +$((${hdr} + 1)) $TMPDIR/percona-toolkit | sort
1686+ ' "$file" > "$tmpfile"
1687+ local hdr=$(grep -n Database "$tmpfile" | cut -d: -f1);
1688+ head -n${hdr} "$tmpfile"
1689+ tail -n +$((${hdr} + 1)) "$tmpfile" | sort
1690 echo
1691 }
1692
1693-# ##############################################################################
1694-# The main() function is called at the end of the script. This makes it
1695-# testable. Major bits of parsing are separated into functions for testability.
1696-# ##############################################################################
1697-main() {
1698-
1699- # Begin by setting the $PATH to include some common locations that are not
1700- # always in the $PATH, including the "sbin" locations. On SunOS systems,
1701- # prefix the path with the location of more sophisticated utilities.
1702- export PATH="${PATH}:/usr/local/bin:/usr/bin:/bin:/usr/libexec"
1703- export PATH="${PATH}:/usr/mysql/bin/:/usr/local/sbin:/usr/sbin:/sbin"
1704- export PATH="/usr/gnu/bin/:/usr/xpg4/bin/:${PATH}"
1705-
1706- # Set up temporary files.
1707- mk_tmpdir
1708- temp_files "rm"
1709- temp_files "touch"
1710-
1711- # ########################################################################
1712- # Header for the whole thing, table of discovered instances
1713- # ########################################################################
1714- section Percona_Toolkit_MySQL_Summary_Report
1715- name_val "System time" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"
1716- section Instances
1717- ps auxww 2>/dev/null | $AP_GREP mysqld > $TMPDIR/percona-toolkit
1718- parse_mysqld_instances $TMPDIR/percona-toolkit
1719-
1720- # ########################################################################
1721- # Fetch some basic info so we can start
1722- # ########################################################################
1723- mysql "$@" -ss -e 'SELECT CURRENT_USER()' > $TMPDIR/percona-toolkit
1724- if [ "$?" != "0" ]; then
1725- echo "Cannot connect to mysql, please specify command-line options."
1726- temp_files "rm"
1727- rm_tmpdir
1728- exit 1
1729- fi
1730- user="$(cat $TMPDIR/percona-toolkit)";
1731- mysql "$@" -ss -e 'SHOW /*!40100 GLOBAL*/ VARIABLES' > $TMPDIR/percona-toolkit-mysql-variables
1732- mysql "$@" -ss -e 'SHOW /*!50000 GLOBAL*/ STATUS' > $TMPDIR/percona-toolkit-mysql-status
1733- mysql "$@" -ss -e 'SHOW DATABASES' > $TMPDIR/percona-toolkit-mysql-databases 2>/dev/null
1734- mysql "$@" -ssE -e 'SHOW SLAVE STATUS' > $TMPDIR/percona-toolkit-mysql-slave 2>/dev/null
1735- mysql "$@" -ssE -e 'SHOW /*!50000 ENGINE*/ INNODB STATUS' > $TMPDIR/percona-toolkit-innodb-status 2>/dev/null
1736- mysql "$@" -ssE -e 'SHOW FULL PROCESSLIST' > $TMPDIR/percona-toolkit-mysql-processlist 2>/dev/null
1737- now="$(mysql "$@" -ss -e 'SELECT NOW()')"
1738- port="$(get_var port)"
1739-
1740- # ########################################################################
1741- # General date, hostname, etc
1742- # ########################################################################
1743- section "Report_On_Port_${port}"
1744- name_val User "${user}"
1745- name_val Time "${now} ($(get_mysql_timezone))"
1746- name_val Hostname "$(get_var hostname)"
1747- get_mysql_version
1748-
1749- uptime="$(get_stat Uptime)"
1750- mysql "$@" -ss -e "SELECT LEFT(NOW() - INTERVAL ${uptime} SECOND, 16)" \
1751- > $TMPDIR/percona-toolkit
1752- name_val Started "$(get_mysql_uptime $TMPDIR/percona-toolkit)"
1753-
1754- name_val Databases "$($AP_GREP -c . $TMPDIR/percona-toolkit-mysql-databases)"
1755- name_val Datadir "$(get_var datadir)"
1756- procs="$(get_stat Threads_connected)"
1757- procr="$(get_stat Threads_running)"
1758- name_val Processes "$(fuzz ${procs}) connected, $(fuzz ${procr}) running"
1759- if [ -s $TMPDIR/percona-toolkit-mysql-slave ]; then slave=""; else slave="not "; fi
1760- slavecount=$($AP_GREP -c 'Binlog Dump' $TMPDIR/percona-toolkit-mysql-processlist)
1761- name_val Replication "Is ${slave}a slave, has ${slavecount} slaves connected"
1762-
1763- # TODO move this into a section with other files: error log, slow log and
1764- # show the sizes
1765- pid_file="$(get_var pid_file)"
1766- [ -e "${pid_file}" ] && PID_EXISTS="(exists)"
1767- name_val Pidfile "${pid_file} ${PID_EXISTS:-(does not exist)}"
1768-
1769- # ########################################################################
1770- # Processlist, sliced several different ways
1771- # ########################################################################
1772- section Processlist
1773- summarize_processlist $TMPDIR/percona-toolkit-mysql-processlist
1774-
1775- # ########################################################################
1776- # Queries and query plans
1777- # ########################################################################
1778- section "Status_Counters_(Wait_10_Seconds)"
1779- sleep 10
1780- # TODO: gather this data in the same format as normal: stats, TS line
1781- mysql "$@" -ss -e 'SHOW /*!50000 GLOBAL*/ STATUS' \
1782- | join $TMPDIR/percona-toolkit-mysql-status - > $TMPDIR/percona-toolkit
1783- # Make a file with a list of things we want to omit because they aren't
1784- # counters, they are gauges (in RRDTool terminology). Gauges are shown
1785- # elsewhere in the output.
1786+section_percona_server_features () {
1787+ local file="$1"
1788+
1789+ [ -e "$file" ] || return
1790+
1791+ name_val "Table & Index Stats" \
1792+ "$(feat_on "$file" userstat_running)"
1793+ name_val "Multiple I/O Threads" \
1794+ "$(feat_on "$file" innodb_read_io_threads gt 1)"
1795+ name_val "Corruption Resilient" \
1796+ "$(feat_on "$file" innodb_pass_corrupt_table)"
1797+ name_val "Durable Replication" \
1798+ "$(feat_on "$file" innodb_overwrite_relay_log_info)"
1799+ name_val "Import InnoDB Tables" \
1800+ "$(feat_on "$file" innodb_expand_import)"
1801+ name_val "Fast Server Restarts" \
1802+ "$(feat_on "$file" innodb_auto_lru_dump)"
1803+ name_val "Enhanced Logging" \
1804+ "$(feat_on "$file" log_slow_verbosity ne microtime)"
1805+ name_val "Replica Perf Logging" \
1806+ "$(feat_on "$file" log_slow_slave_statements)"
1807+ name_val "Response Time Hist." \
1808+ "$(feat_on "$file" enable_query_response_time_stats)"
1809+ name_val "Smooth Flushing" \
1810+ "$(feat_on "$file" innodb_adaptive_checkpoint ne none)"
1811+ name_val "HandlerSocket NoSQL" \
1812+ "$(feat_on "$file" handlersocket_port)"
1813+ name_val "Fast Hash UDFs" \
1814+ "$(get_var "pt-summary-internal-FNV_64" "$file")"
1815+}
1816+
1817+section_myisam () {
1818+ local variables_file="$1"
1819+ local status_file="$2"
1820+
1821+ [ -e "$variables_file" -a -e "$status_file" ] || return
1822+
1823+ local buf_size="$(get_var key_buffer_size "$variables_file")"
1824+ local blk_size="$(get_var key_cache_block_size "$variables_file")"
1825+ local blk_unus="$(get_var Key_blocks_unused "$status_file")"
1826+ local blk_unfl="$(get_var Key_blocks_not_flushed "$variables_file")"
1827+ local unus=$((${blk_unus:-0} * ${blk_size:-0}))
1828+ local unfl=$((${blk_unfl:-0} * ${blk_size:-0}))
1829+ local used=$((${buf_size:-0} - ${unus}))
1830+
1831+ name_val "Key Cache" "$(shorten ${buf_size} 1)"
1832+ name_val "Pct Used" "$(fuzzy_pct ${used} ${buf_size})"
1833+ name_val "Unflushed" "$(fuzzy_pct ${unfl} ${buf_size})"
1834+}
1835+
1836+section_innodb () {
1837+ local variables_file="$1"
1838+ local status_file="$2"
1839+
1840+ [ -e "$variables_file" -a -e "$status_file" ] || return
1841+
1842+ local version=$(get_var innodb_version "$variables_file")
1843+ name_val Version ${version:-default}
1844+
1845+ local bp_size="$(get_var innodb_buffer_pool_size "$variables_file")"
1846+ name_val "Buffer Pool Size" "$(shorten "${bp_size:-0}" 1)"
1847+
1848+ local bp_pags="$(get_var Innodb_buffer_pool_pages_total "$status_file")"
1849+ local bp_free="$(get_var Innodb_buffer_pool_pages_free "$status_file")"
1850+ local bp_dirt="$(get_var Innodb_buffer_pool_pages_dirty "$status_file")"
1851+ local bp_fill=$((${bp_pags} - ${bp_free}))
1852+ name_val "Buffer Pool Fill" "$(fuzzy_pct ${bp_fill} ${bp_pags})"
1853+ name_val "Buffer Pool Dirty" "$(fuzzy_pct ${bp_dirt} ${bp_pags})"
1854+
1855+ name_val "File Per Table" $(get_var innodb_file_per_table "$variables_file")
1856+ name_val "Page Size" $(shorten $(get_var Innodb_page_size "$status_file") 0)
1857+
1858+ local log_size="$(get_var innodb_log_file_size "$variables_file")"
1859+ local log_file="$(get_var innodb_log_files_in_group "$variables_file")"
1860+ local log_total=$(awk "BEGIN {printf \"%.2f\n\", ${log_size}*${log_file}}" )
1861+ name_val "Log File Size" \
1862+ "${log_file} * $(shorten ${log_size} 1 1000) = $(shorten ${log_total} 1 1000)"
1863+ name_val "Log Buffer Size" \
1864+ "$(shorten $(get_var innodb_log_buffer_size "$variables_file") 0)"
1865+ name_val "Flush Method" \
1866+ "$(get_var innodb_flush_method "$variables_file")"
1867+ name_val "Flush Log At Commit" \
1868+ "$(get_var innodb_flush_log_at_trx_commit "$variables_file")"
1869+ name_val "XA Support" \
1870+ "$(get_var innodb_support_xa "$variables_file")"
1871+ name_val "Checksums" \
1872+ "$(get_var innodb_checksums "$variables_file")"
1873+ name_val "Doublewrite" \
1874+ "$(get_var innodb_doublewrite "$variables_file")"
1875+ name_val "R/W I/O Threads" \
1876+ "$(get_var innodb_read_io_threads "$variables_file") $(get_var innodb_write_io_threads "$variables_file")"
1877+ name_val "I/O Capacity" \
1878+ "$(get_var innodb_io_capacity "$variables_file")"
1879+ name_val "Thread Concurrency" \
1880+ "$(get_var innodb_thread_concurrency "$variables_file")"
1881+ name_val "Concurrency Tickets" \
1882+ "$(get_var innodb_concurrency_tickets "$variables_file")"
1883+ name_val "Commit Concurrency" \
1884+ "$(get_var innodb_commit_concurrency "$variables_file")"
1885+ name_val "Txn Isolation Level" \
1886+ "$(get_var tx_isolation "$variables_file")"
1887+ name_val "Adaptive Flushing" \
1888+ "$(get_var innodb_adaptive_flushing "$variables_file")"
1889+ name_val "Adaptive Checkpoint" \
1890+ "$(get_var innodb_adaptive_checkpoint "$variables_file")"
1891+}
1892+
1893+
1894+section_noteworthy_variables () {
1895+ local file="$1"
1896+
1897+ [ -e "$file" ] || return
1898+
1899+ name_val "Auto-Inc Incr/Offset" "$(get_var auto_increment_increment "$file")/$(get_var auto_increment_offset "$file")"
1900+ for v in \
1901+ default_storage_engine flush_time init_connect init_file sql_mode;
1902+ do
1903+ name_val "${v}" "$(get_var ${v} "$file")"
1904+ done
1905+ for v in \
1906+ join_buffer_size sort_buffer_size read_buffer_size read_rnd_buffer_size \
1907+ bulk_insert_buffer max_heap_table_size tmp_table_size \
1908+ max_allowed_packet thread_stack;
1909+ do
1910+ name_val "${v}" "$(shorten $(get_var ${v} "$file") 0)"
1911+ done
1912+ for v in log log_error log_warnings log_slow_queries \
1913+ log_queries_not_using_indexes log_slave_updates;
1914+ do
1915+ name_val "${v}" "$(get_var ${v} "$file")"
1916+ done
1917+}
1918+
1919+_semi_sync_stats_for () {
1920+ local target="$1"
1921+ local file="$2"
1922+
1923+ [ -e "$file" ] || return
1924+
1925+ local semisync_status="$(get_var "Rpl_semi_sync_${target}_status" "${file}" )"
1926+ local semisync_trace="$(get_var "rpl_semi_sync_${target}_trace_level" "${file}")"
1927+
1928+ local trace_extra=""
1929+ if [ -n "${semisync_trace}" ]; then
1930+ if [ $semisync_trace -eq 1 ]; then
1931+ trace_extra="general (for example, time function failures) "
1932+ elif [ $semisync_trace -eq 16 ]; then
1933+ trace_extra="detail (more verbose information) "
1934+ elif [ $semisync_trace -eq 32 ]; then
1935+ trace_extra="net wait (more information about network waits)"
1936+ elif [ $semisync_trace -eq 64 ]; then
1937+ trace_extra="function (information about function entry and exit)"
1938+ else
1939+ trace_extra="Unknown setting"
1940+ fi
1941+ fi
1942+
1943+ name_val "${target} semisync status" "${semisync_status}"
1944+ name_val "${target} trace level" "${semisync_trace}, ${trace_extra}"
1945+
1946+ if [ "${target}" = "master" ]; then
1947+ name_val "${target} timeout in milliseconds" \
1948+ "$(get_var "rpl_semi_sync_${target}_timeout" "${file}")"
1949+ name_val "${target} waits for slaves" \
1950+ "$(get_var "rpl_semi_sync_${target}_wait_no_slave" "${file}")"
1951+
1952+ _d "Prepend Rpl_semi_sync_master_ to the following"
1953+ for v in \
1954+ clients net_avg_wait_time net_wait_time net_waits \
1955+ no_times no_tx timefunc_failures tx_avg_wait_time \
1956+ tx_wait_time tx_waits wait_pos_backtraverse \
1957+ wait_sessions yes_tx;
1958+ do
1959+ name_val "${target} ${v}" \
1960+ "$( get_var "Rpl_semi_sync_master_${v}" "${file}" )"
1961+ done
1962+ fi
1963+}
1964+
1965+noncounters_pattern () {
1966+ local noncounters_pattern=""
1967+
1968 for var in Compression Delayed_insert_threads Innodb_buffer_pool_pages_data \
1969 Innodb_buffer_pool_pages_dirty Innodb_buffer_pool_pages_free \
1970 Innodb_buffer_pool_pages_latched Innodb_buffer_pool_pages_misc \
1971@@ -1018,314 +1920,410 @@
1972 Threads_cached Threads_connected Threads_running \
1973 Uptime_since_flush_status;
1974 do
1975- echo "${var}" >> $TMPDIR/percona-toolkit-noncounters
1976- done
1977- format_status_variables $TMPDIR/percona-toolkit | $AP_GREP -v -f $TMPDIR/percona-toolkit-noncounters
1978-
1979- # ########################################################################
1980- # Table cache
1981- # ########################################################################
1982- section Table_cache
1983- if var_exists table_open_cache; then
1984- table_cache=$(get_var table_open_cache)
1985+ if [ -z "${noncounters_pattern}" ]; then
1986+ noncounters_pattern="${var}"
1987+ else
1988+ noncounters_pattern="${noncounters_pattern}\|${var}"
1989+ fi
1990+ done
1991+ echo $noncounters_pattern
1992+}
1993+
1994+section_mysqld () {
1995+ local executables_file="$1"
1996+ local variables_file="$2"
1997+
1998+ [ -e "$executables_file" -a -e "$variables_file" ] || return
1999+
2000+ section "MySQL Executable"
2001+ local i=1;
2002+ while read executable; do
2003+ name_val "Path to executable" "$executable"
2004+ name_val "Has symbols" "$( get_var "pt-summary-internal-mysqld_executable_${i}" "$variables_file" )"
2005+ i=$(($i + 1))
2006+ done < "$executables_file"
2007+}
2008+
2009+section_mysql_files () {
2010+ local variables_file="$1"
2011+
2012+ section "MySQL Files"
2013+ for file_name in pid_file slow_query_log_file general_log_file log_error; do
2014+ local file="$(get_var "${file_name}" "$variables_file")"
2015+ local name_out="$(echo "$file_name" | sed 'y/[a-z]/[A-Z]/')"
2016+ if [ -e "${file}" ]; then
2017+ name_val "$name_out" "$file"
2018+ name_val "${name_out} Size" "$(du "$file" | awk '{print $1}')"
2019+ else
2020+ name_val "$name_out" "(does not exist)"
2021+ fi
2022+ done
2023+}
2024+
2025+report_mysql_summary () {
2026+ local dir="$1"
2027+
2028+ local NAME_VAL_LEN=25
2029+
2030+
2031+ section "Percona Toolkit MySQL Summary Report"
2032+ name_val "System time" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"
2033+ section "Instances"
2034+ parse_mysqld_instances "$dir/mysqld-instances" "$dir/mysql-variables"
2035+
2036+ section_mysqld "$dir/mysqld-executables" "$dir/mysql-variables"
2037+
2038+ local user="$(get_var "pt-summary-internal-user" "$dir/mysql-variables")"
2039+ local port="$(get_var port "$dir/mysql-variables")"
2040+ local now="$(get_var "pt-summary-internal-now" "$dir/mysql-variables")"
2041+ section "Report On Port ${port}"
2042+ name_val User "${user}"
2043+ name_val Time "${now} ($(get_mysql_timezone "$dir/mysql-variables"))"
2044+ name_val Hostname "$(get_var hostname "$dir/mysql-variables")"
2045+ get_mysql_version "$dir/mysql-variables"
2046+
2047+ local uptime="$(get_var Uptime "$dir/mysql-status")"
2048+ local current_time="$(get_var "pt-summary-internal-current_time" "$dir/mysql-variables")"
2049+ name_val Started "$(get_mysql_uptime "${uptime}" "${current_time}")"
2050+
2051+ local num_dbs="$(grep -c . "$dir/mysql-databases")"
2052+ name_val Databases "${num_dbs}"
2053+ name_val Datadir "$(get_var datadir "$dir/mysql-variables")"
2054+
2055+ local fuzz_procs=$(fuzz $(get_var Threads_connected "$dir/mysql-status"))
2056+ local fuzz_procr=$(fuzz $(get_var Threads_running "$dir/mysql-status"))
2057+ name_val Processes "${fuzz_procs} connected, ${fuzz_procr} running"
2058+
2059+ local slave=""
2060+ if [ -s "$dir/mysql-slave" ]; then slave=""; else slave="not "; fi
2061+ local slavecount=$(grep -c 'Binlog Dump' "$dir/mysql-processlist")
2062+ name_val Replication "Is ${slave}a slave, has ${slavecount} slaves connected"
2063+
2064+
2065+ local pid_file="$(get_var "pid_file" "$dir/mysql-variables")"
2066+ local PID_EXISTS=""
2067+ if [ "$( get_var "pt-summary-internal-pid_file_exists" "$dir/mysql-variables" )" ]; then
2068+ PID_EXISTS="(exists)"
2069 else
2070- table_cache=$(get_var table_cache)
2071+ PID_EXISTS="(does not exist)"
2072 fi
2073- name_val Size "${table_cache}"
2074- open_tables=$(get_stat Open_tables)
2075- name_val Usage "$(fuzzy_pct ${open_tables} ${table_cache})"
2076-
2077- # ########################################################################
2078- # Percona Server features
2079- # ########################################################################
2080- section Key_Percona_Server_features
2081- name_val "Table & Index Stats" "$(feat_on userstat_running)"
2082- name_val "Multiple I/O Threads" "$(feat_on innodb_read_io_threads gt 1)"
2083- name_val "Corruption Resilient" "$(feat_on innodb_pass_corrupt_table)"
2084- name_val "Durable Replication" "$(feat_on innodb_overwrite_relay_log_info)"
2085- name_val "Import InnoDB Tables" "$(feat_on innodb_expand_import)"
2086- name_val "Fast Server Restarts" "$(feat_on innodb_auto_lru_dump)"
2087- name_val "Enhanced Logging" "$(feat_on log_slow_verbosity ne microtime)"
2088- name_val "Replica Perf Logging" "$(feat_on log_slow_slave_statements)"
2089- name_val "Response Time Hist." "$(feat_on enable_query_response_time_stats)"
2090- name_val "Smooth Flushing" "$(feat_on innodb_adaptive_checkpoint ne none)"
2091- name_val "HandlerSocket NoSQL" "$(feat_on handlersocket_port)"
2092- mysql "$@" -e 'SELECT FNV_64("a")' >/dev/null 2>&1 && FNV_64="Enabled";
2093- name_val "Fast Maatkit Hashes" "${FNV_64:-Unknown}"
2094-
2095- # ########################################################################
2096- # Query cache
2097- # ########################################################################
2098- query_cache_size=$(get_var query_cache_size);
2099- if [ "$(get_var have_query_cache)" ]; then
2100- section Query_cache
2101- name_val query_cache_type $(get_var query_cache_type)
2102+ name_val Pidfile "${pid_file} ${PID_EXISTS}"
2103+
2104+ section "Processlist"
2105+ summarize_processlist "$dir/mysql-processlist"
2106+
2107+ section "Status Counters (Wait ${OPT_SLEEP} Seconds)"
2108+ wait
2109+ local noncounters_pattern="$(noncounters_pattern)"
2110+ format_status_variables "$dir/mysql-status-defer" | grep -v "${noncounters_pattern}"
2111+
2112+ section "Table cache"
2113+ local open_tables=$(get_var "Open_tables" "$dir/mysql-status")
2114+ local table_cache=$(get_table_cache "$dir/mysql-variables")
2115+ name_val Size $table_cache
2116+ name_val Usage "$(fuzzy_pct ${open_tables} ${table_cache})"
2117+
2118+ section "Key Percona Server features"
2119+ section_percona_server_features "$dir/mysql-variables"
2120+
2121+ section "Plugins"
2122+ name_val "InnoDB compression" "$(get_plugin_status "$dir/mysql-plugins" "INNODB_CMP")"
2123+
2124+ if [ "$(get_var have_query_cache "$dir/mysql-variables")" ]; then
2125+ section "Query cache"
2126+ local query_cache_size=$(get_var query_cache_size "$dir/mysql-variables")
2127+ local used=$(( ${query_cache_size} - $(get_var Qcache_free_memory "$dir/mysql-status") ))
2128+ local hrat=$(fuzzy_pct $(get_var Qcache_hits "$dir/mysql-status") $(get_var Qcache_inserts "$dir/mysql-status"))
2129+ name_val query_cache_type $(get_var query_cache_type "$dir/mysql-variables")
2130 name_val Size "$(shorten ${query_cache_size} 1)"
2131- used=$(( ${query_cache_size} - $(get_stat Qcache_free_memory) ))
2132 name_val Usage "$(fuzzy_pct ${used} ${query_cache_size})"
2133- hrat=$(fuzzy_pct $(get_stat Qcache_hits) $(get_stat Qcache_inserts))
2134 name_val HitToInsertRatio "${hrat}"
2135 fi
2136
2137- # ########################################################################
2138- # Schema, databases, data type, other analysis.
2139- # ########################################################################
2140- section Schema
2141- # Assume "no" if stdin or stdout is not a terminal, so this can be run and
2142- # put into a file, or piped into a pager, or something else like that.
2143- if [ -t 0 -a -t 1 ]; then
2144+ local semisync_enabled_master="$(get_var "rpl_semi_sync_master_enabled" "$dir/mysql-variables")"
2145+ if [ -n "${semisync_enabled_master}" ]; then
2146+ section "Semisynchronous Replication"
2147+ if [ "$semisync_enabled_master" = "OFF" -o "$semisync_enabled_master" = "0" -o -z "$semisync_enabled_master" ]; then
2148+ name_val "Master" "Disabled"
2149+ else
2150+ _semi_sync_stats_for "master" "$dir/mysql-variables"
2151+ fi
2152+ local semisync_enabled_slave="$(get_var rpl_semi_sync_slave_enabled "$dir/mysql-variables")"
2153+ if [ "$semisync_enabled_slave" = "OFF" -o "$semisync_enabled_slave" = "0" -o -z "$semisync_enabled_slave" ]; then
2154+ name_val "Slave" "Disabled"
2155+ else
2156+ _semi_sync_stats_for "slave" "$dir/mysql-variables"
2157+ fi
2158+ fi
2159+
2160+ section "Schema"
2161+ local reply="n"
2162+ if [ "${OPT_DATABASES}" ] || [ "${OPT_READ_SAMPLES}" ] \
2163+ || [ -e "$dir/mysqldump" -a -s "$dir/mysqldump" ]; then
2164+ reply="y"
2165+ elif [ -t 0 -a -t 1 ]; then
2166 echo -n "Would you like to mysqldump -d the schema and analyze it? y/n "
2167 read reply
2168 reply=${reply:-n}
2169 fi
2170- if echo "${reply:-n}" | $AP_GREP -i '^y' > /dev/null ; then
2171- # If mysqldump supports triggers, then add options for routines.
2172- if mysqldump --help --verbose 2>&1 | $AP_GREP triggers >/dev/null; then
2173- trg_arg="--routines"
2174- fi
2175- if [ "${trg_arg}" ]; then
2176- # Find out if there are any triggers. If there are none, we will skip
2177- # that option to mysqldump, because when mysqldump checks for them, it
2178- # can take a long time, one table at a time.
2179- triggers="--skip-triggers"
2180- trg=$(mysql "$@" -ss -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TRIGGERS" 2>/dev/null);
2181- if [ "${res}" ]; then
2182- if [ "${res}" -gt 0 ]; then
2183- triggers="--triggers"
2184- fi
2185- fi
2186- trg_arg="${trg_arg} ${triggers}";
2187- fi
2188- # Find out which databases to dump
2189- num_dbs="$($AP_GREP -c . $TMPDIR/percona-toolkit-mysql-databases)"
2190- echo "There are ${num_dbs} databases. Would you like to dump all, or just one?"
2191- echo -n "Type the name of the database, or press Enter to dump all of them. "
2192- read dbtodump
2193- mysqldump "$@" --no-data --skip-comments \
2194- --skip-add-locks --skip-add-drop-table --compact \
2195- --skip-lock-all-tables --skip-lock-tables --skip-set-charset \
2196- ${trg_arg} ${dbtodump:---all-databases} > $TMPDIR/percona-toolkit-mysqldump
2197- # Test the result by checking the file, not by the exit status, because we
2198- # might get partway through and then die, and the info is worth analyzing
2199- # anyway.
2200- if $AP_GREP 'CREATE TABLE' $TMPDIR/percona-toolkit-mysqldump >/dev/null 2>&1; then
2201- format_overall_db_stats $TMPDIR/percona-toolkit-mysqldump
2202+ if echo "${reply:-n}" | grep -i '^y' > /dev/null ; then
2203+ if [ -z "${OPT_DATABASES}" ] && [ -z "$OPT_READ_SAMPLES" ] \
2204+ && [ ! -e "$dir/mysqldump" ]; then
2205+ echo "There are ${num_dbs} databases. Would you like to dump all, or just one?"
2206+ echo -n "Type the name of the database, or press Enter to dump all of them. "
2207+ local dbtodump=""
2208+ read dbtodump
2209+ local trg_arg="$( get_mysqldump_args "$dir/mysql-variables" )"
2210+ get_mysqldump_for "${trg_arg}" "${dbtodump}" > "$dir/mysqldump"
2211+ fi
2212+
2213+ if [ -e "$dir/mysqldump" -a -s "$dir/mysqldump" ] \
2214+ && grep 'CREATE TABLE' "$dir/mysqldump" >/dev/null 2>&1; then
2215+ format_overall_db_stats "$dir/mysqldump"
2216+ elif [ ! -e "$dir/mysqldump" -a "$OPT_READ_SAMPLES" ]; then
2217+ echo "Skipping schema analysis as the directory passed in" \
2218+ "doesn't have a dump file"
2219 else
2220 echo "Skipping schema analysis due to apparent error in dump file"
2221- rm -f $TMPDIR/percona-toolkit-mysqldump
2222 fi
2223 else
2224 echo "Skipping schema analysis"
2225 fi
2226
2227- # ########################################################################
2228- # Noteworthy Technologies
2229- # ########################################################################
2230- section Noteworthy_Technologies
2231- if [ -e $TMPDIR/percona-toolkit-mysqldump ]; then
2232- if $AP_GREP FULLTEXT $TMPDIR/percona-toolkit-mysqldump > /dev/null; then
2233- name_val "Full Text Indexing" Yes
2234- else
2235- name_val "Full Text Indexing" No
2236- fi
2237- if $AP_GREP 'GEOMETRY\|POINT\|LINESTRING\|POLYGON' $TMPDIR/percona-toolkit-mysqldump > /dev/null; then
2238- name_val "Geospatial Types" Yes
2239- else
2240- name_val "Geospatial Types" No
2241- fi
2242- if $AP_GREP 'FOREIGN KEY' $TMPDIR/percona-toolkit-mysqldump > /dev/null; then
2243- name_val "Foreign Keys" Yes
2244- else
2245- name_val "Foreign Keys" No
2246- fi
2247- if $AP_GREP 'PARTITION BY' $TMPDIR/percona-toolkit-mysqldump > /dev/null; then
2248- name_val "Partitioning" Yes
2249- else
2250- name_val "Partitioning" No
2251- fi
2252- fi
2253- if [ "$(get_stat Ssl_accepts)" -gt 0 ]; then
2254- name_val "SSL" Yes
2255- else
2256- name_val "SSL" No
2257- fi
2258- if [ "$(get_stat Com_lock_tables)" -gt 0 ]; then
2259- name_val "Explicit LOCK TABLES" Yes
2260- else
2261- name_val "Explicit LOCK TABLES" No
2262- fi
2263- if [ "$(get_stat Delayed_writes)" -gt 0 ]; then
2264- name_val "Delayed Insert" Yes
2265- else
2266- name_val "Delayed Insert" No
2267- fi
2268- if [ "$(get_stat Com_xa_start)" -gt 0 ]; then
2269- name_val "XA Transactions" Yes
2270- else
2271- name_val "XA Transactions" No
2272- fi
2273- if [ "$(get_stat Ndb_cluster_node_id)" -gt 0 ]; then
2274- name_val "NDB Cluster" Yes
2275- else
2276- name_val "NDB Cluster" No
2277- fi
2278- prep=$(( $(get_stat Com_stmt_prepare) + $(get_stat Com_prepare_sql) ))
2279+ section "Noteworthy Technologies"
2280+ if [ -s "$dir/mysqldump" ]; then
2281+ if grep FULLTEXT "$dir/mysqldump" > /dev/null; then
2282+ name_val "Full Text Indexing" "Yes"
2283+ else
2284+ name_val "Full Text Indexing" "No"
2285+ fi
2286+ if grep 'GEOMETRY\|POINT\|LINESTRING\|POLYGON' "$dir/mysqldump" > /dev/null; then
2287+ name_val "Geospatial Types" "Yes"
2288+ else
2289+ name_val "Geospatial Types" "No"
2290+ fi
2291+ if grep 'FOREIGN KEY' "$dir/mysqldump" > /dev/null; then
2292+ name_val "Foreign Keys" "Yes"
2293+ else
2294+ name_val "Foreign Keys" "No"
2295+ fi
2296+ if grep 'PARTITION BY' "$dir/mysqldump" > /dev/null; then
2297+ name_val "Partitioning" "Yes"
2298+ else
2299+ name_val "Partitioning" "No"
2300+ fi
2301+ if grep -e 'ENGINE=InnoDB.*ROW_FORMAT' \
2302+ -e 'ENGINE=InnoDB.*KEY_BLOCK_SIZE' "$dir/mysqldump" > /dev/null; then
2303+ name_val "InnoDB Compression" "Yes"
2304+ else
2305+ name_val "InnoDB Compression" "No"
2306+ fi
2307+ fi
2308+ local ssl="$(get_var Ssl_accepts "$dir/mysql-status")"
2309+ if [ -n "$ssl" -a "${ssl:-0}" -gt 0 ]; then
2310+ name_val "SSL" "Yes"
2311+ else
2312+ name_val "SSL" "No"
2313+ fi
2314+ local lock_tables="$(get_var Com_lock_tables "$dir/mysql-status")"
2315+ if [ -n "$lock_tables" -a "${lock_tables:-0}" -gt 0 ]; then
2316+ name_val "Explicit LOCK TABLES" "Yes"
2317+ else
2318+ name_val "Explicit LOCK TABLES" "No"
2319+ fi
2320+ local delayed_insert="$(get_var Delayed_writes "$dir/mysql-status")"
2321+ if [ -n "$delayed_insert" -a "${delayed_insert:-0}" -gt 0 ]; then
2322+ name_val "Delayed Insert" "Yes"
2323+ else
2324+ name_val "Delayed Insert" "No"
2325+ fi
2326+ local xat="$(get_var Com_xa_start "$dir/mysql-status")"
2327+ if [ -n "$xat" -a "${xat:-0}" -gt 0 ]; then
2328+ name_val "XA Transactions" "Yes"
2329+ else
2330+ name_val "XA Transactions" "No"
2331+ fi
2332+ local ndb_cluster="$(get_var "Ndb_cluster_node_id" "$dir/mysql-status")"
2333+ if [ -n "$ndb_cluster" -a "${ndb_cluster:-0}" -gt 0 ]; then
2334+ name_val "NDB Cluster" "Yes"
2335+ else
2336+ name_val "NDB Cluster" "No"
2337+ fi
2338+ local prep=$(( $(get_var "Com_stmt_prepare" "$dir/mysql-status") + $(get_var "Com_prepare_sql" "$dir/mysql-status") ))
2339 if [ "${prep}" -gt 0 ]; then
2340- name_val "Prepared Statements" Yes
2341+ name_val "Prepared Statements" "Yes"
2342 else
2343- name_val "Prepared Statements" No
2344+ name_val "Prepared Statements" "No"
2345+ fi
2346+ local prep_count="$(get_var Prepared_stmt_count "$dir/mysql-status")"
2347+ if [ "${prep_count}" ]; then
2348+ name_val "Prepared statement count" "${prep_count}"
2349 fi
2350
2351- # ########################################################################
2352- # InnoDB
2353- # ########################################################################
2354- section InnoDB
2355- have_innodb=$(get_var have_innodb)
2356+ section "InnoDB"
2357+ local have_innodb="$(get_var "have_innodb" "$dir/mysql-variables")"
2358 if [ "${have_innodb}" = "YES" ]; then
2359-
2360- version=$(get_var innodb_version)
2361- name_val Version ${version:-default}
2362-
2363- bp_size="$(get_var innodb_buffer_pool_size)"
2364- name_val "Buffer Pool Size" "$(shorten ${bp_size} 1)"
2365-
2366- bp_pags="$(get_stat Innodb_buffer_pool_pages_total)"
2367- bp_free="$(get_stat Innodb_buffer_pool_pages_free)"
2368- bp_dirt="$(get_stat Innodb_buffer_pool_pages_dirty)"
2369- bp_fill=$((${bp_pags} - ${bp_free}))
2370- name_val "Buffer Pool Fill" "$(fuzzy_pct ${bp_fill} ${bp_pags})"
2371- name_val "Buffer Pool Dirty" "$(fuzzy_pct ${bp_dirt} ${bp_pags})"
2372-
2373- name_val "File Per Table" $(get_var innodb_file_per_table)
2374- name_val "Page Size" $(shorten $(get_stat Innodb_page_size))
2375-
2376- lg_size="$(get_var innodb_log_file_size)"
2377- lg_fils="$(get_var innodb_log_files_in_group)"
2378- lg_totl="$((${lg_size} * ${lg_fils}))"
2379- name_val "Log File Size" "${lg_fils} * $(shorten ${lg_size}) = $(shorten ${lg_totl} 1)"
2380- name_val "Log Buffer Size" $(shorten $(get_var innodb_log_buffer_size))
2381- name_val "Flush Method" $(get_var innodb_flush_method)
2382- name_val "Flush Log At Commit" $(get_var innodb_flush_log_at_trx_commit)
2383- name_val "XA Support" $(get_var innodb_support_xa)
2384- name_val "Checksums" $(get_var innodb_checksums)
2385- name_val "Doublewrite" $(get_var innodb_doublewrite)
2386- name_val "R/W I/O Threads" "$(get_var innodb_read_io_threads) $(get_var innodb_write_io_threads)"
2387- name_val "I/O Capacity" $(get_var innodb_io_capacity)
2388- name_val "Thread Concurrency" $(get_var innodb_thread_concurrency)
2389- name_val "Concurrency Tickets" $(get_var innodb_concurrency_tickets)
2390- name_val "Commit Concurrency" $(get_var innodb_commit_concurrency)
2391- name_val "Txn Isolation Level" $(get_var tx_isolation)
2392- name_val "Adaptive Flushing" $(get_var innodb_adaptive_flushing)
2393- name_val "Adaptive Checkpoint" $(get_var innodb_adaptive_checkpoint)
2394-
2395- if [ -s $TMPDIR/percona-toolkit-innodb-status ]; then
2396- format_innodb_status $TMPDIR/percona-toolkit-innodb-status
2397+ section_innodb "$dir/mysql-variables" "$dir/mysql-status"
2398+
2399+ if [ -s "$dir/innodb-status" ]; then
2400+ format_innodb_status "$dir/innodb-status"
2401 fi
2402 fi
2403
2404- # ########################################################################
2405- # MyISAM
2406- # ########################################################################
2407- section MyISAM
2408- buf_size=$(get_var key_buffer_size)
2409- blk_size=$(get_var key_cache_block_size)
2410- blk_unus=$(get_stat Key_blocks_unused)
2411- blk_unfl=$(get_stat Key_blocks_not_flushed)
2412- unus=$((${blk_unus} * ${blk_size}))
2413- unfl=$((${blk_unfl} * ${blk_size}))
2414- used=$((${buf_size} - ${unus}))
2415- name_val "Key Cache" "$(shorten ${buf_size} 1)"
2416- name_val "Pct Used" "$(fuzzy_pct ${used} ${buf_size})"
2417- name_val "Unflushed" "$(fuzzy_pct ${unfl} ${buf_size})"
2418-
2419- # ########################################################################
2420- # Users & Security
2421- # ########################################################################
2422- section Security
2423- users="$(mysql "$@" -ss \
2424- -e 'SELECT COUNT(*), SUM(user=""), SUM(password=""), SUM(password NOT LIKE "*%") FROM mysql.user' 2>/dev/null \
2425- | $AP_AWK '{printf "%d users, %d anon, %d w/o pw, %d old pw\n", $1, $2, $3, $4}')"
2426- name_val Users "${users}"
2427- name_val "Old Passwords" $(get_var old_passwords)
2428-
2429- # ########################################################################
2430- # Binary Logging
2431- # ########################################################################
2432- section Binary_Logging
2433- binlog=$(get_var log_bin)
2434- if [ "${binlog}" ]; then
2435- mysql "$@" -ss -e 'SHOW MASTER LOGS' > $TMPDIR/percona-toolkit 2>/dev/null
2436- summarize_binlogs $TMPDIR/percona-toolkit
2437- format="$(get_var binlog_format)"
2438+ section "MyISAM"
2439+ section_myisam "$dir/mysql-variables" "$dir/mysql-status"
2440+
2441+ section "Security"
2442+ local users="$( format_users "$dir/mysql-users" )"
2443+ name_val "Users" "${users}"
2444+ name_val "Old Passwords" "$(get_var old_passwords "$dir/mysql-variables")"
2445+
2446+ section "Binary Logging"
2447+
2448+ if [ -s "$dir/mysql-master-logs" ] \
2449+ || [ -s "$dir/mysql-master-status" ]; then
2450+ summarize_binlogs "$dir/mysql-master-logs"
2451+ local format="$(get_var binlog_format "$dir/mysql-variables")"
2452 name_val binlog_format "${format:-STATEMENT}"
2453- name_val expire_logs_days $(get_var expire_logs_days)
2454- name_val sync_binlog $(get_var sync_binlog)
2455- name_val server_id $(get_var server_id)
2456- mysql "$@" -ss -e 'SHOW MASTER STATUS' > $TMPDIR/percona-toolkit 2>/dev/null
2457- format_binlog_filters $TMPDIR/percona-toolkit
2458- fi
2459-
2460-# Replication: seconds behind, running, filters, skip_slave_start, skip_errors,
2461-# read_only, temp tables open, slave_net_timeout, slave_exec_mode
2462-
2463- # ########################################################################
2464- # Interesting things that you just ought to know about.
2465- # ########################################################################
2466- section Noteworthy_Variables
2467- name_val "Auto-Inc Incr/Offset" "$(get_var auto_increment_increment)/$(get_var auto_increment_offset)"
2468- for v in \
2469- default_storage_engine flush_time init_connect init_file sql_mode;
2470- do
2471- name_val ${v} $(get_var ${v})
2472- done
2473- for v in \
2474- join_buffer_size sort_buffer_size read_buffer_size read_rnd_buffer_size \
2475- bulk_insert_buffer max_heap_table_size tmp_table_size \
2476- max_allowed_packet thread_stack;
2477- do
2478- name_val ${v} $(shorten $(get_var ${v}))
2479- done
2480- for v in log log_error log_warnings log_slow_queries \
2481- log_queries_not_using_indexes log_slave_updates;
2482- do
2483- name_val ${v} $(get_var ${v})
2484- done
2485-
2486- # ########################################################################
2487- # If there is a my.cnf in a standard location, see if we can pretty-print it.
2488- # ########################################################################
2489- section Configuration_File
2490- ps auxww 2>/dev/null | $AP_GREP mysqld > $TMPDIR/percona-toolkit
2491- cnf_file=$(find_my_cnf_file $TMPDIR/percona-toolkit ${port});
2492- if [ ! -e "${cnf_file}" ]; then
2493- name_val "Config File" "Cannot autodetect, trying common locations"
2494- cnf_file="/etc/my.cnf";
2495- fi
2496- if [ ! -e "${cnf_file}" ]; then
2497- cnf_file="/etc/mysql/my.cnf";
2498- fi
2499- if [ ! -e "${cnf_file}" ]; then
2500- cnf_file="/var/db/mysql/my.cnf";
2501- fi
2502- if [ -e "${cnf_file}" ]; then
2503+ name_val expire_logs_days "$(get_var expire_logs_days "$dir/mysql-variables")"
2504+ name_val sync_binlog "$(get_var sync_binlog "$dir/mysql-variables")"
2505+ name_val server_id "$(get_var server_id "$dir/mysql-variables")"
2506+ format_binlog_filters "$dir/mysql-master-status"
2507+ fi
2508+
2509+
2510+ section "Noteworthy Variables"
2511+ section_noteworthy_variables "$dir/mysql-variables"
2512+
2513+ section "Configuration File"
2514+ local cnf_file="$(get_var "pt-summary-internal-Config_File_path" "$dir/mysql-variables")"
2515+ if [ -n "${cnf_file}" ]; then
2516 name_val "Config File" "${cnf_file}"
2517- cat "${cnf_file}" > $TMPDIR/percona-toolkit
2518- pretty_print_cnf_file $TMPDIR/percona-toolkit
2519+ pretty_print_cnf_file "$dir/mysql-config-file"
2520 else
2521 name_val "Config File" "Cannot autodetect or find, giving up"
2522 fi
2523
2524- temp_files "rm"
2525-
2526- # Make sure that we signal the end of the tool's output.
2527- section The_End
2528-
2529- rm_tmpdir
2530-}
2531-
2532-# Execute the program if it was not included from another file. This makes it
2533-# possible to include without executing, and thus test.
2534-if [ "$(basename "$0")" = "pt-mysql-summary" ]; then main "$@"; fi
2535+ section "The End"
2536+}
2537+
2538+# ###########################################################################
2539+# End report_mysql_info package
2540+# ###########################################################################
2541+
2542+# ########################################################################
2543+# Some global setup is necessary for cross-platform compatibility, even
2544+# when sourcing this script for testing purposes.
2545+# ########################################################################
2546+
2547+TOOL="pt-mysql-summary"
2548+
2549+CMD_MYSQL="$(_which mysql)"
2550+CMD_MYSQLDUMP="$( _which mysqldump )"
2551+
2552+check_mysql () {
2553+ # Check that mysql and mysqldump are in PATH. If not, we're
2554+ # already dead in the water, so don't bother with cmd line opts,
2555+ # just error and exit.
2556+ [ -n "$(mysql --help 2>/dev/null)" ] \
2557+ || die "Cannot execute mysql. Check that it is in PATH."
2558+ [ -n "$(mysqldump --help 2>/dev/null)" ] \
2559+ || die "Cannot execute mysqldump. Check that it is in PATH."
2560+
2561+ # Now that we have the cmd line opts, check that we can actually
2562+ # connect to MySQL.
2563+ [ -n "$(mysql $EXT_ARGV -e 'SELECT 1')" ] \
2564+ || die "Cannot connect to MySQL. Check that MySQL is running and that the options after -- are correct."
2565+
2566+}
2567+
2568+sigtrap() {
2569+ warn "Caught signal, forcing exit"
2570+ rm_tmpdir
2571+ exit $EXIT_STATUS
2572+}
2573+
2574+# ##############################################################################
2575+# The main() function is called at the end of the script. This makes it
2576+# testable. Major bits of parsing are separated into functions for testability.
2577+# ##############################################################################
2578+main() {
2579+ # Prepending SIG to these doesn't work with NetBSD's sh
2580+ trap sigtrap HUP INT TERM
2581+
2582+ local RAN_WITH="--sleep=$OPT_SLEEP --databases=$OPT_DATABASES --save-samples=$OPT_SAVE_SAMPLES"
2583+
2584+ _d "Starting $0 $RAN_WITH"
2585+
2586+ # Begin by setting the $PATH to include some common locations that are not
2587+ # always in the $PATH, including the "sbin" locations. On SunOS systems,
2588+ # prefix the path with the location of more sophisticated utilities.
2589+ export PATH="${PATH}:/usr/local/bin:/usr/bin:/bin:/usr/libexec"
2590+ export PATH="${PATH}:/usr/mysql/bin/:/usr/local/sbin:/usr/sbin:/sbin"
2591+ export PATH="/usr/gnu/bin/:/usr/xpg4/bin/:${PATH}"
2592+
2593+ _d "Going to use: mysql=${CMD_MYSQL} mysqldump=${CMD_MYSQLDUMP}"
2594+
2595+ # Create the tmpdir for everything to run in
2596+ mk_tmpdir
2597+
2598+ # Set DATA_DIR where we'll save collected data files.
2599+ local data_dir="$(setup_data_dir "${OPT_SAVE_SAMPLES:-""}")"
2600+ if [ -z "$data_dir" ]; then
2601+ exit $?
2602+ fi
2603+
2604+ if [ -n "$OPT_READ_SAMPLES" -a -d "$OPT_READ_SAMPLES" ]; then
2605+ # --read-samples was set and is a directory, so the samples
2606+ # will already be there.
2607+ data_dir="$OPT_READ_SAMPLES"
2608+ else
2609+ # #####################################################################
2610+ # Fetch most info, leave a child in the background gathering the rest
2611+ # #####################################################################
2612+ collect_mysql_info "${data_dir}" 2>"${data_dir}/collect.err"
2613+ fi
2614+
2615+ # ########################################################################
2616+ # Format and pretty-print the data
2617+ # ########################################################################
2618+ report_mysql_summary "${data_dir}"
2619+
2620+ rm_tmpdir
2621+
2622+}
2623+
2624+# Execute the program if it was not included from another file.
2625+# This makes it possible to include without executing, and thus test.
2626+if [ "${0##*/}" = "$TOOL" ] \
2627+ || [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
2628+
2629+ # Set up temporary dir.
2630+ mk_tmpdir
2631+ # Parse command line options.
2632+ parse_options "$0" "$@"
2633+
2634+ # Verify that --sleep, if present, is positive
2635+ if [ -n "$OPT_SLEEP" ] && [ "$OPT_SLEEP" -lt 0 ]; then
2636+ option_error "Invalid --sleep value: $sleep"
2637+ fi
2638+
2639+ usage_or_errors "$0"
2640+ po_status=$?
2641+ rm_tmpdir
2642+
2643+ if [ $po_status -ne 0 ]; then
2644+ [ $OPT_ERRS -gt 0 ] && exit 1
2645+ exit 0
2646+ fi
2647+
2648+ # Check if mysql and mysqldump are there, otherwise bail out early.
2649+ # But don't if they passed in --read-samples, since we don't need
2650+ # a connection then.
2651+ [ "$OPT_READ_SAMPLES" ] || check_mysql
2652+
2653+ main "$@"
2654+fi
2655
2656 # ############################################################################
2657 # Documentation
2658@@ -1335,11 +2333,11 @@
2659
2660 =head1 NAME
2661
2662-pt-mysql-summary - Summarize MySQL information in a nice way.
2663+pt-mysql-summary - Summarize MySQL information nicely.
2664
2665 =head1 SYNOPSIS
2666
2667-Usage: pt-mysql-summary [MYSQL-OPTIONS]
2668+Usage: pt-mysql-summary [OPTIONS] [-- MYSQL OPTIONS]
2669
2670 pt-mysql-summary conveniently summarizes the status and configuration of a
2671 MySQL database server so that you can learn about it at a glance. It is not
2672@@ -1356,8 +2354,7 @@
2673
2674 pt-mysql-summary is a read-only tool. It should be very low-risk.
2675
2676-At the time of this release, we know of no bugs that could cause serious harm
2677-to users.
2678+At the time of this release, we know of no bugs that could harm users.
2679
2680 The authoritative source for updated information is always the online issue
2681 tracking system. Issues that affect this tool will be marked as such. You can
2682@@ -1373,34 +2370,435 @@
2683 into files in a temporary directory, and then formats them neatly with awk
2684 and other scripting languages.
2685
2686-To use, simply execute it. Optionally add the same command-line options
2687-you would use to connect to MySQL, like C<pt-mysql-summary --user=foo>.
2688+To use, simply execute it. Optionally add a double dash and then the same
2689+command-line options you would use to connect to MySQL, such as the following:
2690+
2691+ pt-mysql-summary -- --user=root
2692
2693 The tool interacts minimally with the server upon which it runs. It assumes
2694 that you'll run it on the same server you're inspecting, and therefore it
2695-assumes that it will be able to find the my.cnf configuration file, for
2696-example. However, it should degrade gracefully if this is not the case.
2697-Note, however, that its output does not indicate which information comes from
2698-the MySQL database and which comes from the host operating system, so it is
2699-possible for confusing output to be generated if you run the tool on one
2700-server and direct it to connect to a MySQL database server running on another
2701-server.
2702+assumes that it will be able to find the my.cnf configuration file, for example.
2703+However, it should degrade gracefully if this is not the case. Note, however,
2704+that its output does not indicate which information comes from the MySQL
2705+database and which comes from the host operating system, so it is possible for
2706+confusing output to be generated if you run the tool on one server and connect
2707+to a MySQL database server running on another server.
2708
2709-=head1 Fuzzy-Rounding
2710+=head1 OUTPUT
2711
2712 Many of the outputs from this tool are deliberately rounded to show their
2713 magnitude but not the exact detail. This is called fuzzy-rounding. The idea
2714-is that it doesn't matter whether a server is running 918 queries per second
2715+is that it does not matter whether a server is running 918 queries per second
2716 or 921 queries per second; such a small variation is insignificant, and only
2717 makes the output hard to compare to other servers. Fuzzy-rounding rounds in
2718 larger increments as the input grows. It begins by rounding to the nearest 5,
2719 then the nearest 10, nearest 25, and then repeats by a factor of 10 larger
2720 (50, 100, 250), and so on, as the input grows.
2721
2722+The following is a sample of the report that the tool produces:
2723+
2724+ # Percona Toolkit MySQL Summary Report #######################
2725+ System time | 2012-03-30 18:46:05 UTC
2726+ (local TZ: EDT -0400)
2727+ # Instances ##################################################
2728+ Port Data Directory Nice OOM Socket
2729+ ===== ========================== ==== === ======
2730+ 12345 /tmp/12345/data 0 0 /tmp/12345.sock
2731+ 12346 /tmp/12346/data 0 0 /tmp/12346.sock
2732+ 12347 /tmp/12347/data 0 0 /tmp/12347.sock
2733+
2734+The first two sections show which server the report was generated on and which
2735+MySQL instances are running on the server. This is detected from the output of
2736+C<ps> and does not always detect all instances and parameters, but often works
2737+well. From this point forward, the report will be focused on a single MySQL
2738+instance, although several instances may appear in the above paragraph.
2739+
2740+ # Report On Port 12345 #######################################
2741+ User | msandbox@%
2742+ Time | 2012-03-30 14:46:05 (EDT)
2743+ Hostname | localhost.localdomain
2744+ Version | 5.5.20-log MySQL Community Server (GPL)
2745+ Built On | linux2.6 i686
2746+ Started | 2012-03-28 23:33 (up 1+15:12:09)
2747+ Databases | 4
2748+ Datadir | /tmp/12345/data/
2749+ Processes | 2 connected, 2 running
2750+ Replication | Is not a slave, has 1 slaves connected
2751+ Pidfile | /tmp/12345/data/12345.pid (exists)
2752+
2753+This section is a quick summary of the MySQL instance: version, uptime, and
2754+other very basic parameters. The Time output is generated from the MySQL server,
2755+unlike the system date and time printed earlier, so you can see whether the
2756+database and operating system times match.
2757+
2758+ # Processlist ################################################
2759+
2760+ Command COUNT(*) Working SUM(Time) MAX(Time)
2761+ ------------------------------ -------- ------- --------- ---------
2762+ Binlog Dump 1 1 150000 150000
2763+ Query 1 1 0 0
2764+
2765+ User COUNT(*) Working SUM(Time) MAX(Time)
2766+ ------------------------------ -------- ------- --------- ---------
2767+ msandbox 2 2 150000 150000
2768+
2769+ Host COUNT(*) Working SUM(Time) MAX(Time)
2770+ ------------------------------ -------- ------- --------- ---------
2771+ localhost 2 2 150000 150000
2772+
2773+ db COUNT(*) Working SUM(Time) MAX(Time)
2774+ ------------------------------ -------- ------- --------- ---------
2775+ NULL 2 2 150000 150000
2776+
2777+ State COUNT(*) Working SUM(Time) MAX(Time)
2778+ ------------------------------ -------- ------- --------- ---------
2779+ Master has sent all binlog to 1 1 150000 150000
2780+ NULL 1 1 0 0
2781+
2782+This section is a summary of the output from SHOW PROCESSLIST. Each sub-section
2783+is aggregated by a different item, which is shown as the first column heading.
2784+When summarized by Command, every row in SHOW PROCESSLIST is included, but
2785+otherwise, rows whose Command is Sleep are excluded from the SUM and MAX
2786+columns, so they do not skew the numbers too much. In the example shown, the
2787+server is idle except for this tool itself, and one connected replica, which
2788+is executing Binlog Dump.
2789+
2790+The columns are the number of rows included, the number that are not in Sleep
2791+status, the sum of the Time column, and the maximum Time column. The numbers are
2792+fuzzy-rounded.
2793+
2794+ # Status Counters (Wait 10 Seconds) ##########################
2795+ Variable Per day Per second 10 secs
2796+ Binlog_cache_disk_use 4
2797+ Binlog_cache_use 80
2798+ Bytes_received 15000000 175 200
2799+ Bytes_sent 15000000 175 2000
2800+ Com_admin_commands 1
2801+ ...................(many lines omitted)............................
2802+ Threads_created 40 1
2803+ Uptime 90000 1 1
2804+
2805+This section shows selected counters from two snapshots of SHOW GLOBAL STATUS,
2806+gathered approximately 10 seconds apart and fuzzy-rounded. It includes only
2807+items that are incrementing counters; it does not include absolute numbers such
2808+as the Threads_running status variable, which represents a current value, rather
2809+than an accumulated number over time.
2810+
2811+The first column is the variable name, and the second column is the counter from
2812+the first snapshot divided by 86400 (the number of seconds in a day), so you can
2813+see the magnitude of the counter's change per day. 86400 fuzzy-rounds to 90000,
2814+so the Uptime counter should always be about 90000.
2815+
2816+The third column is the value from the first snapshot, divided by Uptime and
2817+then fuzzy-rounded, so it represents approximately how quickly the counter is
2818+growing per-second over the uptime of the server.
2819+
2820+The third column is the incremental difference from the first and second
2821+snapshot, divided by the difference in uptime and then fuzzy-rounded. Therefore,
2822+it shows how quickly the counter is growing per second at the time the report
2823+was generated.
2824+
2825+ # Table cache ################################################
2826+ Size | 400
2827+ Usage | 15%
2828+
2829+This section shows the size of the table cache, followed by the percentage of
2830+the table cache in use. The usage is fuzzy-rounded.
2831+
2832+ # Key Percona Server features ################################
2833+ Table & Index Stats | Not Supported
2834+ Multiple I/O Threads | Enabled
2835+ Corruption Resilient | Not Supported
2836+ Durable Replication | Not Supported
2837+ Import InnoDB Tables | Not Supported
2838+ Fast Server Restarts | Not Supported
2839+ Enhanced Logging | Not Supported
2840+ Replica Perf Logging | Not Supported
2841+ Response Time Hist. | Not Supported
2842+ Smooth Flushing | Not Supported
2843+ HandlerSocket NoSQL | Not Supported
2844+ Fast Hash UDFs | Unknown
2845+
2846+This section shows features that are available in Percona Server and whether
2847+they are enabled or not. In the example shown, the server is standard MySQL, not
2848+Percona Server, so the features are generally not supported.
2849+
2850+ # Plugins ####################################################
2851+ InnoDB compression | ACTIVE
2852+
2853+This feature shows specific plugins and whether they are enabled.
2854+
2855+ # Query cache ################################################
2856+ query_cache_type | ON
2857+ Size | 0.0
2858+ Usage | 0%
2859+ HitToInsertRatio | 0%
2860+
2861+This section shows whether the query cache is enabled and its size, followed by
2862+the percentage of the cache in use and the hit-to-insert ratio. The latter two
2863+are fuzzy-rounded.
2864+
2865+ # Schema #####################################################
2866+ Would you like to mysqldump -d the schema and analyze it? y/n y
2867+ There are 4 databases. Would you like to dump all, or just one?
2868+ Type the name of the database, or press Enter to dump all of them.
2869+
2870+ Database Tables Views SPs Trigs Funcs FKs Partn
2871+ mysql 24
2872+ performance_schema 17
2873+ sakila 16 7 3 6 3 22
2874+
2875+ Database MyISAM CSV PERFORMANCE_SCHEMA InnoDB
2876+ mysql 22 2
2877+ performance_schema 17
2878+ sakila 8 15
2879+
2880+ Database BTREE FULLTEXT
2881+ mysql 31
2882+ performance_schema
2883+ sakila 63 1
2884+
2885+ c t s e l d i t m v s
2886+ h i e n o a n i e a m
2887+ a m t u n t t n d r a
2888+ r e m g e y i c l
2889+ s b t i u h l
2890+ t l i n m a i
2891+ a o m t t r n
2892+ m b e e t
2893+ p x
2894+ t
2895+ Database === === === === === === === === === === ===
2896+ mysql 61 10 6 78 5 4 26 3 4 5 3
2897+ performance_schema 5 16 33
2898+ sakila 1 15 1 3 4 3 19 42 26
2899+
2900+If you select to dump the schema and analyze it, the tool will print the above
2901+section. This summarizes the number and type of objects in the database. It is
2902+generated by running C<mysqldump --no-data>, not by querying the
2903+INFORMATION_SCHEMA, which can freeze a busy server. You can use the
2904+L<"--databases"> option to specify which databases to examine. If you do not,
2905+and you run the tool interactively, it will prompt you as shown.
2906+
2907+You can choose not to dump the schema, to dump all of the databases, or to dump
2908+only a single named one, by specifying the appropriate options. In the example
2909+above, we are dumping all databases.
2910+
2911+The first sub-report in the section is the count of objects by type in each
2912+database: tables, views, and so on. The second one shows how many tables use
2913+various storage engines in each database. The third sub-report shows the number
2914+of each type of indexes in each database.
2915+
2916+The last section shows the number of columns of various data types in each
2917+database. For compact display, the column headers are formatted vertically, so
2918+you need to read downwards from the top. In this example, the first column is
2919+C<char> and the second column is C<timestamp>. This example is truncated so it
2920+does not wrap on a terminal.
2921+
2922+All of the numbers in this portion of the output are exact, not fuzzy-rounded.
2923+
2924+ # Noteworthy Technologies ####################################
2925+ Full Text Indexing | Yes
2926+ Geospatial Types | No
2927+ Foreign Keys | Yes
2928+ Partitioning | No
2929+ InnoDB Compression | Yes
2930+ SSL | No
2931+ Explicit LOCK TABLES | No
2932+ Delayed Insert | No
2933+ XA Transactions | No
2934+ NDB Cluster | No
2935+ Prepared Statements | No
2936+ Prepared statement count | 0
2937+
2938+This section shows some specific technologies used on this server. Some of them
2939+are detected from the schema dump performed for the previous sections; others
2940+can be detected by looking at SHOW GLOBAL STATUS.
2941+
2942+ # InnoDB #####################################################
2943+ Version | 1.1.8
2944+ Buffer Pool Size | 16.0M
2945+ Buffer Pool Fill | 100%
2946+ Buffer Pool Dirty | 0%
2947+ File Per Table | OFF
2948+ Page Size | 16k
2949+ Log File Size | 2 * 5.0M = 10.0M
2950+ Log Buffer Size | 8M
2951+ Flush Method |
2952+ Flush Log At Commit | 1
2953+ XA Support | ON
2954+ Checksums | ON
2955+ Doublewrite | ON
2956+ R/W I/O Threads | 4 4
2957+ I/O Capacity | 200
2958+ Thread Concurrency | 0
2959+ Concurrency Tickets | 500
2960+ Commit Concurrency | 0
2961+ Txn Isolation Level | REPEATABLE-READ
2962+ Adaptive Flushing | ON
2963+ Adaptive Checkpoint |
2964+ Checkpoint Age | 0
2965+ InnoDB Queue | 0 queries inside InnoDB, 0 queries in queue
2966+ Oldest Transaction | 0 Seconds
2967+ History List Len | 209
2968+ Read Views | 1
2969+ Undo Log Entries | 1 transactions, 1 total undo, 1 max undo
2970+ Pending I/O Reads | 0 buf pool reads, 0 normal AIO,
2971+ 0 ibuf AIO, 0 preads
2972+ Pending I/O Writes | 0 buf pool (0 LRU, 0 flush list, 0 page);
2973+ 0 AIO, 0 sync, 0 log IO (0 log, 0 chkp);
2974+ 0 pwrites
2975+ Pending I/O Flushes | 0 buf pool, 0 log
2976+ Transaction States | 1xnot started
2977+
2978+This section shows important configuration variables for the InnoDB storage
2979+engine. The buffer pool fill percent and dirty percent are fuzzy-rounded. The
2980+last few lines are derived from the output of SHOW INNODB STATUS. It is likely
2981+that this output will change in the future to become more useful.
2982+
2983+ # MyISAM #####################################################
2984+ Key Cache | 16.0M
2985+ Pct Used | 10%
2986+ Unflushed | 0%
2987+
2988+This section shows the size of the MyISAM key cache, followed by the percentage
2989+of the cache in use and percentage unflushed (fuzzy-rounded).
2990+
2991+ # Security ###################################################
2992+ Users | 2 users, 0 anon, 0 w/o pw, 0 old pw
2993+ Old Passwords | OFF
2994+
2995+This section is generated from queries to tables in the mysql system database.
2996+It shows how many users exist, and various potential security risks such as
2997+old-style passwords and users without passwords.
2998+
2999+ # Binary Logging #############################################
3000+ Binlogs | 1
3001+ Zero-Sized | 0
3002+ Total Size | 21.8M
3003+ binlog_format | STATEMENT
3004+ expire_logs_days | 0
3005+ sync_binlog | 0
3006+ server_id | 12345
3007+ binlog_do_db |
3008+ binlog_ignore_db |
3009+
3010+This section shows configuration and status of the binary logs. If there are
3011+zero-sized binary logs, then it is possible that the binlog index is out of sync
3012+with the binary logs that actually exist on disk.
3013+
3014+ # Noteworthy Variables #######################################
3015+ Auto-Inc Incr/Offset | 1/1
3016+ default_storage_engine | InnoDB
3017+ flush_time | 0
3018+ init_connect |
3019+ init_file |
3020+ sql_mode |
3021+ join_buffer_size | 128k
3022+ sort_buffer_size | 2M
3023+ read_buffer_size | 128k
3024+ read_rnd_buffer_size | 256k
3025+ bulk_insert_buffer | 0.00
3026+ max_heap_table_size | 16M
3027+ tmp_table_size | 16M
3028+ max_allowed_packet | 1M
3029+ thread_stack | 192k
3030+ log | OFF
3031+ log_error | /tmp/12345/data/mysqld.log
3032+ log_warnings | 1
3033+ log_slow_queries | ON
3034+ log_queries_not_using_indexes | OFF
3035+ log_slave_updates | ON
3036+
3037+This section shows several noteworthy server configuration variables that might
3038+be important to know about when working with this server.
3039+
3040+ # Configuration File #########################################
3041+ Config File | /tmp/12345/my.sandbox.cnf
3042+ [client]
3043+ user = msandbox
3044+ password = msandbox
3045+ port = 12345
3046+ socket = /tmp/12345/mysql_sandbox12345.sock
3047+ [mysqld]
3048+ port = 12345
3049+ socket = /tmp/12345/mysql_sandbox12345.sock
3050+ pid-file = /tmp/12345/data/mysql_sandbox12345.pid
3051+ basedir = /home/baron/5.5.20
3052+ datadir = /tmp/12345/data
3053+ key_buffer_size = 16M
3054+ innodb_buffer_pool_size = 16M
3055+ innodb_data_home_dir = /tmp/12345/data
3056+ innodb_log_group_home_dir = /tmp/12345/data
3057+ innodb_data_file_path = ibdata1:10M:autoextend
3058+ innodb_log_file_size = 5M
3059+ log-bin = mysql-bin
3060+ relay_log = mysql-relay-bin
3061+ log_slave_updates
3062+ server-id = 12345
3063+ report-host = 127.0.0.1
3064+ report-port = 12345
3065+ log-error = mysqld.log
3066+ innodb_lock_wait_timeout = 3
3067+ # The End ####################################################
3068+
3069+This section shows a pretty-printed version of the my.cnf file, with comments
3070+removed and with whitespace added to align things for easy reading. The tool
3071+tries to detect the my.cnf file by looking at the output of ps, and if it does
3072+not find the location of the file there, it tries common locations until it
3073+finds a file. Note that this file might not actually correspond with the server
3074+from which the report was generated. This can happen when the tool isn't run on
3075+the same server it's reporting on, or when detecting the location of the
3076+configuration file fails.
3077+
3078 =head1 OPTIONS
3079
3080-This tool does not have any command-line options of its own. All options
3081-are passed to C<mysql>.
3082+All options after -- are passed to C<mysql>.
3083+
3084+=over
3085+
3086+=item --config
3087+
3088+type: string
3089+
3090+Read this comma-separated list of config files. If specified, this must be the
3091+first option on the command line.
3092+
3093+=item --help
3094+
3095+Print help and exit.
3096+
3097+=item --save-samples
3098+
3099+type: string
3100+
3101+Save the data files used to generate the summary in this directory.
3102+
3103+=item --read-samples
3104+
3105+type: string
3106+
3107+Create a report from the files found in this directory.
3108+
3109+=item --databases
3110+
3111+type: string
3112+
3113+Names of databases to summarize. If you want all of them, you can use the value
3114+C<--all-databases>; you can also pass in a comma-separated list of database
3115+names. If not provided, the program will ask you for manual input.
3116+
3117+=item --sleep
3118+
3119+type: int; default: 10
3120+
3121+Seconds to sleep when gathering status counters.
3122+
3123+=item --version
3124+
3125+Print tool's version and exit.
3126+
3127+=back
3128
3129 =head1 ENVIRONMENT
3130
3131@@ -1408,7 +2806,9 @@
3132
3133 =head1 SYSTEM REQUIREMENTS
3134
3135-This tool requires Bash v3 or newer.
3136+This tool requires Bash v3 or newer, Perl 5.8 or newer, and binutils.
3137+These are generally already provided by most distributions.
3138+On BSD systems, it may require a mounted procfs.
3139
3140 =head1 BUGS
3141
3142@@ -1454,7 +2854,7 @@
3143
3144 =head1 AUTHORS
3145
3146-Baron Schwartz
3147+Baron Schwartz, Brian Fraser, and Daniel Nichter.
3148
3149 =head1 ABOUT PERCONA TOOLKIT
3150
3151@@ -1467,7 +2867,7 @@
3152
3153 =head1 COPYRIGHT, LICENSE, AND WARRANTY
3154
3155-This program is copyright 2010-2011 Baron Schwartz, 2011-2012 Percona Inc.
3156+This program is copyright 2010-2011 Baron Schwartz, 2011 Percona Inc.
3157 Feedback and improvements are welcome.
3158
3159 THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
3160
3161=== modified file 'bin/pt-summary'
3162--- bin/pt-summary 2012-03-07 23:41:54 +0000
3163+++ bin/pt-summary 2012-04-03 15:57:31 +0000
3164@@ -4,45 +4,428 @@
3165 # See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
3166 # notices and disclaimers.
3167
3168+set -u
3169+
3170 # ########################################################################
3171 # Globals, settings, helper functions
3172 # ########################################################################
3173+TOOL="pt-summary"
3174 POSIXLY_CORRECT=1
3175 export POSIXLY_CORRECT
3176
3177-# The awk code for fuzzy rounding. (It's used in a few places, so makes sense
3178-# not to duplicate). It fuzzy-rounds the variable named fuzzy_var. It goes in
3179-# steps of 5, 10, 25, then repeats by a factor of 10 larger (50, 100, 250), and
3180-# so on, until it finds a number that's large enough. The pattern is slightly
3181-# broken between the initial 1 and 50, because rounding to the nearest 2.5
3182-# doesn't seem right to me.
3183-fuzzy_formula='
3184- rounded = 0;
3185- if (fuzzy_var <= 10 ) {
3186- rounded = 1;
3187- }
3188- factor = 1;
3189- while ( rounded == 0 ) {
3190- if ( fuzzy_var <= 50 * factor ) {
3191- fuzzy_var = sprintf("%.0f", fuzzy_var / (5 * factor)) * 5 * factor;
3192- rounded = 1;
3193- }
3194- else if ( fuzzy_var <= 100 * factor) {
3195- fuzzy_var = sprintf("%.0f", fuzzy_var / (10 * factor)) * 10 * factor;
3196- rounded = 1;
3197- }
3198- else if ( fuzzy_var <= 250 * factor) {
3199- fuzzy_var = sprintf("%.0f", fuzzy_var / (25 * factor)) * 25 * factor;
3200- rounded = 1;
3201- }
3202- factor = factor * 10;
3203- }'
3204-
3205-# Does fuzzy rounding: rounds to nearest interval, but the interval gets larger
3206-# as the number gets larger. This is to make things easier to diff.
3207-fuzz () {
3208- echo $1 | $AP_AWK "{fuzzy_var=\$1; ${fuzzy_formula} print fuzzy_var;}"
3209-}
3210+# ###########################################################################
3211+# log_warn_die package
3212+# This package is a copy without comments from the original. The original
3213+# with comments and its test file can be found in the Bazaar repository at,
3214+# lib/bash/log_warn_die.sh
3215+# t/lib/bash/log_warn_die.sh
3216+# See https://launchpad.net/percona-toolkit for more information.
3217+# ###########################################################################
3218+
3219+
3220+set -u
3221+
3222+PTFUNCNAME=""
3223+PTDEBUG="${PTDEBUG:-""}"
3224+EXIT_STATUS=0
3225+
3226+log() {
3227+ TS=$(date +%F-%T | tr :- _);
3228+ echo "$TS $*"
3229+}
3230+
3231+warn() {
3232+ log "$*" >&2
3233+ EXIT_STATUS=1
3234+}
3235+
3236+die() {
3237+ warn "$*"
3238+ exit 1
3239+}
3240+
3241+_d () {
3242+ [ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
3243+}
3244+
3245+# ###########################################################################
3246+# End log_warn_die package
3247+# ###########################################################################
3248+
3249+# ###########################################################################
3250+# parse_options package
3251+# This package is a copy without comments from the original. The original
3252+# with comments and its test file can be found in the Bazaar repository at,
3253+# lib/bash/parse_options.sh
3254+# t/lib/bash/parse_options.sh
3255+# See https://launchpad.net/percona-toolkit for more information.
3256+# ###########################################################################
3257+
3258+
3259+
3260+
3261+
3262+set -u
3263+
3264+ARGV="" # Non-option args (probably input files)
3265+EXT_ARGV="" # Everything after -- (args for an external command)
3266+HAVE_EXT_ARGV="" # Got --, everything else is put into EXT_ARGV
3267+OPT_ERRS=0 # How many command line option errors
3268+OPT_VERSION="" # If --version was specified
3269+OPT_HELP="" # If --help was specified
3270+PO_DIR="" # Directory with program option spec files
3271+
3272+usage() {
3273+ local file="$1"
3274+
3275+ local usage=$(grep '^Usage: ' "$file")
3276+ echo $usage
3277+ echo
3278+ echo "For more information, 'man $TOOL' or 'perldoc $file'."
3279+}
3280+
3281+usage_or_errors() {
3282+ local file="$1"
3283+
3284+ if [ "$OPT_VERSION" ]; then
3285+ local version=$(grep '^pt-[^ ]\+ [0-9]' "$file")
3286+ echo "$version"
3287+ return 1
3288+ fi
3289+
3290+ if [ "$OPT_HELP" ]; then
3291+ usage "$file"
3292+ echo
3293+ echo "Command line options:"
3294+ echo
3295+ perl -e '
3296+ use strict;
3297+ use warnings FATAL => qw(all);
3298+ my $lcol = 20; # Allow this much space for option names.
3299+ my $rcol = 80 - $lcol; # The terminal is assumed to be 80 chars wide.
3300+ my $name;
3301+ while ( <> ) {
3302+ my $line = $_;
3303+ chomp $line;
3304+ if ( $line =~ s/^long:/ --/ ) {
3305+ $name = $line;
3306+ }
3307+ elsif ( $line =~ s/^desc:// ) {
3308+ $line =~ s/ +$//mg;
3309+ my @lines = grep { $_ }
3310+ $line =~ m/(.{0,$rcol})(?:\s+|\Z)/g;
3311+ if ( length($name) >= $lcol ) {
3312+ print $name, "\n", (q{ } x $lcol);
3313+ }
3314+ else {
3315+ printf "%-${lcol}s", $name;
3316+ }
3317+ print join("\n" . (q{ } x $lcol), @lines);
3318+ print "\n";
3319+ }
3320+ }
3321+ ' "$PO_DIR"/*
3322+ echo
3323+ echo "Options and values after processing arguments:"
3324+ echo
3325+ for opt in $(ls "$PO_DIR"); do
3326+ local varname="OPT_$(echo "$opt" | tr a-z- A-Z_)"
3327+ local varvalue="${!varname}"
3328+ printf -- " --%-30s %s" "$opt" "${varvalue:-(No value)}"
3329+ echo
3330+ done
3331+ return 1
3332+ fi
3333+
3334+ if [ $OPT_ERRS -gt 0 ]; then
3335+ echo
3336+ usage "$file"
3337+ return 1
3338+ fi
3339+
3340+ return 0
3341+}
3342+
3343+option_error() {
3344+ local err="$1"
3345+ OPT_ERRS=$(($OPT_ERRS + 1))
3346+ echo "$err" >&2
3347+}
3348+
3349+parse_options() {
3350+ local file="$1"
3351+ shift
3352+
3353+ ARGV=""
3354+ EXT_ARGV=""
3355+ HAVE_EXT_ARGV=""
3356+ OPT_ERRS=0
3357+ OPT_VERSION=""
3358+ OPT_HELP=""
3359+ PO_DIR="$TMPDIR/po"
3360+
3361+ if [ ! -d "$PO_DIR" ]; then
3362+ mkdir "$PO_DIR"
3363+ if [ $? -ne 0 ]; then
3364+ echo "Cannot mkdir $PO_DIR" >&2
3365+ exit 1
3366+ fi
3367+ fi
3368+
3369+ rm -rf "$PO_DIR"/*
3370+ if [ $? -ne 0 ]; then
3371+ echo "Cannot rm -rf $PO_DIR/*" >&2
3372+ exit 1
3373+ fi
3374+
3375+ _parse_pod "$file" # Parse POD into program option (po) spec files
3376+ _eval_po # Eval po into existence with default values
3377+
3378+ if [ $# -ge 2 ] && [ "$1" = "--config" ]; then
3379+ shift # --config
3380+ local user_config_files="$1"
3381+ shift # that ^
3382+ local IFS=","
3383+ for user_config_file in $user_config_files; do
3384+ _parse_config_files "$user_config_file"
3385+ done
3386+ else
3387+ _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf"
3388+ fi
3389+
3390+ _parse_command_line "$@"
3391+}
3392+
3393+_parse_pod() {
3394+ local file="$1"
3395+
3396+ cat "$file" | PO_DIR="$PO_DIR" perl -ne '
3397+ BEGIN { $/ = ""; }
3398+ next unless $_ =~ m/^=head1 OPTIONS/;
3399+ while ( defined(my $para = <>) ) {
3400+ last if $para =~ m/^=head1/;
3401+ chomp;
3402+ if ( $para =~ m/^=item --(\S+)/ ) {
3403+ my $opt = $1;
3404+ my $file = "$ENV{PO_DIR}/$opt";
3405+ open my $opt_fh, ">", $file or die "Cannot open $file: $!";
3406+ print $opt_fh "long:$opt\n";
3407+ $para = <>;
3408+ chomp;
3409+ if ( $para =~ m/^[a-z ]+:/ ) {
3410+ map {
3411+ chomp;
3412+ my ($attrib, $val) = split(/: /, $_);
3413+ print $opt_fh "$attrib:$val\n";
3414+ } split(/; /, $para);
3415+ $para = <>;
3416+ chomp;
3417+ }
3418+ my ($desc) = $para =~ m/^([^?.]+)/;
3419+ print $opt_fh "desc:$desc.\n";
3420+ close $opt_fh;
3421+ }
3422+ }
3423+ last;
3424+ '
3425+}
3426+
3427+_eval_po() {
3428+ local IFS=":"
3429+ for opt_spec in "$PO_DIR"/*; do
3430+ local opt=""
3431+ local default_val=""
3432+ local neg=0
3433+ local size=0
3434+ while read key val; do
3435+ case "$key" in
3436+ long)
3437+ opt=$(echo $val | sed 's/-/_/g' | tr [:lower:] [:upper:])
3438+ ;;
3439+ default)
3440+ default_val="$val"
3441+ ;;
3442+ "short form")
3443+ ;;
3444+ type)
3445+ [ "$val" = "size" ] && size=1
3446+ ;;
3447+ desc)
3448+ ;;
3449+ negatable)
3450+ if [ "$val" = "yes" ]; then
3451+ neg=1
3452+ fi
3453+ ;;
3454+ *)
3455+ echo "Invalid attribute in $opt_spec: $line" >&2
3456+ exit 1
3457+ esac
3458+ done < "$opt_spec"
3459+
3460+ if [ -z "$opt" ]; then
3461+ echo "No long attribute in option spec $opt_spec" >&2
3462+ exit 1
3463+ fi
3464+
3465+ if [ $neg -eq 1 ]; then
3466+ if [ -z "$default_val" ] || [ "$default_val" != "yes" ]; then
3467+ echo "Option $opt_spec is negatable but not default: yes" >&2
3468+ exit 1
3469+ fi
3470+ fi
3471+
3472+ if [ $size -eq 1 -a -n "$default_val" ]; then
3473+ default_val=$(size_to_bytes $default_val)
3474+ fi
3475+
3476+ eval "OPT_${opt}"="$default_val"
3477+ done
3478+}
3479+
3480+_parse_config_files() {
3481+
3482+ for config_file in "$@"; do
3483+ test -f "$config_file" || continue
3484+
3485+ while read config_opt; do
3486+
3487+ echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue
3488+
3489+ config_opt="$(echo "$config_opt" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/[ ]*=[ ]*/=/' -e 's/[ ]*#.*$//')"
3490+
3491+ [ "$config_opt" = "" ] && continue
3492+
3493+ if ! [ "$HAVE_EXT_ARGV" ]; then
3494+ config_opt="--$config_opt"
3495+ fi
3496+
3497+ _parse_command_line "$config_opt"
3498+
3499+ done < "$config_file"
3500+
3501+ HAVE_EXT_ARGV="" # reset for each file
3502+
3503+ done
3504+}
3505+
3506+_parse_command_line() {
3507+ local opt=""
3508+ local val=""
3509+ local next_opt_is_val=""
3510+ local opt_is_ok=""
3511+ local opt_is_negated=""
3512+ local real_opt=""
3513+ local required_arg=""
3514+ local spec=""
3515+
3516+ for opt in "$@"; do
3517+ if [ "$opt" = "--" -o "$opt" = "----" ]; then
3518+ HAVE_EXT_ARGV=1
3519+ continue
3520+ fi
3521+ if [ "$HAVE_EXT_ARGV" ]; then
3522+ if [ "$EXT_ARGV" ]; then
3523+ EXT_ARGV="$EXT_ARGV $opt"
3524+ else
3525+ EXT_ARGV="$opt"
3526+ fi
3527+ continue
3528+ fi
3529+
3530+ if [ "$next_opt_is_val" ]; then
3531+ next_opt_is_val=""
3532+ if [ $# -eq 0 ] || [ $(expr "$opt" : "-") -eq 1 ]; then
3533+ option_error "$real_opt requires a $required_arg argument"
3534+ continue
3535+ fi
3536+ val="$opt"
3537+ opt_is_ok=1
3538+ else
3539+ if [ $(expr "$opt" : "-") -eq 0 ]; then
3540+ if [ -z "$ARGV" ]; then
3541+ ARGV="$opt"
3542+ else
3543+ ARGV="$ARGV $opt"
3544+ fi
3545+ continue
3546+ fi
3547+
3548+ real_opt="$opt"
3549+
3550+ if $(echo $opt | grep '^--no-' >/dev/null); then
3551+ opt_is_negated=1
3552+ opt=$(echo $opt | sed 's/^--no-//')
3553+ else
3554+ opt_is_negated=""
3555+ opt=$(echo $opt | sed 's/^-*//')
3556+ fi
3557+
3558+ if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
3559+ val="$(echo $opt | awk -F= '{print $2}')"
3560+ opt="$(echo $opt | awk -F= '{print $1}')"
3561+ fi
3562+
3563+ if [ -f "$TMPDIR/po/$opt" ]; then
3564+ spec="$TMPDIR/po/$opt"
3565+ else
3566+ spec=$(grep "^short form:-$opt\$" "$TMPDIR"/po/* | cut -d ':' -f 1)
3567+ if [ -z "$spec" ]; then
3568+ option_error "Unknown option: $real_opt"
3569+ continue
3570+ fi
3571+ fi
3572+
3573+ required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}')
3574+ if [ "$required_arg" ]; then
3575+ if [ "$val" ]; then
3576+ opt_is_ok=1
3577+ else
3578+ next_opt_is_val=1
3579+ fi
3580+ else
3581+ if [ "$val" ]; then
3582+ option_error "Option $real_opt does not take a value"
3583+ continue
3584+ fi
3585+ if [ "$opt_is_negated" ]; then
3586+ val=""
3587+ else
3588+ val="yes"
3589+ fi
3590+ opt_is_ok=1
3591+ fi
3592+ fi
3593+
3594+ if [ "$opt_is_ok" ]; then
3595+ opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr [:lower:] [:upper:])
3596+
3597+ if grep "^type:size" "$spec" >/dev/null; then
3598+ val=$(size_to_bytes $val)
3599+ fi
3600+
3601+ eval "OPT_$opt"="'$val'"
3602+
3603+ opt=""
3604+ val=""
3605+ next_opt_is_val=""
3606+ opt_is_ok=""
3607+ opt_is_negated=""
3608+ real_opt=""
3609+ required_arg=""
3610+ spec=""
3611+ fi
3612+ done
3613+}
3614+
3615+size_to_bytes() {
3616+ local size="$1"
3617+ echo $size | perl -ne '%f=(B=>1, K=>1_024, M=>1_048_576, G=>1_073_741_824, T=>1_099_511_627_776); m/^(\d+)([kMGT])?/i; print $1 * $f{uc($2 || "B")};'
3618+}
3619+
3620+# ###########################################################################
3621+# End parse_options package
3622+# ###########################################################################
3623
3624 # ###########################################################################
3625 # tmpdir package
3626@@ -53,18 +436,21 @@
3627 # See https://launchpad.net/percona-toolkit for more information.
3628 # ###########################################################################
3629
3630+
3631+set -u
3632+
3633 TMPDIR=""
3634
3635 mk_tmpdir() {
3636- local dir=${1:-""}
3637+ local dir="${1:-""}"
3638
3639 if [ -n "$dir" ]; then
3640 if [ ! -d "$dir" ]; then
3641- mkdir $dir || die "Cannot make tmpdir $dir"
3642+ mkdir "$dir" || die "Cannot make tmpdir $dir"
3643 fi
3644 TMPDIR="$dir"
3645 else
3646- local tool=`basename $0`
3647+ local tool="${0##*/}"
3648 local pid="$$"
3649 TMPDIR=`mktemp -d /tmp/${tool}.${pid}.XXXXX` \
3650 || die "Cannot make secure tmpdir"
3651@@ -73,7 +459,7 @@
3652
3653 rm_tmpdir() {
3654 if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then
3655- rm -rf $TMPDIR
3656+ rm -rf "$TMPDIR"
3657 fi
3658 TMPDIR=""
3659 }
3660@@ -82,180 +468,893 @@
3661 # End tmpdir package
3662 # ###########################################################################
3663
3664-# The temp files are for storing working results so we don't call commands many
3665-# times (gives inconsistent results, maybe adds load on things I don't want to
3666-# such as RAID controllers). They must not exist -- if they did, someone would
3667-# symlink them to /etc/passwd and then run this program as root. Call this
3668-# function with "rm" or "touch" as an argument.
3669-temp_files() {
3670- for file in $TMPDIR/percona-toolkit $TMPDIR/percona-toolkit2; do
3671- case "$1" in
3672- touch)
3673- if ! touch "${file}"; then
3674- echo "I can't make my temp file ${file}";
3675- exit 1;
3676+# ###########################################################################
3677+# alt_cmds package
3678+# This package is a copy without comments from the original. The original
3679+# with comments and its test file can be found in the Bazaar repository at,
3680+# lib/bash/alt_cmds.sh
3681+# t/lib/bash/alt_cmds.sh
3682+# See https://launchpad.net/percona-toolkit for more information.
3683+# ###########################################################################
3684+
3685+
3686+set -u
3687+
3688+_seq() {
3689+ local i="$1"
3690+ awk "BEGIN { for(i=1; i<=$i; i++) print i; }"
3691+}
3692+
3693+_pidof() {
3694+ local cmd="$1"
3695+ if ! pidof "$cmd" 2>/dev/null; then
3696+ ps -eo pid,ucomm | awk -v comm="$cmd" '$2 == comm { print $1 }'
3697+ fi
3698+}
3699+
3700+_lsof() {
3701+ local pid="$1"
3702+ if ! lsof -p $pid 2>/dev/null; then
3703+ /bin/ls -l /proc/$pid/fd 2>/dev/null
3704+ fi
3705+}
3706+
3707+
3708+
3709+_which() {
3710+ if [ -x /usr/bin/which ]; then
3711+ /usr/bin/which "$1" 2>/dev/null | awk '{print $1}'
3712+ elif which which 1>/dev/null 2>&1; then
3713+ which "$1" 2>/dev/null | awk '{print $1}'
3714+ else
3715+ echo "$1"
3716+ fi
3717+}
3718+
3719+# ###########################################################################
3720+# End alt_cmds package
3721+# ###########################################################################
3722+
3723+# ###########################################################################
3724+# summary_common package
3725+# This package is a copy without comments from the original. The original
3726+# with comments and its test file can be found in the Bazaar repository at,
3727+# lib/bash/summary_common.sh
3728+# t/lib/bash/summary_common.sh
3729+# See https://launchpad.net/percona-toolkit for more information.
3730+# ###########################################################################
3731+
3732+
3733+set -u
3734+
3735+CMD_FILE="$( _which file 2>/dev/null )"
3736+CMD_NM="$( _which nm 2>/dev/null )"
3737+CMD_OBJDUMP="$( _which objdump 2>/dev/null )"
3738+
3739+get_nice_of_pid () {
3740+ local pid="$1"
3741+ local niceness="$(ps -p $pid -o nice | awk '$1 !~ /[^0-9]/ {print $1; exit}')"
3742+
3743+ if [ -n "${niceness}" ]; then
3744+ echo $niceness
3745+ else
3746+ local tmpfile="$TMPDIR/nice_through_c.tmp.c"
3747+ _d "Getting the niceness from ps failed, somehow. We are about to try this:"
3748+ cat <<EOC > "$tmpfile"
3749+
3750+int main(void) {
3751+ int priority = getpriority(PRIO_PROCESS, $pid);
3752+ if ( priority == -1 && errno == ESRCH ) {
3753+ return 1;
3754+ }
3755+ else {
3756+ printf("%d\\n", priority);
3757+ return 0;
3758+ }
3759+}
3760+
3761+EOC
3762+ local c_comp=$(_which gcc)
3763+ if [ -z "${c_comp}" ]; then
3764+ c_comp=$(_which cc)
3765+ fi
3766+ _d "$tmpfile: $( cat "$tmpfile" )"
3767+ _d "$c_comp -xc \"$tmpfile\" -o \"$tmpfile\" && eval \"$tmpfile\""
3768+ $c_comp -xc "$tmpfile" -o "$tmpfile" 2>/dev/null && eval "$tmpfile" 2>/dev/null
3769+ if [ $? -ne 0 ]; then
3770+ echo "?"
3771+ _d "Failed to get a niceness value for $pid"
3772+ fi
3773+ fi
3774+}
3775+
3776+get_oom_of_pid () {
3777+ local pid="$1"
3778+ local oom_adj=""
3779+
3780+ if [ -n "${pid}" -a -e /proc/cpuinfo ]; then
3781+ if [ -s "/proc/$pid/oom_score_adj" ]; then
3782+ oom_adj=$(cat "/proc/$pid/oom_score_adj" 2>/dev/null)
3783+ _d "For $pid, the oom value is $oom_adj, retreived from oom_score_adj"
3784+ else
3785+ oom_adj=$(cat "/proc/$pid/oom_adj" 2>/dev/null)
3786+ _d "For $pid, the oom value is $oom_adj, retreived from oom_adj"
3787+ fi
3788+ fi
3789+
3790+ if [ -n "${oom_adj}" ]; then
3791+ echo "${oom_adj}"
3792+ else
3793+ echo "?"
3794+ _d "Can't find the oom value for $pid"
3795+ fi
3796+}
3797+
3798+has_symbols () {
3799+ local executable="$(_which "$1")"
3800+ local has_symbols=""
3801+
3802+ if [ "${CMD_FILE}" ] \
3803+ && [ "$($CMD_FILE "${executable}" | grep 'not stripped' )" ]; then
3804+ has_symbols=1
3805+ elif [ "${CMD_NM}" ] \
3806+ || [ "${CMD_OBJDMP}" ]; then
3807+ if [ "${CMD_NM}" ] \
3808+ && [ !"$("${CMD_NM}" -- "${executable}" 2>&1 | grep 'File format not recognized' )" ]; then
3809+ if [ -z "$( $CMD_NM -- "${executable}" 2>&1 | grep ': no symbols' )" ]; then
3810+ has_symbols=1
3811 fi
3812- ;;
3813- rm)
3814- rm -f "${file}"
3815- ;;
3816- esac
3817- done
3818-}
3819-
3820-# Print a space-padded string into $line. Then translate spaces to hashes, and
3821-# underscores to spaces. End result is a line of hashes with words at the
3822-# start.
3823+ elif [ -z "$("${CMD_OBJDUMP}" -t -- "${executable}" | grep '^no symbols$' )" ]; then
3824+ has_symbols=1
3825+ fi
3826+ fi
3827+
3828+ if [ "${has_symbols}" ]; then
3829+ echo "Yes"
3830+ else
3831+ echo "No"
3832+ fi
3833+}
3834+
3835+setup_data_dir () {
3836+ local existing_dir="$1"
3837+ local data_dir=""
3838+ if [ -z "$existing_dir" ]; then
3839+ mkdir "$TMPDIR/data" || die "Cannot mkdir $TMPDIR/data"
3840+ data_dir="$TMPDIR/data"
3841+ else
3842+ if [ ! -d "$existing_dir" ]; then
3843+ mkdir "$existing_dir" || die "Cannot mkdir $existing_dir"
3844+ elif [ "$( ls -A "$existing_dir" )" ]; then
3845+ die "--save-samples directory isn't empty, halting."
3846+ fi
3847+ touch "$existing_dir/test" || die "Cannot write to $existing_dir"
3848+ rm "$existing_dir/test" || die "Cannot rm $existing_dir/test"
3849+ data_dir="$existing_dir"
3850+ fi
3851+ echo "$data_dir"
3852+}
3853+
3854+get_var () {
3855+ local varname="$1"
3856+ local file="$2"
3857+ awk -v pattern="${varname}" '$1 == pattern { if (length($2)) { len = length($1); print substr($0, len+index(substr($0, len+1), $2)) } }' "${file}"
3858+}
3859+
3860+# ###########################################################################
3861+# End summary_common package
3862+# ###########################################################################
3863+
3864+# ###########################################################################
3865+# report_formatting package
3866+# This package is a copy without comments from the original. The original
3867+# with comments and its test file can be found in the Bazaar repository at,
3868+# lib/bash/report_formatting.sh
3869+# t/lib/bash/report_formatting.sh
3870+# See https://launchpad.net/percona-toolkit for more information.
3871+# ###########################################################################
3872+
3873+
3874+set -u
3875+
3876+POSIXLY_CORRECT=1
3877+export POSIXLY_CORRECT
3878+
3879+fuzzy_formula='
3880+ rounded = 0;
3881+ if (fuzzy_var <= 10 ) {
3882+ rounded = 1;
3883+ }
3884+ factor = 1;
3885+ while ( rounded == 0 ) {
3886+ if ( fuzzy_var <= 50 * factor ) {
3887+ fuzzy_var = sprintf("%.0f", fuzzy_var / (5 * factor)) * 5 * factor;
3888+ rounded = 1;
3889+ }
3890+ else if ( fuzzy_var <= 100 * factor) {
3891+ fuzzy_var = sprintf("%.0f", fuzzy_var / (10 * factor)) * 10 * factor;
3892+ rounded = 1;
3893+ }
3894+ else if ( fuzzy_var <= 250 * factor) {
3895+ fuzzy_var = sprintf("%.0f", fuzzy_var / (25 * factor)) * 25 * factor;
3896+ rounded = 1;
3897+ }
3898+ factor = factor * 10;
3899+ }'
3900+
3901+fuzz () {
3902+ awk -v fuzzy_var="$1" "BEGIN { ${fuzzy_formula} print fuzzy_var;}"
3903+}
3904+
3905+fuzzy_pct () {
3906+ local pct="$(awk -v one="$1" -v two="$2" 'BEGIN{ if (two > 0) { printf "%d", one/two*100; } else {print 0} }')";
3907+ echo "$(fuzz "${pct}")%"
3908+}
3909+
3910 section () {
3911- echo "$1" | awk '{l=sprintf("#_%-60s", $0 "_"); print l}' | sed -e 's/ /#/g' -e 's/_/ /g'
3912-}
3913-
3914-# Print a "name | value" line.
3915-name_val() {
3916- printf "%12s | %s\n" "$1" "$(echo $2)"
3917-}
3918-
3919-# Converts a value to units of power of 2. Arg 1: the value. Arg 2: precision (defaults to 2).
3920+ local str="$1"
3921+ awk -v var="${str} _" 'BEGIN {
3922+ line = sprintf("# %-60s", var);
3923+ i = index(line, "_");
3924+ x = substr(line, i);
3925+ gsub(/[_ \t]/, "#", x);
3926+ printf("%s%s\n", substr(line, 1, i-1), x);
3927+ }'
3928+}
3929+
3930+NAME_VAL_LEN=12
3931+name_val () {
3932+ printf "%+*s | %s\n" "${NAME_VAL_LEN}" "$1" "$2"
3933+}
3934+
3935 shorten() {
3936- echo $@ | awk '{
3937- unit = "k";
3938- size = 1024;
3939+ local num="$1"
3940+ local prec="${2:-2}"
3941+ local div="${3:-1024}"
3942+
3943+ echo "$num" | awk -v prec="$prec" -v div="$div" '
3944+ {
3945+ size = 4;
3946 val = $1;
3947- prec = 2;
3948- if ( $2 ~ /./ ) {
3949- prec = $2;
3950- }
3951- if ( val >= 1099511627776 ) {
3952- size = 1099511627776;
3953- unit = "T";
3954- }
3955- else if ( val >= 1073741824 ) {
3956- size = 1073741824;
3957- unit = "G";
3958- }
3959- else if ( val >= 1048576 ) {
3960- size = 1048576;
3961- unit = "M";
3962- }
3963- printf "%." prec "f%s", val / size, unit;
3964- }'
3965+
3966+ unit = val >= 1099511627776 ? "T" : val >= 1073741824 ? "G" : val >= 1048576 ? "M" : val >= 1024 ? "k" : "";
3967+
3968+ while ( int(val) && !(val % 1024) ) {
3969+ val /= 1024;
3970+ }
3971+
3972+ while ( val > 1000 ) {
3973+ val /= div;
3974+ }
3975+
3976+ printf "%.*f%s", prec, val, unit;
3977+ }
3978+ '
3979 }
3980
3981-# ##############################################################################
3982-# Function to take a file and collapse it into an aggregated list. This
3983-# function works on $1, which it expects to be created with 'sort |
3984-# uniq -c'. Leading whitespace is deleted. The result will look like
3985-# "4xabc, 1xdef" Copy any changes to 'mysql-summary' too.
3986-# ##############################################################################
3987 group_concat () {
3988- sed -e '{H; $!d}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' ${1}
3989- # In words: save the whole file into the hold space,
3990- # {H; $!d}
3991- # Swap it back into the pattern space,
3992- # x
3993- # Join lines with a comma, delete leading whitespace, and put an 'x' between
3994- # the number and the text that follows,
3995- # s/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g
3996- # Collapse whitespace,
3997- # s/[[:space:]][[:space:]]*/ /g
3998- # And delete the leading comma-space.
3999- # s/, //
4000-}
4001-
4002-# ##############################################################################
4003-# Functions for parsing specific files and getting desired info from them.
4004-# These are called from within main() and are separated so they can be tested
4005-# easily. The calling convention is that the data they need to run is prepared
4006-# first by putting it into $TMPDIR/percona-toolkit. Then code that's testing
4007-# just needs to put sample data into $TMPDIR/percona-toolkit and call it.
4008-# ##############################################################################
4009+ sed -e '{H; $!d;}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' "${1}"
4010+}
4011+
4012+# ###########################################################################
4013+# End report_formatting package
4014+# ###########################################################################
4015+
4016+# ###########################################################################
4017+# collect_system_info package
4018+# This package is a copy without comments from the original. The original
4019+# with comments and its test file can be found in the Bazaar repository at,
4020+# lib/bash/collect_system_info.sh
4021+# t/lib/bash/collect_system_info.sh
4022+# See https://launchpad.net/percona-toolkit for more information.
4023+# ###########################################################################
4024+
4025+
4026+
4027+set -u
4028+
4029+setup_commands () {
4030+ CMD_SYSCTL="$(_which sysctl 2>/dev/null )"
4031+ CMD_DMIDECODE="$(_which dmidecode 2>/dev/null )"
4032+ CMD_ZONENAME="$(_which zonename 2>/dev/null )"
4033+ CMD_DMESG="$(_which dmesg 2>/dev/null )"
4034+ CMD_FILE="$(_which file 2>/dev/null )"
4035+ CMD_LSPCI="$(_which lspci 2>/dev/null )"
4036+ CMD_PRTDIAG="$(_which prtdiag 2>/dev/null )"
4037+ CMD_SMBIOS="$(_which smbios 2>/dev/null )"
4038+ CMD_GETENFORCE="$(_which getenforce 2>/dev/null )"
4039+ CMD_PRTCONF="$(_which prtconf 2>/dev/null )"
4040+ CMD_LVS="$(_which lvs 2>/dev/null)"
4041+ CMD_VGS="$(_which vgs 2>/dev/null)"
4042+ CMD_PRSTAT="$(_which prstat 2>/dev/null)"
4043+ CMD_ISAINFO="$(_which isainfo 2>/dev/null)"
4044+ CMD_TOP="$(_which top 2>/dev/null)"
4045+ CMD_ARCCONF="$( _which arcconf 2>/dev/null )"
4046+ CMD_HPACUCLI="$( _which hpacucli 2>/dev/null )"
4047+ CMD_MEGACLI64="$( _which MegaCli64 2>/dev/null )"
4048+ CMD_VMSTAT="$(_which vmstat 2>/dev/null)"
4049+ CMD_IP="$( _which ip 2>/dev/null )"
4050+ CMD_NETSTAT="$( _which netstat 2>/dev/null )"
4051+ CMD_PSRINFO="$( _which psrinfo 2>/dev/null )"
4052+ CMD_SWAPCTL="$( _which swapctl 2>/dev/null )"
4053+ CMD_LSB_RELEASE="$( _which lsb_release 2>/dev/null )"
4054+ CMD_ETHTOOL="$( _which ethtool 2>/dev/null )"
4055+ CMD_GETCONF="$( _which getconf 2>/dev/null )"
4056+}
4057+
4058+collect_system_data () { local PTFUNCNAME=collect_system_data;
4059+ local data_dir="$1"
4060+
4061+ if [ -r /var/log/dmesg -a -s /var/log/dmesg ]; then
4062+ cat "/var/log/dmesg" > "$data_dir/dmesg_file"
4063+ fi
4064+
4065+ $CMD_SYSCTL -a > "$data_dir/sysctl" 2>/dev/null
4066+
4067+ if [ "${CMD_LSPCI}" ]; then
4068+ $CMD_LSPCI > "$data_dir/lspci_file" 2>/dev/null
4069+ fi
4070+
4071+ local platform="$(uname -s)"
4072+ echo "platform $platform" >> "$data_dir/summary"
4073+ echo "hostname $(uname -n)" >> "$data_dir/summary"
4074+ uptime >> "$data_dir/uptime"
4075+
4076+ processor_info "$data_dir"
4077+ find_release_and_kernel "$platform" >> "$data_dir/summary"
4078+ cpu_and_os_arch "$platform" >> "$data_dir/summary"
4079+ find_virtualization "$platform" "$data_dir/dmesg_file" "$data_dir/lspci_file" >> "$data_dir/summary"
4080+ dmidecode_system_info >> "$data_dir/summary"
4081+
4082+ if [ "${platform}" = "SunOS" -a "${CMD_ZONENAME}" ]; then
4083+ echo "zonename $($CMD_ZONENAME)" >> "$data_dir/summary"
4084+ fi
4085+
4086+ if [ -x /lib/libc.so.6 ]; then
4087+ echo "compiler $(/lib/libc.so.6 | grep 'Compiled by' | cut -c13-)" >> "$data_dir/summary"
4088+ fi
4089+
4090+ local rss=$(ps -eo rss 2>/dev/null | awk '/[0-9]/{total += $1 * 1024} END {print total}')
4091+ echo "rss ${rss}" >> "$data_dir/summary"
4092+
4093+ [ "$CMD_DMIDECODE" ] && $CMD_DMIDECODE > "$data_dir/dmidecode" 2>/dev/null
4094+
4095+ find_memory_stats "$platform" > "$data_dir/memory"
4096+ [ "$OPT_SUMMARIZE_MOUNTS" ] && mounted_fs_info "$platform" > "$data_dir/mounted_fs"
4097+ raid_controller "$data_dir/dmesg_file" "$data_dir/lspci_file" >> "$data_dir/summary"
4098+
4099+ local controller="$(get_var raid_controller "$data_dir/summary")"
4100+ propietary_raid_controller "$data_dir/raid-controller" "$data_dir/summary" "$data_dir" "$controller"
4101+
4102+ [ "${platform}" = "Linux" ] && linux_exclusive_collection "$data_dir"
4103+
4104+ if [ "$CMD_IP" -a "$OPT_SUMMARIZE_NETWORK" ]; then
4105+ $CMD_IP -s link > "$data_dir/ip"
4106+ network_device_info "$data_dir/ip" > "$data_dir/network_devices"
4107+ fi
4108+
4109+ [ "$CMD_SWAPCTL" ] && $CMD_SWAPCTL -s > "$data_dir/swapctl"
4110+
4111+ if [ "$OPT_SUMMARIZE_PROCESSES" ]; then
4112+ top_processes > "$data_dir/processes"
4113+ notable_processes_info > "$data_dir/notable_procs"
4114+
4115+ if [ "$CMD_VMSTAT" ]; then
4116+ touch "$data_dir/vmstat"
4117+ (
4118+ $CMD_VMSTAT 1 $OPT_SLEEP > "$data_dir/vmstat"
4119+ ) &
4120+ fi
4121+ fi
4122+
4123+ for file in $data_dir/*; do
4124+ [ "$file" = "vmstat" ] && continue
4125+ [ ! -s "$file" ] && rm "$file"
4126+ done
4127+}
4128+
4129+linux_exclusive_collection () { local PTFUNCNAME=linux_exclusive_collection;
4130+ local data_dir="$1"
4131+
4132+ echo "threading $(getconf GNU_LIBPTHREAD_VERSION)" >> "$data_dir/summary"
4133+
4134+ local getenforce=""
4135+ [ "$CMD_GETENFORCE" ] && getenforce="$($CMD_GETENFORCE 2>&1)"
4136+ echo "getenforce ${getenforce:-"No SELinux detected"}" >> "$data_dir/summary"
4137+
4138+ echo "swappiness $(awk '/vm.swappiness/{print $3}' "$data_dir/sysctl")" >> "$data_dir/summary"
4139+
4140+ local dirty_ratio="$(awk '/vm.dirty_ratio/{print $3}' "$data_dir/sysctl")"
4141+ local dirty_bg_ratio="$(awk '/vm.dirty_background_ratio/{print $3}' "$data_dir/sysctl")"
4142+ if [ "$dirty_ratio" -a "$dirty_bg_ratio" ]; then
4143+ echo "dirtypolicy $dirty_ratio, $dirty_bg_ratio" >> "$data_dir/summary"
4144+ fi
4145+
4146+ local dirty_bytes="$(awk '/vm.dirty_bytes/{print $3}' "$data_dir/sysctl")"
4147+ if [ "$dirty_bytes" ]; then
4148+ echo "dirtystatus $(awk '/vm.dirty_bytes/{print $3}' "$data_dir/sysctl"), $(awk '/vm.dirty_background_bytes/{print $3}' "$data_dir/sysctl")" >> "$data_dir/summary"
4149+ fi
4150+
4151+ schedulers_and_queue_size "$data_dir/summary" > "$data_dir/partitioning"
4152+
4153+ for file in dentry-state file-nr inode-nr; do
4154+ echo "${file} $(cat /proc/sys/fs/${file} 2>&1)" >> "$data_dir/summary"
4155+ done
4156+
4157+ [ "$CMD_LVS" -a -x "$CMD_LVS" ] && $CMD_LVS 1>"$data_dir/lvs" 2>"$data_dir/lvs.stderr"
4158+
4159+ [ "$CMD_VGS" -a -x "$CMD_VGS" ] && \
4160+ $CMD_VGS -o vg_name,vg_size,vg_free 2>/dev/null > "$data_dir/vgs"
4161+
4162+ [ "$CMD_NETSTAT" -a "$OPT_SUMMARIZE_NETWORK" ] && \
4163+ $CMD_NETSTAT -antp > "$data_dir/netstat" 2>/dev/null
4164+}
4165+
4166+network_device_info () {
4167+ local ip_minus_s_file="$1"
4168+
4169+ if [ "$CMD_ETHTOOL" ]; then
4170+ local tempfile="$TMPDIR/ethtool_output_temp"
4171+ for device in $( awk '/^[1-9]/{ print $2 }' "$ip_minus_s_file" \
4172+ | awk -F: '{print $1}' \
4173+ | grep -v '^lo\|^in\|^gr' \
4174+ | sort -u ); do
4175+ ethtool $device > "$tempfile" 2>/dev/null
4176+
4177+ if ! grep -q 'No data available' "$tempfile"; then
4178+ cat "$tempfile"
4179+ fi
4180+ done
4181+ fi
4182+}
4183+
4184+find_release_and_kernel () { local PTFUNCNAME=find_release_and_kernel;
4185+ local platform="$1"
4186+
4187+ local kernel=""
4188+ local release=""
4189+ if [ "${platform}" = "Linux" ]; then
4190+ kernel="$(uname -r)"
4191+ if [ -e /etc/fedora-release ]; then
4192+ release=$(cat /etc/fedora-release);
4193+ elif [ -e /etc/redhat-release ]; then
4194+ release=$(cat /etc/redhat-release);
4195+ elif [ -e /etc/system-release ]; then
4196+ release=$(cat /etc/system-release);
4197+ elif [ "$CMD_LSB_RELEASE" ]; then
4198+ release="$($CMD_LSB_RELEASE -ds) ($($CMD_LSB_RELEASE -cs))"
4199+ elif [ -e /etc/lsb-release ]; then
4200+ release=$(grep DISTRIB_DESCRIPTION /etc/lsb-release |awk -F'=' '{print $2}' |sed 's#"##g');
4201+ elif [ -e /etc/debian_version ]; then
4202+ release="Debian-based version $(cat /etc/debian_version)";
4203+ if [ -e /etc/apt/sources.list ]; then
4204+ local code=` awk '/^deb/ {print $3}' /etc/apt/sources.list \
4205+ | awk -F/ '{print $1}'| awk 'BEGIN {FS="|"}{print $1}' \
4206+ | sort | uniq -c | sort -rn | head -n1 | awk '{print $2}'`
4207+ release="${release} (${code})"
4208+ fi
4209+ elif ls /etc/*release >/dev/null 2>&1; then
4210+ if grep -q DISTRIB_DESCRIPTION /etc/*release; then
4211+ release=$(grep DISTRIB_DESCRIPTION /etc/*release | head -n1);
4212+ else
4213+ release=$(cat /etc/*release | head -n1);
4214+ fi
4215+ fi
4216+ elif [ "${platform}" = "FreeBSD" ] \
4217+ || [ "${platform}" = "NetBSD" ] \
4218+ || [ "${platform}" = "OpenBSD" ]; then
4219+ release="$(uname -r)"
4220+ kernel="$($CMD_SYSCTL -n "kern.osrevision")"
4221+ elif [ "${platform}" = "SunOS" ]; then
4222+ release="$(head -n1 /etc/release)"
4223+ if [ -z "${release}" ]; then
4224+ release="$(uname -r)"
4225+ fi
4226+ kernel="$(uname -v)"
4227+ fi
4228+ echo "kernel $kernel"
4229+ echo "release $release"
4230+}
4231+
4232+cpu_and_os_arch () { local PTFUNCNAME=cpu_and_os_arch;
4233+ local platform="$1"
4234+
4235+ local CPU_ARCH='32-bit'
4236+ local OS_ARCH='32-bit'
4237+ if [ "${platform}" = "Linux" ]; then
4238+ if grep -q ' lm ' /proc/cpuinfo; then
4239+ CPU_ARCH='64-bit'
4240+ fi
4241+ elif [ "${platform}" = "FreeBSD" ] || [ "${platform}" = "NetBSD" ]; then
4242+ if $CMD_SYSCTL "hw.machine_arch" | grep -v 'i[36]86' >/dev/null; then
4243+ CPU_ARCH='64-bit'
4244+ fi
4245+ elif [ "${platform}" = "OpenBSD" ]; then
4246+ if $CMD_SYSCTL "hw.machine" | grep -v 'i[36]86' >/dev/null; then
4247+ CPU_ARCH='64-bit'
4248+ fi
4249+ elif [ "${platform}" = "SunOS" ]; then
4250+ if $CMD_ISAINFO -b | grep 64 >/dev/null ; then
4251+ CPU_ARCH="64-bit"
4252+ fi
4253+ fi
4254+ if [ -z "$CMD_FILE" ]; then
4255+ if [ "$CMD_GETCONF" ] && $CMD_GETCONF LONG_BIT 1>/dev/null 2>&1; then
4256+ OS_ARCH="$($CMD_GETCONF LONG_BIT 2>/dev/null)-bit"
4257+ else
4258+ OS_ARCH='N/A'
4259+ fi
4260+ elif $CMD_FILE /bin/sh | grep '64-bit' >/dev/null; then
4261+ OS_ARCH='64-bit'
4262+ fi
4263+
4264+ echo "CPU_ARCH $CPU_ARCH"
4265+ echo "OS_ARCH $OS_ARCH"
4266+}
4267+
4268+find_virtualization () { local PTFUNCNAME=find_virtualization;
4269+ local platform="$1"
4270+ local dmesg_file="$2"
4271+ local lspci_file="$3"
4272+
4273+ local tempfile="$TMPDIR/find_virtualziation.tmp"
4274+
4275+ local virt=""
4276+ if [ -s "$dmesg_file" ]; then
4277+ virt="$(find_virtualization_dmesg "$dmesg_file")"
4278+ fi
4279+ if [ -z "${virt}" ] && [ -s "$lspci_file" ]; then
4280+ if grep -qi "virtualbox" "$lspci_file" ; then
4281+ virt="VirtualBox"
4282+ elif grep -qi "vmware" "$lspci_file" ; then
4283+ virt="VMWare"
4284+ fi
4285+ elif [ "${platform}" = "FreeBSD" ]; then
4286+ if ps -o stat | grep J ; then
4287+ virt="FreeBSD Jail"
4288+ fi
4289+ elif [ "${platform}" = "SunOS" ]; then
4290+ if [ "$CMD_PRTDIAG" ] && $CMD_PRTDIAG > "$tempfile" 2>/dev/null; then
4291+ virt="$(find_virtualization_generic "$tempfile" )"
4292+ elif [ "$CMD_SMBIOS" ] && $CMD_SMBIOS > "$tempfile" 2>/dev/null; then
4293+ virt="$(find_virtualization_generic "$tempfile" )"
4294+ fi
4295+ elif [ -e /proc/user_beancounters ]; then
4296+ virt="OpenVZ/Virtuozzo"
4297+ fi
4298+ echo "virt ${virt:-"No virtualization detected"}"
4299+}
4300+
4301+find_virtualization_generic() { local PTFUNCNAME=find_virtualization_generic;
4302+ local file="$1"
4303+ if grep -i -e "virtualbox" "$file" >/dev/null; then
4304+ echo "VirtualBox"
4305+ elif grep -i -e "vmware" "$file" >/dev/null; then
4306+ echo "VMWare"
4307+ fi
4308+}
4309+
4310+find_virtualization_dmesg () { local PTFUNCNAME=find_virtualization_dmesg;
4311+ local file="$1"
4312+ if grep -qi -e "vmware" -e "vmxnet" -e 'paravirtualized kernel on vmi' "${file}"; then
4313+ echo "VMWare";
4314+ elif grep -qi -e 'paravirtualized kernel on xen' -e 'Xen virtual console' "${file}"; then
4315+ echo "Xen";
4316+ elif grep -qi "qemu" "${file}"; then
4317+ echo "QEmu";
4318+ elif grep -qi 'paravirtualized kernel on KVM' "${file}"; then
4319+ echo "KVM";
4320+ elif grep -q "VBOX" "${file}"; then
4321+ echo "VirtualBox";
4322+ elif grep -qi 'hd.: Virtual .., ATA.*drive' "${file}"; then
4323+ echo "Microsoft VirtualPC";
4324+ fi
4325+}
4326+
4327+dmidecode_system_info () { local PTFUNCNAME=dmidecode_system_info;
4328+ if [ "${CMD_DMIDECODE}" ]; then
4329+ local vendor="$($CMD_DMIDECODE -s "system-manufacturer" 2>/dev/null | sed 's/ *$//g')"
4330+ echo "vendor ${vendor}"
4331+ if [ "${vendor}" ]; then
4332+ local product="$($CMD_DMIDECODE -s "system-product-name" 2>/dev/null | sed 's/ *$//g')"
4333+ local version="$($CMD_DMIDECODE -s "system-version" 2>/dev/null | sed 's/ *$//g')"
4334+ local chassis="$($CMD_DMIDECODE -s "chassis-type" 2>/dev/null | sed 's/ *$//g')"
4335+ local servicetag="$($CMD_DMIDECODE -s "system-serial-number" 2>/dev/null | sed 's/ *$//g')"
4336+ local system="${vendor}; ${product}; v${version} (${chassis})"
4337+
4338+ echo "system ${system}"
4339+ echo "servicetag ${servicetag:-"Not found"}"
4340+ fi
4341+ fi
4342+}
4343+
4344+find_memory_stats () { local PTFUNCNAME=find_memory_stats;
4345+ local platform="$1"
4346+
4347+ if [ "${platform}" = "Linux" ]; then
4348+ free -b
4349+ cat /proc/meminfo
4350+ elif [ "${platform}" = "SunOS" ]; then
4351+ $CMD_PRTCONF | awk -F: '/Memory/{print $2}'
4352+ fi
4353+}
4354+
4355+mounted_fs_info () { local PTFUNCNAME=mounted_fs_info;
4356+ local platform="$1"
4357+
4358+ if [ "${platform}" != "SunOS" ]; then
4359+ local cmd="df -h"
4360+ if [ "${platform}" = "Linux" ]; then
4361+ cmd="df -h -P"
4362+ fi
4363+ $cmd | sort > "$TMPDIR/mounted_fs_info.tmp"
4364+ mount | sort | join "$TMPDIR/mounted_fs_info.tmp" -
4365+ fi
4366+}
4367+
4368+raid_controller () { local PTFUNCNAME=raid_controller;
4369+ local dmesg_file="$1"
4370+ local lspci_file="$2"
4371+
4372+ local tempfile="$TMPDIR/raid_controller.tmp"
4373+
4374+ local controller=""
4375+ if [ -s "$lspci_file" ]; then
4376+ controller="$(find_raid_controller_lspci "$lspci_file")"
4377+ fi
4378+ if [ -z "${controller}" ] && [ -s "$dmesg_file" ]; then
4379+ controller="$(find_raid_controller_dmesg "$dmesg_file")"
4380+ fi
4381+
4382+ echo "raid_controller ${controller:-"No RAID controller detected"}"
4383+}
4384+
4385+find_raid_controller_dmesg () { local PTFUNCNAME=find_raid_controller_dmesg;
4386+ local file="$1"
4387+ local pat='scsi[0-9].*: .*'
4388+ if grep -qi "${pat}megaraid" "${file}"; then
4389+ echo 'LSI Logic MegaRAID SAS'
4390+ elif grep -q "Fusion MPT SAS" "${file}"; then
4391+ echo 'Fusion-MPT SAS'
4392+ elif grep -q "${pat}aacraid" "${file}"; then
4393+ echo 'AACRAID'
4394+ elif grep -q "${pat}3ware [0-9]* Storage Controller" "${file}"; then
4395+ echo '3Ware'
4396+ fi
4397+}
4398+
4399+find_raid_controller_lspci () { local PTFUNCNAME=find_raid_controller_lspci;
4400+ local file="$1"
4401+ if grep -q "RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS" "${file}"; then
4402+ echo 'LSI Logic MegaRAID SAS'
4403+ elif grep -q "Fusion-MPT SAS" "${file}"; then
4404+ echo 'Fusion-MPT SAS'
4405+ elif grep -q "RAID bus controller: LSI Logic / Symbios Logic Unknown" "${file}"; then
4406+ echo 'LSI Logic Unknown'
4407+ elif grep -q "RAID bus controller: Adaptec AAC-RAID" "${file}"; then
4408+ echo 'AACRAID'
4409+ elif grep -q "3ware [0-9]* Storage Controller" "${file}"; then
4410+ echo '3Ware'
4411+ elif grep -q "Hewlett-Packard Company Smart Array" "${file}"; then
4412+ echo 'HP Smart Array'
4413+ elif grep -q " RAID bus controller: " "${file}"; then
4414+ awk -F: '/RAID bus controller\:/ {print $3" "$5" "$6}' "${file}"
4415+ fi
4416+}
4417+
4418+schedulers_and_queue_size () { local PTFUNCNAME=schedulers_and_queue_size;
4419+ local file="$1"
4420+
4421+ local disks="$(ls /sys/block/ | grep -v -e ram -e loop -e 'fd[0-9]' | xargs echo)"
4422+ echo "internal::disks $disks" >> "$file"
4423+
4424+ for disk in $disks; do
4425+ if [ -e "/sys/block/${disk}/queue/scheduler" ]; then
4426+ echo "internal::${disk} $(cat /sys/block/${disk}/queue/scheduler | grep -o '\[.*\]') $(cat /sys/block/${disk}/queue/nr_requests)" >> "$file"
4427+ fdisk -l "/dev/${disk}" 2>/dev/null
4428+ fi
4429+ done
4430+}
4431+
4432+top_processes () { local PTFUNCNAME=top_processes;
4433+ if [ "$CMD_PRSTAT" ]; then
4434+ $CMD_PRSTAT | head
4435+ elif [ "$CMD_TOP" ]; then
4436+ local cmd="$CMD_TOP -bn 1"
4437+ if [ "${platform}" = "FreeBSD" ] \
4438+ || [ "${platform}" = "NetBSD" ] \
4439+ || [ "${platform}" = "OpenBSD" ]; then
4440+ cmd="$CMD_TOP -b -d 1"
4441+ fi
4442+ $cmd \
4443+ | sed -e 's# *$##g' -e '/./{H;$!d;}' -e 'x;/PID/!d;' \
4444+ | grep . \
4445+ | head
4446+ fi
4447+}
4448+
4449+notable_processes_info () { local PTFUNCNAME=notable_processes_info;
4450+ local format="%5s %+2d %s\n"
4451+ local sshd_pid=$(ps -eo pid,args | awk '$2 ~ /\/usr\/sbin\/sshd/ { print $1; exit }')
4452+
4453+ echo " PID OOM COMMAND"
4454+
4455+ if [ "$sshd_pid" ]; then
4456+ printf "$format" "$sshd_pid" "$(get_oom_of_pid $sshd_pid)" "sshd"
4457+ else
4458+ printf "%5s %3s %s\n" "?" "?" "sshd doesn't appear to be running"
4459+ fi
4460+
4461+ local PTDEBUG=""
4462+ ps -eo pid,ucomm | grep '^[0-9]' | while read pid proc; do
4463+ [ "$sshd_pid" ] && [ "$sshd_pid" = "$pid" ] && continue
4464+ local oom="$(get_oom_of_pid $pid)"
4465+ if [ "$oom" ] && [ "$oom" != "?" ] && [ "$oom" = "-17" ]; then
4466+ printf "$format" "$pid" "$oom" "$proc"
4467+ fi
4468+ done
4469+}
4470+
4471+processor_info () { local PTFUNCNAME=processor_info;
4472+ local data_dir="$1"
4473+ if [ -f /proc/cpuinfo ]; then
4474+ cat /proc/cpuinfo > "$data_dir/proc_cpuinfo_copy" 2>/dev/null
4475+ elif [ "${platform}" = "SunOS" ]; then
4476+ $CMD_PSRINFO -v > "$data_dir/psrinfo_minus_v"
4477+ fi
4478+}
4479+
4480+propietary_raid_controller () { local PTFUNCNAME=propietary_raid_controller;
4481+ local file="$1"
4482+ local variable_file="$2"
4483+ local data_dir="$3"
4484+ local controller="$4"
4485+
4486+ notfound=""
4487+ if [ "${controller}" = "AACRAID" ]; then
4488+ if [ -z "$CMD_ARCCONF" ]; then
4489+ notfound="e.g. http://www.adaptec.com/en-US/support/raid/scsi_raid/ASR-2120S/"
4490+ elif $CMD_ARCCONF getconfig 1 > "$file" 2>/dev/null; then
4491+ echo "internal::raid_opt 1" >> "$variable_file"
4492+ fi
4493+ elif [ "${controller}" = "HP Smart Array" ]; then
4494+ if [ -z "$CMD_HPACUCLI" ]; then
4495+ notfound="your package repository or the manufacturer's website"
4496+ elif $CMD_HPACUCLI ctrl all show config > "$file" 2>/dev/null; then
4497+ echo "internal::raid_opt 2" >> "$variable_file"
4498+ fi
4499+ elif [ "${controller}" = "LSI Logic MegaRAID SAS" ]; then
4500+ if [ -z "$CMD_MEGACLI64" ]; then
4501+ notfound="your package repository or the manufacturer's website"
4502+ else
4503+ echo "internal::raid_opt 3" >> "$variable_file"
4504+ $CMD_MEGACLI64 -AdpAllInfo -aALL -NoLog > "$data_dir/lsi_megaraid_adapter_info.tmp" 2>/dev/null
4505+ $CMD_MEGACLI64 -AdpBbuCmd -GetBbuStatus -aALL -NoLog > "$data_dir/lsi_megaraid_bbu_status.tmp" 2>/dev/null
4506+ $CMD_MEGACLI64 -LdPdInfo -aALL -NoLog > "$data_dir/lsi_megaraid_devices.tmp" 2>/dev/null
4507+ fi
4508+ fi
4509+
4510+ if [ "${notfound}" ]; then
4511+ echo "internal::raid_opt 0" >> "$variable_file"
4512+ echo " RAID controller software not found; try getting it from" > "$file"
4513+ echo " ${notfound}" >> "$file"
4514+ fi
4515+}
4516+
4517+# ###########################################################################
4518+# End collect_system_info package
4519+# ###########################################################################
4520+
4521+# ###########################################################################
4522+# report_system_info package
4523+# This package is a copy without comments from the original. The original
4524+# with comments and its test file can be found in the Bazaar repository at,
4525+# lib/bash/report_system_info.sh
4526+# t/lib/bash/report_system_info.sh
4527+# See https://launchpad.net/percona-toolkit for more information.
4528+# ###########################################################################
4529+
4530+
4531+set -u
4532+
4533
4534-# ##############################################################################
4535-# Parse Linux's /proc/cpuinfo, which should be stored in $TMPDIR/percona-toolkit.
4536-# ##############################################################################
4537-parse_proc_cpuinfo () {
4538- local file=$1
4539- # Physical processors are indicated by distinct 'physical id'. Virtual CPUs
4540- # are indicated by paragraphs -- one per paragraph. We assume that all
4541- # processors are identical, i.e. that there are not some processors with dual
4542- # cores and some with quad cores.
4543- virtual=$(grep -c ^processor $file);
4544- physical=$(grep 'physical id' $file | sort -u | wc -l);
4545- cores=$(grep 'cpu cores' $file | head -n 1 | cut -d: -f2);
4546-
4547- # Older kernel won't have 'physical id' or 'cpu cores'.
4548- if [ "${physical}" = "0" ]; then physical=${virtual}; fi
4549- if [ -z "${cores}" ]; then cores=0; fi
4550-
4551- # Test for HTT; cannot trust the 'ht' flag. If physical * cores < virtual,
4552- # then hyperthreading is in use.
4553+parse_proc_cpuinfo () { local PTFUNCNAME=parse_proc_cpuinfo;
4554+ local file="$1"
4555+ local virtual="$(grep -c ^processor "${file}")";
4556+ local physical="$(grep 'physical id' "${file}" | sort -u | wc -l)";
4557+ local cores="$(grep 'cpu cores' "${file}" | head -n 1 | cut -d: -f2)";
4558+
4559+ [ "${physical}" = "0" ] && physical="${virtual}"
4560+ [ -z "${cores}" ] && cores=0
4561+
4562 cores=$((${cores} * ${physical}));
4563+ local htt=""
4564 if [ ${cores} -gt 0 -a $cores -lt $virtual ]; then htt=yes; else htt=no; fi
4565
4566 name_val "Processors" "physical = ${physical}, cores = ${cores}, virtual = ${virtual}, hyperthreading = ${htt}"
4567
4568- awk -F: '/cpu MHz/{print $2}' $file \
4569- | sort | uniq -c > "$file.unq"
4570- name_val "Speeds" "$(group_concat "$file.unq")"
4571-
4572- awk -F: '/model name/{print $2}' $file \
4573- | sort | uniq -c > "$file.unq"
4574- name_val "Models" "$(group_concat "$file.unq")"
4575-
4576- awk -F: '/cache size/{print $2}' $file \
4577- | sort | uniq -c > "$file.unq"
4578- name_val "Caches" "$(group_concat "$file.unq")"
4579-}
4580-
4581-# ##############################################################################
4582-# Parse sysctl -a output on FreeBSD, and format it as CPU info. The file is the
4583-# first argument.
4584-# ##############################################################################
4585-parse_sysctl_cpu_freebsd() {
4586- virtual="$(awk '/hw.ncpu/{print $2}' "$1")"
4587- name_val "Processors" "virtual = ${virtual}"
4588- name_val "Speeds" "$(awk '/hw.clockrate/{print $2}' "$1")"
4589- name_val "Models" "$(awk -F: '/hw.model/{print substr($2, 2)}' "$1")"
4590-}
4591-
4592-# ##############################################################################
4593-# Parse CPU info from psrinfo -v
4594-# ##############################################################################
4595-parse_psrinfo_cpus() {
4596- name_val Processors $(grep -c 'Status of .* processor' "$1")
4597+ awk -F: '/cpu MHz/{print $2}' "${file}" \
4598+ | sort | uniq -c > "$TMPDIR/parse_proc_cpuinfo_cpu.unq"
4599+ name_val "Speeds" "$(group_concat "$TMPDIR/parse_proc_cpuinfo_cpu.unq")"
4600+
4601+ awk -F: '/model name/{print $2}' "${file}" \
4602+ | sort | uniq -c > "$TMPDIR/parse_proc_cpuinfo_model.unq"
4603+ name_val "Models" "$(group_concat "$TMPDIR/parse_proc_cpuinfo_model.unq")"
4604+
4605+ awk -F: '/cache size/{print $2}' "${file}" \
4606+ | sort | uniq -c > "$TMPDIR/parse_proc_cpuinfo_cache.unq"
4607+ name_val "Caches" "$(group_concat "$TMPDIR/parse_proc_cpuinfo_cache.unq")"
4608+}
4609+
4610+parse_sysctl_cpu_freebsd() { local PTFUNCNAME=parse_sysctl_cpu_freebsd;
4611+ local file="$1"
4612+ [ -e "$file" ] || return;
4613+ local virtual="$(awk '/hw.ncpu/{print $2}' "$file")"
4614+ name_val "Processors" "virtual = ${virtual}"
4615+ name_val "Speeds" "$(awk '/hw.clockrate/{print $2}' "$file")"
4616+ name_val "Models" "$(awk -F: '/hw.model/{print substr($2, 2)}' "$file")"
4617+}
4618+
4619+parse_sysctl_cpu_netbsd() { local PTFUNCNAME=parse_sysctl_cpu_netbsd;
4620+ local file="$1"
4621+
4622+ [ -e "$file" ] || return
4623+
4624+ local virtual="$(awk '/hw.ncpu /{print $NF}' "$file")"
4625+ name_val "Processors" "virtual = ${virtual}"
4626+ name_val "Models" "$(awk -F: '/hw.model/{print $3}' "$file")"
4627+}
4628+
4629+parse_sysctl_cpu_openbsd() { local PTFUNCNAME=parse_sysctl_cpu_openbsd;
4630+ local file="$1"
4631+
4632+ [ -e "$file" ] || return
4633+
4634+ name_val "Processors" "$(awk -F= '/hw.ncpu=/{print $2}' "$file")"
4635+ name_val "Speeds" "$(awk -F= '/hw.cpuspeed/{print $2}' "$file")"
4636+ name_val "Models" "$(awk -F= '/hw.model/{print substr($2, 1, index($2, " "))}' "$file")"
4637+}
4638+
4639+parse_psrinfo_cpus() { local PTFUNCNAME=parse_psrinfo_cpus;
4640+ local file="$1"
4641+
4642+ [ -e "$file" ] || return
4643+
4644+ name_val "Processors" "$(grep -c 'Status of .* processor' "$file")"
4645 awk '/operates at/ {
4646 start = index($0, " at ") + 4;
4647 end = length($0) - start - 4
4648 print substr($0, start, end);
4649- }' "$1" | sort | uniq -c > $TMPDIR/percona-toolkit2
4650- name_val "Speeds" "$(group_concat $TMPDIR/percona-toolkit2)"
4651+ }' "$file" | sort | uniq -c > "$TMPDIR/parse_psrinfo_cpus.tmp"
4652+ name_val "Speeds" "$(group_concat "$TMPDIR/parse_psrinfo_cpus.tmp")"
4653 }
4654
4655-# ##############################################################################
4656-# Parse the output of 'free -b' plus the contents of /proc/meminfo
4657-# ##############################################################################
4658-parse_free_minus_b () {
4659- local file=$1
4660+parse_free_minus_b () { local PTFUNCNAME=parse_free_minus_b;
4661+ local file="$1"
4662+
4663+ [ -e "$file" ] || return
4664
4665 local physical=$(awk '/Mem:/{print $3}' "${file}")
4666- local swap=$(awk '/Swap:/{print $3}' "${file}")
4667- local virtual=$(shorten $(($physical + $swap)))
4668+ local swap_alloc=$(awk '/Swap:/{print $2}' "${file}")
4669+ local swap_used=$(awk '/Swap:/{print $3}' "${file}")
4670+ local virtual=$(shorten $(($physical + $swap_used)) 1)
4671
4672- name_val Total $(shorten $(awk '/Mem:/{print $2}' "${file}"))
4673- name_val Free $(shorten $(awk '/Mem:/{print $4}' "${file}"))
4674- name_val Used "physical = $(shorten ${physical}), swap = $(shorten ${swap}), virtual = ${virtual}"
4675- name_val Buffers $(shorten $(awk '/Mem:/{print $6}' "${file}"))
4676- name_val Caches $(shorten $(awk '/Mem:/{print $7}' "${file}"))
4677- name_val Dirty "$(awk '/Dirty:/ {print $2, $3}' "${file}")"
4678+ name_val "Total" $(shorten $(awk '/Mem:/{print $2}' "${file}") 1)
4679+ name_val "Free" $(shorten $(awk '/Mem:/{print $4}' "${file}") 1)
4680+ name_val "Used" "physical = $(shorten ${physical} 1), swap allocated = $(shorten ${swap_alloc} 1), swap used = $(shorten ${swap_used} 1), virtual = ${virtual}"
4681+ name_val "Buffers" $(shorten $(awk '/Mem:/{print $6}' "${file}") 1)
4682+ name_val "Caches" $(shorten $(awk '/Mem:/{print $7}' "${file}") 1)
4683+ name_val "Dirty" "$(awk '/Dirty:/ {print $2, $3}' "${file}")"
4684 }
4685
4686-# ##############################################################################
4687-# Parse FreeBSD memory info from sysctl output.
4688-# ##############################################################################
4689-parse_memory_sysctl_freebsd() {
4690- physical=$(awk '/hw.realmem:/{print $2}' "${1}")
4691- mem_hw=$(awk '/hw.physmem:/{print $2}' "${1}")
4692- mem_used=$(awk '
4693+parse_memory_sysctl_freebsd() { local PTFUNCNAME=parse_memory_sysctl_freebsd;
4694+ local file="$1"
4695+
4696+ [ -e "$file" ] || return
4697+
4698+ local physical=$(awk '/hw.realmem:/{print $2}' "${file}")
4699+ local mem_hw=$(awk '/hw.physmem:/{print $2}' "${file}")
4700+ local mem_used=$(awk '
4701 /hw.physmem/ { mem_hw = $2; }
4702 /vm.stats.vm.v_inactive_count/ { mem_inactive = $2; }
4703 /vm.stats.vm.v_cache_count/ { mem_cache = $2; }
4704@@ -267,50 +1366,66 @@
4705 mem_free *= pagesize;
4706 print mem_hw - mem_inactive - mem_cache - mem_free;
4707 }
4708- ' "$1");
4709- name_val Total $(shorten ${mem_hw} 1)
4710- name_val Virtual $(shorten ${physical} 1)
4711- name_val Used $(shorten ${mem_used} 1)
4712-}
4713-
4714-# ##############################################################################
4715-# Parse memory devices from the output of 'dmidecode'.
4716-# ##############################################################################
4717-parse_dmidecode_mem_devices () {
4718- local file=$1
4719+ ' "$file");
4720+ name_val "Total" $(shorten ${mem_hw} 1)
4721+ name_val "Virtual" $(shorten ${physical} 1)
4722+ name_val "Used" $(shorten ${mem_used} 1)
4723+}
4724+
4725+parse_memory_sysctl_netbsd() { local PTFUNCNAME=parse_memory_sysctl_netbsd;
4726+ local file="$1"
4727+ local swapctl_file="$2"
4728+
4729+ [ -e "$file" -a -e "$swapctl_file" ] || return
4730+
4731+ local swap_mem="$(echo "$(awk '{print $2;}' "$swapctl_file")*512" | bc -l)"
4732+ name_val "Total" $(shorten "$(awk '/hw.physmem /{print $NF}' "$file")" 1)
4733+ name_val "User" $(shorten "$(awk '/hw.usermem /{print $NF}' "$file")" 1)
4734+ name_val "Swap" $(shorten ${swap_mem} 1)
4735+}
4736+
4737+parse_memory_sysctl_openbsd() { local PTFUNCNAME=parse_memory_sysctl_openbsd;
4738+ local file="$1"
4739+ local swapctl_file="$2"
4740+
4741+ [ -e "$file" -a -e "$swapctl_file" ] || return
4742+
4743+ local swap_mem="$(echo "$(awk '{print $2;}' "$swapctl_file")*512" | bc -l)"
4744+ name_val "Total" $(shorten "$(awk -F= '/hw.physmem/{print $2}' "$file")" 1)
4745+ name_val "User" $(shorten "$(awk -F= '/hw.usermem/{print $2}' "$file")" 1)
4746+ name_val "Swap" $(shorten ${swap_mem} 1)
4747+}
4748+
4749+parse_dmidecode_mem_devices () { local PTFUNCNAME=parse_dmidecode_mem_devices;
4750+ local file="$1"
4751+
4752+ [ -e "$file" ] || return
4753+
4754 echo " Locator Size Speed Form Factor Type Type Detail"
4755 echo " ========= ======== ================= ============= ============= ==========="
4756- # Print paragraphs containing 'Memory Device\n', extract the desired bits,
4757- # concatenate them into one long line, then format as a table. The data
4758- # comes out in this order for each paragraph:
4759- # $2 Size 2048 MB
4760- # $3 Form Factor <OUT OF SPEC>
4761- # $4 Locator DIMM1
4762- # $5 Type <OUT OF SPEC>
4763- # $6 Type Detail Synchronous
4764- # $7 Speed 667 MHz (1.5 ns)
4765 sed -e '/./{H;$!d;}' \
4766 -e 'x;/Memory Device\n/!d;' \
4767 -e 's/: /:/g' \
4768 -e 's/</{/g' \
4769 -e 's/>/}/g' \
4770 -e 's/[ \t]*\n/\n/g' \
4771- $file \
4772+ "${file}" \
4773 | awk -F: '/Size|Type|Form.Factor|Type.Detail|[^ ]Locator/{printf("|%s", $2)}/Speed/{print "|" $2}' \
4774 | sed -e 's/No Module Installed/{EMPTY}/' \
4775 | sort \
4776 | awk -F'|' '{printf(" %-9s %-8s %-17s %-13s %-13s %-8s\n", $4, $2, $7, $3, $5, $6);}'
4777 }
4778
4779-# ##############################################################################
4780-# Parse the output of 'netstat -antp'
4781-# ##############################################################################
4782-parse_ip_s_link () {
4783+parse_ip_s_link () { local PTFUNCNAME=parse_ip_s_link;
4784+ local file="$1"
4785+
4786+ [ -e "$file" ] || return
4787+
4788 echo " interface rx_bytes rx_packets rx_errors tx_bytes tx_packets tx_errors"
4789 echo " ========= ========= ========== ========== ========== ========== =========="
4790
4791 awk "/^[1-9][0-9]*:/ {
4792- save[\"iface\"] = substr(\$2, 0, index(\$2, \":\") - 1);
4793+ save[\"iface\"] = substr(\$2, 1, index(\$2, \":\") - 1);
4794 new = 1;
4795 }
4796 \$0 !~ /[^0-9 ]/ {
4797@@ -324,20 +1439,48 @@
4798 fuzzy_var = \$1; ${fuzzy_formula} tx_bytes = fuzzy_var;
4799 fuzzy_var = \$2; ${fuzzy_formula} tx_packets = fuzzy_var;
4800 fuzzy_var = \$3; ${fuzzy_formula} tx_errors = fuzzy_var;
4801- printf \" %-8s %10d %10d %10d %10d %10d %10d\\n\", save[\"iface\"], save[\"bytes\"], save[\"packs\"], save[\"errs\"], tx_bytes, tx_packets, tx_errors;
4802- }
4803- }" $@
4804-}
4805-
4806-# ##############################################################################
4807-# Parse the output of 'netstat -antp' which should be in $TMPDIR/percona-toolkit.
4808-# ##############################################################################
4809-parse_netstat () {
4810- local file=$1
4811+ printf \" %-8s %10.0f %10.0f %10.0f %10.0f %10.0f %10.0f\\n\", save[\"iface\"], save[\"bytes\"], save[\"packs\"], save[\"errs\"], tx_bytes, tx_packets, tx_errors;
4812+ }
4813+ }" "$file"
4814+}
4815+
4816+parse_ethtool () {
4817+ local file="$1"
4818+
4819+ [ -e "$file" ] || return
4820+
4821+ echo " Device Speed Duplex"
4822+ echo " ========= ========= ========="
4823+
4824+
4825+ awk '
4826+ /^Settings for / {
4827+ device = substr($3, 1, index($3, ":") ? index($3, ":")-1 : length($3));
4828+ device_names[device] = device;
4829+ }
4830+ /Speed:/ { devices[device ",speed"] = $2 }
4831+ /Duplex:/ { devices[device ",duplex"] = $2 }
4832+ END {
4833+ for ( device in device_names ) {
4834+ printf(" %-10s %-10s %-10s\n",
4835+ device,
4836+ devices[device ",speed"],
4837+ devices[device ",duplex"]);
4838+ }
4839+ }
4840+ ' "$file"
4841+
4842+}
4843+
4844+parse_netstat () { local PTFUNCNAME=parse_netstat;
4845+ local file="$1"
4846+
4847+ [ -e "$file" ] || return
4848+
4849 echo " Connections from remote IP addresses"
4850 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
4851- print substr($5, 0, index($5, ":") - 1);
4852- }' $file | sort | uniq -c \
4853+ print substr($5, 1, index($5, ":") - 1);
4854+ }' "${file}" | sort | uniq -c \
4855 | awk "{
4856 fuzzy_var=\$1;
4857 ${fuzzy_formula}
4858@@ -346,8 +1489,8 @@
4859 | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4
4860 echo " Connections to local IP addresses"
4861 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
4862- print substr($4, 0, index($4, ":") - 1);
4863- }' $file | sort | uniq -c \
4864+ print substr($4, 1, index($4, ":") - 1);
4865+ }' "${file}" | sort | uniq -c \
4866 | awk "{
4867 fuzzy_var=\$1;
4868 ${fuzzy_formula}
4869@@ -357,7 +1500,7 @@
4870 echo " Connections to top 10 local ports"
4871 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
4872 print substr($4, index($4, ":") + 1);
4873- }' $file | sort | uniq -c | sort -rn | head -n10 \
4874+ }' "${file}" | sort | uniq -c | sort -rn | head -n10 \
4875 | awk "{
4876 fuzzy_var=\$1;
4877 ${fuzzy_formula}
4878@@ -366,7 +1509,7 @@
4879 echo " States of connections"
4880 awk '$1 ~ /^tcp/ {
4881 print $6;
4882- }' $file | sort | uniq -c | sort -rn \
4883+ }' "${file}" | sort | uniq -c | sort -rn \
4884 | awk "{
4885 fuzzy_var=\$1;
4886 ${fuzzy_formula}
4887@@ -374,19 +1517,13 @@
4888 }" | sort
4889 }
4890
4891-# ##############################################################################
4892-# Parse the joined output of 'mount' and 'df -hP'. $1 = file; $2 = ostype.
4893-# ##############################################################################
4894-parse_filesystems () {
4895- # Filesystem names and mountpoints can be very long. We try to align things
4896- # as nicely as possible by making columns only as wide as needed. This
4897- # requires two passes through the file. The first pass finds the max size of
4898- # these columns and prints out a printf spec, and the second prints out the
4899- # file nicely aligned.
4900- local file=$1
4901- local platform=$2
4902-
4903- local spec=$(awk "
4904+parse_filesystems () { local PTFUNCNAME=parse_filesystems;
4905+ local file="$1"
4906+ local platform="$2"
4907+
4908+ [ -e "$file" ] || return
4909+
4910+ local spec="$(awk "
4911 BEGIN {
4912 device = 10;
4913 fstype = 4;
4914@@ -396,7 +1533,7 @@
4915 f_device = \$1;
4916 f_fstype = \$10;
4917 f_options = substr(\$11, 2, length(\$11) - 2);
4918- if ( \"$2\" == \"FreeBSD\" ) {
4919+ if ( \"$2\" ~ /(Free|Open|Net)BSD/ ) {
4920 f_fstype = substr(\$9, 2, length(\$9) - 2);
4921 f_options = substr(\$0, index(\$0, \",\") + 2);
4922 f_options = substr(f_options, 1, length(f_options) - 1);
4923@@ -414,7 +1551,7 @@
4924 END{
4925 print \"%-\" device \"s %5s %4s %-\" fstype \"s %-\" options \"s %s\";
4926 }
4927- " $file)
4928+ " "${file}")"
4929
4930 awk "
4931 BEGIN {
4932@@ -424,22 +1561,21 @@
4933 {
4934 f_fstype = \$10;
4935 f_options = substr(\$11, 2, length(\$11) - 2);
4936- if ( \"$2\" == \"FreeBSD\" ) {
4937+ if ( \"$2\" ~ /(Free|Open|Net)BSD/ ) {
4938 f_fstype = substr(\$9, 2, length(\$9) - 2);
4939 f_options = substr(\$0, index(\$0, \",\") + 2);
4940 f_options = substr(f_options, 1, length(f_options) - 1);
4941 }
4942 printf spec, \$1, \$2, \$5, f_fstype, f_options, \$6;
4943 }
4944- " $file
4945+ " "${file}"
4946 }
4947
4948-# ##############################################################################
4949-# Parse the output of fdisk -l, which should be in $TMPDIR/percona-toolkit; there might be
4950-# multiple fdisk -l outputs in the file.
4951-# ##############################################################################
4952-parse_fdisk () {
4953- local file=$1
4954+parse_fdisk () { local PTFUNCNAME=parse_fdisk;
4955+ local file="$1"
4956+
4957+ [ -e "$file" -a -s "$file" ] || return
4958+
4959 awk '
4960 BEGIN {
4961 format="%-12s %4s %10s %10s %18s\n";
4962@@ -465,128 +1601,55 @@
4963 }
4964 printf(format, $1, "Part", start, end, sprintf("%.0f", (end - start) * units));
4965 }
4966- ' $file
4967-}
4968-
4969-# ##############################################################################
4970-# Parse the output of dmesg, which should be in $TMPDIR/percona-toolkit, and detect
4971-# virtualization.
4972-# ##############################################################################
4973-parse_virtualization_dmesg () {
4974- local file=$1
4975- if grep -qi -e vmware -e vmxnet -e 'paravirtualized kernel on vmi' $file; then
4976- echo "VMWare";
4977- elif grep -qi -e 'paravirtualized kernel on xen' -e 'Xen virtual console' $file; then
4978- echo "Xen";
4979- elif grep -qi qemu $file; then
4980- echo "QEmu";
4981- elif grep -qi 'paravirtualized kernel on KVM' $file; then
4982- echo "KVM";
4983- elif grep -q VBOX $file; then
4984- echo "VirtualBox";
4985- elif grep -qi 'hd.: Virtual .., ATA.*drive' $file; then
4986- echo "Microsoft VirtualPC";
4987- fi
4988-}
4989-
4990-# ##############################################################################
4991-# Try to figure out if a system is a guest by looking at prtdiag, smbios, etc.
4992-# ##############################################################################
4993-parse_virtualization_generic() {
4994- if grep -i -e virtualbox "$1" >/dev/null; then
4995- echo VirtualBox
4996- elif grep -i -e vmware "$1" >/dev/null; then
4997- echo VMWare
4998- fi
4999-}
5000-
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches