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