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
=== modified file 'bin/pt-mysql-summary'
--- bin/pt-mysql-summary 2012-03-07 23:41:54 +0000
+++ bin/pt-mysql-summary 2012-04-03 15:57:31 +0000
@@ -4,14 +4,421 @@
4# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal4# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
5# notices and disclaimers.5# notices and disclaimers.
66
7set -u
8
9# ###########################################################################
10# log_warn_die package
11# This package is a copy without comments from the original. The original
12# with comments and its test file can be found in the Bazaar repository at,
13# lib/bash/log_warn_die.sh
14# t/lib/bash/log_warn_die.sh
15# See https://launchpad.net/percona-toolkit for more information.
16# ###########################################################################
17
18
19set -u
20
21PTFUNCNAME=""
22PTDEBUG="${PTDEBUG:-""}"
23EXIT_STATUS=0
24
25log() {
26 TS=$(date +%F-%T | tr :- _);
27 echo "$TS $*"
28}
29
30warn() {
31 log "$*" >&2
32 EXIT_STATUS=1
33}
34
35die() {
36 warn "$*"
37 exit 1
38}
39
40_d () {
41 [ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
42}
43
44# ###########################################################################
45# End log_warn_die package
46# ###########################################################################
47
48# ###########################################################################
49# parse_options package
50# This package is a copy without comments from the original. The original
51# with comments and its test file can be found in the Bazaar repository at,
52# lib/bash/parse_options.sh
53# t/lib/bash/parse_options.sh
54# See https://launchpad.net/percona-toolkit for more information.
55# ###########################################################################
56
57
58
59
60
61set -u
62
63ARGV="" # Non-option args (probably input files)
64EXT_ARGV="" # Everything after -- (args for an external command)
65HAVE_EXT_ARGV="" # Got --, everything else is put into EXT_ARGV
66OPT_ERRS=0 # How many command line option errors
67OPT_VERSION="" # If --version was specified
68OPT_HELP="" # If --help was specified
69PO_DIR="" # Directory with program option spec files
70
7usage() {71usage() {
8 if [ "${OPT_ERR}" ]; then72 local file="$1"
9 echo "${OPT_ERR}" >&273
10 fi74 local usage=$(grep '^Usage: ' "$file")
11 echo "Usage: pt-mysql-summary [MYSQL-OPTIONS]" >&275 echo $usage
12 echo "For more information, 'man pt-mysql-summary' or 'perldoc $0'" >&276 echo
13 exit 177 echo "For more information, 'man $TOOL' or 'perldoc $file'."
14}78}
79
80usage_or_errors() {
81 local file="$1"
82
83 if [ "$OPT_VERSION" ]; then
84 local version=$(grep '^pt-[^ ]\+ [0-9]' "$file")
85 echo "$version"
86 return 1
87 fi
88
89 if [ "$OPT_HELP" ]; then
90 usage "$file"
91 echo
92 echo "Command line options:"
93 echo
94 perl -e '
95 use strict;
96 use warnings FATAL => qw(all);
97 my $lcol = 20; # Allow this much space for option names.
98 my $rcol = 80 - $lcol; # The terminal is assumed to be 80 chars wide.
99 my $name;
100 while ( <> ) {
101 my $line = $_;
102 chomp $line;
103 if ( $line =~ s/^long:/ --/ ) {
104 $name = $line;
105 }
106 elsif ( $line =~ s/^desc:// ) {
107 $line =~ s/ +$//mg;
108 my @lines = grep { $_ }
109 $line =~ m/(.{0,$rcol})(?:\s+|\Z)/g;
110 if ( length($name) >= $lcol ) {
111 print $name, "\n", (q{ } x $lcol);
112 }
113 else {
114 printf "%-${lcol}s", $name;
115 }
116 print join("\n" . (q{ } x $lcol), @lines);
117 print "\n";
118 }
119 }
120 ' "$PO_DIR"/*
121 echo
122 echo "Options and values after processing arguments:"
123 echo
124 for opt in $(ls "$PO_DIR"); do
125 local varname="OPT_$(echo "$opt" | tr a-z- A-Z_)"
126 local varvalue="${!varname}"
127 printf -- " --%-30s %s" "$opt" "${varvalue:-(No value)}"
128 echo
129 done
130 return 1
131 fi
132
133 if [ $OPT_ERRS -gt 0 ]; then
134 echo
135 usage "$file"
136 return 1
137 fi
138
139 return 0
140}
141
142option_error() {
143 local err="$1"
144 OPT_ERRS=$(($OPT_ERRS + 1))
145 echo "$err" >&2
146}
147
148parse_options() {
149 local file="$1"
150 shift
151
152 ARGV=""
153 EXT_ARGV=""
154 HAVE_EXT_ARGV=""
155 OPT_ERRS=0
156 OPT_VERSION=""
157 OPT_HELP=""
158 PO_DIR="$TMPDIR/po"
159
160 if [ ! -d "$PO_DIR" ]; then
161 mkdir "$PO_DIR"
162 if [ $? -ne 0 ]; then
163 echo "Cannot mkdir $PO_DIR" >&2
164 exit 1
165 fi
166 fi
167
168 rm -rf "$PO_DIR"/*
169 if [ $? -ne 0 ]; then
170 echo "Cannot rm -rf $PO_DIR/*" >&2
171 exit 1
172 fi
173
174 _parse_pod "$file" # Parse POD into program option (po) spec files
175 _eval_po # Eval po into existence with default values
176
177 if [ $# -ge 2 ] && [ "$1" = "--config" ]; then
178 shift # --config
179 local user_config_files="$1"
180 shift # that ^
181 local IFS=","
182 for user_config_file in $user_config_files; do
183 _parse_config_files "$user_config_file"
184 done
185 else
186 _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf"
187 fi
188
189 _parse_command_line "$@"
190}
191
192_parse_pod() {
193 local file="$1"
194
195 cat "$file" | PO_DIR="$PO_DIR" perl -ne '
196 BEGIN { $/ = ""; }
197 next unless $_ =~ m/^=head1 OPTIONS/;
198 while ( defined(my $para = <>) ) {
199 last if $para =~ m/^=head1/;
200 chomp;
201 if ( $para =~ m/^=item --(\S+)/ ) {
202 my $opt = $1;
203 my $file = "$ENV{PO_DIR}/$opt";
204 open my $opt_fh, ">", $file or die "Cannot open $file: $!";
205 print $opt_fh "long:$opt\n";
206 $para = <>;
207 chomp;
208 if ( $para =~ m/^[a-z ]+:/ ) {
209 map {
210 chomp;
211 my ($attrib, $val) = split(/: /, $_);
212 print $opt_fh "$attrib:$val\n";
213 } split(/; /, $para);
214 $para = <>;
215 chomp;
216 }
217 my ($desc) = $para =~ m/^([^?.]+)/;
218 print $opt_fh "desc:$desc.\n";
219 close $opt_fh;
220 }
221 }
222 last;
223 '
224}
225
226_eval_po() {
227 local IFS=":"
228 for opt_spec in "$PO_DIR"/*; do
229 local opt=""
230 local default_val=""
231 local neg=0
232 local size=0
233 while read key val; do
234 case "$key" in
235 long)
236 opt=$(echo $val | sed 's/-/_/g' | tr [:lower:] [:upper:])
237 ;;
238 default)
239 default_val="$val"
240 ;;
241 "short form")
242 ;;
243 type)
244 [ "$val" = "size" ] && size=1
245 ;;
246 desc)
247 ;;
248 negatable)
249 if [ "$val" = "yes" ]; then
250 neg=1
251 fi
252 ;;
253 *)
254 echo "Invalid attribute in $opt_spec: $line" >&2
255 exit 1
256 esac
257 done < "$opt_spec"
258
259 if [ -z "$opt" ]; then
260 echo "No long attribute in option spec $opt_spec" >&2
261 exit 1
262 fi
263
264 if [ $neg -eq 1 ]; then
265 if [ -z "$default_val" ] || [ "$default_val" != "yes" ]; then
266 echo "Option $opt_spec is negatable but not default: yes" >&2
267 exit 1
268 fi
269 fi
270
271 if [ $size -eq 1 -a -n "$default_val" ]; then
272 default_val=$(size_to_bytes $default_val)
273 fi
274
275 eval "OPT_${opt}"="$default_val"
276 done
277}
278
279_parse_config_files() {
280
281 for config_file in "$@"; do
282 test -f "$config_file" || continue
283
284 while read config_opt; do
285
286 echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue
287
288 config_opt="$(echo "$config_opt" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/[ ]*=[ ]*/=/' -e 's/[ ]*#.*$//')"
289
290 [ "$config_opt" = "" ] && continue
291
292 if ! [ "$HAVE_EXT_ARGV" ]; then
293 config_opt="--$config_opt"
294 fi
295
296 _parse_command_line "$config_opt"
297
298 done < "$config_file"
299
300 HAVE_EXT_ARGV="" # reset for each file
301
302 done
303}
304
305_parse_command_line() {
306 local opt=""
307 local val=""
308 local next_opt_is_val=""
309 local opt_is_ok=""
310 local opt_is_negated=""
311 local real_opt=""
312 local required_arg=""
313 local spec=""
314
315 for opt in "$@"; do
316 if [ "$opt" = "--" -o "$opt" = "----" ]; then
317 HAVE_EXT_ARGV=1
318 continue
319 fi
320 if [ "$HAVE_EXT_ARGV" ]; then
321 if [ "$EXT_ARGV" ]; then
322 EXT_ARGV="$EXT_ARGV $opt"
323 else
324 EXT_ARGV="$opt"
325 fi
326 continue
327 fi
328
329 if [ "$next_opt_is_val" ]; then
330 next_opt_is_val=""
331 if [ $# -eq 0 ] || [ $(expr "$opt" : "-") -eq 1 ]; then
332 option_error "$real_opt requires a $required_arg argument"
333 continue
334 fi
335 val="$opt"
336 opt_is_ok=1
337 else
338 if [ $(expr "$opt" : "-") -eq 0 ]; then
339 if [ -z "$ARGV" ]; then
340 ARGV="$opt"
341 else
342 ARGV="$ARGV $opt"
343 fi
344 continue
345 fi
346
347 real_opt="$opt"
348
349 if $(echo $opt | grep '^--no-' >/dev/null); then
350 opt_is_negated=1
351 opt=$(echo $opt | sed 's/^--no-//')
352 else
353 opt_is_negated=""
354 opt=$(echo $opt | sed 's/^-*//')
355 fi
356
357 if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
358 val="$(echo $opt | awk -F= '{print $2}')"
359 opt="$(echo $opt | awk -F= '{print $1}')"
360 fi
361
362 if [ -f "$TMPDIR/po/$opt" ]; then
363 spec="$TMPDIR/po/$opt"
364 else
365 spec=$(grep "^short form:-$opt\$" "$TMPDIR"/po/* | cut -d ':' -f 1)
366 if [ -z "$spec" ]; then
367 option_error "Unknown option: $real_opt"
368 continue
369 fi
370 fi
371
372 required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}')
373 if [ "$required_arg" ]; then
374 if [ "$val" ]; then
375 opt_is_ok=1
376 else
377 next_opt_is_val=1
378 fi
379 else
380 if [ "$val" ]; then
381 option_error "Option $real_opt does not take a value"
382 continue
383 fi
384 if [ "$opt_is_negated" ]; then
385 val=""
386 else
387 val="yes"
388 fi
389 opt_is_ok=1
390 fi
391 fi
392
393 if [ "$opt_is_ok" ]; then
394 opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr [:lower:] [:upper:])
395
396 if grep "^type:size" "$spec" >/dev/null; then
397 val=$(size_to_bytes $val)
398 fi
399
400 eval "OPT_$opt"="'$val'"
401
402 opt=""
403 val=""
404 next_opt_is_val=""
405 opt_is_ok=""
406 opt_is_negated=""
407 real_opt=""
408 required_arg=""
409 spec=""
410 fi
411 done
412}
413
414size_to_bytes() {
415 local size="$1"
416 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")};'
417}
418
419# ###########################################################################
420# End parse_options package
421# ###########################################################################
15422
16# ###########################################################################423# ###########################################################################
17# tmpdir package424# tmpdir package
@@ -22,18 +429,21 @@
22# See https://launchpad.net/percona-toolkit for more information.429# See https://launchpad.net/percona-toolkit for more information.
23# ###########################################################################430# ###########################################################################
24431
432
433set -u
434
25TMPDIR=""435TMPDIR=""
26436
27mk_tmpdir() {437mk_tmpdir() {
28 local dir=${1:-""}438 local dir="${1:-""}"
29439
30 if [ -n "$dir" ]; then440 if [ -n "$dir" ]; then
31 if [ ! -d "$dir" ]; then441 if [ ! -d "$dir" ]; then
32 mkdir $dir || die "Cannot make tmpdir $dir"442 mkdir "$dir" || die "Cannot make tmpdir $dir"
33 fi443 fi
34 TMPDIR="$dir"444 TMPDIR="$dir"
35 else445 else
36 local tool=`basename $0`446 local tool="${0##*/}"
37 local pid="$$"447 local pid="$$"
38 TMPDIR=`mktemp -d /tmp/${tool}.${pid}.XXXXX` \448 TMPDIR=`mktemp -d /tmp/${tool}.${pid}.XXXXX` \
39 || die "Cannot make secure tmpdir"449 || die "Cannot make secure tmpdir"
@@ -42,7 +452,7 @@
42452
43rm_tmpdir() {453rm_tmpdir() {
44 if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then454 if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then
45 rm -rf $TMPDIR455 rm -rf "$TMPDIR"
46 fi456 fi
47 TMPDIR=""457 TMPDIR=""
48}458}
@@ -51,27 +461,68 @@
51# End tmpdir package461# End tmpdir package
52# ###########################################################################462# ###########################################################################
53463
54# ########################################################################464# ###########################################################################
55# Some global setup is necessary for cross-platform compatibility, even465# alt_cmds package
56# when sourcing this script for testing purposes.466# This package is a copy without comments from the original. The original
57# ########################################################################467# with comments and its test file can be found in the Bazaar repository at,
58AP_AWK="$(which awk)"468# lib/bash/alt_cmds.sh
59which gawk >/dev/null 2>&1 && AP_AWK="$(which gawk)"469# t/lib/bash/alt_cmds.sh
60AP_SED="$(which sed)"470# See https://launchpad.net/percona-toolkit for more information.
61which gsed >/dev/null 2>&1 && AP_SED="$(which gsed)"471# ###########################################################################
62AP_GREP="$(which grep)"472
63which ggrep >/dev/null 2>&1 && AP_GREP="$(which ggrep)"473
64474set -u
65# ########################################################################475
66# Globals, helper functions476_seq() {
67# ########################################################################477 local i="$1"
68478 awk "BEGIN { for(i=1; i<=$i; i++) print i; }"
69# The awk code for fuzzy rounding. (It's used in a few places, so makes sense479}
70# not to duplicate). It fuzzy-rounds the variable named fuzzy_var. It goes in480
71# steps of 5, 10, 25, then repeats by a factor of 10 larger (50, 100, 250), and481_pidof() {
72# so on, until it finds a number that's large enough. The pattern is slightly482 local cmd="$1"
73# broken between the initial 1 and 50, because rounding to the nearest 2.5483 if ! pidof "$cmd" 2>/dev/null; then
74# doesn't seem right to me.484 ps -eo pid,ucomm | awk -v comm="$cmd" '$2 == comm { print $1 }'
485 fi
486}
487
488_lsof() {
489 local pid="$1"
490 if ! lsof -p $pid 2>/dev/null; then
491 /bin/ls -l /proc/$pid/fd 2>/dev/null
492 fi
493}
494
495
496
497_which() {
498 if [ -x /usr/bin/which ]; then
499 /usr/bin/which "$1" 2>/dev/null | awk '{print $1}'
500 elif which which 1>/dev/null 2>&1; then
501 which "$1" 2>/dev/null | awk '{print $1}'
502 else
503 echo "$1"
504 fi
505}
506
507# ###########################################################################
508# End alt_cmds package
509# ###########################################################################
510
511# ###########################################################################
512# report_formatting package
513# This package is a copy without comments from the original. The original
514# with comments and its test file can be found in the Bazaar repository at,
515# lib/bash/report_formatting.sh
516# t/lib/bash/report_formatting.sh
517# See https://launchpad.net/percona-toolkit for more information.
518# ###########################################################################
519
520
521set -u
522
523POSIXLY_CORRECT=1
524export POSIXLY_CORRECT
525
75fuzzy_formula='526fuzzy_formula='
76 rounded = 0;527 rounded = 0;
77 if (fuzzy_var <= 10 ) {528 if (fuzzy_var <= 10 ) {
@@ -94,108 +545,461 @@
94 factor = factor * 10;545 factor = factor * 10;
95 }'546 }'
96547
97# The temp files are for storing working results so we don't call commands many548fuzz () {
98# times (gives inconsistent results, maybe adds load on things I don't want to549 awk -v fuzzy_var="$1" "BEGIN { ${fuzzy_formula} print fuzzy_var;}"
99# such as RAID controllers). They must not exist -- if they did, someone would550}
100# symlink them to /etc/passwd and then run this program as root. Call this551
101# function with "rm" or "touch" as an argument.552fuzzy_pct () {
102temp_files() {553 local pct="$(awk -v one="$1" -v two="$2" 'BEGIN{ if (two > 0) { printf "%d", one/two*100; } else {print 0} }')";
103 for file in $TMPDIR/percona-toolkit{,-mysql-variables,-mysql-status,-innodb-status} \554 echo "$(fuzz "${pct}")%"
104 $TMPDIR/percona-toolkit{2,-mysql-databases,-mysql-processlist,-noncounters} \555}
105 $TMPDIR/percona-toolkit-mysql{dump,-slave};556
106 do
107 case "$1" in
108 touch)
109 if ! touch "${file}"; then
110 echo "I can't make my temp file ${file}";
111 exit 1;
112 fi
113 ;;
114 rm)
115 rm -f "${file}"
116 ;;
117 esac
118 done
119}
120
121# Print a space-padded string into $line. Then translate spaces to hashes, and
122# underscores to spaces. End result is a line of hashes with words at the
123# start.
124section () {557section () {
125 line="$(printf '#_%-60s' "$1_")"558 local str="$1"
126 line="${line// /#}"559 awk -v var="${str} _" 'BEGIN {
127 printf "%s\n" "${line//_/ }"560 line = sprintf("# %-60s", var);
128}561 i = index(line, "_");
129562 x = substr(line, i);
130# Print a "name | value" line.563 gsub(/[_ \t]/, "#", x);
131name_val() {564 printf("%s%s\n", substr(line, 1, i-1), x);
132 printf "%20s | %s\n" "$1" "$2"565 }'
133}566}
134567
135# Converts a value to units of power of 2. Optional precision is $2.568NAME_VAL_LEN=12
569name_val () {
570 printf "%+*s | %s\n" "${NAME_VAL_LEN}" "$1" "$2"
571}
572
136shorten() {573shorten() {
137 unit=k574 local num="$1"
138 size=1024575 local prec="${2:-2}"
139 if [ $1 -ge 1099511627776 ] ; then576 local div="${3:-1024}"
140 size=1099511627776577
141 unit=T578 echo "$num" | awk -v prec="$prec" -v div="$div" '
142 elif [ $1 -ge 1073741824 ] ; then579 {
143 size=1073741824580 size = 4;
144 unit=G581 val = $1;
145 elif [ $1 -ge 1048576 ] ; then582
146 size=1048576583 unit = val >= 1099511627776 ? "T" : val >= 1073741824 ? "G" : val >= 1048576 ? "M" : val >= 1024 ? "k" : "";
147 unit=M584
148 fi585 while ( int(val) && !(val % 1024) ) {
149 result=$(echo "$1 $size ${2:-0}" | $AP_AWK '{printf "%." $3 "f", $1 / $2}')586 val /= 1024;
150 echo "${result}${unit}"587 }
588
589 while ( val > 1000 ) {
590 val /= div;
591 }
592
593 printf "%.*f%s", prec, val, unit;
594 }
595 '
151}596}
152597
153# Collapse a file into an aggregated list; file must be created with 'sort |
154# uniq -c'. This function is copy-pasted from 'summary' so see there for full
155# docs and tests.
156# ##############################################################################
157group_concat () {598group_concat () {
158 sed -e '{H; $!d}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' ${1}599 sed -e '{H; $!d;}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' "${1}"
159}600}
160601
161# Accepts a number of seconds, and outputs a d+h:m:s formatted string602# ###########################################################################
603# End report_formatting package
604# ###########################################################################
605
606# ###########################################################################
607# summary_common package
608# This package is a copy without comments from the original. The original
609# with comments and its test file can be found in the Bazaar repository at,
610# lib/bash/summary_common.sh
611# t/lib/bash/summary_common.sh
612# See https://launchpad.net/percona-toolkit for more information.
613# ###########################################################################
614
615
616set -u
617
618CMD_FILE="$( _which file 2>/dev/null )"
619CMD_NM="$( _which nm 2>/dev/null )"
620CMD_OBJDUMP="$( _which objdump 2>/dev/null )"
621
622get_nice_of_pid () {
623 local pid="$1"
624 local niceness="$(ps -p $pid -o nice | awk '$1 !~ /[^0-9]/ {print $1; exit}')"
625
626 if [ -n "${niceness}" ]; then
627 echo $niceness
628 else
629 local tmpfile="$TMPDIR/nice_through_c.tmp.c"
630 _d "Getting the niceness from ps failed, somehow. We are about to try this:"
631 cat <<EOC > "$tmpfile"
632
633int main(void) {
634 int priority = getpriority(PRIO_PROCESS, $pid);
635 if ( priority == -1 && errno == ESRCH ) {
636 return 1;
637 }
638 else {
639 printf("%d\\n", priority);
640 return 0;
641 }
642}
643
644EOC
645 local c_comp=$(_which gcc)
646 if [ -z "${c_comp}" ]; then
647 c_comp=$(_which cc)
648 fi
649 _d "$tmpfile: $( cat "$tmpfile" )"
650 _d "$c_comp -xc \"$tmpfile\" -o \"$tmpfile\" && eval \"$tmpfile\""
651 $c_comp -xc "$tmpfile" -o "$tmpfile" 2>/dev/null && eval "$tmpfile" 2>/dev/null
652 if [ $? -ne 0 ]; then
653 echo "?"
654 _d "Failed to get a niceness value for $pid"
655 fi
656 fi
657}
658
659get_oom_of_pid () {
660 local pid="$1"
661 local oom_adj=""
662
663 if [ -n "${pid}" -a -e /proc/cpuinfo ]; then
664 if [ -s "/proc/$pid/oom_score_adj" ]; then
665 oom_adj=$(cat "/proc/$pid/oom_score_adj" 2>/dev/null)
666 _d "For $pid, the oom value is $oom_adj, retreived from oom_score_adj"
667 else
668 oom_adj=$(cat "/proc/$pid/oom_adj" 2>/dev/null)
669 _d "For $pid, the oom value is $oom_adj, retreived from oom_adj"
670 fi
671 fi
672
673 if [ -n "${oom_adj}" ]; then
674 echo "${oom_adj}"
675 else
676 echo "?"
677 _d "Can't find the oom value for $pid"
678 fi
679}
680
681has_symbols () {
682 local executable="$(_which "$1")"
683 local has_symbols=""
684
685 if [ "${CMD_FILE}" ] \
686 && [ "$($CMD_FILE "${executable}" | grep 'not stripped' )" ]; then
687 has_symbols=1
688 elif [ "${CMD_NM}" ] \
689 || [ "${CMD_OBJDMP}" ]; then
690 if [ "${CMD_NM}" ] \
691 && [ !"$("${CMD_NM}" -- "${executable}" 2>&1 | grep 'File format not recognized' )" ]; then
692 if [ -z "$( $CMD_NM -- "${executable}" 2>&1 | grep ': no symbols' )" ]; then
693 has_symbols=1
694 fi
695 elif [ -z "$("${CMD_OBJDUMP}" -t -- "${executable}" | grep '^no symbols$' )" ]; then
696 has_symbols=1
697 fi
698 fi
699
700 if [ "${has_symbols}" ]; then
701 echo "Yes"
702 else
703 echo "No"
704 fi
705}
706
707setup_data_dir () {
708 local existing_dir="$1"
709 local data_dir=""
710 if [ -z "$existing_dir" ]; then
711 mkdir "$TMPDIR/data" || die "Cannot mkdir $TMPDIR/data"
712 data_dir="$TMPDIR/data"
713 else
714 if [ ! -d "$existing_dir" ]; then
715 mkdir "$existing_dir" || die "Cannot mkdir $existing_dir"
716 elif [ "$( ls -A "$existing_dir" )" ]; then
717 die "--save-samples directory isn't empty, halting."
718 fi
719 touch "$existing_dir/test" || die "Cannot write to $existing_dir"
720 rm "$existing_dir/test" || die "Cannot rm $existing_dir/test"
721 data_dir="$existing_dir"
722 fi
723 echo "$data_dir"
724}
725
726get_var () {
727 local varname="$1"
728 local file="$2"
729 awk -v pattern="${varname}" '$1 == pattern { if (length($2)) { len = length($1); print substr($0, len+index(substr($0, len+1), $2)) } }' "${file}"
730}
731
732# ###########################################################################
733# End summary_common package
734# ###########################################################################
735
736# ###########################################################################
737# collect_mysql_info package
738# This package is a copy without comments from the original. The original
739# with comments and its test file can be found in the Bazaar repository at,
740# lib/bash/collect_mysql_info.sh
741# t/lib/bash/collect_mysql_info.sh
742# See https://launchpad.net/percona-toolkit for more information.
743# ###########################################################################
744
745
746
747CMD_MYSQL="${CMD_MYSQL:-""}"
748CMD_MYSQLDUMP="${CMD_MYSQLDUMP:-""}"
749
750collect_mysqld_instances () {
751 local variables_file="$1"
752
753 local pids="$(_pidof mysqld)"
754
755 if [ -n "$pids" ]; then
756
757 for pid in $pids; do
758 local nice="$( get_nice_of_pid $pid )"
759 local oom="$( get_oom_of_pid $pid )"
760 echo "internal::nice_of_$pid $nice" >> "$variables_file"
761 echo "internal::oom_of_$pid $oom" >> "$variables_file"
762 done
763
764 pids="$(echo $pids | sed -e 's/ /,/g')"
765 ps ww -p "$pids" 2>/dev/null
766 else
767 echo "mysqld doesn't appear to be running"
768 fi
769
770}
771
772find_my_cnf_file() {
773 local file="$1"
774 local port="${2:-""}"
775
776 local cnf_file=""
777 if test -n "$port" && grep -- "/mysqld.*--port=$port" "${file}" >/dev/null 2>&1 ; then
778 cnf_file="$(grep -- "/mysqld.*--port=$port" "${file}" \
779 | awk 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
780 | head -n1)"
781 else
782 cnf_file="$(grep '/mysqld' "${file}" \
783 | awk 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
784 | head -n1)"
785 fi
786
787 if [ ! -n "${cnf_file}" ]; then
788 cnf_file="/etc/my.cnf";
789 if [ ! -e "${cnf_file}" ]; then
790 cnf_file="/etc/mysql/my.cnf";
791 fi
792 if [ ! -e "${cnf_file}" ]; then
793 cnf_file="/var/db/mysql/my.cnf";
794 fi
795 fi
796
797 echo "$cnf_file"
798}
799
800collect_mysql_variables () {
801 $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW /*!40100 GLOBAL*/ VARIABLES'
802}
803
804collect_mysql_status () {
805 $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW /*!50000 GLOBAL*/ STATUS'
806}
807
808collect_mysql_databases () {
809 $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW DATABASES' 2>/dev/null
810}
811
812collect_mysql_plugins () {
813 $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW PLUGINS' 2>/dev/null
814}
815
816collect_mysql_slave_status () {
817 $CMD_MYSQL $EXT_ARGV -ssE -e 'SHOW SLAVE STATUS' 2>/dev/null
818}
819
820collect_mysql_innodb_status () {
821 $CMD_MYSQL $EXT_ARGV -ssE -e 'SHOW /*!50000 ENGINE*/ INNODB STATUS' 2>/dev/null
822}
823
824collect_mysql_processlist () {
825 $CMD_MYSQL $EXT_ARGV -ssE -e 'SHOW FULL PROCESSLIST' 2>/dev/null
826}
827
828collect_mysql_users () {
829 $CMD_MYSQL $EXT_ARGV -ss -e 'SELECT COUNT(*), SUM(user=""), SUM(password=""), SUM(password NOT LIKE "*%") FROM mysql.user' 2>/dev/null
830}
831
832collect_master_logs_status () {
833 local master_logs_file="$1"
834 local master_status_file="$2"
835 $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW MASTER LOGS' > "$master_logs_file" 2>/dev/null
836 $CMD_MYSQL $EXT_ARGV -ss -e 'SHOW MASTER STATUS' > "$master_status_file" 2>/dev/null
837}
838
839collect_mysql_deferred_status () {
840 local status_file="$1"
841 collect_mysql_status > "$TMPDIR/defer_gatherer"
842 join "$status_file" "$TMPDIR/defer_gatherer"
843}
844
845collect_internal_vars () {
846 local mysqld_executables="${1:-""}"
847
848 local FNV_64=""
849 if $CMD_MYSQL $EXT_ARGV -e 'SELECT FNV_64("a")' >/dev/null 2>&1; then
850 FNV_64="Enabled";
851 else
852 FNV_64="Unknown";
853 fi
854
855 local now="$($CMD_MYSQL $EXT_ARGV -ss -e 'SELECT NOW()')"
856 local user="$($CMD_MYSQL $EXT_ARGV -ss -e 'SELECT CURRENT_USER()')"
857 local trigger_count=$($CMD_MYSQL $EXT_ARGV -ss -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TRIGGERS" 2>/dev/null)
858
859 echo "pt-summary-internal-mysql_executable $CMD_MYSQL"
860 echo "pt-summary-internal-now $now"
861 echo "pt-summary-internal-user $user"
862 echo "pt-summary-internal-FNV_64 $FNV_64"
863 echo "pt-summary-internal-trigger_count $trigger_count"
864
865 if [ -e "$mysqld_executables" ]; then
866 local i=1
867 while read executable; do
868 echo "pt-summary-internal-mysqld_executable_${i} $(has_symbols "$executable")"
869 i=$(($i + 1))
870 done < "$mysqld_executables"
871 fi
872}
873
874get_mysqldump_for () {
875 local args="$1"
876 local dbtodump="${2:-"--all-databases"}"
877
878 $CMD_MYSQLDUMP $EXT_ARGV --no-data --skip-comments \
879 --skip-add-locks --skip-add-drop-table --compact \
880 --skip-lock-all-tables --skip-lock-tables --skip-set-charset \
881 ${args} --databases $( local IFS=,; echo ${dbtodump})
882}
883
884get_mysqldump_args () {
885 local file="$1"
886 local trg_arg=""
887
888 if $CMD_MYSQLDUMP --help --verbose 2>&1 | grep triggers >/dev/null; then
889 trg_arg="--routines"
890 fi
891
892 if [ "${trg_arg}" ]; then
893 local triggers="--skip-triggers"
894 local trg=$(get_var "pt-summary-internal-trigger_count" "$file" )
895 if [ -n "${trg}" ] && [ "${trg}" -gt 0 ]; then
896 triggers="--triggers"
897 fi
898 trg_arg="${trg_arg} ${triggers}";
899 fi
900 echo "${trg_arg}"
901}
902
903collect_mysqld_executables () {
904 local mysqld_instances="$1"
905
906 for pid in $( grep '/mysqld' "$mysqld_instances" | awk '/^ .*[0-9]/{print $1}' ); do
907 ps -o cmd -p $pid | sed -e 's/^\(.*mysqld\) .*/\1/' | grep -v '^CMD$'
908 done | sort -u
909}
910
911collect_mysql_info () {
912 local dir="$1"
913
914 collect_mysql_variables > "$dir/mysql-variables"
915 collect_mysql_status > "$dir/mysql-status"
916 collect_mysql_databases > "$dir/mysql-databases"
917 collect_mysql_plugins > "$dir/mysql-plugins"
918 collect_mysql_slave_status > "$dir/mysql-slave"
919 collect_mysql_innodb_status > "$dir/innodb-status"
920 collect_mysql_processlist > "$dir/mysql-processlist"
921 collect_mysql_users > "$dir/mysql-users"
922
923 collect_mysqld_instances "$dir/mysql-variables" > "$dir/mysqld-instances"
924 collect_mysqld_executables "$dir/mysqld-instances" > "$dir/mysqld-executables"
925
926 local binlog="$(get_var log_bin "$dir/mysql-variables")"
927 if [ "${binlog}" ]; then
928 collect_master_logs_status "$dir/mysql-master-logs" "$dir/mysql-master-status"
929 fi
930
931 local uptime="$(get_var Uptime "$dir/mysql-status")"
932 local current_time="$($CMD_MYSQL $EXT_ARGV -ss -e \
933 "SELECT LEFT(NOW() - INTERVAL ${uptime} SECOND, 16)")"
934
935 local port="$(get_var port "$dir/mysql-variables")"
936 local cnf_file="$(find_my_cnf_file "$dir/mysqld-instances" ${port})"
937
938 cat "$cnf_file" > "$dir/mysql-config-file"
939
940 local pid_file="$(get_var "pid_file" "$dir/mysql-variables")"
941 local pid_file_exists=""
942 [ -e "${pid_file}" ] && pid_file_exists=1
943 echo "pt-summary-internal-pid_file_exists $pid_file_exists" >> "$dir/mysql-variables"
944
945 echo "pt-summary-internal-current_time $current_time" >> "$dir/mysql-variables"
946 echo "pt-summary-internal-Config_File_path $cnf_file" >> "$dir/mysql-variables"
947 collect_internal_vars "$dir/mysqld-executables" >> "$dir/mysql-variables"
948
949 if [ -n "${OPT_DATABASES}" ]; then
950 local trg_arg="$( get_mysqldump_args "$dir/mysql-variables" )"
951 get_mysqldump_for "${trg_arg}" "${OPT_DATABASES}" > "$dir/mysqldump"
952 fi
953
954 (
955 sleep $OPT_SLEEP
956 collect_mysql_deferred_status "$dir/mysql-status" > "$dir/mysql-status-defer"
957 ) &
958 _d "Forked child is $!"
959}
960
961# ###########################################################################
962# End collect_mysql_info package
963# ###########################################################################
964
965# ###########################################################################
966# report_mysql_info package
967# This package is a copy without comments from the original. The original
968# with comments and its test file can be found in the Bazaar repository at,
969# lib/bash/report_mysql_info.sh
970# t/lib/bash/report_mysql_info.sh
971# See https://launchpad.net/percona-toolkit for more information.
972# ###########################################################################
973
974
975set -u
976POSIXLY_CORRECT=1
977
162secs_to_time () {978secs_to_time () {
163 echo "$1" | $AP_AWK '{979 awk -v sec="$1" 'BEGIN {
164 printf( "%d+%02d:%02d:%02d", $1 / 86400, ($1 % 86400) / 3600, ($1 % 3600) / 60, $1 % 60);980 printf( "%d+%02d:%02d:%02d", sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
165 }'981 }'
166}982}
167983
168# gets a value from $TMPDIR/percona-toolkit-mysql-variables. Returns zero if it doesn't
169# exist.
170get_var () {
171 v="$($AP_AWK "\$1 ~ /^$1$/ { print \$2 }" $TMPDIR/percona-toolkit-mysql-variables)"
172 echo "${v:-0}"
173}
174
175# Returns true if a variable exists
176var_exists () {
177 $AP_GREP "$1" $TMPDIR/percona-toolkit-mysql-variables >/dev/null 2>&1;
178}
179
180# Returns "Enabled", "Disabled", or "Not Supported" depending on whether the
181# variable exists and is ON or enabled. You can pass 2nd and 3rd variables to
182# control whether the variable should be 'gt' (numeric greater than) or 'eq'
183# (string equal) to some value.
184feat_on() {984feat_on() {
185 if var_exists $1 ; then985 local file="$1"
186 var="$($AP_AWK "\$1 ~ /^$1$/ { print \$2 }" $TMPDIR/percona-toolkit-mysql-variables)"986 local varname="$2"
987 [ -e "$file" ] || return
988
989 if [ "$( get_var "$varname" "${file}" )" ]; then
990 local var="$(awk "\$1 ~ /^$2$/ { print \$2 }" $file)"
187 if [ "${var}" = "ON" ]; then991 if [ "${var}" = "ON" ]; then
188 echo "Enabled"992 echo "Enabled"
189 elif [ "${var}" = "OFF" -o "${var}" = "0" -o -z "${var}" ]; then993 elif [ "${var}" = "OFF" -o "${var}" = "0" -o -z "${var}" ]; then
190 echo "Disabled"994 echo "Disabled"
191 elif [ "$2" = "ne" ]; then995 elif [ "$3" = "ne" ]; then
192 if [ "${var}" != "$3" ]; then996 if [ "${var}" != "$4" ]; then
193 echo "Enabled"997 echo "Enabled"
194 else998 else
195 echo "Disabled"999 echo "Disabled"
196 fi1000 fi
197 elif [ "$2" = "gt" ]; then1001 elif [ "$3" = "gt" ]; then
198 if [ "${var}" -gt "$3" ]; then1002 if [ "${var}" -gt "$4" ]; then
199 echo "Enabled"1003 echo "Enabled"
200 else1004 else
201 echo "Disabled"1005 echo "Disabled"
@@ -210,128 +1014,124 @@
210 fi1014 fi
211}1015}
2121016
213# gets a value from $TMPDIR/percona-toolkit-mysql-status. Returns zero if it doesn't1017get_table_cache () {
214# exist.1018 local file="$1"
215get_stat () {1019
216 v="$($AP_AWK "\$1 ~ /^$1$/ { print \$2 }" $TMPDIR/percona-toolkit-mysql-status)"1020 [ -e "$file" ] || return
217 echo "${v:-0}"1021
218}1022 local table_cache=""
2191023 if [ "$( get_var table_open_cache "${file}" )" ]; then
220# Does fuzzy rounding: rounds to nearest interval, but the interval gets larger1024 table_cache="$(get_var table_open_cache "${file}")"
221# as the number gets larger. This is to make things easier to diff.1025 else
222fuzz () {1026 table_cache="$(get_var table_cache "${file}")"
223 echo $1 | $AP_AWK "{fuzzy_var=\$1; ${fuzzy_formula} print fuzzy_var;}"1027 fi
224}1028 echo ${table_cache:-0}
2251029}
226# Fuzzy computes the percent that $1 is of $21030
227fuzzy_pct () {1031get_plugin_status () {
228 pct=$(echo $1 $2 | $AP_AWK '{ if ($2 > 0) { printf "%d", $1/$2*100; } else {print 0} }');1032 local file="$1"
229 echo "$(fuzz ${pct})%"1033 local plugin="$2"
230}1034
2311035 local status="$(grep -w "$plugin" "$file" | awk '{ print $2 }')"
232# ##############################################################################1036
233# Functions for parsing specific files and getting desired info from them.1037 echo ${status:-"Not found"}
234# These are called from within main() and are separated so they can be tested1038}
235# easily. The calling convention is that the data they need to run is prepared1039
236# first by putting it into $TMPDIR/percona-toolkit. Then code that's testing1040
237# just needs to put sample data into $TMPDIR/percona-toolkit and call it.1041_NO_FALSE_NEGATIVES=""
238# ##############################################################################
239
240# Parses the output of 'ps -e -o args | $AP_GREP mysqld' or 'ps auxww...'
241# which should be in $TMPDIR/percona-toolkit.
242parse_mysqld_instances () {1042parse_mysqld_instances () {
243 local file=$11043 local file="$1"
1044 local variables_file="$2"
1045
244 local socket=${socket:-""}1046 local socket=${socket:-""}
245 local port=${port:-""}1047 local port=${port:-""}
246 local datadir=${datadir:-""}1048 local datadir="${datadir:-""}"
247 echo " Port Data Directory Socket"1049
248 echo " ===== ========================== ======"1050 [ -e "$file" ] || return
249 $AP_GREP '/mysqld ' $file | while read line; do1051
1052 echo " Port Data Directory Nice OOM Socket"
1053 echo " ===== ========================== ==== === ======"
1054
1055 grep '/mysqld ' "$file" | while read line; do
1056 local pid=$(echo "$line" | awk '{print $1;}')
250 for word in ${line}; do1057 for word in ${line}; do
251 # Some grep doesn't have -o, so I have to pull out the words I want by1058 if echo "${word}" | grep -- "--socket=" > /dev/null; then
252 # looking at each word
253 if echo "${word}" | $AP_GREP -- "--socket=" > /dev/null; then
254 socket="$(echo "${word}" | cut -d= -f2)"1059 socket="$(echo "${word}" | cut -d= -f2)"
255 fi1060 fi
256 if echo "${word}" | $AP_GREP -- "--port=" > /dev/null; then1061 if echo "${word}" | grep -- "--port=" > /dev/null; then
257 port="$(echo "${word}" | cut -d= -f2)"1062 port="$(echo "${word}" | cut -d= -f2)"
258 fi1063 fi
259 if echo "${word}" | $AP_GREP -- "--datadir=" > /dev/null; then1064 if echo "${word}" | grep -- "--datadir=" > /dev/null; then
260 datadir="$(echo "${word}" | cut -d= -f2)"1065 datadir="$(echo "${word}" | cut -d= -f2)"
261 fi1066 fi
262 done1067 done
263 printf " %5s %-26s %s\n" "${port}" "${datadir}" "${socket}"1068 local nice="$(get_var "internal::nice_of_$pid" "$variables_file")"
1069 local oom="$(get_var "internal::oom_of_$pid" "$variables_file")"
1070 if [ -n "${_NO_FALSE_NEGATIVES}" ]; then
1071 nice="?"
1072 oom="?"
1073 fi
1074 printf " %5s %-26s %-4s %-3s %s\n" "${port}" "${datadir}" "${nice:-"?"}" "${oom:-"?"}" "${socket}"
264 done1075 done
265}1076}
2661077
267# Tries to find the my.cnf file by examining 'ps' output, which should be in
268# $TMPDIR/percona-toolkit. You have to specify the port for the instance you are
269# interested in, in case there are multiple instances.
270find_my_cnf_file() {
271 local file=$1
272 local port=${2:-""}
273 if test -n "$port" && $AP_GREP -- "/mysqld.*--port=$port" $file >/dev/null 2>&1 ; then
274 $AP_GREP -- "/mysqld.*--port=$port" $file \
275 | $AP_AWK 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
276 | head -n1
277 else
278 $AP_GREP '/mysqld' $file \
279 | $AP_AWK 'BEGIN{RS=" "; FS="=";} $1 ~ /--defaults-file/ { print $2; }' \
280 | head -n1
281 fi
282}
283
284# Gets the MySQL system time. Uses input from $TMPDIR/percona-toolkit-mysql-variables.
285get_mysql_timezone () {1078get_mysql_timezone () {
286 tz="$(get_var time_zone)"1079 local file="$1"
1080
1081 [ -e "$file" ] || return
1082
1083 local tz="$(get_var time_zone "${file}")"
287 if [ "${tz}" = "SYSTEM" ]; then1084 if [ "${tz}" = "SYSTEM" ]; then
288 tz="$(get_var system_time_zone)"1085 tz="$(get_var system_time_zone "${file}")"
289 fi1086 fi
290 echo "${tz}"1087 echo "${tz}"
291}1088}
2921089
293# Gets the MySQL system version. Uses input from $TMPDIR/percona-toolkit-mysql-variables.
294get_mysql_version () {1090get_mysql_version () {
295 name_val Version "$(get_var version) $(get_var version_comment)"1091 local file="$1"
296 name_val "Built On" "$(get_var version_compile_os) $(get_var version_compile_machine)"1092
1093 name_val Version "$(get_var version "${file}") $(get_var version_comment "${file}")"
1094 name_val "Built On" "$(get_var version_compile_os "${file}") $(get_var version_compile_machine "${file}")"
297}1095}
2981096
299# Gets the system start and uptime in human readable format. Last restart date
300# should be in $TMPDIR/percona-toolkit.
301get_mysql_uptime () {1097get_mysql_uptime () {
302 local file=$11098 local uptime="$1"
303 restart="$(cat $file)"1099 local restart="$2"
304 uptime="$(get_stat Uptime)"
305 uptime="$(secs_to_time ${uptime})"1100 uptime="$(secs_to_time ${uptime})"
306 echo "${restart} (up ${uptime})"1101 echo "${restart} (up ${uptime})"
307}1102}
3081103
309# Summarizes the output of SHOW MASTER LOGS, which is in $TMPDIR/percona-toolkit
310summarize_binlogs () {1104summarize_binlogs () {
311 local file=$11105 local file="$1"
312 name_val "Binlogs" $(wc -l $file)1106
313 name_val "Zero-Sized" $($AP_GREP -c '\<0$' $file)1107 [ -e "$file" ] || return
314 size=$($AP_AWK '{t += $2} END{printf "%0.f\n", t}' $file)1108
1109 local size="$(awk '{t += $2} END{printf "%0.f\n", t}' "$file")"
1110 name_val "Binlogs" $(wc -l "$file")
1111 name_val "Zero-Sized" $(grep -c '\<0$' "$file")
315 name_val "Total Size" $(shorten ${size} 1)1112 name_val "Total Size" $(shorten ${size} 1)
316}1113}
3171114
318# Print out binlog_do_db and binlog_ignore_db1115format_users () {
1116 local file="$1"
1117 [ -e "$file" ] || return
1118 awk '{printf "%d users, %d anon, %d w/o pw, %d old pw\n", $1, $2, $3, $4}' "${file}"
1119}
1120
319format_binlog_filters () {1121format_binlog_filters () {
320 local file=$11122 local file="$1"
321 name_val "binlog_do_db" $(cut -f3 $file)1123 [ -e "$file" ] || return
322 name_val "binlog_ignore_db" $(cut -f4 $file)1124 name_val "binlog_do_db" "$(cut -f3 "$file")"
1125 name_val "binlog_ignore_db" "$(cut -f4 "$file")"
323}1126}
3241127
325# Takes as input a file that has two samples of SHOW STATUS, columnized next to
326# each other. These should be in $TMPDIR/percona-toolkit. Outputs fuzzy-ed numbers:
327# absolute, all-time per second, and per-second over the interval between the
328# samples. Omits any rows that are all zeroes.
329format_status_variables () {1128format_status_variables () {
330 local file=$11129 local file="$1"
331 # First, figure out the intervals.1130 [ -e "$file" ] || return
332 utime1=$($AP_AWK '/Uptime /{print $2}' $file);1131
333 utime2=$($AP_AWK '/Uptime /{print $3}' $file);1132 utime1="$(awk '/Uptime /{print $2}' "$file")";
334 ${AP_AWK} "1133 utime2="$(awk '/Uptime /{print $3}' "$file")";
1134 awk "
335 BEGIN {1135 BEGIN {
336 utime1 = ${utime1};1136 utime1 = ${utime1};
337 utime2 = ${utime2};1137 utime2 = ${utime2};
@@ -367,28 +1167,22 @@
367 printf(format, \$1, perday, persec, nowsec);1167 printf(format, \$1, perday, persec, nowsec);
368 }1168 }
369 }1169 }
370 }" $file1170 }" "$file"
371}1171}
3721172
373# Slices the processlist a bunch of different ways. The processlist should be
374# created with the \G flag so it's vertical.
375# The parsing is a bit awkward because different
376# versions of awk have limitations like "too many fields on line xyz". So we
377# use 'cut' to shorten the lines. We count all things into temporary variables
378# for each process in the processlist, and when we hit the Info: line which
379# ought to be the last line in the process, we decide what to do with the temp
380# variables. If we're summarizing Command, we count everything; otherwise, only
381# non-Sleep processes get counted towards the sum and max of Time.
382summarize_processlist () {1173summarize_processlist () {
383 local file=$11174 local file="$1"
1175
1176 [ -e "$file" ] || return
1177
384 for param in Command User Host db State; do1178 for param in Command User Host db State; do
385 echo1179 echo
386 printf ' %-30s %8s %7s %9s %9s\n' \1180 printf ' %-30s %8s %7s %9s %9s\n' \
387 "${param}" "COUNT(*)" Working "SUM(Time)" "MAX(Time)"1181 "${param}" "COUNT(*)" Working "SUM(Time)" "MAX(Time)"
388 echo " ------------------------------" \1182 echo " ------------------------------" \
389 "-------- ------- --------- ---------"1183 "-------- ------- --------- ---------"
390 cut -c1-80 $file \1184 cut -c1-80 "$file" \
391 | $AP_AWK "1185 | awk "
392 \$1 == \"${param}:\" {1186 \$1 == \"${param}:\" {
393 p = substr(\$0, index(\$0, \":\") + 2);1187 p = substr(\$0, index(\$0, \":\") + 2);
394 if ( index(p, \":\") > 0 ) {1188 if ( index(p, \":\") > 0 ) {
@@ -428,22 +1222,21 @@
428 echo1222 echo
429}1223}
4301224
431# Pretty-prints the my.cnf file, which should be in $TMPDIR/percona-toolkit. It's super
432# annoying, but some *modern* versions of awk don't support POSIX character
433# sets in regular expressions, like [[:space:]] (looking at you, Debian). So
434# the below patterns contain [<space><tab>] and must remain that way.
435pretty_print_cnf_file () {1225pretty_print_cnf_file () {
436 local file=$11226 local file="$1"
437 $AP_AWK '1227
1228 [ -e "$file" ] || return
1229
1230 awk '
438 BEGIN {1231 BEGIN {
439 FS="="1232 FS="="
440 }1233 }
441 /^ *[a-zA-Z[]/ {1234 /^[ \t]*[a-zA-Z[]/ {
442 if ($2) {1235 if (length($2)) {
443 gsub(/^[ ]*/, "", $1);1236 gsub(/^[ \t]*/, "", $1);
444 gsub(/^[ ]*/, "", $2);1237 gsub(/^[ \t]*/, "", $2);
445 gsub(/[ ]*$/, "", $1);1238 gsub(/[ \t]*$/, "", $1);
446 gsub(/[ ]*$/, "", $2);1239 gsub(/[ \t]*$/, "", $2);
447 printf("%-35s = %s\n", $1, $2);1240 printf("%-35s = %s\n", $1, $2);
448 }1241 }
449 else if ( $0 ~ /\[/ ) {1242 else if ( $0 ~ /\[/ ) {
@@ -453,11 +1246,12 @@
453 else {1246 else {
454 print $1;1247 print $1;
455 }1248 }
456 }' $file1249 }' "$file"
457}1250}
4581251
459find_checkpoint_age() {1252find_checkpoint_age() {
460 $AP_AWK '1253 local file="$1"
1254 awk '
461 /Log sequence number/{1255 /Log sequence number/{
462 if ( $5 ) {1256 if ( $5 ) {
463 lsn = $5 + ($4 * 4294967296);1257 lsn = $5 + ($4 * 4294967296);
@@ -474,11 +1268,15 @@
474 print lsn - $4;1268 print lsn - $4;
475 }1269 }
476 }1270 }
477 ' "$@"1271 ' "$file"
478}1272}
4791273
480find_pending_io_reads() {1274find_pending_io_reads() {
481 $AP_AWK '1275 local file="$1"
1276
1277 [ -e "$file" ] || return
1278
1279 awk '
482 /Pending normal aio reads/ {1280 /Pending normal aio reads/ {
483 normal_aio_reads = substr($5, 1, index($5, ","));1281 normal_aio_reads = substr($5, 1, index($5, ","));
484 }1282 }
@@ -495,11 +1293,15 @@
495 printf "%d buf pool reads, %d normal AIO", reads, normal_aio_reads;1293 printf "%d buf pool reads, %d normal AIO", reads, normal_aio_reads;
496 printf ", %d ibuf AIO, %d preads", ibuf_aio_reads, preads;1294 printf ", %d ibuf AIO, %d preads", ibuf_aio_reads, preads;
497 }1295 }
498 ' "${1}"1296 ' "${file}"
499}1297}
5001298
501find_pending_io_writes() {1299find_pending_io_writes() {
502 $AP_AWK '1300 local file="$1"
1301
1302 [ -e "$file" ] || return
1303
1304 awk '
503 /aio writes/ {1305 /aio writes/ {
504 aio_writes = substr($NF, 1, index($NF, ","));1306 aio_writes = substr($NF, 1, index($NF, ","));
505 }1307 }
@@ -522,11 +1324,15 @@
522 END {1324 END {
523 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;1325 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;
524 }1326 }
525 ' "${1}"1327 ' "${file}"
526}1328}
5271329
528find_pending_io_flushes() {1330find_pending_io_flushes() {
529 $AP_AWK '1331 local file="$1"
1332
1333 [ -e "$file" ] || return
1334
1335 awk '
530 /Pending flushes/ {1336 /Pending flushes/ {
531 log_flushes = substr($5, 1, index($5, ";"));1337 log_flushes = substr($5, 1, index($5, ";"));
532 buf_pool = $NF;1338 buf_pool = $NF;
@@ -534,13 +1340,17 @@
534 END {1340 END {
535 printf "%d buf pool, %d log", buf_pool, log_flushes;1341 printf "%d buf pool, %d log", buf_pool, log_flushes;
536 }1342 }
537 ' "${1}"1343 ' "${file}"
538}1344}
5391345
540summarize_undo_log_entries() {1346summarize_undo_log_entries() {
541 $AP_GREP 'undo log entries' "$1" \1347 local file="$1"
542 | $AP_SED -e 's/^.*undo log entries \([0-9]*\)/\1/' \1348
543 | $AP_AWK '1349 [ -e "$file" ] || return
1350
1351 grep 'undo log entries' "${file}" \
1352 | sed -e 's/^.*undo log entries \([0-9]*\)/\1/' \
1353 | awk '
544 {1354 {
545 count++;1355 count++;
546 sum += $1;1356 sum += $1;
@@ -554,7 +1364,11 @@
554}1364}
5551365
556find_max_trx_time() {1366find_max_trx_time() {
557 $AP_AWK '1367 local file="$1"
1368
1369 [ -e "$file" ] || return
1370
1371 awk '
558 BEGIN {1372 BEGIN {
559 max = 0;1373 max = 0;
560 }1374 }
@@ -570,59 +1384,69 @@
570 }1384 }
571 END {1385 END {
572 print max;1386 print max;
573 }' "$@"1387 }' "${file}"
574}1388}
5751389
576# Summarizes various things about InnoDB status that are not easy to see by eye.1390find_transation_states () {
1391 local file="$1"
1392 local tmpfile="$TMPDIR/find_transation_states.tmp"
1393
1394 [ -e "$file" ] || return
1395
1396 awk -F, '/^---TRANSACTION/{print $2}' "${file}" \
1397 | sed -e 's/ [0-9]* sec.*//' \
1398 | sort \
1399 | uniq -c > "${tmpfile}"
1400 group_concat "${tmpfile}"
1401}
1402
577format_innodb_status () {1403format_innodb_status () {
578 local file=$11404 local file=$1
579 name_val "Checkpoint Age" $(shorten $(find_checkpoint_age "${file}"))1405
1406 [ -e "$file" ] || return
1407
1408 name_val "Checkpoint Age" "$(shorten $(find_checkpoint_age "${file}") 0)"
580 name_val "InnoDB Queue" "$(awk '/queries inside/{print}' "${file}")"1409 name_val "InnoDB Queue" "$(awk '/queries inside/{print}' "${file}")"
581 name_val "Oldest Transaction" "$(find_max_trx_time "${file}") Seconds";1410 name_val "Oldest Transaction" "$(find_max_trx_time "${file}") Seconds";
582 name_val "History List Len" $(awk '/History list length/{print $4}' "${file}")1411 name_val "History List Len" "$(awk '/History list length/{print $4}' "${file}")"
583 name_val "Read Views" $(awk '/read views open inside/{print $1}' "${file}")1412 name_val "Read Views" "$(awk '/read views open inside/{print $1}' "${file}")"
584 name_val "Undo Log Entries" "$(summarize_undo_log_entries "${file}")"1413 name_val "Undo Log Entries" "$(summarize_undo_log_entries "${file}")"
585 name_val "Pending I/O Reads" "$(find_pending_io_reads "${file}")"1414 name_val "Pending I/O Reads" "$(find_pending_io_reads "${file}")"
586 name_val "Pending I/O Writes" "$(find_pending_io_writes "${file}")"1415 name_val "Pending I/O Writes" "$(find_pending_io_writes "${file}")"
587 name_val "Pending I/O Flushes" "$(find_pending_io_flushes "${file}")"1416 name_val "Pending I/O Flushes" "$(find_pending_io_flushes "${file}")"
588 $AP_AWK -F, '/^---TRANSACTION/{print $2}' "${file}" \1417 name_val "Transaction States" "$(find_transation_states "${file}" )"
589 | $AP_SED -e 's/ [0-9]* sec.*//' | sort | uniq -c > $TMPDIR/percona-toolkit21418 if grep 'TABLE LOCK table' "${file}" >/dev/null ; then
590 name_val "Transaction States" "$(group_concat $TMPDIR/percona-toolkit2)"
591 if $AP_GREP 'TABLE LOCK table' "${file}" >/dev/null ; then
592 echo "Tables Locked"1419 echo "Tables Locked"
593 $AP_AWK '/^TABLE LOCK table/{print $4}' "${file}" \1420 awk '/^TABLE LOCK table/{print $4}' "${file}" \
594 | sort | uniq -c | sort -rn1421 | sort | uniq -c | sort -rn
595 fi1422 fi
596 if $AP_GREP 'has waited at' "${file}" > /dev/null ; then1423 if grep 'has waited at' "${file}" > /dev/null ; then
597 echo "Semaphore Waits"1424 echo "Semaphore Waits"
598 $AP_GREP 'has waited at' "${file}" | cut -d' ' -f6-8 \1425 grep 'has waited at' "${file}" | cut -d' ' -f6-8 \
599 | sort | uniq -c | sort -rn1426 | sort | uniq -c | sort -rn
600 fi1427 fi
601 if $AP_GREP 'reserved it in mode' "${file}" > /dev/null; then1428 if grep 'reserved it in mode' "${file}" > /dev/null; then
602 echo "Semaphore Holders"1429 echo "Semaphore Holders"
603 $AP_AWK '/has reserved it in mode/{1430 awk '/has reserved it in mode/{
604 print substr($0, 1 + index($0, "("), index($0, ")") - index($0, "(") - 1);1431 print substr($0, 1 + index($0, "("), index($0, ")") - index($0, "(") - 1);
605 }' "${file}" | sort | uniq -c | sort -rn1432 }' "${file}" | sort | uniq -c | sort -rn
606 fi1433 fi
607 if $AP_GREP -e 'Mutex at' -e 'lock on' "${file}" >/dev/null 2>&1; then1434 if grep -e 'Mutex at' -e 'lock on' "${file}" >/dev/null 2>&1; then
608 echo "Mutexes/Locks Waited For"1435 echo "Mutexes/Locks Waited For"
609 $AP_GREP -e 'Mutex at' -e 'lock on' "${file}" | $AP_SED -e 's/^[XS]-//' -e 's/,.*$//' \1436 grep -e 'Mutex at' -e 'lock on' "${file}" | sed -e 's/^[XS]-//' -e 's/,.*$//' \
610 | sort | uniq -c | sort -rn1437 | sort | uniq -c | sort -rn
611 fi1438 fi
612}1439}
6131440
614# Summarizes per-database statistics for a bunch of different things: count of
615# tables, views, etc. $1 is the file name. $2 is the database name; if none,
616# then there should be multiple databases.
617format_overall_db_stats () {1441format_overall_db_stats () {
618 local file=$11442 local file="$1"
1443 local tmpfile="$TMPDIR/format_overall_db_stats.tmp"
1444
1445 [ -e "$file" ] || return
1446
619 echo1447 echo
620 # We keep counts of everything in an associative array keyed by db name, and1448 awk '
621 # what it is. The num_dbs counter is to ensure sort order is consistent when
622 # we run the awk commands following this one.
623 $AP_AWK '
624 BEGIN {1449 BEGIN {
625 # In case there is no USE statement in the file.
626 db = "{chosen}";1450 db = "{chosen}";
627 num_dbs = 0;1451 num_dbs = 0;
628 }1452 }
@@ -634,7 +1458,6 @@
634 }1458 }
635 }1459 }
636 /^CREATE TABLE/ {1460 /^CREATE TABLE/ {
637 # Handle single-DB dumps, where there is no USE statement.
638 if (num_dbs == 0) {1461 if (num_dbs == 0) {
639 num_dbs = 1;1462 num_dbs = 1;
640 db_seen[db] = 1;1463 db_seen[db] = 1;
@@ -674,15 +1497,13 @@
674 printf fmt, db, counts[db ",tables"], counts[db ",views"], counts[db ",sps"], counts[db ",trg"], counts[db ",func"], counts[db ",fk"], counts[db ",partn"];1497 printf fmt, db, counts[db ",tables"], counts[db ",views"], counts[db ",sps"], counts[db ",trg"], counts[db ",func"], counts[db ",fk"], counts[db ",partn"];
675 }1498 }
676 }1499 }
677 ' $file > $TMPDIR/percona-toolkit1500 ' "$file" > "$tmpfile"
678 head -n2 $TMPDIR/percona-toolkit1501 head -n2 "$tmpfile"
679 tail -n +3 $TMPDIR/percona-toolkit | sort1502 tail -n +3 "$tmpfile" | sort
6801503
681 echo1504 echo
682 # Now do the summary of engines per DB1505 awk '
683 $AP_AWK '
684 BEGIN {1506 BEGIN {
685 # In case there is no USE statement in the file.
686 db = "{chosen}";1507 db = "{chosen}";
687 num_dbs = 0;1508 num_dbs = 0;
688 num_engines = 0;1509 num_engines = 0;
@@ -695,7 +1516,6 @@
695 }1516 }
696 }1517 }
697 /^\) ENGINE=/ {1518 /^\) ENGINE=/ {
698 # Handle single-DB dumps, where there is no USE statement.
699 if (num_dbs == 0) {1519 if (num_dbs == 0) {
700 num_dbs = 1;1520 num_dbs = 1;
701 db_seen[db] = 1;1521 db_seen[db] = 1;
@@ -734,16 +1554,13 @@
734 print "";1554 print "";
735 }1555 }
736 }1556 }
737 ' $file > $TMPDIR/percona-toolkit1557 ' "$file" > "$tmpfile"
738 head -n1 $TMPDIR/percona-toolkit1558 head -n1 "$tmpfile"
739 tail -n +2 $TMPDIR/percona-toolkit | sort1559 tail -n +2 "$tmpfile" | sort
7401560
741 echo1561 echo
742 # Now do the summary of index types per DB. Careful -- index is a reserved1562 awk '
743 # word in awk.
744 $AP_AWK '
745 BEGIN {1563 BEGIN {
746 # In case there is no USE statement in the file.
747 db = "{chosen}";1564 db = "{chosen}";
748 num_dbs = 0;1565 num_dbs = 0;
749 num_idxes = 0;1566 num_idxes = 0;
@@ -756,7 +1573,6 @@
756 }1573 }
757 }1574 }
758 /KEY/ {1575 /KEY/ {
759 # Handle single-DB dumps, where there is no USE statement.
760 if (num_dbs == 0) {1576 if (num_dbs == 0) {
761 num_dbs = 1;1577 num_dbs = 1;
762 db_seen[db] = 1;1578 db_seen[db] = 1;
@@ -807,15 +1623,13 @@
807 print "";1623 print "";
808 }1624 }
809 }1625 }
810 ' $file > $TMPDIR/percona-toolkit1626 ' "$file" > "$tmpfile"
811 head -n1 $TMPDIR/percona-toolkit1627 head -n1 "$tmpfile"
812 tail -n +2 $TMPDIR/percona-toolkit | sort1628 tail -n +2 "$tmpfile" | sort
8131629
814 echo1630 echo
815 # Now do the summary of datatypes per DB1631 awk '
816 $AP_AWK '
817 BEGIN {1632 BEGIN {
818 # In case there is no USE statement in the file.
819 db = "{chosen}";1633 db = "{chosen}";
820 num_dbs = 0;1634 num_dbs = 0;
821 num_types = 0;1635 num_types = 0;
@@ -828,7 +1642,6 @@
828 }1642 }
829 }1643 }
830 /^ `/ {1644 /^ `/ {
831 # Handle single-DB dumps, where there is no USE statement.
832 if (num_dbs == 0) {1645 if (num_dbs == 0) {
833 num_dbs = 1;1646 num_dbs = 1;
834 db_seen[db] = 1;1647 db_seen[db] = 1;
@@ -898,106 +1711,195 @@
898 print "";1711 print "";
899 }1712 }
900 }1713 }
901 ' $file > $TMPDIR/percona-toolkit1714 ' "$file" > "$tmpfile"
902 hdr=$($AP_GREP -n Database $TMPDIR/percona-toolkit | cut -d: -f1);1715 local hdr=$(grep -n Database "$tmpfile" | cut -d: -f1);
903 head -n${hdr} $TMPDIR/percona-toolkit1716 head -n${hdr} "$tmpfile"
904 tail -n +$((${hdr} + 1)) $TMPDIR/percona-toolkit | sort1717 tail -n +$((${hdr} + 1)) "$tmpfile" | sort
905 echo1718 echo
906}1719}
9071720
908# ##############################################################################1721section_percona_server_features () {
909# The main() function is called at the end of the script. This makes it1722 local file="$1"
910# testable. Major bits of parsing are separated into functions for testability.1723
911# ##############################################################################1724 [ -e "$file" ] || return
912main() {1725
9131726 name_val "Table & Index Stats" \
914 # Begin by setting the $PATH to include some common locations that are not1727 "$(feat_on "$file" userstat_running)"
915 # always in the $PATH, including the "sbin" locations. On SunOS systems,1728 name_val "Multiple I/O Threads" \
916 # prefix the path with the location of more sophisticated utilities.1729 "$(feat_on "$file" innodb_read_io_threads gt 1)"
917 export PATH="${PATH}:/usr/local/bin:/usr/bin:/bin:/usr/libexec"1730 name_val "Corruption Resilient" \
918 export PATH="${PATH}:/usr/mysql/bin/:/usr/local/sbin:/usr/sbin:/sbin"1731 "$(feat_on "$file" innodb_pass_corrupt_table)"
919 export PATH="/usr/gnu/bin/:/usr/xpg4/bin/:${PATH}"1732 name_val "Durable Replication" \
9201733 "$(feat_on "$file" innodb_overwrite_relay_log_info)"
921 # Set up temporary files.1734 name_val "Import InnoDB Tables" \
922 mk_tmpdir1735 "$(feat_on "$file" innodb_expand_import)"
923 temp_files "rm"1736 name_val "Fast Server Restarts" \
924 temp_files "touch"1737 "$(feat_on "$file" innodb_auto_lru_dump)"
9251738 name_val "Enhanced Logging" \
926 # ########################################################################1739 "$(feat_on "$file" log_slow_verbosity ne microtime)"
927 # Header for the whole thing, table of discovered instances1740 name_val "Replica Perf Logging" \
928 # ########################################################################1741 "$(feat_on "$file" log_slow_slave_statements)"
929 section Percona_Toolkit_MySQL_Summary_Report1742 name_val "Response Time Hist." \
930 name_val "System time" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"1743 "$(feat_on "$file" enable_query_response_time_stats)"
931 section Instances1744 name_val "Smooth Flushing" \
932 ps auxww 2>/dev/null | $AP_GREP mysqld > $TMPDIR/percona-toolkit1745 "$(feat_on "$file" innodb_adaptive_checkpoint ne none)"
933 parse_mysqld_instances $TMPDIR/percona-toolkit1746 name_val "HandlerSocket NoSQL" \
9341747 "$(feat_on "$file" handlersocket_port)"
935 # ########################################################################1748 name_val "Fast Hash UDFs" \
936 # Fetch some basic info so we can start1749 "$(get_var "pt-summary-internal-FNV_64" "$file")"
937 # ########################################################################1750}
938 mysql "$@" -ss -e 'SELECT CURRENT_USER()' > $TMPDIR/percona-toolkit1751
939 if [ "$?" != "0" ]; then1752section_myisam () {
940 echo "Cannot connect to mysql, please specify command-line options."1753 local variables_file="$1"
941 temp_files "rm"1754 local status_file="$2"
942 rm_tmpdir1755
943 exit 11756 [ -e "$variables_file" -a -e "$status_file" ] || return
944 fi1757
945 user="$(cat $TMPDIR/percona-toolkit)";1758 local buf_size="$(get_var key_buffer_size "$variables_file")"
946 mysql "$@" -ss -e 'SHOW /*!40100 GLOBAL*/ VARIABLES' > $TMPDIR/percona-toolkit-mysql-variables1759 local blk_size="$(get_var key_cache_block_size "$variables_file")"
947 mysql "$@" -ss -e 'SHOW /*!50000 GLOBAL*/ STATUS' > $TMPDIR/percona-toolkit-mysql-status1760 local blk_unus="$(get_var Key_blocks_unused "$status_file")"
948 mysql "$@" -ss -e 'SHOW DATABASES' > $TMPDIR/percona-toolkit-mysql-databases 2>/dev/null1761 local blk_unfl="$(get_var Key_blocks_not_flushed "$variables_file")"
949 mysql "$@" -ssE -e 'SHOW SLAVE STATUS' > $TMPDIR/percona-toolkit-mysql-slave 2>/dev/null1762 local unus=$((${blk_unus:-0} * ${blk_size:-0}))
950 mysql "$@" -ssE -e 'SHOW /*!50000 ENGINE*/ INNODB STATUS' > $TMPDIR/percona-toolkit-innodb-status 2>/dev/null1763 local unfl=$((${blk_unfl:-0} * ${blk_size:-0}))
951 mysql "$@" -ssE -e 'SHOW FULL PROCESSLIST' > $TMPDIR/percona-toolkit-mysql-processlist 2>/dev/null1764 local used=$((${buf_size:-0} - ${unus}))
952 now="$(mysql "$@" -ss -e 'SELECT NOW()')"1765
953 port="$(get_var port)"1766 name_val "Key Cache" "$(shorten ${buf_size} 1)"
9541767 name_val "Pct Used" "$(fuzzy_pct ${used} ${buf_size})"
955 # ########################################################################1768 name_val "Unflushed" "$(fuzzy_pct ${unfl} ${buf_size})"
956 # General date, hostname, etc1769}
957 # ########################################################################1770
958 section "Report_On_Port_${port}"1771section_innodb () {
959 name_val User "${user}"1772 local variables_file="$1"
960 name_val Time "${now} ($(get_mysql_timezone))"1773 local status_file="$2"
961 name_val Hostname "$(get_var hostname)"1774
962 get_mysql_version1775 [ -e "$variables_file" -a -e "$status_file" ] || return
9631776
964 uptime="$(get_stat Uptime)"1777 local version=$(get_var innodb_version "$variables_file")
965 mysql "$@" -ss -e "SELECT LEFT(NOW() - INTERVAL ${uptime} SECOND, 16)" \1778 name_val Version ${version:-default}
966 > $TMPDIR/percona-toolkit1779
967 name_val Started "$(get_mysql_uptime $TMPDIR/percona-toolkit)"1780 local bp_size="$(get_var innodb_buffer_pool_size "$variables_file")"
9681781 name_val "Buffer Pool Size" "$(shorten "${bp_size:-0}" 1)"
969 name_val Databases "$($AP_GREP -c . $TMPDIR/percona-toolkit-mysql-databases)"1782
970 name_val Datadir "$(get_var datadir)"1783 local bp_pags="$(get_var Innodb_buffer_pool_pages_total "$status_file")"
971 procs="$(get_stat Threads_connected)"1784 local bp_free="$(get_var Innodb_buffer_pool_pages_free "$status_file")"
972 procr="$(get_stat Threads_running)"1785 local bp_dirt="$(get_var Innodb_buffer_pool_pages_dirty "$status_file")"
973 name_val Processes "$(fuzz ${procs}) connected, $(fuzz ${procr}) running"1786 local bp_fill=$((${bp_pags} - ${bp_free}))
974 if [ -s $TMPDIR/percona-toolkit-mysql-slave ]; then slave=""; else slave="not "; fi1787 name_val "Buffer Pool Fill" "$(fuzzy_pct ${bp_fill} ${bp_pags})"
975 slavecount=$($AP_GREP -c 'Binlog Dump' $TMPDIR/percona-toolkit-mysql-processlist)1788 name_val "Buffer Pool Dirty" "$(fuzzy_pct ${bp_dirt} ${bp_pags})"
976 name_val Replication "Is ${slave}a slave, has ${slavecount} slaves connected"1789
9771790 name_val "File Per Table" $(get_var innodb_file_per_table "$variables_file")
978 # TODO move this into a section with other files: error log, slow log and1791 name_val "Page Size" $(shorten $(get_var Innodb_page_size "$status_file") 0)
979 # show the sizes1792
980 pid_file="$(get_var pid_file)"1793 local log_size="$(get_var innodb_log_file_size "$variables_file")"
981 [ -e "${pid_file}" ] && PID_EXISTS="(exists)"1794 local log_file="$(get_var innodb_log_files_in_group "$variables_file")"
982 name_val Pidfile "${pid_file} ${PID_EXISTS:-(does not exist)}"1795 local log_total=$(awk "BEGIN {printf \"%.2f\n\", ${log_size}*${log_file}}" )
9831796 name_val "Log File Size" \
984 # ########################################################################1797 "${log_file} * $(shorten ${log_size} 1 1000) = $(shorten ${log_total} 1 1000)"
985 # Processlist, sliced several different ways1798 name_val "Log Buffer Size" \
986 # ########################################################################1799 "$(shorten $(get_var innodb_log_buffer_size "$variables_file") 0)"
987 section Processlist1800 name_val "Flush Method" \
988 summarize_processlist $TMPDIR/percona-toolkit-mysql-processlist1801 "$(get_var innodb_flush_method "$variables_file")"
9891802 name_val "Flush Log At Commit" \
990 # ########################################################################1803 "$(get_var innodb_flush_log_at_trx_commit "$variables_file")"
991 # Queries and query plans1804 name_val "XA Support" \
992 # ########################################################################1805 "$(get_var innodb_support_xa "$variables_file")"
993 section "Status_Counters_(Wait_10_Seconds)"1806 name_val "Checksums" \
994 sleep 101807 "$(get_var innodb_checksums "$variables_file")"
995 # TODO: gather this data in the same format as normal: stats, TS line1808 name_val "Doublewrite" \
996 mysql "$@" -ss -e 'SHOW /*!50000 GLOBAL*/ STATUS' \1809 "$(get_var innodb_doublewrite "$variables_file")"
997 | join $TMPDIR/percona-toolkit-mysql-status - > $TMPDIR/percona-toolkit 1810 name_val "R/W I/O Threads" \
998 # Make a file with a list of things we want to omit because they aren't1811 "$(get_var innodb_read_io_threads "$variables_file") $(get_var innodb_write_io_threads "$variables_file")"
999 # counters, they are gauges (in RRDTool terminology). Gauges are shown1812 name_val "I/O Capacity" \
1000 # elsewhere in the output.1813 "$(get_var innodb_io_capacity "$variables_file")"
1814 name_val "Thread Concurrency" \
1815 "$(get_var innodb_thread_concurrency "$variables_file")"
1816 name_val "Concurrency Tickets" \
1817 "$(get_var innodb_concurrency_tickets "$variables_file")"
1818 name_val "Commit Concurrency" \
1819 "$(get_var innodb_commit_concurrency "$variables_file")"
1820 name_val "Txn Isolation Level" \
1821 "$(get_var tx_isolation "$variables_file")"
1822 name_val "Adaptive Flushing" \
1823 "$(get_var innodb_adaptive_flushing "$variables_file")"
1824 name_val "Adaptive Checkpoint" \
1825 "$(get_var innodb_adaptive_checkpoint "$variables_file")"
1826}
1827
1828
1829section_noteworthy_variables () {
1830 local file="$1"
1831
1832 [ -e "$file" ] || return
1833
1834 name_val "Auto-Inc Incr/Offset" "$(get_var auto_increment_increment "$file")/$(get_var auto_increment_offset "$file")"
1835 for v in \
1836 default_storage_engine flush_time init_connect init_file sql_mode;
1837 do
1838 name_val "${v}" "$(get_var ${v} "$file")"
1839 done
1840 for v in \
1841 join_buffer_size sort_buffer_size read_buffer_size read_rnd_buffer_size \
1842 bulk_insert_buffer max_heap_table_size tmp_table_size \
1843 max_allowed_packet thread_stack;
1844 do
1845 name_val "${v}" "$(shorten $(get_var ${v} "$file") 0)"
1846 done
1847 for v in log log_error log_warnings log_slow_queries \
1848 log_queries_not_using_indexes log_slave_updates;
1849 do
1850 name_val "${v}" "$(get_var ${v} "$file")"
1851 done
1852}
1853
1854_semi_sync_stats_for () {
1855 local target="$1"
1856 local file="$2"
1857
1858 [ -e "$file" ] || return
1859
1860 local semisync_status="$(get_var "Rpl_semi_sync_${target}_status" "${file}" )"
1861 local semisync_trace="$(get_var "rpl_semi_sync_${target}_trace_level" "${file}")"
1862
1863 local trace_extra=""
1864 if [ -n "${semisync_trace}" ]; then
1865 if [ $semisync_trace -eq 1 ]; then
1866 trace_extra="general (for example, time function failures) "
1867 elif [ $semisync_trace -eq 16 ]; then
1868 trace_extra="detail (more verbose information) "
1869 elif [ $semisync_trace -eq 32 ]; then
1870 trace_extra="net wait (more information about network waits)"
1871 elif [ $semisync_trace -eq 64 ]; then
1872 trace_extra="function (information about function entry and exit)"
1873 else
1874 trace_extra="Unknown setting"
1875 fi
1876 fi
1877
1878 name_val "${target} semisync status" "${semisync_status}"
1879 name_val "${target} trace level" "${semisync_trace}, ${trace_extra}"
1880
1881 if [ "${target}" = "master" ]; then
1882 name_val "${target} timeout in milliseconds" \
1883 "$(get_var "rpl_semi_sync_${target}_timeout" "${file}")"
1884 name_val "${target} waits for slaves" \
1885 "$(get_var "rpl_semi_sync_${target}_wait_no_slave" "${file}")"
1886
1887 _d "Prepend Rpl_semi_sync_master_ to the following"
1888 for v in \
1889 clients net_avg_wait_time net_wait_time net_waits \
1890 no_times no_tx timefunc_failures tx_avg_wait_time \
1891 tx_wait_time tx_waits wait_pos_backtraverse \
1892 wait_sessions yes_tx;
1893 do
1894 name_val "${target} ${v}" \
1895 "$( get_var "Rpl_semi_sync_master_${v}" "${file}" )"
1896 done
1897 fi
1898}
1899
1900noncounters_pattern () {
1901 local noncounters_pattern=""
1902
1001 for var in Compression Delayed_insert_threads Innodb_buffer_pool_pages_data \1903 for var in Compression Delayed_insert_threads Innodb_buffer_pool_pages_data \
1002 Innodb_buffer_pool_pages_dirty Innodb_buffer_pool_pages_free \1904 Innodb_buffer_pool_pages_dirty Innodb_buffer_pool_pages_free \
1003 Innodb_buffer_pool_pages_latched Innodb_buffer_pool_pages_misc \1905 Innodb_buffer_pool_pages_latched Innodb_buffer_pool_pages_misc \
@@ -1018,314 +1920,410 @@
1018 Threads_cached Threads_connected Threads_running \1920 Threads_cached Threads_connected Threads_running \
1019 Uptime_since_flush_status;1921 Uptime_since_flush_status;
1020 do1922 do
1021 echo "${var}" >> $TMPDIR/percona-toolkit-noncounters1923 if [ -z "${noncounters_pattern}" ]; then
1022 done1924 noncounters_pattern="${var}"
1023 format_status_variables $TMPDIR/percona-toolkit | $AP_GREP -v -f $TMPDIR/percona-toolkit-noncounters1925 else
10241926 noncounters_pattern="${noncounters_pattern}\|${var}"
1025 # ########################################################################1927 fi
1026 # Table cache1928 done
1027 # ########################################################################1929 echo $noncounters_pattern
1028 section Table_cache1930}
1029 if var_exists table_open_cache; then1931
1030 table_cache=$(get_var table_open_cache)1932section_mysqld () {
1933 local executables_file="$1"
1934 local variables_file="$2"
1935
1936 [ -e "$executables_file" -a -e "$variables_file" ] || return
1937
1938 section "MySQL Executable"
1939 local i=1;
1940 while read executable; do
1941 name_val "Path to executable" "$executable"
1942 name_val "Has symbols" "$( get_var "pt-summary-internal-mysqld_executable_${i}" "$variables_file" )"
1943 i=$(($i + 1))
1944 done < "$executables_file"
1945}
1946
1947section_mysql_files () {
1948 local variables_file="$1"
1949
1950 section "MySQL Files"
1951 for file_name in pid_file slow_query_log_file general_log_file log_error; do
1952 local file="$(get_var "${file_name}" "$variables_file")"
1953 local name_out="$(echo "$file_name" | sed 'y/[a-z]/[A-Z]/')"
1954 if [ -e "${file}" ]; then
1955 name_val "$name_out" "$file"
1956 name_val "${name_out} Size" "$(du "$file" | awk '{print $1}')"
1957 else
1958 name_val "$name_out" "(does not exist)"
1959 fi
1960 done
1961}
1962
1963report_mysql_summary () {
1964 local dir="$1"
1965
1966 local NAME_VAL_LEN=25
1967
1968
1969 section "Percona Toolkit MySQL Summary Report"
1970 name_val "System time" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"
1971 section "Instances"
1972 parse_mysqld_instances "$dir/mysqld-instances" "$dir/mysql-variables"
1973
1974 section_mysqld "$dir/mysqld-executables" "$dir/mysql-variables"
1975
1976 local user="$(get_var "pt-summary-internal-user" "$dir/mysql-variables")"
1977 local port="$(get_var port "$dir/mysql-variables")"
1978 local now="$(get_var "pt-summary-internal-now" "$dir/mysql-variables")"
1979 section "Report On Port ${port}"
1980 name_val User "${user}"
1981 name_val Time "${now} ($(get_mysql_timezone "$dir/mysql-variables"))"
1982 name_val Hostname "$(get_var hostname "$dir/mysql-variables")"
1983 get_mysql_version "$dir/mysql-variables"
1984
1985 local uptime="$(get_var Uptime "$dir/mysql-status")"
1986 local current_time="$(get_var "pt-summary-internal-current_time" "$dir/mysql-variables")"
1987 name_val Started "$(get_mysql_uptime "${uptime}" "${current_time}")"
1988
1989 local num_dbs="$(grep -c . "$dir/mysql-databases")"
1990 name_val Databases "${num_dbs}"
1991 name_val Datadir "$(get_var datadir "$dir/mysql-variables")"
1992
1993 local fuzz_procs=$(fuzz $(get_var Threads_connected "$dir/mysql-status"))
1994 local fuzz_procr=$(fuzz $(get_var Threads_running "$dir/mysql-status"))
1995 name_val Processes "${fuzz_procs} connected, ${fuzz_procr} running"
1996
1997 local slave=""
1998 if [ -s "$dir/mysql-slave" ]; then slave=""; else slave="not "; fi
1999 local slavecount=$(grep -c 'Binlog Dump' "$dir/mysql-processlist")
2000 name_val Replication "Is ${slave}a slave, has ${slavecount} slaves connected"
2001
2002
2003 local pid_file="$(get_var "pid_file" "$dir/mysql-variables")"
2004 local PID_EXISTS=""
2005 if [ "$( get_var "pt-summary-internal-pid_file_exists" "$dir/mysql-variables" )" ]; then
2006 PID_EXISTS="(exists)"
1031 else2007 else
1032 table_cache=$(get_var table_cache)2008 PID_EXISTS="(does not exist)"
1033 fi2009 fi
1034 name_val Size "${table_cache}"2010 name_val Pidfile "${pid_file} ${PID_EXISTS}"
1035 open_tables=$(get_stat Open_tables)2011
1036 name_val Usage "$(fuzzy_pct ${open_tables} ${table_cache})"2012 section "Processlist"
10372013 summarize_processlist "$dir/mysql-processlist"
1038 # ########################################################################2014
1039 # Percona Server features2015 section "Status Counters (Wait ${OPT_SLEEP} Seconds)"
1040 # ########################################################################2016 wait
1041 section Key_Percona_Server_features2017 local noncounters_pattern="$(noncounters_pattern)"
1042 name_val "Table & Index Stats" "$(feat_on userstat_running)"2018 format_status_variables "$dir/mysql-status-defer" | grep -v "${noncounters_pattern}"
1043 name_val "Multiple I/O Threads" "$(feat_on innodb_read_io_threads gt 1)"2019
1044 name_val "Corruption Resilient" "$(feat_on innodb_pass_corrupt_table)"2020 section "Table cache"
1045 name_val "Durable Replication" "$(feat_on innodb_overwrite_relay_log_info)"2021 local open_tables=$(get_var "Open_tables" "$dir/mysql-status")
1046 name_val "Import InnoDB Tables" "$(feat_on innodb_expand_import)"2022 local table_cache=$(get_table_cache "$dir/mysql-variables")
1047 name_val "Fast Server Restarts" "$(feat_on innodb_auto_lru_dump)"2023 name_val Size $table_cache
1048 name_val "Enhanced Logging" "$(feat_on log_slow_verbosity ne microtime)"2024 name_val Usage "$(fuzzy_pct ${open_tables} ${table_cache})"
1049 name_val "Replica Perf Logging" "$(feat_on log_slow_slave_statements)"2025
1050 name_val "Response Time Hist." "$(feat_on enable_query_response_time_stats)"2026 section "Key Percona Server features"
1051 name_val "Smooth Flushing" "$(feat_on innodb_adaptive_checkpoint ne none)"2027 section_percona_server_features "$dir/mysql-variables"
1052 name_val "HandlerSocket NoSQL" "$(feat_on handlersocket_port)"2028
1053 mysql "$@" -e 'SELECT FNV_64("a")' >/dev/null 2>&1 && FNV_64="Enabled";2029 section "Plugins"
1054 name_val "Fast Maatkit Hashes" "${FNV_64:-Unknown}"2030 name_val "InnoDB compression" "$(get_plugin_status "$dir/mysql-plugins" "INNODB_CMP")"
10552031
1056 # ########################################################################2032 if [ "$(get_var have_query_cache "$dir/mysql-variables")" ]; then
1057 # Query cache2033 section "Query cache"
1058 # ########################################################################2034 local query_cache_size=$(get_var query_cache_size "$dir/mysql-variables")
1059 query_cache_size=$(get_var query_cache_size);2035 local used=$(( ${query_cache_size} - $(get_var Qcache_free_memory "$dir/mysql-status") ))
1060 if [ "$(get_var have_query_cache)" ]; then2036 local hrat=$(fuzzy_pct $(get_var Qcache_hits "$dir/mysql-status") $(get_var Qcache_inserts "$dir/mysql-status"))
1061 section Query_cache2037 name_val query_cache_type $(get_var query_cache_type "$dir/mysql-variables")
1062 name_val query_cache_type $(get_var query_cache_type)
1063 name_val Size "$(shorten ${query_cache_size} 1)"2038 name_val Size "$(shorten ${query_cache_size} 1)"
1064 used=$(( ${query_cache_size} - $(get_stat Qcache_free_memory) ))
1065 name_val Usage "$(fuzzy_pct ${used} ${query_cache_size})"2039 name_val Usage "$(fuzzy_pct ${used} ${query_cache_size})"
1066 hrat=$(fuzzy_pct $(get_stat Qcache_hits) $(get_stat Qcache_inserts))
1067 name_val HitToInsertRatio "${hrat}"2040 name_val HitToInsertRatio "${hrat}"
1068 fi2041 fi
10692042
1070 # ########################################################################2043 local semisync_enabled_master="$(get_var "rpl_semi_sync_master_enabled" "$dir/mysql-variables")"
1071 # Schema, databases, data type, other analysis.2044 if [ -n "${semisync_enabled_master}" ]; then
1072 # ########################################################################2045 section "Semisynchronous Replication"
1073 section Schema2046 if [ "$semisync_enabled_master" = "OFF" -o "$semisync_enabled_master" = "0" -o -z "$semisync_enabled_master" ]; then
1074 # Assume "no" if stdin or stdout is not a terminal, so this can be run and2047 name_val "Master" "Disabled"
1075 # put into a file, or piped into a pager, or something else like that.2048 else
1076 if [ -t 0 -a -t 1 ]; then2049 _semi_sync_stats_for "master" "$dir/mysql-variables"
2050 fi
2051 local semisync_enabled_slave="$(get_var rpl_semi_sync_slave_enabled "$dir/mysql-variables")"
2052 if [ "$semisync_enabled_slave" = "OFF" -o "$semisync_enabled_slave" = "0" -o -z "$semisync_enabled_slave" ]; then
2053 name_val "Slave" "Disabled"
2054 else
2055 _semi_sync_stats_for "slave" "$dir/mysql-variables"
2056 fi
2057 fi
2058
2059 section "Schema"
2060 local reply="n"
2061 if [ "${OPT_DATABASES}" ] || [ "${OPT_READ_SAMPLES}" ] \
2062 || [ -e "$dir/mysqldump" -a -s "$dir/mysqldump" ]; then
2063 reply="y"
2064 elif [ -t 0 -a -t 1 ]; then
1077 echo -n "Would you like to mysqldump -d the schema and analyze it? y/n "2065 echo -n "Would you like to mysqldump -d the schema and analyze it? y/n "
1078 read reply2066 read reply
1079 reply=${reply:-n}2067 reply=${reply:-n}
1080 fi2068 fi
1081 if echo "${reply:-n}" | $AP_GREP -i '^y' > /dev/null ; then2069 if echo "${reply:-n}" | grep -i '^y' > /dev/null ; then
1082 # If mysqldump supports triggers, then add options for routines.2070 if [ -z "${OPT_DATABASES}" ] && [ -z "$OPT_READ_SAMPLES" ] \
1083 if mysqldump --help --verbose 2>&1 | $AP_GREP triggers >/dev/null; then2071 && [ ! -e "$dir/mysqldump" ]; then
1084 trg_arg="--routines"2072 echo "There are ${num_dbs} databases. Would you like to dump all, or just one?"
1085 fi2073 echo -n "Type the name of the database, or press Enter to dump all of them. "
1086 if [ "${trg_arg}" ]; then2074 local dbtodump=""
1087 # Find out if there are any triggers. If there are none, we will skip2075 read dbtodump
1088 # that option to mysqldump, because when mysqldump checks for them, it2076 local trg_arg="$( get_mysqldump_args "$dir/mysql-variables" )"
1089 # can take a long time, one table at a time.2077 get_mysqldump_for "${trg_arg}" "${dbtodump}" > "$dir/mysqldump"
1090 triggers="--skip-triggers"2078 fi
1091 trg=$(mysql "$@" -ss -e "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TRIGGERS" 2>/dev/null);2079
1092 if [ "${res}" ]; then2080 if [ -e "$dir/mysqldump" -a -s "$dir/mysqldump" ] \
1093 if [ "${res}" -gt 0 ]; then2081 && grep 'CREATE TABLE' "$dir/mysqldump" >/dev/null 2>&1; then
1094 triggers="--triggers"2082 format_overall_db_stats "$dir/mysqldump"
1095 fi2083 elif [ ! -e "$dir/mysqldump" -a "$OPT_READ_SAMPLES" ]; then
1096 fi2084 echo "Skipping schema analysis as the directory passed in" \
1097 trg_arg="${trg_arg} ${triggers}";2085 "doesn't have a dump file"
1098 fi
1099 # Find out which databases to dump
1100 num_dbs="$($AP_GREP -c . $TMPDIR/percona-toolkit-mysql-databases)"
1101 echo "There are ${num_dbs} databases. Would you like to dump all, or just one?"
1102 echo -n "Type the name of the database, or press Enter to dump all of them. "
1103 read dbtodump
1104 mysqldump "$@" --no-data --skip-comments \
1105 --skip-add-locks --skip-add-drop-table --compact \
1106 --skip-lock-all-tables --skip-lock-tables --skip-set-charset \
1107 ${trg_arg} ${dbtodump:---all-databases} > $TMPDIR/percona-toolkit-mysqldump
1108 # Test the result by checking the file, not by the exit status, because we
1109 # might get partway through and then die, and the info is worth analyzing
1110 # anyway.
1111 if $AP_GREP 'CREATE TABLE' $TMPDIR/percona-toolkit-mysqldump >/dev/null 2>&1; then
1112 format_overall_db_stats $TMPDIR/percona-toolkit-mysqldump
1113 else2086 else
1114 echo "Skipping schema analysis due to apparent error in dump file"2087 echo "Skipping schema analysis due to apparent error in dump file"
1115 rm -f $TMPDIR/percona-toolkit-mysqldump
1116 fi2088 fi
1117 else2089 else
1118 echo "Skipping schema analysis"2090 echo "Skipping schema analysis"
1119 fi2091 fi
11202092
1121 # ########################################################################2093 section "Noteworthy Technologies"
1122 # Noteworthy Technologies2094 if [ -s "$dir/mysqldump" ]; then
1123 # ########################################################################2095 if grep FULLTEXT "$dir/mysqldump" > /dev/null; then
1124 section Noteworthy_Technologies2096 name_val "Full Text Indexing" "Yes"
1125 if [ -e $TMPDIR/percona-toolkit-mysqldump ]; then2097 else
1126 if $AP_GREP FULLTEXT $TMPDIR/percona-toolkit-mysqldump > /dev/null; then2098 name_val "Full Text Indexing" "No"
1127 name_val "Full Text Indexing" Yes2099 fi
1128 else2100 if grep 'GEOMETRY\|POINT\|LINESTRING\|POLYGON' "$dir/mysqldump" > /dev/null; then
1129 name_val "Full Text Indexing" No2101 name_val "Geospatial Types" "Yes"
1130 fi2102 else
1131 if $AP_GREP 'GEOMETRY\|POINT\|LINESTRING\|POLYGON' $TMPDIR/percona-toolkit-mysqldump > /dev/null; then2103 name_val "Geospatial Types" "No"
1132 name_val "Geospatial Types" Yes2104 fi
1133 else2105 if grep 'FOREIGN KEY' "$dir/mysqldump" > /dev/null; then
1134 name_val "Geospatial Types" No2106 name_val "Foreign Keys" "Yes"
1135 fi2107 else
1136 if $AP_GREP 'FOREIGN KEY' $TMPDIR/percona-toolkit-mysqldump > /dev/null; then2108 name_val "Foreign Keys" "No"
1137 name_val "Foreign Keys" Yes2109 fi
1138 else2110 if grep 'PARTITION BY' "$dir/mysqldump" > /dev/null; then
1139 name_val "Foreign Keys" No2111 name_val "Partitioning" "Yes"
1140 fi2112 else
1141 if $AP_GREP 'PARTITION BY' $TMPDIR/percona-toolkit-mysqldump > /dev/null; then2113 name_val "Partitioning" "No"
1142 name_val "Partitioning" Yes2114 fi
1143 else2115 if grep -e 'ENGINE=InnoDB.*ROW_FORMAT' \
1144 name_val "Partitioning" No2116 -e 'ENGINE=InnoDB.*KEY_BLOCK_SIZE' "$dir/mysqldump" > /dev/null; then
1145 fi2117 name_val "InnoDB Compression" "Yes"
1146 fi2118 else
1147 if [ "$(get_stat Ssl_accepts)" -gt 0 ]; then2119 name_val "InnoDB Compression" "No"
1148 name_val "SSL" Yes2120 fi
1149 else2121 fi
1150 name_val "SSL" No2122 local ssl="$(get_var Ssl_accepts "$dir/mysql-status")"
1151 fi2123 if [ -n "$ssl" -a "${ssl:-0}" -gt 0 ]; then
1152 if [ "$(get_stat Com_lock_tables)" -gt 0 ]; then2124 name_val "SSL" "Yes"
1153 name_val "Explicit LOCK TABLES" Yes2125 else
1154 else2126 name_val "SSL" "No"
1155 name_val "Explicit LOCK TABLES" No2127 fi
1156 fi2128 local lock_tables="$(get_var Com_lock_tables "$dir/mysql-status")"
1157 if [ "$(get_stat Delayed_writes)" -gt 0 ]; then2129 if [ -n "$lock_tables" -a "${lock_tables:-0}" -gt 0 ]; then
1158 name_val "Delayed Insert" Yes2130 name_val "Explicit LOCK TABLES" "Yes"
1159 else2131 else
1160 name_val "Delayed Insert" No2132 name_val "Explicit LOCK TABLES" "No"
1161 fi2133 fi
1162 if [ "$(get_stat Com_xa_start)" -gt 0 ]; then2134 local delayed_insert="$(get_var Delayed_writes "$dir/mysql-status")"
1163 name_val "XA Transactions" Yes2135 if [ -n "$delayed_insert" -a "${delayed_insert:-0}" -gt 0 ]; then
1164 else2136 name_val "Delayed Insert" "Yes"
1165 name_val "XA Transactions" No2137 else
1166 fi2138 name_val "Delayed Insert" "No"
1167 if [ "$(get_stat Ndb_cluster_node_id)" -gt 0 ]; then2139 fi
1168 name_val "NDB Cluster" Yes2140 local xat="$(get_var Com_xa_start "$dir/mysql-status")"
1169 else2141 if [ -n "$xat" -a "${xat:-0}" -gt 0 ]; then
1170 name_val "NDB Cluster" No2142 name_val "XA Transactions" "Yes"
1171 fi2143 else
1172 prep=$(( $(get_stat Com_stmt_prepare) + $(get_stat Com_prepare_sql) ))2144 name_val "XA Transactions" "No"
2145 fi
2146 local ndb_cluster="$(get_var "Ndb_cluster_node_id" "$dir/mysql-status")"
2147 if [ -n "$ndb_cluster" -a "${ndb_cluster:-0}" -gt 0 ]; then
2148 name_val "NDB Cluster" "Yes"
2149 else
2150 name_val "NDB Cluster" "No"
2151 fi
2152 local prep=$(( $(get_var "Com_stmt_prepare" "$dir/mysql-status") + $(get_var "Com_prepare_sql" "$dir/mysql-status") ))
1173 if [ "${prep}" -gt 0 ]; then2153 if [ "${prep}" -gt 0 ]; then
1174 name_val "Prepared Statements" Yes2154 name_val "Prepared Statements" "Yes"
1175 else2155 else
1176 name_val "Prepared Statements" No2156 name_val "Prepared Statements" "No"
2157 fi
2158 local prep_count="$(get_var Prepared_stmt_count "$dir/mysql-status")"
2159 if [ "${prep_count}" ]; then
2160 name_val "Prepared statement count" "${prep_count}"
1177 fi2161 fi
11782162
1179 # ########################################################################2163 section "InnoDB"
1180 # InnoDB2164 local have_innodb="$(get_var "have_innodb" "$dir/mysql-variables")"
1181 # ########################################################################
1182 section InnoDB
1183 have_innodb=$(get_var have_innodb)
1184 if [ "${have_innodb}" = "YES" ]; then2165 if [ "${have_innodb}" = "YES" ]; then
11852166 section_innodb "$dir/mysql-variables" "$dir/mysql-status"
1186 version=$(get_var innodb_version)2167
1187 name_val Version ${version:-default}2168 if [ -s "$dir/innodb-status" ]; then
11882169 format_innodb_status "$dir/innodb-status"
1189 bp_size="$(get_var innodb_buffer_pool_size)"
1190 name_val "Buffer Pool Size" "$(shorten ${bp_size} 1)"
1191
1192 bp_pags="$(get_stat Innodb_buffer_pool_pages_total)"
1193 bp_free="$(get_stat Innodb_buffer_pool_pages_free)"
1194 bp_dirt="$(get_stat Innodb_buffer_pool_pages_dirty)"
1195 bp_fill=$((${bp_pags} - ${bp_free}))
1196 name_val "Buffer Pool Fill" "$(fuzzy_pct ${bp_fill} ${bp_pags})"
1197 name_val "Buffer Pool Dirty" "$(fuzzy_pct ${bp_dirt} ${bp_pags})"
1198
1199 name_val "File Per Table" $(get_var innodb_file_per_table)
1200 name_val "Page Size" $(shorten $(get_stat Innodb_page_size))
1201
1202 lg_size="$(get_var innodb_log_file_size)"
1203 lg_fils="$(get_var innodb_log_files_in_group)"
1204 lg_totl="$((${lg_size} * ${lg_fils}))"
1205 name_val "Log File Size" "${lg_fils} * $(shorten ${lg_size}) = $(shorten ${lg_totl} 1)"
1206 name_val "Log Buffer Size" $(shorten $(get_var innodb_log_buffer_size))
1207 name_val "Flush Method" $(get_var innodb_flush_method)
1208 name_val "Flush Log At Commit" $(get_var innodb_flush_log_at_trx_commit)
1209 name_val "XA Support" $(get_var innodb_support_xa)
1210 name_val "Checksums" $(get_var innodb_checksums)
1211 name_val "Doublewrite" $(get_var innodb_doublewrite)
1212 name_val "R/W I/O Threads" "$(get_var innodb_read_io_threads) $(get_var innodb_write_io_threads)"
1213 name_val "I/O Capacity" $(get_var innodb_io_capacity)
1214 name_val "Thread Concurrency" $(get_var innodb_thread_concurrency)
1215 name_val "Concurrency Tickets" $(get_var innodb_concurrency_tickets)
1216 name_val "Commit Concurrency" $(get_var innodb_commit_concurrency)
1217 name_val "Txn Isolation Level" $(get_var tx_isolation)
1218 name_val "Adaptive Flushing" $(get_var innodb_adaptive_flushing)
1219 name_val "Adaptive Checkpoint" $(get_var innodb_adaptive_checkpoint)
1220
1221 if [ -s $TMPDIR/percona-toolkit-innodb-status ]; then
1222 format_innodb_status $TMPDIR/percona-toolkit-innodb-status
1223 fi2170 fi
1224 fi2171 fi
12252172
1226 # ########################################################################2173 section "MyISAM"
1227 # MyISAM2174 section_myisam "$dir/mysql-variables" "$dir/mysql-status"
1228 # ########################################################################2175
1229 section MyISAM2176 section "Security"
1230 buf_size=$(get_var key_buffer_size)2177 local users="$( format_users "$dir/mysql-users" )"
1231 blk_size=$(get_var key_cache_block_size)2178 name_val "Users" "${users}"
1232 blk_unus=$(get_stat Key_blocks_unused)2179 name_val "Old Passwords" "$(get_var old_passwords "$dir/mysql-variables")"
1233 blk_unfl=$(get_stat Key_blocks_not_flushed)2180
1234 unus=$((${blk_unus} * ${blk_size}))2181 section "Binary Logging"
1235 unfl=$((${blk_unfl} * ${blk_size}))2182
1236 used=$((${buf_size} - ${unus}))2183 if [ -s "$dir/mysql-master-logs" ] \
1237 name_val "Key Cache" "$(shorten ${buf_size} 1)"2184 || [ -s "$dir/mysql-master-status" ]; then
1238 name_val "Pct Used" "$(fuzzy_pct ${used} ${buf_size})"2185 summarize_binlogs "$dir/mysql-master-logs"
1239 name_val "Unflushed" "$(fuzzy_pct ${unfl} ${buf_size})"2186 local format="$(get_var binlog_format "$dir/mysql-variables")"
1240
1241 # ########################################################################
1242 # Users & Security
1243 # ########################################################################
1244 section Security
1245 users="$(mysql "$@" -ss \
1246 -e 'SELECT COUNT(*), SUM(user=""), SUM(password=""), SUM(password NOT LIKE "*%") FROM mysql.user' 2>/dev/null \
1247 | $AP_AWK '{printf "%d users, %d anon, %d w/o pw, %d old pw\n", $1, $2, $3, $4}')"
1248 name_val Users "${users}"
1249 name_val "Old Passwords" $(get_var old_passwords)
1250
1251 # ########################################################################
1252 # Binary Logging
1253 # ########################################################################
1254 section Binary_Logging
1255 binlog=$(get_var log_bin)
1256 if [ "${binlog}" ]; then
1257 mysql "$@" -ss -e 'SHOW MASTER LOGS' > $TMPDIR/percona-toolkit 2>/dev/null
1258 summarize_binlogs $TMPDIR/percona-toolkit
1259 format="$(get_var binlog_format)"
1260 name_val binlog_format "${format:-STATEMENT}"2187 name_val binlog_format "${format:-STATEMENT}"
1261 name_val expire_logs_days $(get_var expire_logs_days)2188 name_val expire_logs_days "$(get_var expire_logs_days "$dir/mysql-variables")"
1262 name_val sync_binlog $(get_var sync_binlog)2189 name_val sync_binlog "$(get_var sync_binlog "$dir/mysql-variables")"
1263 name_val server_id $(get_var server_id)2190 name_val server_id "$(get_var server_id "$dir/mysql-variables")"
1264 mysql "$@" -ss -e 'SHOW MASTER STATUS' > $TMPDIR/percona-toolkit 2>/dev/null2191 format_binlog_filters "$dir/mysql-master-status"
1265 format_binlog_filters $TMPDIR/percona-toolkit2192 fi
1266 fi2193
12672194
1268# Replication: seconds behind, running, filters, skip_slave_start, skip_errors,2195 section "Noteworthy Variables"
1269# read_only, temp tables open, slave_net_timeout, slave_exec_mode2196 section_noteworthy_variables "$dir/mysql-variables"
12702197
1271 # ########################################################################2198 section "Configuration File"
1272 # Interesting things that you just ought to know about.2199 local cnf_file="$(get_var "pt-summary-internal-Config_File_path" "$dir/mysql-variables")"
1273 # ########################################################################2200 if [ -n "${cnf_file}" ]; then
1274 section Noteworthy_Variables
1275 name_val "Auto-Inc Incr/Offset" "$(get_var auto_increment_increment)/$(get_var auto_increment_offset)"
1276 for v in \
1277 default_storage_engine flush_time init_connect init_file sql_mode;
1278 do
1279 name_val ${v} $(get_var ${v})
1280 done
1281 for v in \
1282 join_buffer_size sort_buffer_size read_buffer_size read_rnd_buffer_size \
1283 bulk_insert_buffer max_heap_table_size tmp_table_size \
1284 max_allowed_packet thread_stack;
1285 do
1286 name_val ${v} $(shorten $(get_var ${v}))
1287 done
1288 for v in log log_error log_warnings log_slow_queries \
1289 log_queries_not_using_indexes log_slave_updates;
1290 do
1291 name_val ${v} $(get_var ${v})
1292 done
1293
1294 # ########################################################################
1295 # If there is a my.cnf in a standard location, see if we can pretty-print it.
1296 # ########################################################################
1297 section Configuration_File
1298 ps auxww 2>/dev/null | $AP_GREP mysqld > $TMPDIR/percona-toolkit
1299 cnf_file=$(find_my_cnf_file $TMPDIR/percona-toolkit ${port});
1300 if [ ! -e "${cnf_file}" ]; then
1301 name_val "Config File" "Cannot autodetect, trying common locations"
1302 cnf_file="/etc/my.cnf";
1303 fi
1304 if [ ! -e "${cnf_file}" ]; then
1305 cnf_file="/etc/mysql/my.cnf";
1306 fi
1307 if [ ! -e "${cnf_file}" ]; then
1308 cnf_file="/var/db/mysql/my.cnf";
1309 fi
1310 if [ -e "${cnf_file}" ]; then
1311 name_val "Config File" "${cnf_file}"2201 name_val "Config File" "${cnf_file}"
1312 cat "${cnf_file}" > $TMPDIR/percona-toolkit2202 pretty_print_cnf_file "$dir/mysql-config-file"
1313 pretty_print_cnf_file $TMPDIR/percona-toolkit
1314 else2203 else
1315 name_val "Config File" "Cannot autodetect or find, giving up"2204 name_val "Config File" "Cannot autodetect or find, giving up"
1316 fi2205 fi
13172206
1318 temp_files "rm"2207 section "The End"
13192208}
1320 # Make sure that we signal the end of the tool's output.2209
1321 section The_End2210# ###########################################################################
13222211# End report_mysql_info package
1323 rm_tmpdir2212# ###########################################################################
1324}2213
13252214# ########################################################################
1326# Execute the program if it was not included from another file. This makes it2215# Some global setup is necessary for cross-platform compatibility, even
1327# possible to include without executing, and thus test.2216# when sourcing this script for testing purposes.
1328if [ "$(basename "$0")" = "pt-mysql-summary" ]; then main "$@"; fi2217# ########################################################################
2218
2219TOOL="pt-mysql-summary"
2220
2221CMD_MYSQL="$(_which mysql)"
2222CMD_MYSQLDUMP="$( _which mysqldump )"
2223
2224check_mysql () {
2225 # Check that mysql and mysqldump are in PATH. If not, we're
2226 # already dead in the water, so don't bother with cmd line opts,
2227 # just error and exit.
2228 [ -n "$(mysql --help 2>/dev/null)" ] \
2229 || die "Cannot execute mysql. Check that it is in PATH."
2230 [ -n "$(mysqldump --help 2>/dev/null)" ] \
2231 || die "Cannot execute mysqldump. Check that it is in PATH."
2232
2233 # Now that we have the cmd line opts, check that we can actually
2234 # connect to MySQL.
2235 [ -n "$(mysql $EXT_ARGV -e 'SELECT 1')" ] \
2236 || die "Cannot connect to MySQL. Check that MySQL is running and that the options after -- are correct."
2237
2238}
2239
2240sigtrap() {
2241 warn "Caught signal, forcing exit"
2242 rm_tmpdir
2243 exit $EXIT_STATUS
2244}
2245
2246# ##############################################################################
2247# The main() function is called at the end of the script. This makes it
2248# testable. Major bits of parsing are separated into functions for testability.
2249# ##############################################################################
2250main() {
2251 # Prepending SIG to these doesn't work with NetBSD's sh
2252 trap sigtrap HUP INT TERM
2253
2254 local RAN_WITH="--sleep=$OPT_SLEEP --databases=$OPT_DATABASES --save-samples=$OPT_SAVE_SAMPLES"
2255
2256 _d "Starting $0 $RAN_WITH"
2257
2258 # Begin by setting the $PATH to include some common locations that are not
2259 # always in the $PATH, including the "sbin" locations. On SunOS systems,
2260 # prefix the path with the location of more sophisticated utilities.
2261 export PATH="${PATH}:/usr/local/bin:/usr/bin:/bin:/usr/libexec"
2262 export PATH="${PATH}:/usr/mysql/bin/:/usr/local/sbin:/usr/sbin:/sbin"
2263 export PATH="/usr/gnu/bin/:/usr/xpg4/bin/:${PATH}"
2264
2265 _d "Going to use: mysql=${CMD_MYSQL} mysqldump=${CMD_MYSQLDUMP}"
2266
2267 # Create the tmpdir for everything to run in
2268 mk_tmpdir
2269
2270 # Set DATA_DIR where we'll save collected data files.
2271 local data_dir="$(setup_data_dir "${OPT_SAVE_SAMPLES:-""}")"
2272 if [ -z "$data_dir" ]; then
2273 exit $?
2274 fi
2275
2276 if [ -n "$OPT_READ_SAMPLES" -a -d "$OPT_READ_SAMPLES" ]; then
2277 # --read-samples was set and is a directory, so the samples
2278 # will already be there.
2279 data_dir="$OPT_READ_SAMPLES"
2280 else
2281 # #####################################################################
2282 # Fetch most info, leave a child in the background gathering the rest
2283 # #####################################################################
2284 collect_mysql_info "${data_dir}" 2>"${data_dir}/collect.err"
2285 fi
2286
2287 # ########################################################################
2288 # Format and pretty-print the data
2289 # ########################################################################
2290 report_mysql_summary "${data_dir}"
2291
2292 rm_tmpdir
2293
2294}
2295
2296# Execute the program if it was not included from another file.
2297# This makes it possible to include without executing, and thus test.
2298if [ "${0##*/}" = "$TOOL" ] \
2299 || [ "${0##*/}" = "bash" -a "$_" = "$0" ]; then
2300
2301 # Set up temporary dir.
2302 mk_tmpdir
2303 # Parse command line options.
2304 parse_options "$0" "$@"
2305
2306 # Verify that --sleep, if present, is positive
2307 if [ -n "$OPT_SLEEP" ] && [ "$OPT_SLEEP" -lt 0 ]; then
2308 option_error "Invalid --sleep value: $sleep"
2309 fi
2310
2311 usage_or_errors "$0"
2312 po_status=$?
2313 rm_tmpdir
2314
2315 if [ $po_status -ne 0 ]; then
2316 [ $OPT_ERRS -gt 0 ] && exit 1
2317 exit 0
2318 fi
2319
2320 # Check if mysql and mysqldump are there, otherwise bail out early.
2321 # But don't if they passed in --read-samples, since we don't need
2322 # a connection then.
2323 [ "$OPT_READ_SAMPLES" ] || check_mysql
2324
2325 main "$@"
2326fi
13292327
1330# ############################################################################2328# ############################################################################
1331# Documentation2329# Documentation
@@ -1335,11 +2333,11 @@
13352333
1336=head1 NAME2334=head1 NAME
13372335
1338pt-mysql-summary - Summarize MySQL information in a nice way.2336pt-mysql-summary - Summarize MySQL information nicely.
13392337
1340=head1 SYNOPSIS2338=head1 SYNOPSIS
13412339
1342Usage: pt-mysql-summary [MYSQL-OPTIONS]2340Usage: pt-mysql-summary [OPTIONS] [-- MYSQL OPTIONS]
13432341
1344pt-mysql-summary conveniently summarizes the status and configuration of a2342pt-mysql-summary conveniently summarizes the status and configuration of a
1345MySQL database server so that you can learn about it at a glance. It is not2343MySQL database server so that you can learn about it at a glance. It is not
@@ -1356,8 +2354,7 @@
13562354
1357pt-mysql-summary is a read-only tool. It should be very low-risk.2355pt-mysql-summary is a read-only tool. It should be very low-risk.
13582356
1359At the time of this release, we know of no bugs that could cause serious harm2357At the time of this release, we know of no bugs that could harm users.
1360to users.
13612358
1362The authoritative source for updated information is always the online issue2359The authoritative source for updated information is always the online issue
1363tracking system. Issues that affect this tool will be marked as such. You can2360tracking system. Issues that affect this tool will be marked as such. You can
@@ -1373,34 +2370,435 @@
1373into files in a temporary directory, and then formats them neatly with awk2370into files in a temporary directory, and then formats them neatly with awk
1374and other scripting languages.2371and other scripting languages.
13752372
1376To use, simply execute it. Optionally add the same command-line options2373To use, simply execute it. Optionally add a double dash and then the same
1377you would use to connect to MySQL, like C<pt-mysql-summary --user=foo>.2374command-line options you would use to connect to MySQL, such as the following:
2375
2376 pt-mysql-summary -- --user=root
13782377
1379The tool interacts minimally with the server upon which it runs. It assumes2378The tool interacts minimally with the server upon which it runs. It assumes
1380that you'll run it on the same server you're inspecting, and therefore it2379that you'll run it on the same server you're inspecting, and therefore it
1381assumes that it will be able to find the my.cnf configuration file, for2380assumes that it will be able to find the my.cnf configuration file, for example.
1382example. However, it should degrade gracefully if this is not the case.2381However, it should degrade gracefully if this is not the case. Note, however,
1383Note, however, that its output does not indicate which information comes from2382that its output does not indicate which information comes from the MySQL
1384the MySQL database and which comes from the host operating system, so it is2383database and which comes from the host operating system, so it is possible for
1385possible for confusing output to be generated if you run the tool on one2384confusing output to be generated if you run the tool on one server and connect
1386server and direct it to connect to a MySQL database server running on another2385to a MySQL database server running on another server.
1387server.
13882386
1389=head1 Fuzzy-Rounding2387=head1 OUTPUT
13902388
1391Many of the outputs from this tool are deliberately rounded to show their2389Many of the outputs from this tool are deliberately rounded to show their
1392magnitude but not the exact detail. This is called fuzzy-rounding. The idea2390magnitude but not the exact detail. This is called fuzzy-rounding. The idea
1393is that it doesn't matter whether a server is running 918 queries per second2391is that it does not matter whether a server is running 918 queries per second
1394or 921 queries per second; such a small variation is insignificant, and only2392or 921 queries per second; such a small variation is insignificant, and only
1395makes the output hard to compare to other servers. Fuzzy-rounding rounds in2393makes the output hard to compare to other servers. Fuzzy-rounding rounds in
1396larger increments as the input grows. It begins by rounding to the nearest 5,2394larger increments as the input grows. It begins by rounding to the nearest 5,
1397then the nearest 10, nearest 25, and then repeats by a factor of 10 larger2395then the nearest 10, nearest 25, and then repeats by a factor of 10 larger
1398(50, 100, 250), and so on, as the input grows.2396(50, 100, 250), and so on, as the input grows.
13992397
2398The following is a sample of the report that the tool produces:
2399
2400 # Percona Toolkit MySQL Summary Report #######################
2401 System time | 2012-03-30 18:46:05 UTC
2402 (local TZ: EDT -0400)
2403 # Instances ##################################################
2404 Port Data Directory Nice OOM Socket
2405 ===== ========================== ==== === ======
2406 12345 /tmp/12345/data 0 0 /tmp/12345.sock
2407 12346 /tmp/12346/data 0 0 /tmp/12346.sock
2408 12347 /tmp/12347/data 0 0 /tmp/12347.sock
2409
2410The first two sections show which server the report was generated on and which
2411MySQL instances are running on the server. This is detected from the output of
2412C<ps> and does not always detect all instances and parameters, but often works
2413well. From this point forward, the report will be focused on a single MySQL
2414instance, although several instances may appear in the above paragraph.
2415
2416 # Report On Port 12345 #######################################
2417 User | msandbox@%
2418 Time | 2012-03-30 14:46:05 (EDT)
2419 Hostname | localhost.localdomain
2420 Version | 5.5.20-log MySQL Community Server (GPL)
2421 Built On | linux2.6 i686
2422 Started | 2012-03-28 23:33 (up 1+15:12:09)
2423 Databases | 4
2424 Datadir | /tmp/12345/data/
2425 Processes | 2 connected, 2 running
2426 Replication | Is not a slave, has 1 slaves connected
2427 Pidfile | /tmp/12345/data/12345.pid (exists)
2428
2429This section is a quick summary of the MySQL instance: version, uptime, and
2430other very basic parameters. The Time output is generated from the MySQL server,
2431unlike the system date and time printed earlier, so you can see whether the
2432database and operating system times match.
2433
2434 # Processlist ################################################
2435
2436 Command COUNT(*) Working SUM(Time) MAX(Time)
2437 ------------------------------ -------- ------- --------- ---------
2438 Binlog Dump 1 1 150000 150000
2439 Query 1 1 0 0
2440
2441 User COUNT(*) Working SUM(Time) MAX(Time)
2442 ------------------------------ -------- ------- --------- ---------
2443 msandbox 2 2 150000 150000
2444
2445 Host COUNT(*) Working SUM(Time) MAX(Time)
2446 ------------------------------ -------- ------- --------- ---------
2447 localhost 2 2 150000 150000
2448
2449 db COUNT(*) Working SUM(Time) MAX(Time)
2450 ------------------------------ -------- ------- --------- ---------
2451 NULL 2 2 150000 150000
2452
2453 State COUNT(*) Working SUM(Time) MAX(Time)
2454 ------------------------------ -------- ------- --------- ---------
2455 Master has sent all binlog to 1 1 150000 150000
2456 NULL 1 1 0 0
2457
2458This section is a summary of the output from SHOW PROCESSLIST. Each sub-section
2459is aggregated by a different item, which is shown as the first column heading.
2460When summarized by Command, every row in SHOW PROCESSLIST is included, but
2461otherwise, rows whose Command is Sleep are excluded from the SUM and MAX
2462columns, so they do not skew the numbers too much. In the example shown, the
2463server is idle except for this tool itself, and one connected replica, which
2464is executing Binlog Dump.
2465
2466The columns are the number of rows included, the number that are not in Sleep
2467status, the sum of the Time column, and the maximum Time column. The numbers are
2468fuzzy-rounded.
2469
2470 # Status Counters (Wait 10 Seconds) ##########################
2471 Variable Per day Per second 10 secs
2472 Binlog_cache_disk_use 4
2473 Binlog_cache_use 80
2474 Bytes_received 15000000 175 200
2475 Bytes_sent 15000000 175 2000
2476 Com_admin_commands 1
2477 ...................(many lines omitted)............................
2478 Threads_created 40 1
2479 Uptime 90000 1 1
2480
2481This section shows selected counters from two snapshots of SHOW GLOBAL STATUS,
2482gathered approximately 10 seconds apart and fuzzy-rounded. It includes only
2483items that are incrementing counters; it does not include absolute numbers such
2484as the Threads_running status variable, which represents a current value, rather
2485than an accumulated number over time.
2486
2487The first column is the variable name, and the second column is the counter from
2488the first snapshot divided by 86400 (the number of seconds in a day), so you can
2489see the magnitude of the counter's change per day. 86400 fuzzy-rounds to 90000,
2490so the Uptime counter should always be about 90000.
2491
2492The third column is the value from the first snapshot, divided by Uptime and
2493then fuzzy-rounded, so it represents approximately how quickly the counter is
2494growing per-second over the uptime of the server.
2495
2496The third column is the incremental difference from the first and second
2497snapshot, divided by the difference in uptime and then fuzzy-rounded. Therefore,
2498it shows how quickly the counter is growing per second at the time the report
2499was generated.
2500
2501 # Table cache ################################################
2502 Size | 400
2503 Usage | 15%
2504
2505This section shows the size of the table cache, followed by the percentage of
2506the table cache in use. The usage is fuzzy-rounded.
2507
2508 # Key Percona Server features ################################
2509 Table & Index Stats | Not Supported
2510 Multiple I/O Threads | Enabled
2511 Corruption Resilient | Not Supported
2512 Durable Replication | Not Supported
2513 Import InnoDB Tables | Not Supported
2514 Fast Server Restarts | Not Supported
2515 Enhanced Logging | Not Supported
2516 Replica Perf Logging | Not Supported
2517 Response Time Hist. | Not Supported
2518 Smooth Flushing | Not Supported
2519 HandlerSocket NoSQL | Not Supported
2520 Fast Hash UDFs | Unknown
2521
2522This section shows features that are available in Percona Server and whether
2523they are enabled or not. In the example shown, the server is standard MySQL, not
2524Percona Server, so the features are generally not supported.
2525
2526 # Plugins ####################################################
2527 InnoDB compression | ACTIVE
2528
2529This feature shows specific plugins and whether they are enabled.
2530
2531 # Query cache ################################################
2532 query_cache_type | ON
2533 Size | 0.0
2534 Usage | 0%
2535 HitToInsertRatio | 0%
2536
2537This section shows whether the query cache is enabled and its size, followed by
2538the percentage of the cache in use and the hit-to-insert ratio. The latter two
2539are fuzzy-rounded.
2540
2541 # Schema #####################################################
2542 Would you like to mysqldump -d the schema and analyze it? y/n y
2543 There are 4 databases. Would you like to dump all, or just one?
2544 Type the name of the database, or press Enter to dump all of them.
2545
2546 Database Tables Views SPs Trigs Funcs FKs Partn
2547 mysql 24
2548 performance_schema 17
2549 sakila 16 7 3 6 3 22
2550
2551 Database MyISAM CSV PERFORMANCE_SCHEMA InnoDB
2552 mysql 22 2
2553 performance_schema 17
2554 sakila 8 15
2555
2556 Database BTREE FULLTEXT
2557 mysql 31
2558 performance_schema
2559 sakila 63 1
2560
2561 c t s e l d i t m v s
2562 h i e n o a n i e a m
2563 a m t u n t t n d r a
2564 r e m g e y i c l
2565 s b t i u h l
2566 t l i n m a i
2567 a o m t t r n
2568 m b e e t
2569 p x
2570 t
2571 Database === === === === === === === === === === ===
2572 mysql 61 10 6 78 5 4 26 3 4 5 3
2573 performance_schema 5 16 33
2574 sakila 1 15 1 3 4 3 19 42 26
2575
2576If you select to dump the schema and analyze it, the tool will print the above
2577section. This summarizes the number and type of objects in the database. It is
2578generated by running C<mysqldump --no-data>, not by querying the
2579INFORMATION_SCHEMA, which can freeze a busy server. You can use the
2580L<"--databases"> option to specify which databases to examine. If you do not,
2581and you run the tool interactively, it will prompt you as shown.
2582
2583You can choose not to dump the schema, to dump all of the databases, or to dump
2584only a single named one, by specifying the appropriate options. In the example
2585above, we are dumping all databases.
2586
2587The first sub-report in the section is the count of objects by type in each
2588database: tables, views, and so on. The second one shows how many tables use
2589various storage engines in each database. The third sub-report shows the number
2590of each type of indexes in each database.
2591
2592The last section shows the number of columns of various data types in each
2593database. For compact display, the column headers are formatted vertically, so
2594you need to read downwards from the top. In this example, the first column is
2595C<char> and the second column is C<timestamp>. This example is truncated so it
2596does not wrap on a terminal.
2597
2598All of the numbers in this portion of the output are exact, not fuzzy-rounded.
2599
2600 # Noteworthy Technologies ####################################
2601 Full Text Indexing | Yes
2602 Geospatial Types | No
2603 Foreign Keys | Yes
2604 Partitioning | No
2605 InnoDB Compression | Yes
2606 SSL | No
2607 Explicit LOCK TABLES | No
2608 Delayed Insert | No
2609 XA Transactions | No
2610 NDB Cluster | No
2611 Prepared Statements | No
2612 Prepared statement count | 0
2613
2614This section shows some specific technologies used on this server. Some of them
2615are detected from the schema dump performed for the previous sections; others
2616can be detected by looking at SHOW GLOBAL STATUS.
2617
2618 # InnoDB #####################################################
2619 Version | 1.1.8
2620 Buffer Pool Size | 16.0M
2621 Buffer Pool Fill | 100%
2622 Buffer Pool Dirty | 0%
2623 File Per Table | OFF
2624 Page Size | 16k
2625 Log File Size | 2 * 5.0M = 10.0M
2626 Log Buffer Size | 8M
2627 Flush Method |
2628 Flush Log At Commit | 1
2629 XA Support | ON
2630 Checksums | ON
2631 Doublewrite | ON
2632 R/W I/O Threads | 4 4
2633 I/O Capacity | 200
2634 Thread Concurrency | 0
2635 Concurrency Tickets | 500
2636 Commit Concurrency | 0
2637 Txn Isolation Level | REPEATABLE-READ
2638 Adaptive Flushing | ON
2639 Adaptive Checkpoint |
2640 Checkpoint Age | 0
2641 InnoDB Queue | 0 queries inside InnoDB, 0 queries in queue
2642 Oldest Transaction | 0 Seconds
2643 History List Len | 209
2644 Read Views | 1
2645 Undo Log Entries | 1 transactions, 1 total undo, 1 max undo
2646 Pending I/O Reads | 0 buf pool reads, 0 normal AIO,
2647 0 ibuf AIO, 0 preads
2648 Pending I/O Writes | 0 buf pool (0 LRU, 0 flush list, 0 page);
2649 0 AIO, 0 sync, 0 log IO (0 log, 0 chkp);
2650 0 pwrites
2651 Pending I/O Flushes | 0 buf pool, 0 log
2652 Transaction States | 1xnot started
2653
2654This section shows important configuration variables for the InnoDB storage
2655engine. The buffer pool fill percent and dirty percent are fuzzy-rounded. The
2656last few lines are derived from the output of SHOW INNODB STATUS. It is likely
2657that this output will change in the future to become more useful.
2658
2659 # MyISAM #####################################################
2660 Key Cache | 16.0M
2661 Pct Used | 10%
2662 Unflushed | 0%
2663
2664This section shows the size of the MyISAM key cache, followed by the percentage
2665of the cache in use and percentage unflushed (fuzzy-rounded).
2666
2667 # Security ###################################################
2668 Users | 2 users, 0 anon, 0 w/o pw, 0 old pw
2669 Old Passwords | OFF
2670
2671This section is generated from queries to tables in the mysql system database.
2672It shows how many users exist, and various potential security risks such as
2673old-style passwords and users without passwords.
2674
2675 # Binary Logging #############################################
2676 Binlogs | 1
2677 Zero-Sized | 0
2678 Total Size | 21.8M
2679 binlog_format | STATEMENT
2680 expire_logs_days | 0
2681 sync_binlog | 0
2682 server_id | 12345
2683 binlog_do_db |
2684 binlog_ignore_db |
2685
2686This section shows configuration and status of the binary logs. If there are
2687zero-sized binary logs, then it is possible that the binlog index is out of sync
2688with the binary logs that actually exist on disk.
2689
2690 # Noteworthy Variables #######################################
2691 Auto-Inc Incr/Offset | 1/1
2692 default_storage_engine | InnoDB
2693 flush_time | 0
2694 init_connect |
2695 init_file |
2696 sql_mode |
2697 join_buffer_size | 128k
2698 sort_buffer_size | 2M
2699 read_buffer_size | 128k
2700 read_rnd_buffer_size | 256k
2701 bulk_insert_buffer | 0.00
2702 max_heap_table_size | 16M
2703 tmp_table_size | 16M
2704 max_allowed_packet | 1M
2705 thread_stack | 192k
2706 log | OFF
2707 log_error | /tmp/12345/data/mysqld.log
2708 log_warnings | 1
2709 log_slow_queries | ON
2710 log_queries_not_using_indexes | OFF
2711 log_slave_updates | ON
2712
2713This section shows several noteworthy server configuration variables that might
2714be important to know about when working with this server.
2715
2716 # Configuration File #########################################
2717 Config File | /tmp/12345/my.sandbox.cnf
2718 [client]
2719 user = msandbox
2720 password = msandbox
2721 port = 12345
2722 socket = /tmp/12345/mysql_sandbox12345.sock
2723 [mysqld]
2724 port = 12345
2725 socket = /tmp/12345/mysql_sandbox12345.sock
2726 pid-file = /tmp/12345/data/mysql_sandbox12345.pid
2727 basedir = /home/baron/5.5.20
2728 datadir = /tmp/12345/data
2729 key_buffer_size = 16M
2730 innodb_buffer_pool_size = 16M
2731 innodb_data_home_dir = /tmp/12345/data
2732 innodb_log_group_home_dir = /tmp/12345/data
2733 innodb_data_file_path = ibdata1:10M:autoextend
2734 innodb_log_file_size = 5M
2735 log-bin = mysql-bin
2736 relay_log = mysql-relay-bin
2737 log_slave_updates
2738 server-id = 12345
2739 report-host = 127.0.0.1
2740 report-port = 12345
2741 log-error = mysqld.log
2742 innodb_lock_wait_timeout = 3
2743 # The End ####################################################
2744
2745This section shows a pretty-printed version of the my.cnf file, with comments
2746removed and with whitespace added to align things for easy reading. The tool
2747tries to detect the my.cnf file by looking at the output of ps, and if it does
2748not find the location of the file there, it tries common locations until it
2749finds a file. Note that this file might not actually correspond with the server
2750from which the report was generated. This can happen when the tool isn't run on
2751the same server it's reporting on, or when detecting the location of the
2752configuration file fails.
2753
1400=head1 OPTIONS2754=head1 OPTIONS
14012755
1402This tool does not have any command-line options of its own. All options2756All options after -- are passed to C<mysql>.
1403are passed to C<mysql>.2757
2758=over
2759
2760=item --config
2761
2762type: string
2763
2764Read this comma-separated list of config files. If specified, this must be the
2765first option on the command line.
2766
2767=item --help
2768
2769Print help and exit.
2770
2771=item --save-samples
2772
2773type: string
2774
2775Save the data files used to generate the summary in this directory.
2776
2777=item --read-samples
2778
2779type: string
2780
2781Create a report from the files found in this directory.
2782
2783=item --databases
2784
2785type: string
2786
2787Names of databases to summarize. If you want all of them, you can use the value
2788C<--all-databases>; you can also pass in a comma-separated list of database
2789names. If not provided, the program will ask you for manual input.
2790
2791=item --sleep
2792
2793type: int; default: 10
2794
2795Seconds to sleep when gathering status counters.
2796
2797=item --version
2798
2799Print tool's version and exit.
2800
2801=back
14042802
1405=head1 ENVIRONMENT2803=head1 ENVIRONMENT
14062804
@@ -1408,7 +2806,9 @@
14082806
1409=head1 SYSTEM REQUIREMENTS2807=head1 SYSTEM REQUIREMENTS
14102808
1411This tool requires Bash v3 or newer.2809This tool requires Bash v3 or newer, Perl 5.8 or newer, and binutils.
2810These are generally already provided by most distributions.
2811On BSD systems, it may require a mounted procfs.
14122812
1413=head1 BUGS2813=head1 BUGS
14142814
@@ -1454,7 +2854,7 @@
14542854
1455=head1 AUTHORS2855=head1 AUTHORS
14562856
1457Baron Schwartz2857Baron Schwartz, Brian Fraser, and Daniel Nichter.
14582858
1459=head1 ABOUT PERCONA TOOLKIT2859=head1 ABOUT PERCONA TOOLKIT
14602860
@@ -1467,7 +2867,7 @@
14672867
1468=head1 COPYRIGHT, LICENSE, AND WARRANTY2868=head1 COPYRIGHT, LICENSE, AND WARRANTY
14692869
1470This program is copyright 2010-2011 Baron Schwartz, 2011-2012 Percona Inc.2870This program is copyright 2010-2011 Baron Schwartz, 2011 Percona Inc.
1471Feedback and improvements are welcome.2871Feedback and improvements are welcome.
14722872
1473THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED2873THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
14742874
=== modified file 'bin/pt-summary'
--- bin/pt-summary 2012-03-07 23:41:54 +0000
+++ bin/pt-summary 2012-04-03 15:57:31 +0000
@@ -4,45 +4,428 @@
4# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal4# See "COPYRIGHT, LICENSE, AND WARRANTY" at the end of this file for legal
5# notices and disclaimers.5# notices and disclaimers.
66
7set -u
8
7# ########################################################################9# ########################################################################
8# Globals, settings, helper functions10# Globals, settings, helper functions
9# ########################################################################11# ########################################################################
12TOOL="pt-summary"
10POSIXLY_CORRECT=113POSIXLY_CORRECT=1
11export POSIXLY_CORRECT14export POSIXLY_CORRECT
1215
13# The awk code for fuzzy rounding. (It's used in a few places, so makes sense16# ###########################################################################
14# not to duplicate). It fuzzy-rounds the variable named fuzzy_var. It goes in17# log_warn_die package
15# steps of 5, 10, 25, then repeats by a factor of 10 larger (50, 100, 250), and18# This package is a copy without comments from the original. The original
16# so on, until it finds a number that's large enough. The pattern is slightly19# with comments and its test file can be found in the Bazaar repository at,
17# broken between the initial 1 and 50, because rounding to the nearest 2.520# lib/bash/log_warn_die.sh
18# doesn't seem right to me.21# t/lib/bash/log_warn_die.sh
19fuzzy_formula='22# See https://launchpad.net/percona-toolkit for more information.
20 rounded = 0;23# ###########################################################################
21 if (fuzzy_var <= 10 ) {24
22 rounded = 1;25
23 }26set -u
24 factor = 1;27
25 while ( rounded == 0 ) {28PTFUNCNAME=""
26 if ( fuzzy_var <= 50 * factor ) {29PTDEBUG="${PTDEBUG:-""}"
27 fuzzy_var = sprintf("%.0f", fuzzy_var / (5 * factor)) * 5 * factor;30EXIT_STATUS=0
28 rounded = 1;31
29 }32log() {
30 else if ( fuzzy_var <= 100 * factor) {33 TS=$(date +%F-%T | tr :- _);
31 fuzzy_var = sprintf("%.0f", fuzzy_var / (10 * factor)) * 10 * factor;34 echo "$TS $*"
32 rounded = 1;35}
33 }36
34 else if ( fuzzy_var <= 250 * factor) {37warn() {
35 fuzzy_var = sprintf("%.0f", fuzzy_var / (25 * factor)) * 25 * factor;38 log "$*" >&2
36 rounded = 1;39 EXIT_STATUS=1
37 }40}
38 factor = factor * 10;41
39 }'42die() {
4043 warn "$*"
41# Does fuzzy rounding: rounds to nearest interval, but the interval gets larger44 exit 1
42# as the number gets larger. This is to make things easier to diff.45}
43fuzz () {46
44 echo $1 | $AP_AWK "{fuzzy_var=\$1; ${fuzzy_formula} print fuzzy_var;}"47_d () {
45}48 [ "$PTDEBUG" ] && echo "# $PTFUNCNAME: $(log "$*")" >&2
49}
50
51# ###########################################################################
52# End log_warn_die package
53# ###########################################################################
54
55# ###########################################################################
56# parse_options package
57# This package is a copy without comments from the original. The original
58# with comments and its test file can be found in the Bazaar repository at,
59# lib/bash/parse_options.sh
60# t/lib/bash/parse_options.sh
61# See https://launchpad.net/percona-toolkit for more information.
62# ###########################################################################
63
64
65
66
67
68set -u
69
70ARGV="" # Non-option args (probably input files)
71EXT_ARGV="" # Everything after -- (args for an external command)
72HAVE_EXT_ARGV="" # Got --, everything else is put into EXT_ARGV
73OPT_ERRS=0 # How many command line option errors
74OPT_VERSION="" # If --version was specified
75OPT_HELP="" # If --help was specified
76PO_DIR="" # Directory with program option spec files
77
78usage() {
79 local file="$1"
80
81 local usage=$(grep '^Usage: ' "$file")
82 echo $usage
83 echo
84 echo "For more information, 'man $TOOL' or 'perldoc $file'."
85}
86
87usage_or_errors() {
88 local file="$1"
89
90 if [ "$OPT_VERSION" ]; then
91 local version=$(grep '^pt-[^ ]\+ [0-9]' "$file")
92 echo "$version"
93 return 1
94 fi
95
96 if [ "$OPT_HELP" ]; then
97 usage "$file"
98 echo
99 echo "Command line options:"
100 echo
101 perl -e '
102 use strict;
103 use warnings FATAL => qw(all);
104 my $lcol = 20; # Allow this much space for option names.
105 my $rcol = 80 - $lcol; # The terminal is assumed to be 80 chars wide.
106 my $name;
107 while ( <> ) {
108 my $line = $_;
109 chomp $line;
110 if ( $line =~ s/^long:/ --/ ) {
111 $name = $line;
112 }
113 elsif ( $line =~ s/^desc:// ) {
114 $line =~ s/ +$//mg;
115 my @lines = grep { $_ }
116 $line =~ m/(.{0,$rcol})(?:\s+|\Z)/g;
117 if ( length($name) >= $lcol ) {
118 print $name, "\n", (q{ } x $lcol);
119 }
120 else {
121 printf "%-${lcol}s", $name;
122 }
123 print join("\n" . (q{ } x $lcol), @lines);
124 print "\n";
125 }
126 }
127 ' "$PO_DIR"/*
128 echo
129 echo "Options and values after processing arguments:"
130 echo
131 for opt in $(ls "$PO_DIR"); do
132 local varname="OPT_$(echo "$opt" | tr a-z- A-Z_)"
133 local varvalue="${!varname}"
134 printf -- " --%-30s %s" "$opt" "${varvalue:-(No value)}"
135 echo
136 done
137 return 1
138 fi
139
140 if [ $OPT_ERRS -gt 0 ]; then
141 echo
142 usage "$file"
143 return 1
144 fi
145
146 return 0
147}
148
149option_error() {
150 local err="$1"
151 OPT_ERRS=$(($OPT_ERRS + 1))
152 echo "$err" >&2
153}
154
155parse_options() {
156 local file="$1"
157 shift
158
159 ARGV=""
160 EXT_ARGV=""
161 HAVE_EXT_ARGV=""
162 OPT_ERRS=0
163 OPT_VERSION=""
164 OPT_HELP=""
165 PO_DIR="$TMPDIR/po"
166
167 if [ ! -d "$PO_DIR" ]; then
168 mkdir "$PO_DIR"
169 if [ $? -ne 0 ]; then
170 echo "Cannot mkdir $PO_DIR" >&2
171 exit 1
172 fi
173 fi
174
175 rm -rf "$PO_DIR"/*
176 if [ $? -ne 0 ]; then
177 echo "Cannot rm -rf $PO_DIR/*" >&2
178 exit 1
179 fi
180
181 _parse_pod "$file" # Parse POD into program option (po) spec files
182 _eval_po # Eval po into existence with default values
183
184 if [ $# -ge 2 ] && [ "$1" = "--config" ]; then
185 shift # --config
186 local user_config_files="$1"
187 shift # that ^
188 local IFS=","
189 for user_config_file in $user_config_files; do
190 _parse_config_files "$user_config_file"
191 done
192 else
193 _parse_config_files "/etc/percona-toolkit/percona-toolkit.conf" "/etc/percona-toolkit/$TOOL.conf" "$HOME/.percona-toolkit.conf" "$HOME/.$TOOL.conf"
194 fi
195
196 _parse_command_line "$@"
197}
198
199_parse_pod() {
200 local file="$1"
201
202 cat "$file" | PO_DIR="$PO_DIR" perl -ne '
203 BEGIN { $/ = ""; }
204 next unless $_ =~ m/^=head1 OPTIONS/;
205 while ( defined(my $para = <>) ) {
206 last if $para =~ m/^=head1/;
207 chomp;
208 if ( $para =~ m/^=item --(\S+)/ ) {
209 my $opt = $1;
210 my $file = "$ENV{PO_DIR}/$opt";
211 open my $opt_fh, ">", $file or die "Cannot open $file: $!";
212 print $opt_fh "long:$opt\n";
213 $para = <>;
214 chomp;
215 if ( $para =~ m/^[a-z ]+:/ ) {
216 map {
217 chomp;
218 my ($attrib, $val) = split(/: /, $_);
219 print $opt_fh "$attrib:$val\n";
220 } split(/; /, $para);
221 $para = <>;
222 chomp;
223 }
224 my ($desc) = $para =~ m/^([^?.]+)/;
225 print $opt_fh "desc:$desc.\n";
226 close $opt_fh;
227 }
228 }
229 last;
230 '
231}
232
233_eval_po() {
234 local IFS=":"
235 for opt_spec in "$PO_DIR"/*; do
236 local opt=""
237 local default_val=""
238 local neg=0
239 local size=0
240 while read key val; do
241 case "$key" in
242 long)
243 opt=$(echo $val | sed 's/-/_/g' | tr [:lower:] [:upper:])
244 ;;
245 default)
246 default_val="$val"
247 ;;
248 "short form")
249 ;;
250 type)
251 [ "$val" = "size" ] && size=1
252 ;;
253 desc)
254 ;;
255 negatable)
256 if [ "$val" = "yes" ]; then
257 neg=1
258 fi
259 ;;
260 *)
261 echo "Invalid attribute in $opt_spec: $line" >&2
262 exit 1
263 esac
264 done < "$opt_spec"
265
266 if [ -z "$opt" ]; then
267 echo "No long attribute in option spec $opt_spec" >&2
268 exit 1
269 fi
270
271 if [ $neg -eq 1 ]; then
272 if [ -z "$default_val" ] || [ "$default_val" != "yes" ]; then
273 echo "Option $opt_spec is negatable but not default: yes" >&2
274 exit 1
275 fi
276 fi
277
278 if [ $size -eq 1 -a -n "$default_val" ]; then
279 default_val=$(size_to_bytes $default_val)
280 fi
281
282 eval "OPT_${opt}"="$default_val"
283 done
284}
285
286_parse_config_files() {
287
288 for config_file in "$@"; do
289 test -f "$config_file" || continue
290
291 while read config_opt; do
292
293 echo "$config_opt" | grep '^[ ]*[^#]' >/dev/null 2>&1 || continue
294
295 config_opt="$(echo "$config_opt" | sed -e 's/^ *//g' -e 's/ *$//g' -e 's/[ ]*=[ ]*/=/' -e 's/[ ]*#.*$//')"
296
297 [ "$config_opt" = "" ] && continue
298
299 if ! [ "$HAVE_EXT_ARGV" ]; then
300 config_opt="--$config_opt"
301 fi
302
303 _parse_command_line "$config_opt"
304
305 done < "$config_file"
306
307 HAVE_EXT_ARGV="" # reset for each file
308
309 done
310}
311
312_parse_command_line() {
313 local opt=""
314 local val=""
315 local next_opt_is_val=""
316 local opt_is_ok=""
317 local opt_is_negated=""
318 local real_opt=""
319 local required_arg=""
320 local spec=""
321
322 for opt in "$@"; do
323 if [ "$opt" = "--" -o "$opt" = "----" ]; then
324 HAVE_EXT_ARGV=1
325 continue
326 fi
327 if [ "$HAVE_EXT_ARGV" ]; then
328 if [ "$EXT_ARGV" ]; then
329 EXT_ARGV="$EXT_ARGV $opt"
330 else
331 EXT_ARGV="$opt"
332 fi
333 continue
334 fi
335
336 if [ "$next_opt_is_val" ]; then
337 next_opt_is_val=""
338 if [ $# -eq 0 ] || [ $(expr "$opt" : "-") -eq 1 ]; then
339 option_error "$real_opt requires a $required_arg argument"
340 continue
341 fi
342 val="$opt"
343 opt_is_ok=1
344 else
345 if [ $(expr "$opt" : "-") -eq 0 ]; then
346 if [ -z "$ARGV" ]; then
347 ARGV="$opt"
348 else
349 ARGV="$ARGV $opt"
350 fi
351 continue
352 fi
353
354 real_opt="$opt"
355
356 if $(echo $opt | grep '^--no-' >/dev/null); then
357 opt_is_negated=1
358 opt=$(echo $opt | sed 's/^--no-//')
359 else
360 opt_is_negated=""
361 opt=$(echo $opt | sed 's/^-*//')
362 fi
363
364 if $(echo $opt | grep '^[a-z-][a-z-]*=' >/dev/null 2>&1); then
365 val="$(echo $opt | awk -F= '{print $2}')"
366 opt="$(echo $opt | awk -F= '{print $1}')"
367 fi
368
369 if [ -f "$TMPDIR/po/$opt" ]; then
370 spec="$TMPDIR/po/$opt"
371 else
372 spec=$(grep "^short form:-$opt\$" "$TMPDIR"/po/* | cut -d ':' -f 1)
373 if [ -z "$spec" ]; then
374 option_error "Unknown option: $real_opt"
375 continue
376 fi
377 fi
378
379 required_arg=$(cat "$spec" | awk -F: '/^type:/{print $2}')
380 if [ "$required_arg" ]; then
381 if [ "$val" ]; then
382 opt_is_ok=1
383 else
384 next_opt_is_val=1
385 fi
386 else
387 if [ "$val" ]; then
388 option_error "Option $real_opt does not take a value"
389 continue
390 fi
391 if [ "$opt_is_negated" ]; then
392 val=""
393 else
394 val="yes"
395 fi
396 opt_is_ok=1
397 fi
398 fi
399
400 if [ "$opt_is_ok" ]; then
401 opt=$(cat "$spec" | grep '^long:' | cut -d':' -f2 | sed 's/-/_/g' | tr [:lower:] [:upper:])
402
403 if grep "^type:size" "$spec" >/dev/null; then
404 val=$(size_to_bytes $val)
405 fi
406
407 eval "OPT_$opt"="'$val'"
408
409 opt=""
410 val=""
411 next_opt_is_val=""
412 opt_is_ok=""
413 opt_is_negated=""
414 real_opt=""
415 required_arg=""
416 spec=""
417 fi
418 done
419}
420
421size_to_bytes() {
422 local size="$1"
423 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")};'
424}
425
426# ###########################################################################
427# End parse_options package
428# ###########################################################################
46429
47# ###########################################################################430# ###########################################################################
48# tmpdir package431# tmpdir package
@@ -53,18 +436,21 @@
53# See https://launchpad.net/percona-toolkit for more information.436# See https://launchpad.net/percona-toolkit for more information.
54# ###########################################################################437# ###########################################################################
55438
439
440set -u
441
56TMPDIR=""442TMPDIR=""
57443
58mk_tmpdir() {444mk_tmpdir() {
59 local dir=${1:-""}445 local dir="${1:-""}"
60446
61 if [ -n "$dir" ]; then447 if [ -n "$dir" ]; then
62 if [ ! -d "$dir" ]; then448 if [ ! -d "$dir" ]; then
63 mkdir $dir || die "Cannot make tmpdir $dir"449 mkdir "$dir" || die "Cannot make tmpdir $dir"
64 fi450 fi
65 TMPDIR="$dir"451 TMPDIR="$dir"
66 else452 else
67 local tool=`basename $0`453 local tool="${0##*/}"
68 local pid="$$"454 local pid="$$"
69 TMPDIR=`mktemp -d /tmp/${tool}.${pid}.XXXXX` \455 TMPDIR=`mktemp -d /tmp/${tool}.${pid}.XXXXX` \
70 || die "Cannot make secure tmpdir"456 || die "Cannot make secure tmpdir"
@@ -73,7 +459,7 @@
73459
74rm_tmpdir() {460rm_tmpdir() {
75 if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then461 if [ -n "$TMPDIR" ] && [ -d "$TMPDIR" ]; then
76 rm -rf $TMPDIR462 rm -rf "$TMPDIR"
77 fi463 fi
78 TMPDIR=""464 TMPDIR=""
79}465}
@@ -82,180 +468,893 @@
82# End tmpdir package468# End tmpdir package
83# ###########################################################################469# ###########################################################################
84470
85# The temp files are for storing working results so we don't call commands many471# ###########################################################################
86# times (gives inconsistent results, maybe adds load on things I don't want to472# alt_cmds package
87# such as RAID controllers). They must not exist -- if they did, someone would473# This package is a copy without comments from the original. The original
88# symlink them to /etc/passwd and then run this program as root. Call this474# with comments and its test file can be found in the Bazaar repository at,
89# function with "rm" or "touch" as an argument.475# lib/bash/alt_cmds.sh
90temp_files() {476# t/lib/bash/alt_cmds.sh
91 for file in $TMPDIR/percona-toolkit $TMPDIR/percona-toolkit2; do477# See https://launchpad.net/percona-toolkit for more information.
92 case "$1" in478# ###########################################################################
93 touch)479
94 if ! touch "${file}"; then480
95 echo "I can't make my temp file ${file}";481set -u
96 exit 1;482
483_seq() {
484 local i="$1"
485 awk "BEGIN { for(i=1; i<=$i; i++) print i; }"
486}
487
488_pidof() {
489 local cmd="$1"
490 if ! pidof "$cmd" 2>/dev/null; then
491 ps -eo pid,ucomm | awk -v comm="$cmd" '$2 == comm { print $1 }'
492 fi
493}
494
495_lsof() {
496 local pid="$1"
497 if ! lsof -p $pid 2>/dev/null; then
498 /bin/ls -l /proc/$pid/fd 2>/dev/null
499 fi
500}
501
502
503
504_which() {
505 if [ -x /usr/bin/which ]; then
506 /usr/bin/which "$1" 2>/dev/null | awk '{print $1}'
507 elif which which 1>/dev/null 2>&1; then
508 which "$1" 2>/dev/null | awk '{print $1}'
509 else
510 echo "$1"
511 fi
512}
513
514# ###########################################################################
515# End alt_cmds package
516# ###########################################################################
517
518# ###########################################################################
519# summary_common package
520# This package is a copy without comments from the original. The original
521# with comments and its test file can be found in the Bazaar repository at,
522# lib/bash/summary_common.sh
523# t/lib/bash/summary_common.sh
524# See https://launchpad.net/percona-toolkit for more information.
525# ###########################################################################
526
527
528set -u
529
530CMD_FILE="$( _which file 2>/dev/null )"
531CMD_NM="$( _which nm 2>/dev/null )"
532CMD_OBJDUMP="$( _which objdump 2>/dev/null )"
533
534get_nice_of_pid () {
535 local pid="$1"
536 local niceness="$(ps -p $pid -o nice | awk '$1 !~ /[^0-9]/ {print $1; exit}')"
537
538 if [ -n "${niceness}" ]; then
539 echo $niceness
540 else
541 local tmpfile="$TMPDIR/nice_through_c.tmp.c"
542 _d "Getting the niceness from ps failed, somehow. We are about to try this:"
543 cat <<EOC > "$tmpfile"
544
545int main(void) {
546 int priority = getpriority(PRIO_PROCESS, $pid);
547 if ( priority == -1 && errno == ESRCH ) {
548 return 1;
549 }
550 else {
551 printf("%d\\n", priority);
552 return 0;
553 }
554}
555
556EOC
557 local c_comp=$(_which gcc)
558 if [ -z "${c_comp}" ]; then
559 c_comp=$(_which cc)
560 fi
561 _d "$tmpfile: $( cat "$tmpfile" )"
562 _d "$c_comp -xc \"$tmpfile\" -o \"$tmpfile\" && eval \"$tmpfile\""
563 $c_comp -xc "$tmpfile" -o "$tmpfile" 2>/dev/null && eval "$tmpfile" 2>/dev/null
564 if [ $? -ne 0 ]; then
565 echo "?"
566 _d "Failed to get a niceness value for $pid"
567 fi
568 fi
569}
570
571get_oom_of_pid () {
572 local pid="$1"
573 local oom_adj=""
574
575 if [ -n "${pid}" -a -e /proc/cpuinfo ]; then
576 if [ -s "/proc/$pid/oom_score_adj" ]; then
577 oom_adj=$(cat "/proc/$pid/oom_score_adj" 2>/dev/null)
578 _d "For $pid, the oom value is $oom_adj, retreived from oom_score_adj"
579 else
580 oom_adj=$(cat "/proc/$pid/oom_adj" 2>/dev/null)
581 _d "For $pid, the oom value is $oom_adj, retreived from oom_adj"
582 fi
583 fi
584
585 if [ -n "${oom_adj}" ]; then
586 echo "${oom_adj}"
587 else
588 echo "?"
589 _d "Can't find the oom value for $pid"
590 fi
591}
592
593has_symbols () {
594 local executable="$(_which "$1")"
595 local has_symbols=""
596
597 if [ "${CMD_FILE}" ] \
598 && [ "$($CMD_FILE "${executable}" | grep 'not stripped' )" ]; then
599 has_symbols=1
600 elif [ "${CMD_NM}" ] \
601 || [ "${CMD_OBJDMP}" ]; then
602 if [ "${CMD_NM}" ] \
603 && [ !"$("${CMD_NM}" -- "${executable}" 2>&1 | grep 'File format not recognized' )" ]; then
604 if [ -z "$( $CMD_NM -- "${executable}" 2>&1 | grep ': no symbols' )" ]; then
605 has_symbols=1
97 fi606 fi
98 ;;607 elif [ -z "$("${CMD_OBJDUMP}" -t -- "${executable}" | grep '^no symbols$' )" ]; then
99 rm)608 has_symbols=1
100 rm -f "${file}"609 fi
101 ;;610 fi
102 esac611
103 done612 if [ "${has_symbols}" ]; then
104}613 echo "Yes"
105614 else
106# Print a space-padded string into $line. Then translate spaces to hashes, and615 echo "No"
107# underscores to spaces. End result is a line of hashes with words at the616 fi
108# start.617}
618
619setup_data_dir () {
620 local existing_dir="$1"
621 local data_dir=""
622 if [ -z "$existing_dir" ]; then
623 mkdir "$TMPDIR/data" || die "Cannot mkdir $TMPDIR/data"
624 data_dir="$TMPDIR/data"
625 else
626 if [ ! -d "$existing_dir" ]; then
627 mkdir "$existing_dir" || die "Cannot mkdir $existing_dir"
628 elif [ "$( ls -A "$existing_dir" )" ]; then
629 die "--save-samples directory isn't empty, halting."
630 fi
631 touch "$existing_dir/test" || die "Cannot write to $existing_dir"
632 rm "$existing_dir/test" || die "Cannot rm $existing_dir/test"
633 data_dir="$existing_dir"
634 fi
635 echo "$data_dir"
636}
637
638get_var () {
639 local varname="$1"
640 local file="$2"
641 awk -v pattern="${varname}" '$1 == pattern { if (length($2)) { len = length($1); print substr($0, len+index(substr($0, len+1), $2)) } }' "${file}"
642}
643
644# ###########################################################################
645# End summary_common package
646# ###########################################################################
647
648# ###########################################################################
649# report_formatting package
650# This package is a copy without comments from the original. The original
651# with comments and its test file can be found in the Bazaar repository at,
652# lib/bash/report_formatting.sh
653# t/lib/bash/report_formatting.sh
654# See https://launchpad.net/percona-toolkit for more information.
655# ###########################################################################
656
657
658set -u
659
660POSIXLY_CORRECT=1
661export POSIXLY_CORRECT
662
663fuzzy_formula='
664 rounded = 0;
665 if (fuzzy_var <= 10 ) {
666 rounded = 1;
667 }
668 factor = 1;
669 while ( rounded == 0 ) {
670 if ( fuzzy_var <= 50 * factor ) {
671 fuzzy_var = sprintf("%.0f", fuzzy_var / (5 * factor)) * 5 * factor;
672 rounded = 1;
673 }
674 else if ( fuzzy_var <= 100 * factor) {
675 fuzzy_var = sprintf("%.0f", fuzzy_var / (10 * factor)) * 10 * factor;
676 rounded = 1;
677 }
678 else if ( fuzzy_var <= 250 * factor) {
679 fuzzy_var = sprintf("%.0f", fuzzy_var / (25 * factor)) * 25 * factor;
680 rounded = 1;
681 }
682 factor = factor * 10;
683 }'
684
685fuzz () {
686 awk -v fuzzy_var="$1" "BEGIN { ${fuzzy_formula} print fuzzy_var;}"
687}
688
689fuzzy_pct () {
690 local pct="$(awk -v one="$1" -v two="$2" 'BEGIN{ if (two > 0) { printf "%d", one/two*100; } else {print 0} }')";
691 echo "$(fuzz "${pct}")%"
692}
693
109section () {694section () {
110 echo "$1" | awk '{l=sprintf("#_%-60s", $0 "_"); print l}' | sed -e 's/ /#/g' -e 's/_/ /g'695 local str="$1"
111}696 awk -v var="${str} _" 'BEGIN {
112697 line = sprintf("# %-60s", var);
113# Print a "name | value" line.698 i = index(line, "_");
114name_val() {699 x = substr(line, i);
115 printf "%12s | %s\n" "$1" "$(echo $2)"700 gsub(/[_ \t]/, "#", x);
116}701 printf("%s%s\n", substr(line, 1, i-1), x);
117702 }'
118# Converts a value to units of power of 2. Arg 1: the value. Arg 2: precision (defaults to 2).703}
704
705NAME_VAL_LEN=12
706name_val () {
707 printf "%+*s | %s\n" "${NAME_VAL_LEN}" "$1" "$2"
708}
709
119shorten() {710shorten() {
120 echo $@ | awk '{711 local num="$1"
121 unit = "k";712 local prec="${2:-2}"
122 size = 1024;713 local div="${3:-1024}"
714
715 echo "$num" | awk -v prec="$prec" -v div="$div" '
716 {
717 size = 4;
123 val = $1;718 val = $1;
124 prec = 2;719
125 if ( $2 ~ /./ ) {720 unit = val >= 1099511627776 ? "T" : val >= 1073741824 ? "G" : val >= 1048576 ? "M" : val >= 1024 ? "k" : "";
126 prec = $2;721
127 }722 while ( int(val) && !(val % 1024) ) {
128 if ( val >= 1099511627776 ) {723 val /= 1024;
129 size = 1099511627776;724 }
130 unit = "T";725
131 }726 while ( val > 1000 ) {
132 else if ( val >= 1073741824 ) {727 val /= div;
133 size = 1073741824;728 }
134 unit = "G";729
135 }730 printf "%.*f%s", prec, val, unit;
136 else if ( val >= 1048576 ) {731 }
137 size = 1048576;732 '
138 unit = "M";
139 }
140 printf "%." prec "f%s", val / size, unit;
141 }'
142}733}
143734
144# ##############################################################################
145# Function to take a file and collapse it into an aggregated list. This
146# function works on $1, which it expects to be created with 'sort |
147# uniq -c'. Leading whitespace is deleted. The result will look like
148# "4xabc, 1xdef" Copy any changes to 'mysql-summary' too.
149# ##############################################################################
150group_concat () {735group_concat () {
151 sed -e '{H; $!d}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' ${1}736 sed -e '{H; $!d;}' -e 'x' -e 's/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/, //' "${1}"
152 # In words: save the whole file into the hold space,737}
153 # {H; $!d}738
154 # Swap it back into the pattern space,739# ###########################################################################
155 # x740# End report_formatting package
156 # Join lines with a comma, delete leading whitespace, and put an 'x' between741# ###########################################################################
157 # the number and the text that follows,742
158 # s/\n[[:space:]]*\([[:digit:]]*\)[[:space:]]*/, \1x/g743# ###########################################################################
159 # Collapse whitespace,744# collect_system_info package
160 # s/[[:space:]][[:space:]]*/ /g745# This package is a copy without comments from the original. The original
161 # And delete the leading comma-space.746# with comments and its test file can be found in the Bazaar repository at,
162 # s/, //747# lib/bash/collect_system_info.sh
163}748# t/lib/bash/collect_system_info.sh
164749# See https://launchpad.net/percona-toolkit for more information.
165# ##############################################################################750# ###########################################################################
166# Functions for parsing specific files and getting desired info from them.751
167# These are called from within main() and are separated so they can be tested752
168# easily. The calling convention is that the data they need to run is prepared753
169# first by putting it into $TMPDIR/percona-toolkit. Then code that's testing754set -u
170# just needs to put sample data into $TMPDIR/percona-toolkit and call it.755
171# ##############################################################################756setup_commands () {
757 CMD_SYSCTL="$(_which sysctl 2>/dev/null )"
758 CMD_DMIDECODE="$(_which dmidecode 2>/dev/null )"
759 CMD_ZONENAME="$(_which zonename 2>/dev/null )"
760 CMD_DMESG="$(_which dmesg 2>/dev/null )"
761 CMD_FILE="$(_which file 2>/dev/null )"
762 CMD_LSPCI="$(_which lspci 2>/dev/null )"
763 CMD_PRTDIAG="$(_which prtdiag 2>/dev/null )"
764 CMD_SMBIOS="$(_which smbios 2>/dev/null )"
765 CMD_GETENFORCE="$(_which getenforce 2>/dev/null )"
766 CMD_PRTCONF="$(_which prtconf 2>/dev/null )"
767 CMD_LVS="$(_which lvs 2>/dev/null)"
768 CMD_VGS="$(_which vgs 2>/dev/null)"
769 CMD_PRSTAT="$(_which prstat 2>/dev/null)"
770 CMD_ISAINFO="$(_which isainfo 2>/dev/null)"
771 CMD_TOP="$(_which top 2>/dev/null)"
772 CMD_ARCCONF="$( _which arcconf 2>/dev/null )"
773 CMD_HPACUCLI="$( _which hpacucli 2>/dev/null )"
774 CMD_MEGACLI64="$( _which MegaCli64 2>/dev/null )"
775 CMD_VMSTAT="$(_which vmstat 2>/dev/null)"
776 CMD_IP="$( _which ip 2>/dev/null )"
777 CMD_NETSTAT="$( _which netstat 2>/dev/null )"
778 CMD_PSRINFO="$( _which psrinfo 2>/dev/null )"
779 CMD_SWAPCTL="$( _which swapctl 2>/dev/null )"
780 CMD_LSB_RELEASE="$( _which lsb_release 2>/dev/null )"
781 CMD_ETHTOOL="$( _which ethtool 2>/dev/null )"
782 CMD_GETCONF="$( _which getconf 2>/dev/null )"
783}
784
785collect_system_data () { local PTFUNCNAME=collect_system_data;
786 local data_dir="$1"
787
788 if [ -r /var/log/dmesg -a -s /var/log/dmesg ]; then
789 cat "/var/log/dmesg" > "$data_dir/dmesg_file"
790 fi
791
792 $CMD_SYSCTL -a > "$data_dir/sysctl" 2>/dev/null
793
794 if [ "${CMD_LSPCI}" ]; then
795 $CMD_LSPCI > "$data_dir/lspci_file" 2>/dev/null
796 fi
797
798 local platform="$(uname -s)"
799 echo "platform $platform" >> "$data_dir/summary"
800 echo "hostname $(uname -n)" >> "$data_dir/summary"
801 uptime >> "$data_dir/uptime"
802
803 processor_info "$data_dir"
804 find_release_and_kernel "$platform" >> "$data_dir/summary"
805 cpu_and_os_arch "$platform" >> "$data_dir/summary"
806 find_virtualization "$platform" "$data_dir/dmesg_file" "$data_dir/lspci_file" >> "$data_dir/summary"
807 dmidecode_system_info >> "$data_dir/summary"
808
809 if [ "${platform}" = "SunOS" -a "${CMD_ZONENAME}" ]; then
810 echo "zonename $($CMD_ZONENAME)" >> "$data_dir/summary"
811 fi
812
813 if [ -x /lib/libc.so.6 ]; then
814 echo "compiler $(/lib/libc.so.6 | grep 'Compiled by' | cut -c13-)" >> "$data_dir/summary"
815 fi
816
817 local rss=$(ps -eo rss 2>/dev/null | awk '/[0-9]/{total += $1 * 1024} END {print total}')
818 echo "rss ${rss}" >> "$data_dir/summary"
819
820 [ "$CMD_DMIDECODE" ] && $CMD_DMIDECODE > "$data_dir/dmidecode" 2>/dev/null
821
822 find_memory_stats "$platform" > "$data_dir/memory"
823 [ "$OPT_SUMMARIZE_MOUNTS" ] && mounted_fs_info "$platform" > "$data_dir/mounted_fs"
824 raid_controller "$data_dir/dmesg_file" "$data_dir/lspci_file" >> "$data_dir/summary"
825
826 local controller="$(get_var raid_controller "$data_dir/summary")"
827 propietary_raid_controller "$data_dir/raid-controller" "$data_dir/summary" "$data_dir" "$controller"
828
829 [ "${platform}" = "Linux" ] && linux_exclusive_collection "$data_dir"
830
831 if [ "$CMD_IP" -a "$OPT_SUMMARIZE_NETWORK" ]; then
832 $CMD_IP -s link > "$data_dir/ip"
833 network_device_info "$data_dir/ip" > "$data_dir/network_devices"
834 fi
835
836 [ "$CMD_SWAPCTL" ] && $CMD_SWAPCTL -s > "$data_dir/swapctl"
837
838 if [ "$OPT_SUMMARIZE_PROCESSES" ]; then
839 top_processes > "$data_dir/processes"
840 notable_processes_info > "$data_dir/notable_procs"
841
842 if [ "$CMD_VMSTAT" ]; then
843 touch "$data_dir/vmstat"
844 (
845 $CMD_VMSTAT 1 $OPT_SLEEP > "$data_dir/vmstat"
846 ) &
847 fi
848 fi
849
850 for file in $data_dir/*; do
851 [ "$file" = "vmstat" ] && continue
852 [ ! -s "$file" ] && rm "$file"
853 done
854}
855
856linux_exclusive_collection () { local PTFUNCNAME=linux_exclusive_collection;
857 local data_dir="$1"
858
859 echo "threading $(getconf GNU_LIBPTHREAD_VERSION)" >> "$data_dir/summary"
860
861 local getenforce=""
862 [ "$CMD_GETENFORCE" ] && getenforce="$($CMD_GETENFORCE 2>&1)"
863 echo "getenforce ${getenforce:-"No SELinux detected"}" >> "$data_dir/summary"
864
865 echo "swappiness $(awk '/vm.swappiness/{print $3}' "$data_dir/sysctl")" >> "$data_dir/summary"
866
867 local dirty_ratio="$(awk '/vm.dirty_ratio/{print $3}' "$data_dir/sysctl")"
868 local dirty_bg_ratio="$(awk '/vm.dirty_background_ratio/{print $3}' "$data_dir/sysctl")"
869 if [ "$dirty_ratio" -a "$dirty_bg_ratio" ]; then
870 echo "dirtypolicy $dirty_ratio, $dirty_bg_ratio" >> "$data_dir/summary"
871 fi
872
873 local dirty_bytes="$(awk '/vm.dirty_bytes/{print $3}' "$data_dir/sysctl")"
874 if [ "$dirty_bytes" ]; then
875 echo "dirtystatus $(awk '/vm.dirty_bytes/{print $3}' "$data_dir/sysctl"), $(awk '/vm.dirty_background_bytes/{print $3}' "$data_dir/sysctl")" >> "$data_dir/summary"
876 fi
877
878 schedulers_and_queue_size "$data_dir/summary" > "$data_dir/partitioning"
879
880 for file in dentry-state file-nr inode-nr; do
881 echo "${file} $(cat /proc/sys/fs/${file} 2>&1)" >> "$data_dir/summary"
882 done
883
884 [ "$CMD_LVS" -a -x "$CMD_LVS" ] && $CMD_LVS 1>"$data_dir/lvs" 2>"$data_dir/lvs.stderr"
885
886 [ "$CMD_VGS" -a -x "$CMD_VGS" ] && \
887 $CMD_VGS -o vg_name,vg_size,vg_free 2>/dev/null > "$data_dir/vgs"
888
889 [ "$CMD_NETSTAT" -a "$OPT_SUMMARIZE_NETWORK" ] && \
890 $CMD_NETSTAT -antp > "$data_dir/netstat" 2>/dev/null
891}
892
893network_device_info () {
894 local ip_minus_s_file="$1"
895
896 if [ "$CMD_ETHTOOL" ]; then
897 local tempfile="$TMPDIR/ethtool_output_temp"
898 for device in $( awk '/^[1-9]/{ print $2 }' "$ip_minus_s_file" \
899 | awk -F: '{print $1}' \
900 | grep -v '^lo\|^in\|^gr' \
901 | sort -u ); do
902 ethtool $device > "$tempfile" 2>/dev/null
903
904 if ! grep -q 'No data available' "$tempfile"; then
905 cat "$tempfile"
906 fi
907 done
908 fi
909}
910
911find_release_and_kernel () { local PTFUNCNAME=find_release_and_kernel;
912 local platform="$1"
913
914 local kernel=""
915 local release=""
916 if [ "${platform}" = "Linux" ]; then
917 kernel="$(uname -r)"
918 if [ -e /etc/fedora-release ]; then
919 release=$(cat /etc/fedora-release);
920 elif [ -e /etc/redhat-release ]; then
921 release=$(cat /etc/redhat-release);
922 elif [ -e /etc/system-release ]; then
923 release=$(cat /etc/system-release);
924 elif [ "$CMD_LSB_RELEASE" ]; then
925 release="$($CMD_LSB_RELEASE -ds) ($($CMD_LSB_RELEASE -cs))"
926 elif [ -e /etc/lsb-release ]; then
927 release=$(grep DISTRIB_DESCRIPTION /etc/lsb-release |awk -F'=' '{print $2}' |sed 's#"##g');
928 elif [ -e /etc/debian_version ]; then
929 release="Debian-based version $(cat /etc/debian_version)";
930 if [ -e /etc/apt/sources.list ]; then
931 local code=` awk '/^deb/ {print $3}' /etc/apt/sources.list \
932 | awk -F/ '{print $1}'| awk 'BEGIN {FS="|"}{print $1}' \
933 | sort | uniq -c | sort -rn | head -n1 | awk '{print $2}'`
934 release="${release} (${code})"
935 fi
936 elif ls /etc/*release >/dev/null 2>&1; then
937 if grep -q DISTRIB_DESCRIPTION /etc/*release; then
938 release=$(grep DISTRIB_DESCRIPTION /etc/*release | head -n1);
939 else
940 release=$(cat /etc/*release | head -n1);
941 fi
942 fi
943 elif [ "${platform}" = "FreeBSD" ] \
944 || [ "${platform}" = "NetBSD" ] \
945 || [ "${platform}" = "OpenBSD" ]; then
946 release="$(uname -r)"
947 kernel="$($CMD_SYSCTL -n "kern.osrevision")"
948 elif [ "${platform}" = "SunOS" ]; then
949 release="$(head -n1 /etc/release)"
950 if [ -z "${release}" ]; then
951 release="$(uname -r)"
952 fi
953 kernel="$(uname -v)"
954 fi
955 echo "kernel $kernel"
956 echo "release $release"
957}
958
959cpu_and_os_arch () { local PTFUNCNAME=cpu_and_os_arch;
960 local platform="$1"
961
962 local CPU_ARCH='32-bit'
963 local OS_ARCH='32-bit'
964 if [ "${platform}" = "Linux" ]; then
965 if grep -q ' lm ' /proc/cpuinfo; then
966 CPU_ARCH='64-bit'
967 fi
968 elif [ "${platform}" = "FreeBSD" ] || [ "${platform}" = "NetBSD" ]; then
969 if $CMD_SYSCTL "hw.machine_arch" | grep -v 'i[36]86' >/dev/null; then
970 CPU_ARCH='64-bit'
971 fi
972 elif [ "${platform}" = "OpenBSD" ]; then
973 if $CMD_SYSCTL "hw.machine" | grep -v 'i[36]86' >/dev/null; then
974 CPU_ARCH='64-bit'
975 fi
976 elif [ "${platform}" = "SunOS" ]; then
977 if $CMD_ISAINFO -b | grep 64 >/dev/null ; then
978 CPU_ARCH="64-bit"
979 fi
980 fi
981 if [ -z "$CMD_FILE" ]; then
982 if [ "$CMD_GETCONF" ] && $CMD_GETCONF LONG_BIT 1>/dev/null 2>&1; then
983 OS_ARCH="$($CMD_GETCONF LONG_BIT 2>/dev/null)-bit"
984 else
985 OS_ARCH='N/A'
986 fi
987 elif $CMD_FILE /bin/sh | grep '64-bit' >/dev/null; then
988 OS_ARCH='64-bit'
989 fi
990
991 echo "CPU_ARCH $CPU_ARCH"
992 echo "OS_ARCH $OS_ARCH"
993}
994
995find_virtualization () { local PTFUNCNAME=find_virtualization;
996 local platform="$1"
997 local dmesg_file="$2"
998 local lspci_file="$3"
999
1000 local tempfile="$TMPDIR/find_virtualziation.tmp"
1001
1002 local virt=""
1003 if [ -s "$dmesg_file" ]; then
1004 virt="$(find_virtualization_dmesg "$dmesg_file")"
1005 fi
1006 if [ -z "${virt}" ] && [ -s "$lspci_file" ]; then
1007 if grep -qi "virtualbox" "$lspci_file" ; then
1008 virt="VirtualBox"
1009 elif grep -qi "vmware" "$lspci_file" ; then
1010 virt="VMWare"
1011 fi
1012 elif [ "${platform}" = "FreeBSD" ]; then
1013 if ps -o stat | grep J ; then
1014 virt="FreeBSD Jail"
1015 fi
1016 elif [ "${platform}" = "SunOS" ]; then
1017 if [ "$CMD_PRTDIAG" ] && $CMD_PRTDIAG > "$tempfile" 2>/dev/null; then
1018 virt="$(find_virtualization_generic "$tempfile" )"
1019 elif [ "$CMD_SMBIOS" ] && $CMD_SMBIOS > "$tempfile" 2>/dev/null; then
1020 virt="$(find_virtualization_generic "$tempfile" )"
1021 fi
1022 elif [ -e /proc/user_beancounters ]; then
1023 virt="OpenVZ/Virtuozzo"
1024 fi
1025 echo "virt ${virt:-"No virtualization detected"}"
1026}
1027
1028find_virtualization_generic() { local PTFUNCNAME=find_virtualization_generic;
1029 local file="$1"
1030 if grep -i -e "virtualbox" "$file" >/dev/null; then
1031 echo "VirtualBox"
1032 elif grep -i -e "vmware" "$file" >/dev/null; then
1033 echo "VMWare"
1034 fi
1035}
1036
1037find_virtualization_dmesg () { local PTFUNCNAME=find_virtualization_dmesg;
1038 local file="$1"
1039 if grep -qi -e "vmware" -e "vmxnet" -e 'paravirtualized kernel on vmi' "${file}"; then
1040 echo "VMWare";
1041 elif grep -qi -e 'paravirtualized kernel on xen' -e 'Xen virtual console' "${file}"; then
1042 echo "Xen";
1043 elif grep -qi "qemu" "${file}"; then
1044 echo "QEmu";
1045 elif grep -qi 'paravirtualized kernel on KVM' "${file}"; then
1046 echo "KVM";
1047 elif grep -q "VBOX" "${file}"; then
1048 echo "VirtualBox";
1049 elif grep -qi 'hd.: Virtual .., ATA.*drive' "${file}"; then
1050 echo "Microsoft VirtualPC";
1051 fi
1052}
1053
1054dmidecode_system_info () { local PTFUNCNAME=dmidecode_system_info;
1055 if [ "${CMD_DMIDECODE}" ]; then
1056 local vendor="$($CMD_DMIDECODE -s "system-manufacturer" 2>/dev/null | sed 's/ *$//g')"
1057 echo "vendor ${vendor}"
1058 if [ "${vendor}" ]; then
1059 local product="$($CMD_DMIDECODE -s "system-product-name" 2>/dev/null | sed 's/ *$//g')"
1060 local version="$($CMD_DMIDECODE -s "system-version" 2>/dev/null | sed 's/ *$//g')"
1061 local chassis="$($CMD_DMIDECODE -s "chassis-type" 2>/dev/null | sed 's/ *$//g')"
1062 local servicetag="$($CMD_DMIDECODE -s "system-serial-number" 2>/dev/null | sed 's/ *$//g')"
1063 local system="${vendor}; ${product}; v${version} (${chassis})"
1064
1065 echo "system ${system}"
1066 echo "servicetag ${servicetag:-"Not found"}"
1067 fi
1068 fi
1069}
1070
1071find_memory_stats () { local PTFUNCNAME=find_memory_stats;
1072 local platform="$1"
1073
1074 if [ "${platform}" = "Linux" ]; then
1075 free -b
1076 cat /proc/meminfo
1077 elif [ "${platform}" = "SunOS" ]; then
1078 $CMD_PRTCONF | awk -F: '/Memory/{print $2}'
1079 fi
1080}
1081
1082mounted_fs_info () { local PTFUNCNAME=mounted_fs_info;
1083 local platform="$1"
1084
1085 if [ "${platform}" != "SunOS" ]; then
1086 local cmd="df -h"
1087 if [ "${platform}" = "Linux" ]; then
1088 cmd="df -h -P"
1089 fi
1090 $cmd | sort > "$TMPDIR/mounted_fs_info.tmp"
1091 mount | sort | join "$TMPDIR/mounted_fs_info.tmp" -
1092 fi
1093}
1094
1095raid_controller () { local PTFUNCNAME=raid_controller;
1096 local dmesg_file="$1"
1097 local lspci_file="$2"
1098
1099 local tempfile="$TMPDIR/raid_controller.tmp"
1100
1101 local controller=""
1102 if [ -s "$lspci_file" ]; then
1103 controller="$(find_raid_controller_lspci "$lspci_file")"
1104 fi
1105 if [ -z "${controller}" ] && [ -s "$dmesg_file" ]; then
1106 controller="$(find_raid_controller_dmesg "$dmesg_file")"
1107 fi
1108
1109 echo "raid_controller ${controller:-"No RAID controller detected"}"
1110}
1111
1112find_raid_controller_dmesg () { local PTFUNCNAME=find_raid_controller_dmesg;
1113 local file="$1"
1114 local pat='scsi[0-9].*: .*'
1115 if grep -qi "${pat}megaraid" "${file}"; then
1116 echo 'LSI Logic MegaRAID SAS'
1117 elif grep -q "Fusion MPT SAS" "${file}"; then
1118 echo 'Fusion-MPT SAS'
1119 elif grep -q "${pat}aacraid" "${file}"; then
1120 echo 'AACRAID'
1121 elif grep -q "${pat}3ware [0-9]* Storage Controller" "${file}"; then
1122 echo '3Ware'
1123 fi
1124}
1125
1126find_raid_controller_lspci () { local PTFUNCNAME=find_raid_controller_lspci;
1127 local file="$1"
1128 if grep -q "RAID bus controller: LSI Logic / Symbios Logic MegaRAID SAS" "${file}"; then
1129 echo 'LSI Logic MegaRAID SAS'
1130 elif grep -q "Fusion-MPT SAS" "${file}"; then
1131 echo 'Fusion-MPT SAS'
1132 elif grep -q "RAID bus controller: LSI Logic / Symbios Logic Unknown" "${file}"; then
1133 echo 'LSI Logic Unknown'
1134 elif grep -q "RAID bus controller: Adaptec AAC-RAID" "${file}"; then
1135 echo 'AACRAID'
1136 elif grep -q "3ware [0-9]* Storage Controller" "${file}"; then
1137 echo '3Ware'
1138 elif grep -q "Hewlett-Packard Company Smart Array" "${file}"; then
1139 echo 'HP Smart Array'
1140 elif grep -q " RAID bus controller: " "${file}"; then
1141 awk -F: '/RAID bus controller\:/ {print $3" "$5" "$6}' "${file}"
1142 fi
1143}
1144
1145schedulers_and_queue_size () { local PTFUNCNAME=schedulers_and_queue_size;
1146 local file="$1"
1147
1148 local disks="$(ls /sys/block/ | grep -v -e ram -e loop -e 'fd[0-9]' | xargs echo)"
1149 echo "internal::disks $disks" >> "$file"
1150
1151 for disk in $disks; do
1152 if [ -e "/sys/block/${disk}/queue/scheduler" ]; then
1153 echo "internal::${disk} $(cat /sys/block/${disk}/queue/scheduler | grep -o '\[.*\]') $(cat /sys/block/${disk}/queue/nr_requests)" >> "$file"
1154 fdisk -l "/dev/${disk}" 2>/dev/null
1155 fi
1156 done
1157}
1158
1159top_processes () { local PTFUNCNAME=top_processes;
1160 if [ "$CMD_PRSTAT" ]; then
1161 $CMD_PRSTAT | head
1162 elif [ "$CMD_TOP" ]; then
1163 local cmd="$CMD_TOP -bn 1"
1164 if [ "${platform}" = "FreeBSD" ] \
1165 || [ "${platform}" = "NetBSD" ] \
1166 || [ "${platform}" = "OpenBSD" ]; then
1167 cmd="$CMD_TOP -b -d 1"
1168 fi
1169 $cmd \
1170 | sed -e 's# *$##g' -e '/./{H;$!d;}' -e 'x;/PID/!d;' \
1171 | grep . \
1172 | head
1173 fi
1174}
1175
1176notable_processes_info () { local PTFUNCNAME=notable_processes_info;
1177 local format="%5s %+2d %s\n"
1178 local sshd_pid=$(ps -eo pid,args | awk '$2 ~ /\/usr\/sbin\/sshd/ { print $1; exit }')
1179
1180 echo " PID OOM COMMAND"
1181
1182 if [ "$sshd_pid" ]; then
1183 printf "$format" "$sshd_pid" "$(get_oom_of_pid $sshd_pid)" "sshd"
1184 else
1185 printf "%5s %3s %s\n" "?" "?" "sshd doesn't appear to be running"
1186 fi
1187
1188 local PTDEBUG=""
1189 ps -eo pid,ucomm | grep '^[0-9]' | while read pid proc; do
1190 [ "$sshd_pid" ] && [ "$sshd_pid" = "$pid" ] && continue
1191 local oom="$(get_oom_of_pid $pid)"
1192 if [ "$oom" ] && [ "$oom" != "?" ] && [ "$oom" = "-17" ]; then
1193 printf "$format" "$pid" "$oom" "$proc"
1194 fi
1195 done
1196}
1197
1198processor_info () { local PTFUNCNAME=processor_info;
1199 local data_dir="$1"
1200 if [ -f /proc/cpuinfo ]; then
1201 cat /proc/cpuinfo > "$data_dir/proc_cpuinfo_copy" 2>/dev/null
1202 elif [ "${platform}" = "SunOS" ]; then
1203 $CMD_PSRINFO -v > "$data_dir/psrinfo_minus_v"
1204 fi
1205}
1206
1207propietary_raid_controller () { local PTFUNCNAME=propietary_raid_controller;
1208 local file="$1"
1209 local variable_file="$2"
1210 local data_dir="$3"
1211 local controller="$4"
1212
1213 notfound=""
1214 if [ "${controller}" = "AACRAID" ]; then
1215 if [ -z "$CMD_ARCCONF" ]; then
1216 notfound="e.g. http://www.adaptec.com/en-US/support/raid/scsi_raid/ASR-2120S/"
1217 elif $CMD_ARCCONF getconfig 1 > "$file" 2>/dev/null; then
1218 echo "internal::raid_opt 1" >> "$variable_file"
1219 fi
1220 elif [ "${controller}" = "HP Smart Array" ]; then
1221 if [ -z "$CMD_HPACUCLI" ]; then
1222 notfound="your package repository or the manufacturer's website"
1223 elif $CMD_HPACUCLI ctrl all show config > "$file" 2>/dev/null; then
1224 echo "internal::raid_opt 2" >> "$variable_file"
1225 fi
1226 elif [ "${controller}" = "LSI Logic MegaRAID SAS" ]; then
1227 if [ -z "$CMD_MEGACLI64" ]; then
1228 notfound="your package repository or the manufacturer's website"
1229 else
1230 echo "internal::raid_opt 3" >> "$variable_file"
1231 $CMD_MEGACLI64 -AdpAllInfo -aALL -NoLog > "$data_dir/lsi_megaraid_adapter_info.tmp" 2>/dev/null
1232 $CMD_MEGACLI64 -AdpBbuCmd -GetBbuStatus -aALL -NoLog > "$data_dir/lsi_megaraid_bbu_status.tmp" 2>/dev/null
1233 $CMD_MEGACLI64 -LdPdInfo -aALL -NoLog > "$data_dir/lsi_megaraid_devices.tmp" 2>/dev/null
1234 fi
1235 fi
1236
1237 if [ "${notfound}" ]; then
1238 echo "internal::raid_opt 0" >> "$variable_file"
1239 echo " RAID controller software not found; try getting it from" > "$file"
1240 echo " ${notfound}" >> "$file"
1241 fi
1242}
1243
1244# ###########################################################################
1245# End collect_system_info package
1246# ###########################################################################
1247
1248# ###########################################################################
1249# report_system_info package
1250# This package is a copy without comments from the original. The original
1251# with comments and its test file can be found in the Bazaar repository at,
1252# lib/bash/report_system_info.sh
1253# t/lib/bash/report_system_info.sh
1254# See https://launchpad.net/percona-toolkit for more information.
1255# ###########################################################################
1256
1257
1258set -u
1259
172 1260
173# ##############################################################################1261parse_proc_cpuinfo () { local PTFUNCNAME=parse_proc_cpuinfo;
174# Parse Linux's /proc/cpuinfo, which should be stored in $TMPDIR/percona-toolkit.1262 local file="$1"
175# ##############################################################################1263 local virtual="$(grep -c ^processor "${file}")";
176parse_proc_cpuinfo () {1264 local physical="$(grep 'physical id' "${file}" | sort -u | wc -l)";
177 local file=$11265 local cores="$(grep 'cpu cores' "${file}" | head -n 1 | cut -d: -f2)";
178 # Physical processors are indicated by distinct 'physical id'. Virtual CPUs1266
179 # are indicated by paragraphs -- one per paragraph. We assume that all1267 [ "${physical}" = "0" ] && physical="${virtual}"
180 # processors are identical, i.e. that there are not some processors with dual1268 [ -z "${cores}" ] && cores=0
181 # cores and some with quad cores.1269
182 virtual=$(grep -c ^processor $file);
183 physical=$(grep 'physical id' $file | sort -u | wc -l);
184 cores=$(grep 'cpu cores' $file | head -n 1 | cut -d: -f2);
185
186 # Older kernel won't have 'physical id' or 'cpu cores'.
187 if [ "${physical}" = "0" ]; then physical=${virtual}; fi
188 if [ -z "${cores}" ]; then cores=0; fi
189
190 # Test for HTT; cannot trust the 'ht' flag. If physical * cores < virtual,
191 # then hyperthreading is in use.
192 cores=$((${cores} * ${physical}));1270 cores=$((${cores} * ${physical}));
1271 local htt=""
193 if [ ${cores} -gt 0 -a $cores -lt $virtual ]; then htt=yes; else htt=no; fi1272 if [ ${cores} -gt 0 -a $cores -lt $virtual ]; then htt=yes; else htt=no; fi
1941273
195 name_val "Processors" "physical = ${physical}, cores = ${cores}, virtual = ${virtual}, hyperthreading = ${htt}"1274 name_val "Processors" "physical = ${physical}, cores = ${cores}, virtual = ${virtual}, hyperthreading = ${htt}"
1961275
197 awk -F: '/cpu MHz/{print $2}' $file \1276 awk -F: '/cpu MHz/{print $2}' "${file}" \
198 | sort | uniq -c > "$file.unq"1277 | sort | uniq -c > "$TMPDIR/parse_proc_cpuinfo_cpu.unq"
199 name_val "Speeds" "$(group_concat "$file.unq")"1278 name_val "Speeds" "$(group_concat "$TMPDIR/parse_proc_cpuinfo_cpu.unq")"
2001279
201 awk -F: '/model name/{print $2}' $file \1280 awk -F: '/model name/{print $2}' "${file}" \
202 | sort | uniq -c > "$file.unq"1281 | sort | uniq -c > "$TMPDIR/parse_proc_cpuinfo_model.unq"
203 name_val "Models" "$(group_concat "$file.unq")"1282 name_val "Models" "$(group_concat "$TMPDIR/parse_proc_cpuinfo_model.unq")"
2041283
205 awk -F: '/cache size/{print $2}' $file \1284 awk -F: '/cache size/{print $2}' "${file}" \
206 | sort | uniq -c > "$file.unq"1285 | sort | uniq -c > "$TMPDIR/parse_proc_cpuinfo_cache.unq"
207 name_val "Caches" "$(group_concat "$file.unq")"1286 name_val "Caches" "$(group_concat "$TMPDIR/parse_proc_cpuinfo_cache.unq")"
208}1287}
2091288
210# ##############################################################################1289parse_sysctl_cpu_freebsd() { local PTFUNCNAME=parse_sysctl_cpu_freebsd;
211# Parse sysctl -a output on FreeBSD, and format it as CPU info. The file is the1290 local file="$1"
212# first argument.1291 [ -e "$file" ] || return;
213# ##############################################################################1292 local virtual="$(awk '/hw.ncpu/{print $2}' "$file")"
214parse_sysctl_cpu_freebsd() {1293 name_val "Processors" "virtual = ${virtual}"
215 virtual="$(awk '/hw.ncpu/{print $2}' "$1")"1294 name_val "Speeds" "$(awk '/hw.clockrate/{print $2}' "$file")"
216 name_val "Processors" "virtual = ${virtual}"1295 name_val "Models" "$(awk -F: '/hw.model/{print substr($2, 2)}' "$file")"
217 name_val "Speeds" "$(awk '/hw.clockrate/{print $2}' "$1")"1296}
218 name_val "Models" "$(awk -F: '/hw.model/{print substr($2, 2)}' "$1")"1297
219}1298parse_sysctl_cpu_netbsd() { local PTFUNCNAME=parse_sysctl_cpu_netbsd;
2201299 local file="$1"
221# ##############################################################################1300
222# Parse CPU info from psrinfo -v1301 [ -e "$file" ] || return
223# ##############################################################################1302
224parse_psrinfo_cpus() {1303 local virtual="$(awk '/hw.ncpu /{print $NF}' "$file")"
225 name_val Processors $(grep -c 'Status of .* processor' "$1")1304 name_val "Processors" "virtual = ${virtual}"
1305 name_val "Models" "$(awk -F: '/hw.model/{print $3}' "$file")"
1306}
1307
1308parse_sysctl_cpu_openbsd() { local PTFUNCNAME=parse_sysctl_cpu_openbsd;
1309 local file="$1"
1310
1311 [ -e "$file" ] || return
1312
1313 name_val "Processors" "$(awk -F= '/hw.ncpu=/{print $2}' "$file")"
1314 name_val "Speeds" "$(awk -F= '/hw.cpuspeed/{print $2}' "$file")"
1315 name_val "Models" "$(awk -F= '/hw.model/{print substr($2, 1, index($2, " "))}' "$file")"
1316}
1317
1318parse_psrinfo_cpus() { local PTFUNCNAME=parse_psrinfo_cpus;
1319 local file="$1"
1320
1321 [ -e "$file" ] || return
1322
1323 name_val "Processors" "$(grep -c 'Status of .* processor' "$file")"
226 awk '/operates at/ {1324 awk '/operates at/ {
227 start = index($0, " at ") + 4;1325 start = index($0, " at ") + 4;
228 end = length($0) - start - 41326 end = length($0) - start - 4
229 print substr($0, start, end);1327 print substr($0, start, end);
230 }' "$1" | sort | uniq -c > $TMPDIR/percona-toolkit21328 }' "$file" | sort | uniq -c > "$TMPDIR/parse_psrinfo_cpus.tmp"
231 name_val "Speeds" "$(group_concat $TMPDIR/percona-toolkit2)"1329 name_val "Speeds" "$(group_concat "$TMPDIR/parse_psrinfo_cpus.tmp")"
232}1330}
2331331
234# ##############################################################################1332parse_free_minus_b () { local PTFUNCNAME=parse_free_minus_b;
235# Parse the output of 'free -b' plus the contents of /proc/meminfo1333 local file="$1"
236# ##############################################################################1334
237parse_free_minus_b () {1335 [ -e "$file" ] || return
238 local file=$1
2391336
240 local physical=$(awk '/Mem:/{print $3}' "${file}")1337 local physical=$(awk '/Mem:/{print $3}' "${file}")
241 local swap=$(awk '/Swap:/{print $3}' "${file}")1338 local swap_alloc=$(awk '/Swap:/{print $2}' "${file}")
242 local virtual=$(shorten $(($physical + $swap)))1339 local swap_used=$(awk '/Swap:/{print $3}' "${file}")
1340 local virtual=$(shorten $(($physical + $swap_used)) 1)
2431341
244 name_val Total $(shorten $(awk '/Mem:/{print $2}' "${file}"))1342 name_val "Total" $(shorten $(awk '/Mem:/{print $2}' "${file}") 1)
245 name_val Free $(shorten $(awk '/Mem:/{print $4}' "${file}"))1343 name_val "Free" $(shorten $(awk '/Mem:/{print $4}' "${file}") 1)
246 name_val Used "physical = $(shorten ${physical}), swap = $(shorten ${swap}), virtual = ${virtual}"1344 name_val "Used" "physical = $(shorten ${physical} 1), swap allocated = $(shorten ${swap_alloc} 1), swap used = $(shorten ${swap_used} 1), virtual = ${virtual}"
247 name_val Buffers $(shorten $(awk '/Mem:/{print $6}' "${file}"))1345 name_val "Buffers" $(shorten $(awk '/Mem:/{print $6}' "${file}") 1)
248 name_val Caches $(shorten $(awk '/Mem:/{print $7}' "${file}"))1346 name_val "Caches" $(shorten $(awk '/Mem:/{print $7}' "${file}") 1)
249 name_val Dirty "$(awk '/Dirty:/ {print $2, $3}' "${file}")"1347 name_val "Dirty" "$(awk '/Dirty:/ {print $2, $3}' "${file}")"
250}1348}
2511349
252# ##############################################################################1350parse_memory_sysctl_freebsd() { local PTFUNCNAME=parse_memory_sysctl_freebsd;
253# Parse FreeBSD memory info from sysctl output.1351 local file="$1"
254# ##############################################################################1352
255parse_memory_sysctl_freebsd() {1353 [ -e "$file" ] || return
256 physical=$(awk '/hw.realmem:/{print $2}' "${1}")1354
257 mem_hw=$(awk '/hw.physmem:/{print $2}' "${1}")1355 local physical=$(awk '/hw.realmem:/{print $2}' "${file}")
258 mem_used=$(awk '1356 local mem_hw=$(awk '/hw.physmem:/{print $2}' "${file}")
1357 local mem_used=$(awk '
259 /hw.physmem/ { mem_hw = $2; }1358 /hw.physmem/ { mem_hw = $2; }
260 /vm.stats.vm.v_inactive_count/ { mem_inactive = $2; }1359 /vm.stats.vm.v_inactive_count/ { mem_inactive = $2; }
261 /vm.stats.vm.v_cache_count/ { mem_cache = $2; }1360 /vm.stats.vm.v_cache_count/ { mem_cache = $2; }
@@ -267,50 +1366,66 @@
267 mem_free *= pagesize;1366 mem_free *= pagesize;
268 print mem_hw - mem_inactive - mem_cache - mem_free;1367 print mem_hw - mem_inactive - mem_cache - mem_free;
269 }1368 }
270 ' "$1");1369 ' "$file");
271 name_val Total $(shorten ${mem_hw} 1)1370 name_val "Total" $(shorten ${mem_hw} 1)
272 name_val Virtual $(shorten ${physical} 1)1371 name_val "Virtual" $(shorten ${physical} 1)
273 name_val Used $(shorten ${mem_used} 1)1372 name_val "Used" $(shorten ${mem_used} 1)
274}1373}
2751374
276# ##############################################################################1375parse_memory_sysctl_netbsd() { local PTFUNCNAME=parse_memory_sysctl_netbsd;
277# Parse memory devices from the output of 'dmidecode'.1376 local file="$1"
278# ##############################################################################1377 local swapctl_file="$2"
279parse_dmidecode_mem_devices () {1378
280 local file=$11379 [ -e "$file" -a -e "$swapctl_file" ] || return
1380
1381 local swap_mem="$(echo "$(awk '{print $2;}' "$swapctl_file")*512" | bc -l)"
1382 name_val "Total" $(shorten "$(awk '/hw.physmem /{print $NF}' "$file")" 1)
1383 name_val "User" $(shorten "$(awk '/hw.usermem /{print $NF}' "$file")" 1)
1384 name_val "Swap" $(shorten ${swap_mem} 1)
1385}
1386
1387parse_memory_sysctl_openbsd() { local PTFUNCNAME=parse_memory_sysctl_openbsd;
1388 local file="$1"
1389 local swapctl_file="$2"
1390
1391 [ -e "$file" -a -e "$swapctl_file" ] || return
1392
1393 local swap_mem="$(echo "$(awk '{print $2;}' "$swapctl_file")*512" | bc -l)"
1394 name_val "Total" $(shorten "$(awk -F= '/hw.physmem/{print $2}' "$file")" 1)
1395 name_val "User" $(shorten "$(awk -F= '/hw.usermem/{print $2}' "$file")" 1)
1396 name_val "Swap" $(shorten ${swap_mem} 1)
1397}
1398
1399parse_dmidecode_mem_devices () { local PTFUNCNAME=parse_dmidecode_mem_devices;
1400 local file="$1"
1401
1402 [ -e "$file" ] || return
1403
281 echo " Locator Size Speed Form Factor Type Type Detail"1404 echo " Locator Size Speed Form Factor Type Type Detail"
282 echo " ========= ======== ================= ============= ============= ==========="1405 echo " ========= ======== ================= ============= ============= ==========="
283 # Print paragraphs containing 'Memory Device\n', extract the desired bits,
284 # concatenate them into one long line, then format as a table. The data
285 # comes out in this order for each paragraph:
286 # $2 Size 2048 MB
287 # $3 Form Factor <OUT OF SPEC>
288 # $4 Locator DIMM1
289 # $5 Type <OUT OF SPEC>
290 # $6 Type Detail Synchronous
291 # $7 Speed 667 MHz (1.5 ns)
292 sed -e '/./{H;$!d;}' \1406 sed -e '/./{H;$!d;}' \
293 -e 'x;/Memory Device\n/!d;' \1407 -e 'x;/Memory Device\n/!d;' \
294 -e 's/: /:/g' \1408 -e 's/: /:/g' \
295 -e 's/</{/g' \1409 -e 's/</{/g' \
296 -e 's/>/}/g' \1410 -e 's/>/}/g' \
297 -e 's/[ \t]*\n/\n/g' \1411 -e 's/[ \t]*\n/\n/g' \
298 $file \1412 "${file}" \
299 | awk -F: '/Size|Type|Form.Factor|Type.Detail|[^ ]Locator/{printf("|%s", $2)}/Speed/{print "|" $2}' \1413 | awk -F: '/Size|Type|Form.Factor|Type.Detail|[^ ]Locator/{printf("|%s", $2)}/Speed/{print "|" $2}' \
300 | sed -e 's/No Module Installed/{EMPTY}/' \1414 | sed -e 's/No Module Installed/{EMPTY}/' \
301 | sort \1415 | sort \
302 | awk -F'|' '{printf(" %-9s %-8s %-17s %-13s %-13s %-8s\n", $4, $2, $7, $3, $5, $6);}'1416 | awk -F'|' '{printf(" %-9s %-8s %-17s %-13s %-13s %-8s\n", $4, $2, $7, $3, $5, $6);}'
303}1417}
3041418
305# ##############################################################################1419parse_ip_s_link () { local PTFUNCNAME=parse_ip_s_link;
306# Parse the output of 'netstat -antp'1420 local file="$1"
307# ##############################################################################1421
308parse_ip_s_link () {1422 [ -e "$file" ] || return
1423
309 echo " interface rx_bytes rx_packets rx_errors tx_bytes tx_packets tx_errors"1424 echo " interface rx_bytes rx_packets rx_errors tx_bytes tx_packets tx_errors"
310 echo " ========= ========= ========== ========== ========== ========== =========="1425 echo " ========= ========= ========== ========== ========== ========== =========="
3111426
312 awk "/^[1-9][0-9]*:/ {1427 awk "/^[1-9][0-9]*:/ {
313 save[\"iface\"] = substr(\$2, 0, index(\$2, \":\") - 1);1428 save[\"iface\"] = substr(\$2, 1, index(\$2, \":\") - 1);
314 new = 1;1429 new = 1;
315 }1430 }
316 \$0 !~ /[^0-9 ]/ {1431 \$0 !~ /[^0-9 ]/ {
@@ -324,20 +1439,48 @@
324 fuzzy_var = \$1; ${fuzzy_formula} tx_bytes = fuzzy_var;1439 fuzzy_var = \$1; ${fuzzy_formula} tx_bytes = fuzzy_var;
325 fuzzy_var = \$2; ${fuzzy_formula} tx_packets = fuzzy_var;1440 fuzzy_var = \$2; ${fuzzy_formula} tx_packets = fuzzy_var;
326 fuzzy_var = \$3; ${fuzzy_formula} tx_errors = fuzzy_var;1441 fuzzy_var = \$3; ${fuzzy_formula} tx_errors = fuzzy_var;
327 printf \" %-8s %10d %10d %10d %10d %10d %10d\\n\", save[\"iface\"], save[\"bytes\"], save[\"packs\"], save[\"errs\"], tx_bytes, tx_packets, tx_errors;1442 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;
328 }1443 }
329 }" $@1444 }" "$file"
330}1445}
3311446
332# ##############################################################################1447parse_ethtool () {
333# Parse the output of 'netstat -antp' which should be in $TMPDIR/percona-toolkit.1448 local file="$1"
334# ##############################################################################1449
335parse_netstat () {1450 [ -e "$file" ] || return
336 local file=$11451
1452 echo " Device Speed Duplex"
1453 echo " ========= ========= ========="
1454
1455
1456 awk '
1457 /^Settings for / {
1458 device = substr($3, 1, index($3, ":") ? index($3, ":")-1 : length($3));
1459 device_names[device] = device;
1460 }
1461 /Speed:/ { devices[device ",speed"] = $2 }
1462 /Duplex:/ { devices[device ",duplex"] = $2 }
1463 END {
1464 for ( device in device_names ) {
1465 printf(" %-10s %-10s %-10s\n",
1466 device,
1467 devices[device ",speed"],
1468 devices[device ",duplex"]);
1469 }
1470 }
1471 ' "$file"
1472
1473}
1474
1475parse_netstat () { local PTFUNCNAME=parse_netstat;
1476 local file="$1"
1477
1478 [ -e "$file" ] || return
1479
337 echo " Connections from remote IP addresses"1480 echo " Connections from remote IP addresses"
338 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {1481 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
339 print substr($5, 0, index($5, ":") - 1);1482 print substr($5, 1, index($5, ":") - 1);
340 }' $file | sort | uniq -c \1483 }' "${file}" | sort | uniq -c \
341 | awk "{1484 | awk "{
342 fuzzy_var=\$1;1485 fuzzy_var=\$1;
343 ${fuzzy_formula}1486 ${fuzzy_formula}
@@ -346,8 +1489,8 @@
346 | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,41489 | sort -n -t . -k 1,1 -k 2,2 -k 3,3 -k 4,4
347 echo " Connections to local IP addresses"1490 echo " Connections to local IP addresses"
348 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {1491 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
349 print substr($4, 0, index($4, ":") - 1);1492 print substr($4, 1, index($4, ":") - 1);
350 }' $file | sort | uniq -c \1493 }' "${file}" | sort | uniq -c \
351 | awk "{1494 | awk "{
352 fuzzy_var=\$1;1495 fuzzy_var=\$1;
353 ${fuzzy_formula}1496 ${fuzzy_formula}
@@ -357,7 +1500,7 @@
357 echo " Connections to top 10 local ports"1500 echo " Connections to top 10 local ports"
358 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {1501 awk '$1 ~ /^tcp/ && $5 ~ /^[1-9]/ {
359 print substr($4, index($4, ":") + 1);1502 print substr($4, index($4, ":") + 1);
360 }' $file | sort | uniq -c | sort -rn | head -n10 \1503 }' "${file}" | sort | uniq -c | sort -rn | head -n10 \
361 | awk "{1504 | awk "{
362 fuzzy_var=\$1;1505 fuzzy_var=\$1;
363 ${fuzzy_formula}1506 ${fuzzy_formula}
@@ -366,7 +1509,7 @@
366 echo " States of connections"1509 echo " States of connections"
367 awk '$1 ~ /^tcp/ {1510 awk '$1 ~ /^tcp/ {
368 print $6;1511 print $6;
369 }' $file | sort | uniq -c | sort -rn \1512 }' "${file}" | sort | uniq -c | sort -rn \
370 | awk "{1513 | awk "{
371 fuzzy_var=\$1;1514 fuzzy_var=\$1;
372 ${fuzzy_formula}1515 ${fuzzy_formula}
@@ -374,19 +1517,13 @@
374 }" | sort1517 }" | sort
375}1518}
3761519
377# ##############################################################################1520parse_filesystems () { local PTFUNCNAME=parse_filesystems;
378# Parse the joined output of 'mount' and 'df -hP'. $1 = file; $2 = ostype.1521 local file="$1"
379# ##############################################################################1522 local platform="$2"
380parse_filesystems () {1523
381 # Filesystem names and mountpoints can be very long. We try to align things1524 [ -e "$file" ] || return
382 # as nicely as possible by making columns only as wide as needed. This1525
383 # requires two passes through the file. The first pass finds the max size of1526 local spec="$(awk "
384 # these columns and prints out a printf spec, and the second prints out the
385 # file nicely aligned.
386 local file=$1
387 local platform=$2
388
389 local spec=$(awk "
390 BEGIN {1527 BEGIN {
391 device = 10;1528 device = 10;
392 fstype = 4;1529 fstype = 4;
@@ -396,7 +1533,7 @@
396 f_device = \$1;1533 f_device = \$1;
397 f_fstype = \$10;1534 f_fstype = \$10;
398 f_options = substr(\$11, 2, length(\$11) - 2);1535 f_options = substr(\$11, 2, length(\$11) - 2);
399 if ( \"$2\" == \"FreeBSD\" ) {1536 if ( \"$2\" ~ /(Free|Open|Net)BSD/ ) {
400 f_fstype = substr(\$9, 2, length(\$9) - 2);1537 f_fstype = substr(\$9, 2, length(\$9) - 2);
401 f_options = substr(\$0, index(\$0, \",\") + 2);1538 f_options = substr(\$0, index(\$0, \",\") + 2);
402 f_options = substr(f_options, 1, length(f_options) - 1);1539 f_options = substr(f_options, 1, length(f_options) - 1);
@@ -414,7 +1551,7 @@
414 END{1551 END{
415 print \"%-\" device \"s %5s %4s %-\" fstype \"s %-\" options \"s %s\";1552 print \"%-\" device \"s %5s %4s %-\" fstype \"s %-\" options \"s %s\";
416 }1553 }
417 " $file)1554 " "${file}")"
4181555
419 awk "1556 awk "
420 BEGIN {1557 BEGIN {
@@ -424,22 +1561,21 @@
424 {1561 {
425 f_fstype = \$10;1562 f_fstype = \$10;
426 f_options = substr(\$11, 2, length(\$11) - 2);1563 f_options = substr(\$11, 2, length(\$11) - 2);
427 if ( \"$2\" == \"FreeBSD\" ) {1564 if ( \"$2\" ~ /(Free|Open|Net)BSD/ ) {
428 f_fstype = substr(\$9, 2, length(\$9) - 2);1565 f_fstype = substr(\$9, 2, length(\$9) - 2);
429 f_options = substr(\$0, index(\$0, \",\") + 2);1566 f_options = substr(\$0, index(\$0, \",\") + 2);
430 f_options = substr(f_options, 1, length(f_options) - 1);1567 f_options = substr(f_options, 1, length(f_options) - 1);
431 }1568 }
432 printf spec, \$1, \$2, \$5, f_fstype, f_options, \$6;1569 printf spec, \$1, \$2, \$5, f_fstype, f_options, \$6;
433 }1570 }
434 " $file1571 " "${file}"
435}1572}
4361573
437# ##############################################################################1574parse_fdisk () { local PTFUNCNAME=parse_fdisk;
438# Parse the output of fdisk -l, which should be in $TMPDIR/percona-toolkit; there might be1575 local file="$1"
439# multiple fdisk -l outputs in the file.1576
440# ##############################################################################1577 [ -e "$file" -a -s "$file" ] || return
441parse_fdisk () {1578
442 local file=$1
443 awk '1579 awk '
444 BEGIN {1580 BEGIN {
445 format="%-12s %4s %10s %10s %18s\n";1581 format="%-12s %4s %10s %10s %18s\n";
@@ -465,128 +1601,55 @@
465 }1601 }
466 printf(format, $1, "Part", start, end, sprintf("%.0f", (end - start) * units));1602 printf(format, $1, "Part", start, end, sprintf("%.0f", (end - start) * units));
467 }1603 }
468 ' $file
469}
470
471# ##############################################################################
472# Parse the output of dmesg, which should be in $TMPDIR/percona-toolkit, and detect
473# virtualization.
474# ##############################################################################
475parse_virtualization_dmesg () {
476 local file=$1
477 if grep -qi -e vmware -e vmxnet -e 'paravirtualized kernel on vmi' $file; then
478 echo "VMWare";
479 elif grep -qi -e 'paravirtualized kernel on xen' -e 'Xen virtual console' $file; then
480 echo "Xen";
481 elif grep -qi qemu $file; then
482 echo "QEmu";
483 elif grep -qi 'paravirtualized kernel on KVM' $file; then
484 echo "KVM";
485 elif grep -q VBOX $file; then
486 echo "VirtualBox";
487 elif grep -qi 'hd.: Virtual .., ATA.*drive' $file; then
488 echo "Microsoft VirtualPC";
489 fi
490}
491
492# ##############################################################################
493# Try to figure out if a system is a guest by looking at prtdiag, smbios, etc.
494# ##############################################################################
495parse_virtualization_generic() {
496 if grep -i -e virtualbox "$1" >/dev/null; then
497 echo VirtualBox
498 elif grep -i -e vmware "$1" >/dev/null; then
499 echo VMWare
500 fi
501}
502
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches