~percona-toolkit-dev/percona-toolkit/fix-empty-table-bug-987393

« back to all changes in this revision

Viewing changes to lib/bash/report_mysql_info.sh

  • Committer: Daniel Nichter
  • Date: 2012-04-03 16:14:55 UTC
  • mfrom: (217.6.22 2.0.3)
  • Revision ID: daniel@percona.com-20120403161455-ntv33vju9o6njtqv
Merge summary-tools-2.1.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# This program is copyright 2011 Percona Inc.
 
2
# Feedback and improvements are welcome.
 
3
#
 
4
# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 
5
# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 
6
# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 
7
#
 
8
# This program is free software; you can redistribute it and/or modify it under
 
9
# the terms of the GNU General Public License as published by the Free Software
 
10
# Foundation, version 2; OR the Perl Artistic License.  On UNIX and similar
 
11
# systems, you can issue `man perlgpl' or `man perlartistic' to read these
 
12
# licenses.
 
13
#
 
14
# You should have received a copy of the GNU General Public License along with
 
15
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 
16
# Place, Suite 330, Boston, MA  02111-1307  USA.
 
17
# ###########################################################################
 
18
# report_mysql_info package
 
19
# ###########################################################################
 
20
 
 
21
# Package: report_mysql_info
 
22
# Report various aspects of MySQL
 
23
 
 
24
set -u
 
25
POSIXLY_CORRECT=1
 
26
 
 
27
# Accepts a number of seconds, and outputs a d+h:m:s formatted string
 
28
secs_to_time () {
 
29
   awk -v sec="$1" 'BEGIN {
 
30
      printf( "%d+%02d:%02d:%02d", sec / 86400, (sec % 86400) / 3600, (sec % 3600) / 60, sec % 60);
 
31
   }'
 
32
}
 
33
 
 
34
# Returns "Enabled", "Disabled", or "Not Supported" depending on whether the
 
35
# variable exists and is ON or enabled.  You can pass 2nd and 3rd variables to
 
36
# control whether the variable should be 'gt' (numeric greater than) or 'eq'
 
37
# (string equal) to some value.
 
38
feat_on() {
 
39
   local file="$1"
 
40
   local varname="$2"
 
41
   [ -e "$file" ] || return
 
42
 
 
43
   if [ "$( get_var "$varname" "${file}" )" ]; then
 
44
      local var="$(awk "\$1 ~ /^$2$/ { print \$2 }" $file)"
 
45
      if [ "${var}" = "ON" ]; then
 
46
         echo "Enabled"
 
47
      elif [ "${var}" = "OFF" -o "${var}" = "0" -o -z "${var}" ]; then
 
48
         echo "Disabled"
 
49
      elif [ "$3" = "ne" ]; then
 
50
         if [ "${var}" != "$4" ]; then
 
51
            echo "Enabled"
 
52
         else
 
53
            echo "Disabled"
 
54
         fi
 
55
      elif [ "$3" = "gt" ]; then
 
56
         if [ "${var}" -gt "$4" ]; then
 
57
            echo "Enabled"
 
58
         else
 
59
            echo "Disabled"
 
60
         fi
 
61
      elif [ "${var}" ]; then
 
62
         echo "Enabled"
 
63
      else
 
64
         echo "Disabled"
 
65
      fi
 
66
   else
 
67
      echo "Not Supported"
 
68
   fi
 
69
}
 
70
 
 
71
get_table_cache () {
 
72
   local file="$1"
 
73
 
 
74
   [ -e "$file" ] || return
 
75
 
 
76
   local table_cache=""
 
77
   if [ "$( get_var table_open_cache "${file}" )" ]; then
 
78
      table_cache="$(get_var table_open_cache "${file}")"
 
79
   else
 
80
      table_cache="$(get_var table_cache "${file}")"
 
81
   fi
 
82
   echo ${table_cache:-0}
 
83
}
 
84
 
 
85
# Gets the status of a plugin, or returns "Not found"
 
86
get_plugin_status () {
 
87
   local file="$1"
 
88
   local plugin="$2"
 
89
 
 
90
   local status="$(grep -w "$plugin" "$file" | awk '{ print $2 }')"
 
91
 
 
92
   echo ${status:-"Not found"}
 
93
}
 
94
 
 
95
# ##############################################################################
 
96
# Functions for parsing specific files and getting desired info from them.
 
97
# These are called from within main() and are separated so they can be tested
 
98
# easily.
 
99
# ##############################################################################
 
100
 
 
101
# Parses the output of 'ps -e -o args | grep mysqld' or 'ps auxww...'
 
102
_NO_FALSE_NEGATIVES=""
 
103
parse_mysqld_instances () {
 
104
   local file="$1"
 
105
   local variables_file="$2"
 
106
 
 
107
   local socket=${socket:-""}
 
108
   local port=${port:-""}
 
109
   local datadir="${datadir:-""}"
 
110
 
 
111
   [ -e "$file" ] || return
 
112
 
 
113
   echo "  Port  Data Directory             Nice OOM Socket"
 
114
   echo "  ===== ========================== ==== === ======"
 
115
 
 
116
   grep '/mysqld ' "$file" | while read line; do
 
117
      local pid=$(echo "$line" | awk '{print $1;}')
 
118
      for word in ${line}; do
 
119
         # Some grep doesn't have -o, so I have to pull out the words I want by
 
120
         # looking at each word
 
121
         if echo "${word}" | grep -- "--socket=" > /dev/null; then
 
122
            socket="$(echo "${word}" | cut -d= -f2)"
 
123
         fi
 
124
         if echo "${word}" | grep -- "--port=" > /dev/null; then
 
125
            port="$(echo "${word}" | cut -d= -f2)"
 
126
         fi
 
127
         if echo "${word}" | grep -- "--datadir=" > /dev/null; then
 
128
            datadir="$(echo "${word}" | cut -d= -f2)"
 
129
         fi
 
130
      done
 
131
      local nice="$(get_var "internal::nice_of_$pid" "$variables_file")"
 
132
      local oom="$(get_var "internal::oom_of_$pid" "$variables_file")"
 
133
      # Only used during testing
 
134
      if [ -n "${_NO_FALSE_NEGATIVES}" ]; then
 
135
         nice="?"
 
136
         oom="?"
 
137
      fi
 
138
      printf "  %5s %-26s %-4s %-3s %s\n" "${port}" "${datadir}" "${nice:-"?"}" "${oom:-"?"}" "${socket}"
 
139
   done
 
140
}
 
141
 
 
142
# Gets the MySQL system time.  Uses input from $MYSQL_VARIABLES_FILE.
 
143
get_mysql_timezone () {
 
144
   local file="$1"
 
145
 
 
146
   [ -e "$file" ] || return
 
147
 
 
148
   local tz="$(get_var time_zone "${file}")"
 
149
   if [ "${tz}" = "SYSTEM" ]; then
 
150
      tz="$(get_var system_time_zone "${file}")"
 
151
   fi
 
152
   echo "${tz}"
 
153
}
 
154
 
 
155
# Gets the MySQL system version.
 
156
get_mysql_version () {
 
157
   local file="$1"
 
158
 
 
159
   name_val Version "$(get_var version "${file}") $(get_var version_comment "${file}")"
 
160
   name_val "Built On" "$(get_var version_compile_os "${file}") $(get_var version_compile_machine "${file}")"
 
161
}
 
162
 
 
163
# Gets the system start and uptime in human readable format.
 
164
get_mysql_uptime () {
 
165
   local uptime="$1"
 
166
   local restart="$2"
 
167
   uptime="$(secs_to_time ${uptime})"
 
168
   echo "${restart} (up ${uptime})"
 
169
}
 
170
 
 
171
# Summarizes the output of SHOW MASTER LOGS.
 
172
summarize_binlogs () {
 
173
   local file="$1"
 
174
 
 
175
   [ -e "$file" ] || return
 
176
 
 
177
   local size="$(awk '{t += $2} END{printf "%0.f\n", t}' "$file")"
 
178
   name_val "Binlogs" $(wc -l "$file")
 
179
   name_val "Zero-Sized" $(grep -c '\<0$' "$file")
 
180
   name_val "Total Size" $(shorten ${size} 1)
 
181
}
 
182
 
 
183
format_users () {
 
184
   local file="$1"
 
185
   [ -e "$file" ] || return
 
186
   awk '{printf "%d users, %d anon, %d w/o pw, %d old pw\n", $1, $2, $3, $4}' "${file}"
 
187
}
 
188
 
 
189
# Print out binlog_do_db and binlog_ignore_db
 
190
format_binlog_filters () {
 
191
   local file="$1"
 
192
   [ -e "$file" ] || return
 
193
   name_val "binlog_do_db" "$(cut -f3 "$file")"
 
194
   name_val "binlog_ignore_db" "$(cut -f4 "$file")"
 
195
}
 
196
 
 
197
# Takes as input a file that has two samples of SHOW STATUS, columnized next to
 
198
# each other.  Outputs fuzzy-ed numbers:
 
199
# absolute, all-time per second, and per-second over the interval between the
 
200
# samples.  Omits any rows that are all zeroes.
 
201
format_status_variables () {
 
202
   local file="$1"
 
203
   [ -e "$file" ] || return
 
204
 
 
205
   # First, figure out the intervals.
 
206
   utime1="$(awk '/Uptime /{print $2}' "$file")";
 
207
   utime2="$(awk '/Uptime /{print $3}' "$file")";
 
208
   awk "
 
209
   BEGIN {
 
210
      utime1 = ${utime1};
 
211
      utime2 = ${utime2};
 
212
      udays  = utime1 / 86400;
 
213
      udiff  = utime2 - utime1;
 
214
      format=\"%-35s %11s %11s %11s\\n\";
 
215
      printf(format, \"Variable\", \"Per day\", \"Per second\", udiff \" secs\");
 
216
   }
 
217
   \$2 ~ /^[0-9]*\$/ {
 
218
      if ( \$2 > 0 && \$2 < 18446744073709551615 ) {
 
219
         if ( udays > 0 ) {
 
220
            fuzzy_var=\$2 / udays;
 
221
            ${fuzzy_formula};
 
222
            perday=fuzzy_var;
 
223
         }
 
224
         if ( utime1 > 0 ) {
 
225
            fuzzy_var=\$2 / utime1;
 
226
            ${fuzzy_formula};
 
227
            persec=fuzzy_var;
 
228
         }
 
229
         if ( udiff > 0 ) {
 
230
            fuzzy_var=(\$3 - \$2) / udiff;
 
231
            ${fuzzy_formula};
 
232
            nowsec=fuzzy_var;
 
233
         }
 
234
         perday = int(perday);
 
235
         persec = int(persec);
 
236
         nowsec = int(nowsec);
 
237
         if ( perday + persec + nowsec > 0 ) {
 
238
            if ( perday == 0 ) { perday = \"\"; }
 
239
            if ( persec == 0 ) { persec = \"\"; }
 
240
            if ( nowsec == 0 ) { nowsec = \"\"; }
 
241
            printf(format, \$1, perday, persec, nowsec);
 
242
         }
 
243
      }
 
244
   }" "$file"
 
245
}
 
246
 
 
247
# Slices the processlist a bunch of different ways.  The processlist should be
 
248
# created with the \G flag so it's vertical.
 
249
# The parsing is a bit awkward because different
 
250
# versions of awk have limitations like "too many fields on line xyz".  So we
 
251
# use 'cut' to shorten the lines.  We count all things into temporary variables
 
252
# for each process in the processlist, and when we hit the Info: line which
 
253
# ought to be the last line in the process, we decide what to do with the temp
 
254
# variables.  If we're summarizing Command, we count everything; otherwise, only
 
255
# non-Sleep processes get counted towards the sum and max of Time.
 
256
summarize_processlist () {
 
257
   local file="$1"
 
258
 
 
259
   [ -e "$file" ] || return
 
260
 
 
261
   for param in Command User Host db State; do
 
262
      echo
 
263
      printf '  %-30s %8s %7s %9s %9s\n' \
 
264
         "${param}" "COUNT(*)" Working "SUM(Time)" "MAX(Time)"
 
265
      echo "  ------------------------------" \
 
266
         "-------- ------- --------- ---------"
 
267
      cut -c1-80 "$file" \
 
268
         | awk "
 
269
         \$1 == \"${param}:\" {
 
270
            p = substr(\$0, index(\$0, \":\") + 2);
 
271
            if ( index(p, \":\") > 0 ) {
 
272
               p = substr(p, 1, index(p, \":\") - 1);
 
273
            }
 
274
            if ( length(p) > 30 ) {
 
275
               p = substr(p, 1, 30);
 
276
            }
 
277
         }
 
278
         \$1 == \"Time:\" {
 
279
            t = \$2;
 
280
         }
 
281
         \$1 == \"Command:\" {
 
282
            c = \$2;
 
283
         }
 
284
         \$1 == \"Info:\" {
 
285
            count[p]++;
 
286
            if ( c == \"Sleep\" ) {
 
287
               sleep[p]++;
 
288
            }
 
289
            if ( \"${param}\" == \"Command\" || c != \"Sleep\" ) {
 
290
               time[p] += t;
 
291
               if ( t > mtime[p] ) { mtime[p] = t; }
 
292
            }
 
293
         }
 
294
         END {
 
295
            for ( p in count ) {
 
296
               fuzzy_var=count[p]-sleep[p]; ${fuzzy_formula} fuzzy_work=fuzzy_var;
 
297
               fuzzy_var=count[p];          ${fuzzy_formula} fuzzy_count=fuzzy_var;
 
298
               fuzzy_var=time[p];           ${fuzzy_formula} fuzzy_time=fuzzy_var;
 
299
               fuzzy_var=mtime[p];          ${fuzzy_formula} fuzzy_mtime=fuzzy_var;
 
300
               printf \"  %-30s %8d %7d %9d %9d\n\", p, fuzzy_count, fuzzy_work, fuzzy_time, fuzzy_mtime;
 
301
            }
 
302
         }
 
303
      " | sort
 
304
   done
 
305
   echo
 
306
}
 
307
 
 
308
# Pretty-prints the my.cnf file.  It's super annoying, but some *modern*
 
309
# versions of awk don't support POSIX character sets in regular
 
310
# expressions, like [[:space:]] (looking at you, Debian).  So
 
311
# the below patterns contain [<space><tab>] and must remain that way.
 
312
pretty_print_cnf_file () {
 
313
   local file="$1"
 
314
 
 
315
   [ -e "$file" ] || return
 
316
 
 
317
   awk '
 
318
   BEGIN {
 
319
      FS="="
 
320
   }
 
321
   /^[ \t]*[a-zA-Z[]/ {
 
322
      if (length($2)) {
 
323
         gsub(/^[ \t]*/, "", $1);
 
324
         gsub(/^[ \t]*/, "", $2);
 
325
         gsub(/[ \t]*$/, "", $1);
 
326
         gsub(/[ \t]*$/, "", $2);
 
327
         printf("%-35s = %s\n", $1, $2);
 
328
      }
 
329
      else if ( $0 ~ /\[/ ) {
 
330
         print "";
 
331
         print $1;
 
332
      }
 
333
      else {
 
334
         print $1;
 
335
      }
 
336
   }' "$file"
 
337
}
 
338
 
 
339
find_checkpoint_age() {
 
340
   local file="$1"
 
341
   awk '
 
342
   /Log sequence number/{
 
343
      if ( $5 ) {
 
344
         lsn = $5 + ($4 * 4294967296);
 
345
      }
 
346
      else {
 
347
         lsn = $4;
 
348
      }
 
349
   }
 
350
   /Last checkpoint at/{
 
351
      if ( $5 ) {
 
352
         print lsn - ($5 + ($4 * 4294967296));
 
353
      }
 
354
      else {
 
355
         print lsn - $4;
 
356
      }
 
357
   }
 
358
   ' "$file"
 
359
}
 
360
 
 
361
find_pending_io_reads() {
 
362
   local file="$1"
 
363
 
 
364
   [ -e "$file" ] || return
 
365
 
 
366
   awk '
 
367
   /Pending normal aio reads/ {
 
368
      normal_aio_reads  = substr($5, 1, index($5, ","));
 
369
   }
 
370
   /ibuf aio reads/ {
 
371
      ibuf_aio_reads = substr($4, 1, index($4, ","));
 
372
   }
 
373
   /pending preads/ {
 
374
      preads = $1;
 
375
   }
 
376
   /Pending reads/ {
 
377
      reads = $3;
 
378
   }
 
379
   END {
 
380
      printf "%d buf pool reads, %d normal AIO", reads, normal_aio_reads;
 
381
      printf ", %d ibuf AIO, %d preads", ibuf_aio_reads, preads;
 
382
   }
 
383
   ' "${file}"
 
384
}
 
385
 
 
386
find_pending_io_writes() {
 
387
   local file="$1"
 
388
 
 
389
   [ -e "$file" ] || return
 
390
 
 
391
   awk '
 
392
   /aio writes/ {
 
393
      aio_writes = substr($NF, 1, index($NF, ","));
 
394
   }
 
395
   /ibuf aio reads/ {
 
396
      log_ios = substr($7, 1, index($7, ","));
 
397
      sync_ios = substr($10, 1, index($10, ","));
 
398
   }
 
399
   /pending log writes/ {
 
400
      log_writes = $1;
 
401
      chkp_writes = $5;
 
402
   }
 
403
   /pending pwrites/ {
 
404
      pwrites = $4;
 
405
   }
 
406
   /Pending writes:/ {
 
407
      lru = substr($4, 1, index($4, ","));
 
408
      flush_list = substr($7, 1, index($7, ","));
 
409
      single_page = $NF;
 
410
   }
 
411
   END {
 
412
      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;
 
413
   }
 
414
   ' "${file}"
 
415
}
 
416
 
 
417
find_pending_io_flushes() {
 
418
   local file="$1"
 
419
 
 
420
   [ -e "$file" ] || return
 
421
 
 
422
   awk '
 
423
   /Pending flushes/ {
 
424
      log_flushes = substr($5, 1, index($5, ";"));
 
425
      buf_pool = $NF;
 
426
   }
 
427
   END {
 
428
      printf "%d buf pool, %d log", buf_pool, log_flushes;
 
429
   }
 
430
   ' "${file}"
 
431
}
 
432
 
 
433
summarize_undo_log_entries() {
 
434
   local file="$1"
 
435
 
 
436
   [ -e "$file" ] || return
 
437
 
 
438
   grep 'undo log entries' "${file}" \
 
439
      | sed -e 's/^.*undo log entries \([0-9]*\)/\1/' \
 
440
      | awk '
 
441
      {
 
442
         count++;
 
443
         sum += $1;
 
444
         if ( $1 > max ) {
 
445
            max = $1;
 
446
         }
 
447
      }
 
448
      END {
 
449
         printf "%d transactions, %d total undo, %d max undo\n", count, sum, max;
 
450
      }'
 
451
}
 
452
 
 
453
find_max_trx_time() {
 
454
   local file="$1"
 
455
 
 
456
   [ -e "$file" ] || return
 
457
 
 
458
   awk '
 
459
   BEGIN {
 
460
      max = 0;
 
461
   }
 
462
   /^---TRANSACTION.* sec,/ {
 
463
      for ( i = 0; i < 7; ++i ) {
 
464
         if ( $i == "sec," ) {
 
465
            j = i-1;
 
466
            if ( max < $j ) {
 
467
               max = $j;
 
468
            }
 
469
         }
 
470
      }
 
471
   }
 
472
   END {
 
473
      print max;
 
474
   }' "${file}"
 
475
}
 
476
 
 
477
find_transation_states () {
 
478
   local file="$1"
 
479
   local tmpfile="$TMPDIR/find_transation_states.tmp"
 
480
 
 
481
   [ -e "$file" ] || return
 
482
 
 
483
   awk -F, '/^---TRANSACTION/{print $2}' "${file}"   \
 
484
                        | sed -e 's/ [0-9]* sec.*//' \
 
485
                        | sort                       \
 
486
                        | uniq -c > "${tmpfile}"
 
487
   group_concat "${tmpfile}"
 
488
}
 
489
 
 
490
# Summarizes various things about InnoDB status that are not easy to see by eye.
 
491
format_innodb_status () {
 
492
   local file=$1
 
493
 
 
494
   [ -e "$file" ] || return
 
495
 
 
496
   name_val "Checkpoint Age"      "$(shorten $(find_checkpoint_age "${file}") 0)"
 
497
   name_val "InnoDB Queue"        "$(awk '/queries inside/{print}' "${file}")"
 
498
   name_val "Oldest Transaction"  "$(find_max_trx_time "${file}") Seconds";
 
499
   name_val "History List Len"    "$(awk '/History list length/{print $4}' "${file}")"
 
500
   name_val "Read Views"          "$(awk '/read views open inside/{print $1}' "${file}")"
 
501
   name_val "Undo Log Entries"    "$(summarize_undo_log_entries "${file}")"
 
502
   name_val "Pending I/O Reads"   "$(find_pending_io_reads "${file}")"
 
503
   name_val "Pending I/O Writes"  "$(find_pending_io_writes "${file}")"
 
504
   name_val "Pending I/O Flushes" "$(find_pending_io_flushes "${file}")"
 
505
   name_val "Transaction States"  "$(find_transation_states "${file}" )"
 
506
   if grep 'TABLE LOCK table' "${file}" >/dev/null ; then
 
507
      echo "Tables Locked"
 
508
      awk '/^TABLE LOCK table/{print $4}' "${file}" \
 
509
         | sort | uniq -c | sort -rn
 
510
   fi
 
511
   if grep 'has waited at' "${file}" > /dev/null ; then
 
512
      echo "Semaphore Waits"
 
513
      grep 'has waited at' "${file}" | cut -d' ' -f6-8 \
 
514
         | sort | uniq -c | sort -rn
 
515
   fi
 
516
   if grep 'reserved it in mode' "${file}" > /dev/null; then
 
517
      echo "Semaphore Holders"
 
518
      awk '/has reserved it in mode/{
 
519
         print substr($0, 1 + index($0, "("), index($0, ")") - index($0, "(") - 1);
 
520
      }' "${file}" | sort | uniq -c | sort -rn
 
521
   fi
 
522
   if grep -e 'Mutex at' -e 'lock on' "${file}" >/dev/null 2>&1; then
 
523
      echo "Mutexes/Locks Waited For"
 
524
      grep -e 'Mutex at' -e 'lock on' "${file}" | sed -e 's/^[XS]-//' -e 's/,.*$//' \
 
525
         | sort | uniq -c | sort -rn
 
526
   fi
 
527
}
 
528
 
 
529
# Summarizes per-database statistics for a bunch of different things: count of
 
530
# tables, views, etc.  $1 is the file name.  $2 is the database name; if none,
 
531
# then there should be multiple databases.
 
532
format_overall_db_stats () {
 
533
   local file="$1"
 
534
   local tmpfile="$TMPDIR/format_overall_db_stats.tmp"
 
535
 
 
536
   [ -e "$file" ] || return
 
537
 
 
538
   echo
 
539
   # We keep counts of everything in an associative array keyed by db name, and
 
540
   # what it is.  The num_dbs counter is to ensure sort order is consistent when
 
541
   # we run the awk commands following this one.
 
542
   awk '
 
543
      BEGIN {
 
544
         # In case there is no USE statement in the file.
 
545
         db      = "{chosen}";
 
546
         num_dbs = 0;
 
547
      }
 
548
      /^USE `.*`;$/ {
 
549
         db = substr($2, 2, length($2) - 3);
 
550
         if ( db_seen[db]++ == 0 ) {
 
551
            dbs[num_dbs] = db;
 
552
            num_dbs++;
 
553
         }
 
554
      }
 
555
      /^CREATE TABLE/ {
 
556
         # Handle single-DB dumps, where there is no USE statement.
 
557
         if (num_dbs == 0) {
 
558
            num_dbs     = 1;
 
559
            db_seen[db] = 1;
 
560
            dbs[0]      = db;
 
561
         }
 
562
         counts[db ",tables"]++;
 
563
      }
 
564
      /CREATE ALGORITHM=/ {
 
565
         counts[db ",views"]++;
 
566
      }
 
567
      /03 CREATE.*03 PROCEDURE/ {
 
568
         counts[db ",sps"]++;
 
569
      }
 
570
      /03 CREATE.*03 FUNCTION/ {
 
571
         counts[db ",func"]++;
 
572
      }
 
573
      /03 CREATE.*03 TRIGGER/ {
 
574
         counts[db ",trg"]++;
 
575
      }
 
576
      /FOREIGN KEY/ {
 
577
         counts[db ",fk"]++;
 
578
      }
 
579
      /PARTITION BY/ {
 
580
         counts[db ",partn"]++;
 
581
      }
 
582
      END {
 
583
         mdb = length("Database");
 
584
         for ( i = 0; i < num_dbs; i++ ) {
 
585
            if ( length(dbs[i]) > mdb ) {
 
586
               mdb = length(dbs[i]);
 
587
            }
 
588
         }
 
589
         fmt = "  %-" mdb "s %6s %5s %3s %5s %5s %5s %5s\n";
 
590
         printf fmt, "Database", "Tables", "Views", "SPs", "Trigs", "Funcs", "FKs", "Partn";
 
591
         for ( i=0;i<num_dbs;i++ ) {
 
592
            db = dbs[i];
 
593
            printf fmt, db, counts[db ",tables"], counts[db ",views"], counts[db ",sps"], counts[db ",trg"], counts[db ",func"], counts[db ",fk"], counts[db ",partn"];
 
594
         }
 
595
      }
 
596
   ' "$file" > "$tmpfile"
 
597
   head -n2 "$tmpfile"
 
598
   tail -n +3 "$tmpfile" | sort
 
599
 
 
600
   echo
 
601
   # Now do the summary of engines per DB
 
602
   awk '
 
603
      BEGIN {
 
604
         # In case there is no USE statement in the file.
 
605
         db          = "{chosen}";
 
606
         num_dbs     = 0;
 
607
         num_engines = 0;
 
608
      }
 
609
      /^USE `.*`;$/ {
 
610
         db = substr($2, 2, length($2) - 3);
 
611
         if ( db_seen[db]++ == 0 ) {
 
612
            dbs[num_dbs] = db;
 
613
            num_dbs++;
 
614
         }
 
615
      }
 
616
      /^\) ENGINE=/ {
 
617
         # Handle single-DB dumps, where there is no USE statement.
 
618
         if (num_dbs == 0) {
 
619
            num_dbs     = 1;
 
620
            db_seen[db] = 1;
 
621
            dbs[0]      = db;
 
622
         }
 
623
         engine=substr($2, index($2, "=") + 1);
 
624
         if ( engine_seen[engine]++ == 0 ) {
 
625
            engines[num_engines] = engine;
 
626
            num_engines++;
 
627
         }
 
628
         counts[db "," engine]++;
 
629
      }
 
630
      END {
 
631
         mdb = length("Database");
 
632
         for ( i=0;i<num_dbs;i++ ) {
 
633
            db = dbs[i];
 
634
            if ( length(db) > mdb ) {
 
635
               mdb = length(db);
 
636
            }
 
637
         }
 
638
         fmt = "  %-" mdb "s"
 
639
         printf fmt, "Database";
 
640
         for ( i=0;i<num_engines;i++ ) {
 
641
            engine = engines[i];
 
642
            fmts[engine] = " %" length(engine) "s";
 
643
            printf fmts[engine], engine;
 
644
         }
 
645
         print "";
 
646
         for ( i=0;i<num_dbs;i++ ) {
 
647
            db = dbs[i];
 
648
            printf fmt, db;
 
649
            for ( j=0;j<num_engines;j++ ) {
 
650
               engine = engines[j];
 
651
               printf fmts[engine], counts[db "," engine];
 
652
            }
 
653
            print "";
 
654
         }
 
655
      }
 
656
   ' "$file" > "$tmpfile"
 
657
   head -n1 "$tmpfile"
 
658
   tail -n +2 "$tmpfile" | sort
 
659
 
 
660
   echo
 
661
   # Now do the summary of index types per DB. Careful -- index is a reserved
 
662
   # word in awk.
 
663
   awk '
 
664
      BEGIN {
 
665
         # In case there is no USE statement in the file.
 
666
         db        = "{chosen}";
 
667
         num_dbs   = 0;
 
668
         num_idxes = 0;
 
669
      }
 
670
      /^USE `.*`;$/ {
 
671
         db = substr($2, 2, length($2) - 3);
 
672
         if ( db_seen[db]++ == 0 ) {
 
673
            dbs[num_dbs] = db;
 
674
            num_dbs++;
 
675
         }
 
676
      }
 
677
      /KEY/ {
 
678
         # Handle single-DB dumps, where there is no USE statement.
 
679
         if (num_dbs == 0) {
 
680
            num_dbs     = 1;
 
681
            db_seen[db] = 1;
 
682
            dbs[0]      = db;
 
683
         }
 
684
         idx="BTREE";
 
685
         if ( $0 ~ /SPATIAL/ ) {
 
686
            idx="SPATIAL";
 
687
         }
 
688
         if ( $0 ~ /FULLTEXT/ ) {
 
689
            idx="FULLTEXT";
 
690
         }
 
691
         if ( $0 ~ /USING RTREE/ ) {
 
692
            idx="RTREE";
 
693
         }
 
694
         if ( $0 ~ /USING HASH/ ) {
 
695
            idx="HASH";
 
696
         }
 
697
         if ( idx_seen[idx]++ == 0 ) {
 
698
            idxes[num_idxes] = idx;
 
699
            num_idxes++;
 
700
         }
 
701
         counts[db "," idx]++;
 
702
      }
 
703
      END {
 
704
         mdb = length("Database");
 
705
         for ( i=0;i<num_dbs;i++ ) {
 
706
            db = dbs[i];
 
707
            if ( length(db) > mdb ) {
 
708
               mdb = length(db);
 
709
            }
 
710
         }
 
711
         fmt = "  %-" mdb "s"
 
712
         printf fmt, "Database";
 
713
         for ( i=0;i<num_idxes;i++ ) {
 
714
            idx = idxes[i];
 
715
            fmts[idx] = " %" length(idx) "s";
 
716
            printf fmts[idx], idx;
 
717
         }
 
718
         print "";
 
719
         for ( i=0;i<num_dbs;i++ ) {
 
720
            db = dbs[i];
 
721
            printf fmt, db;
 
722
            for ( j=0;j<num_idxes;j++ ) {
 
723
               idx = idxes[j];
 
724
               printf fmts[idx], counts[db "," idx];
 
725
            }
 
726
            print "";
 
727
         }
 
728
      }
 
729
   ' "$file" > "$tmpfile"
 
730
   head -n1 "$tmpfile"
 
731
   tail -n +2 "$tmpfile" | sort
 
732
 
 
733
   echo
 
734
   # Now do the summary of datatypes per DB
 
735
   awk '
 
736
      BEGIN {
 
737
         # In case there is no USE statement in the file.
 
738
         db          = "{chosen}";
 
739
         num_dbs     = 0;
 
740
         num_types = 0;
 
741
      }
 
742
      /^USE `.*`;$/ {
 
743
         db = substr($2, 2, length($2) - 3);
 
744
         if ( db_seen[db]++ == 0 ) {
 
745
            dbs[num_dbs] = db;
 
746
            num_dbs++;
 
747
         }
 
748
      }
 
749
      /^  `/ {
 
750
         # Handle single-DB dumps, where there is no USE statement.
 
751
         if (num_dbs == 0) {
 
752
            num_dbs     = 1;
 
753
            db_seen[db] = 1;
 
754
            dbs[0]      = db;
 
755
         }
 
756
         str = $0;
 
757
         str = substr(str, index(str, "`") + 1);
 
758
         str = substr(str, index(str, "`") + 2);
 
759
         if ( index(str, " ") > 0 ) {
 
760
            str = substr(str, 1, index(str, " ") - 1);
 
761
         }
 
762
         if ( index(str, ",") > 0 ) {
 
763
            str = substr(str, 1, index(str, ",") - 1);
 
764
         }
 
765
         if ( index(str, "(") > 0 ) {
 
766
            str = substr(str, 1, index(str, "(") - 1);
 
767
         }
 
768
         type = str;
 
769
         if ( type_seen[type]++ == 0 ) {
 
770
            types[num_types] = type;
 
771
            num_types++;
 
772
         }
 
773
         counts[db "," type]++;
 
774
      }
 
775
      END {
 
776
         mdb = length("Database");
 
777
         for ( i=0;i<num_dbs;i++ ) {
 
778
            db = dbs[i];
 
779
            if ( length(db) > mdb ) {
 
780
               mdb = length(db);
 
781
            }
 
782
         }
 
783
         fmt = "  %-" mdb "s"
 
784
         mtlen = 0; # max type length
 
785
         for ( i=0;i<num_types;i++ ) {
 
786
            type = types[i];
 
787
            if ( length(type) > mtlen ) {
 
788
               mtlen = length(type);
 
789
            }
 
790
         }
 
791
         for ( i=1;i<=mtlen;i++ ) {
 
792
            printf "  %-" mdb "s", "";
 
793
            for ( j=0;j<num_types;j++ ) {
 
794
               type = types[j];
 
795
               if ( i > length(type) ) {
 
796
                  ch = " ";
 
797
               }
 
798
               else {
 
799
                  ch = substr(type, i, 1);
 
800
               }
 
801
               printf(" %3s", ch);
 
802
            }
 
803
            print "";
 
804
         }
 
805
         printf "  %-" mdb "s", "Database";
 
806
         for ( i=0;i<num_types;i++ ) {
 
807
            printf " %3s", "===";
 
808
         }
 
809
         print "";
 
810
         for ( i=0;i<num_dbs;i++ ) {
 
811
            db = dbs[i];
 
812
            printf fmt, db;
 
813
            for ( j=0;j<num_types;j++ ) {
 
814
               type = types[j];
 
815
               printf " %3s", counts[db "," type];
 
816
            }
 
817
            print "";
 
818
         }
 
819
      }
 
820
   ' "$file" > "$tmpfile"
 
821
   local hdr=$(grep -n Database "$tmpfile" | cut -d: -f1);
 
822
   head -n${hdr} "$tmpfile"
 
823
   tail -n +$((${hdr} + 1)) "$tmpfile" | sort
 
824
   echo
 
825
}
 
826
 
 
827
section_percona_server_features () {
 
828
   local file="$1"
 
829
 
 
830
   [ -e "$file" ] || return
 
831
 
 
832
   name_val "Table & Index Stats"   \
 
833
            "$(feat_on "$file" userstat_running)"
 
834
   name_val "Multiple I/O Threads"  \
 
835
            "$(feat_on "$file" innodb_read_io_threads gt 1)"
 
836
   name_val "Corruption Resilient"  \
 
837
            "$(feat_on "$file" innodb_pass_corrupt_table)"
 
838
   name_val "Durable Replication"   \
 
839
            "$(feat_on "$file" innodb_overwrite_relay_log_info)"
 
840
   name_val "Import InnoDB Tables"  \
 
841
            "$(feat_on "$file" innodb_expand_import)"
 
842
   name_val "Fast Server Restarts"  \
 
843
            "$(feat_on "$file" innodb_auto_lru_dump)"
 
844
   name_val "Enhanced Logging"      \
 
845
            "$(feat_on "$file" log_slow_verbosity ne microtime)"
 
846
   name_val "Replica Perf Logging"  \
 
847
            "$(feat_on "$file" log_slow_slave_statements)"
 
848
   name_val "Response Time Hist."   \
 
849
            "$(feat_on "$file" enable_query_response_time_stats)"
 
850
   name_val "Smooth Flushing"       \
 
851
            "$(feat_on "$file" innodb_adaptive_checkpoint ne none)"
 
852
   name_val "HandlerSocket NoSQL"   \
 
853
            "$(feat_on "$file" handlersocket_port)"
 
854
   name_val "Fast Hash UDFs"   \
 
855
            "$(get_var "pt-summary-internal-FNV_64" "$file")"
 
856
}
 
857
 
 
858
section_myisam () {
 
859
   local variables_file="$1"
 
860
   local status_file="$2"
 
861
 
 
862
   [ -e "$variables_file" -a -e "$status_file" ] || return
 
863
 
 
864
   local buf_size="$(get_var key_buffer_size "$variables_file")"
 
865
   local blk_size="$(get_var key_cache_block_size "$variables_file")"
 
866
   local blk_unus="$(get_var Key_blocks_unused "$status_file")"
 
867
   local blk_unfl="$(get_var Key_blocks_not_flushed "$variables_file")"
 
868
   local unus=$((${blk_unus:-0} * ${blk_size:-0}))
 
869
   local unfl=$((${blk_unfl:-0} * ${blk_size:-0}))
 
870
   local used=$((${buf_size:-0} - ${unus}))
 
871
 
 
872
   name_val "Key Cache" "$(shorten ${buf_size} 1)"
 
873
   name_val "Pct Used" "$(fuzzy_pct ${used} ${buf_size})"
 
874
   name_val "Unflushed" "$(fuzzy_pct ${unfl} ${buf_size})"
 
875
}
 
876
 
 
877
section_innodb () {
 
878
   local variables_file="$1"
 
879
   local status_file="$2"
 
880
 
 
881
   [ -e "$variables_file" -a -e "$status_file" ] || return
 
882
 
 
883
   # XXX TODO I don't think this is working right.
 
884
   # XXX TODO Should it use data from information_schema.plugins too?
 
885
   local version=$(get_var innodb_version "$variables_file")
 
886
   name_val Version ${version:-default}
 
887
 
 
888
   local bp_size="$(get_var innodb_buffer_pool_size "$variables_file")"
 
889
   name_val "Buffer Pool Size" "$(shorten "${bp_size:-0}" 1)"
 
890
 
 
891
   local bp_pags="$(get_var Innodb_buffer_pool_pages_total "$status_file")"
 
892
   local bp_free="$(get_var Innodb_buffer_pool_pages_free "$status_file")"
 
893
   local bp_dirt="$(get_var Innodb_buffer_pool_pages_dirty "$status_file")"
 
894
   local bp_fill=$((${bp_pags} - ${bp_free}))
 
895
   name_val "Buffer Pool Fill"   "$(fuzzy_pct ${bp_fill} ${bp_pags})"
 
896
   name_val "Buffer Pool Dirty"  "$(fuzzy_pct ${bp_dirt} ${bp_pags})"
 
897
 
 
898
   name_val "File Per Table"      $(get_var innodb_file_per_table "$variables_file")
 
899
   name_val "Page Size"           $(shorten $(get_var Innodb_page_size "$status_file") 0)
 
900
 
 
901
   local log_size="$(get_var innodb_log_file_size "$variables_file")"
 
902
   local log_file="$(get_var innodb_log_files_in_group "$variables_file")"
 
903
   local log_total=$(awk "BEGIN {printf \"%.2f\n\", ${log_size}*${log_file}}" )
 
904
   name_val "Log File Size"       \
 
905
            "${log_file} * $(shorten ${log_size} 1 1000) = $(shorten ${log_total} 1 1000)"
 
906
   name_val "Log Buffer Size"     \
 
907
            "$(shorten $(get_var innodb_log_buffer_size "$variables_file") 0)"
 
908
   name_val "Flush Method"        \
 
909
            "$(get_var innodb_flush_method "$variables_file")"
 
910
   name_val "Flush Log At Commit" \
 
911
            "$(get_var innodb_flush_log_at_trx_commit "$variables_file")"
 
912
   name_val "XA Support"          \
 
913
            "$(get_var innodb_support_xa "$variables_file")"
 
914
   name_val "Checksums"           \
 
915
            "$(get_var innodb_checksums "$variables_file")"
 
916
   name_val "Doublewrite"         \
 
917
            "$(get_var innodb_doublewrite "$variables_file")"
 
918
   name_val "R/W I/O Threads"     \
 
919
            "$(get_var innodb_read_io_threads "$variables_file") $(get_var innodb_write_io_threads "$variables_file")"
 
920
   name_val "I/O Capacity"        \
 
921
            "$(get_var innodb_io_capacity "$variables_file")"
 
922
   name_val "Thread Concurrency"  \
 
923
            "$(get_var innodb_thread_concurrency "$variables_file")"
 
924
   name_val "Concurrency Tickets" \
 
925
            "$(get_var innodb_concurrency_tickets "$variables_file")"
 
926
   name_val "Commit Concurrency"  \
 
927
            "$(get_var innodb_commit_concurrency "$variables_file")"
 
928
   name_val "Txn Isolation Level" \
 
929
            "$(get_var tx_isolation "$variables_file")"
 
930
   name_val "Adaptive Flushing"   \
 
931
            "$(get_var innodb_adaptive_flushing "$variables_file")"
 
932
   name_val "Adaptive Checkpoint" \
 
933
            "$(get_var innodb_adaptive_checkpoint "$variables_file")"
 
934
}
 
935
 
 
936
 
 
937
section_noteworthy_variables () {
 
938
   local file="$1"
 
939
 
 
940
   [ -e "$file" ] || return
 
941
 
 
942
   name_val "Auto-Inc Incr/Offset" "$(get_var auto_increment_increment "$file")/$(get_var auto_increment_offset "$file")"
 
943
   for v in \
 
944
      default_storage_engine flush_time init_connect init_file sql_mode;
 
945
   do
 
946
      name_val "${v}" "$(get_var ${v} "$file")"
 
947
   done
 
948
   for v in \
 
949
      join_buffer_size sort_buffer_size read_buffer_size read_rnd_buffer_size \
 
950
      bulk_insert_buffer max_heap_table_size tmp_table_size \
 
951
      max_allowed_packet thread_stack;
 
952
   do
 
953
      name_val "${v}" "$(shorten $(get_var ${v} "$file") 0)"
 
954
   done
 
955
   for v in log log_error log_warnings log_slow_queries \
 
956
         log_queries_not_using_indexes log_slave_updates;
 
957
   do
 
958
      name_val "${v}" "$(get_var ${v} "$file")"
 
959
   done
 
960
}
 
961
 
 
962
#
 
963
# Formats and outputs the semisyncronious replication-related variables
 
964
#
 
965
_semi_sync_stats_for () {
 
966
   local target="$1"
 
967
   local file="$2"
 
968
 
 
969
   [ -e "$file" ] || return
 
970
 
 
971
   local semisync_status="$(get_var "Rpl_semi_sync_${target}_status" "${file}" )"
 
972
   local semisync_trace="$(get_var "rpl_semi_sync_${target}_trace_level" "${file}")"
 
973
 
 
974
   local trace_extra=""
 
975
   if [ -n "${semisync_trace}" ]; then
 
976
      if [ $semisync_trace -eq 1 ]; then
 
977
         trace_extra="general (for example, time function failures) "
 
978
      elif [ $semisync_trace -eq 16 ]; then
 
979
         trace_extra="detail (more verbose information) "
 
980
      elif [ $semisync_trace -eq 32 ]; then
 
981
         trace_extra="net wait (more information about network waits)"
 
982
      elif [ $semisync_trace -eq 64 ]; then
 
983
         trace_extra="function (information about function entry and exit)"
 
984
      else
 
985
         trace_extra="Unknown setting"
 
986
      fi
 
987
   fi
 
988
   
 
989
   name_val "${target} semisync status" "${semisync_status}"
 
990
   name_val "${target} trace level" "${semisync_trace}, ${trace_extra}"
 
991
 
 
992
   if [ "${target}" = "master" ]; then
 
993
      name_val "${target} timeout in milliseconds" \
 
994
               "$(get_var "rpl_semi_sync_${target}_timeout" "${file}")"
 
995
      name_val "${target} waits for slaves"        \
 
996
               "$(get_var "rpl_semi_sync_${target}_wait_no_slave" "${file}")"
 
997
 
 
998
      _d "Prepend Rpl_semi_sync_master_ to the following"
 
999
      for v in                                              \
 
1000
         clients net_avg_wait_time net_wait_time net_waits  \
 
1001
         no_times no_tx timefunc_failures tx_avg_wait_time  \
 
1002
         tx_wait_time tx_waits wait_pos_backtraverse        \
 
1003
         wait_sessions yes_tx;
 
1004
      do
 
1005
         name_val "${target} ${v}" \
 
1006
                  "$( get_var "Rpl_semi_sync_master_${v}" "${file}" )"
 
1007
      done
 
1008
   fi
 
1009
}
 
1010
 
 
1011
# Make a pattern of things we want to omit because they aren't
 
1012
# counters, they are gauges (in RRDTool terminology).  Gauges are shown
 
1013
# elsewhere in the output.
 
1014
noncounters_pattern () {
 
1015
   local noncounters_pattern=""
 
1016
 
 
1017
   for var in Compression Delayed_insert_threads Innodb_buffer_pool_pages_data \
 
1018
      Innodb_buffer_pool_pages_dirty Innodb_buffer_pool_pages_free \
 
1019
      Innodb_buffer_pool_pages_latched Innodb_buffer_pool_pages_misc \
 
1020
      Innodb_buffer_pool_pages_total Innodb_data_pending_fsyncs \
 
1021
      Innodb_data_pending_reads Innodb_data_pending_writes \
 
1022
      Innodb_os_log_pending_fsyncs Innodb_os_log_pending_writes \
 
1023
      Innodb_page_size Innodb_row_lock_current_waits Innodb_row_lock_time_avg \
 
1024
      Innodb_row_lock_time_max Key_blocks_not_flushed Key_blocks_unused \
 
1025
      Key_blocks_used Last_query_cost Max_used_connections Ndb_cluster_node_id \
 
1026
      Ndb_config_from_host Ndb_config_from_port Ndb_number_of_data_nodes \
 
1027
      Not_flushed_delayed_rows Open_files Open_streams Open_tables \
 
1028
      Prepared_stmt_count Qcache_free_blocks Qcache_free_memory \
 
1029
      Qcache_queries_in_cache Qcache_total_blocks Rpl_status \
 
1030
      Slave_open_temp_tables Slave_running Ssl_cipher Ssl_cipher_list \
 
1031
      Ssl_ctx_verify_depth Ssl_ctx_verify_mode Ssl_default_timeout \
 
1032
      Ssl_session_cache_mode Ssl_session_cache_size Ssl_verify_depth \
 
1033
      Ssl_verify_mode Ssl_version Tc_log_max_pages_used Tc_log_page_size \
 
1034
      Threads_cached Threads_connected Threads_running \
 
1035
      Uptime_since_flush_status;
 
1036
   do
 
1037
      if [ -z "${noncounters_pattern}" ]; then
 
1038
         noncounters_pattern="${var}"
 
1039
      else
 
1040
         noncounters_pattern="${noncounters_pattern}\|${var}"
 
1041
      fi
 
1042
   done
 
1043
   echo $noncounters_pattern
 
1044
}
 
1045
 
 
1046
section_mysqld () {
 
1047
   local executables_file="$1"
 
1048
   local variables_file="$2"
 
1049
 
 
1050
   [ -e "$executables_file" -a -e "$variables_file" ] || return
 
1051
 
 
1052
   section "MySQL Executable"
 
1053
   local i=1;
 
1054
   while read executable; do
 
1055
      name_val "Path to executable" "$executable"
 
1056
      name_val "Has symbols" "$( get_var "pt-summary-internal-mysqld_executable_${i}" "$variables_file" )"
 
1057
      i=$(($i + 1))
 
1058
   done < "$executables_file"
 
1059
}
 
1060
 
 
1061
section_mysql_files () {
 
1062
   local variables_file="$1"
 
1063
 
 
1064
   section "MySQL Files"
 
1065
   for file_name in pid_file slow_query_log_file general_log_file log_error; do
 
1066
      local file="$(get_var "${file_name}" "$variables_file")"
 
1067
      local name_out="$(echo "$file_name" | sed 'y/[a-z]/[A-Z]/')"
 
1068
      if [ -e "${file}" ]; then
 
1069
         name_val "$name_out" "$file"
 
1070
         name_val "${name_out} Size" "$(du "$file" | awk '{print $1}')"
 
1071
      else
 
1072
         name_val "$name_out" "(does not exist)"
 
1073
      fi
 
1074
   done
 
1075
}
 
1076
 
 
1077
report_mysql_summary () {
 
1078
   local dir="$1"
 
1079
 
 
1080
   # Field width for name_val
 
1081
   local NAME_VAL_LEN=25
 
1082
 
 
1083
   # ########################################################################
 
1084
   # Header for the whole thing, table of discovered instances
 
1085
   # ########################################################################
 
1086
 
 
1087
   section "Percona Toolkit MySQL Summary Report"
 
1088
   name_val "System time" "`date -u +'%F %T UTC'` (local TZ: `date +'%Z %z'`)"
 
1089
   section "Instances"
 
1090
   parse_mysqld_instances "$dir/mysqld-instances" "$dir/mysql-variables"
 
1091
 
 
1092
   section_mysqld "$dir/mysqld-executables" "$dir/mysql-variables"
 
1093
 
 
1094
   # ########################################################################
 
1095
   # General date, hostname, etc
 
1096
   # ########################################################################
 
1097
   local user="$(get_var "pt-summary-internal-user" "$dir/mysql-variables")"
 
1098
   local port="$(get_var port "$dir/mysql-variables")"
 
1099
   local now="$(get_var "pt-summary-internal-now" "$dir/mysql-variables")"
 
1100
   section "Report On Port ${port}"
 
1101
   name_val User "${user}"
 
1102
   name_val Time "${now} ($(get_mysql_timezone "$dir/mysql-variables"))"
 
1103
   name_val Hostname "$(get_var hostname "$dir/mysql-variables")"
 
1104
   get_mysql_version "$dir/mysql-variables"
 
1105
 
 
1106
   local uptime="$(get_var Uptime "$dir/mysql-status")"
 
1107
   local current_time="$(get_var "pt-summary-internal-current_time" "$dir/mysql-variables")"
 
1108
   name_val Started "$(get_mysql_uptime "${uptime}" "${current_time}")"
 
1109
 
 
1110
   local num_dbs="$(grep -c . "$dir/mysql-databases")"
 
1111
   name_val Databases "${num_dbs}"
 
1112
   name_val Datadir "$(get_var datadir "$dir/mysql-variables")"
 
1113
 
 
1114
   local fuzz_procs=$(fuzz $(get_var Threads_connected "$dir/mysql-status"))
 
1115
   local fuzz_procr=$(fuzz $(get_var Threads_running "$dir/mysql-status"))
 
1116
   name_val Processes "${fuzz_procs} connected, ${fuzz_procr} running"
 
1117
 
 
1118
   local slave=""
 
1119
   if [ -s "$dir/mysql-slave" ]; then slave=""; else slave="not "; fi
 
1120
   local slavecount=$(grep -c 'Binlog Dump' "$dir/mysql-processlist")
 
1121
   name_val Replication "Is ${slave}a slave, has ${slavecount} slaves connected"
 
1122
 
 
1123
 
 
1124
   # TODO move this into a section with other files: error log, slow log and
 
1125
   # show the sizes
 
1126
   #   section_mysql_files "$dir/mysql-variables"
 
1127
   local pid_file="$(get_var "pid_file" "$dir/mysql-variables")"
 
1128
   local PID_EXISTS=""
 
1129
   if [ "$( get_var "pt-summary-internal-pid_file_exists" "$dir/mysql-variables" )" ]; then
 
1130
      PID_EXISTS="(exists)"
 
1131
   else
 
1132
      PID_EXISTS="(does not exist)"
 
1133
   fi
 
1134
   name_val Pidfile "${pid_file} ${PID_EXISTS}"
 
1135
 
 
1136
   # ########################################################################
 
1137
   # Processlist, sliced several different ways
 
1138
   # ########################################################################
 
1139
   section "Processlist"
 
1140
   summarize_processlist "$dir/mysql-processlist"
 
1141
 
 
1142
   # ########################################################################
 
1143
   # Queries and query plans
 
1144
   # ########################################################################
 
1145
   section "Status Counters (Wait ${OPT_SLEEP} Seconds)"
 
1146
   # Wait for the child that was forked during collection.
 
1147
   wait
 
1148
   local noncounters_pattern="$(noncounters_pattern)"
 
1149
   format_status_variables "$dir/mysql-status-defer" | grep -v "${noncounters_pattern}"
 
1150
 
 
1151
   # ########################################################################
 
1152
   # Table cache
 
1153
   # ########################################################################
 
1154
   section "Table cache"
 
1155
   local open_tables=$(get_var "Open_tables" "$dir/mysql-status")
 
1156
   local table_cache=$(get_table_cache "$dir/mysql-variables")
 
1157
   name_val Size  $table_cache
 
1158
   name_val Usage "$(fuzzy_pct ${open_tables} ${table_cache})"
 
1159
 
 
1160
   # ########################################################################
 
1161
   # Percona Server features
 
1162
   # ########################################################################
 
1163
   section "Key Percona Server features"
 
1164
   section_percona_server_features "$dir/mysql-variables"
 
1165
 
 
1166
   # ########################################################################
 
1167
   # Plugins
 
1168
   # ########################################################################
 
1169
   # TODO: what would be good is to show nonstandard plugins here.
 
1170
   section "Plugins"
 
1171
   name_val "InnoDB compression" "$(get_plugin_status "$dir/mysql-plugins" "INNODB_CMP")"
 
1172
 
 
1173
   # ########################################################################
 
1174
   # Query cache
 
1175
   # ########################################################################
 
1176
   if [ "$(get_var have_query_cache "$dir/mysql-variables")" ]; then
 
1177
      section "Query cache"
 
1178
      local query_cache_size=$(get_var query_cache_size "$dir/mysql-variables")
 
1179
      local used=$(( ${query_cache_size} - $(get_var Qcache_free_memory "$dir/mysql-status") ))
 
1180
      local hrat=$(fuzzy_pct $(get_var Qcache_hits "$dir/mysql-status") $(get_var Qcache_inserts "$dir/mysql-status"))
 
1181
      name_val query_cache_type $(get_var query_cache_type "$dir/mysql-variables")
 
1182
      name_val Size "$(shorten ${query_cache_size} 1)"
 
1183
      name_val Usage "$(fuzzy_pct ${used} ${query_cache_size})"
 
1184
      name_val HitToInsertRatio "${hrat}"
 
1185
   fi
 
1186
 
 
1187
   local semisync_enabled_master="$(get_var "rpl_semi_sync_master_enabled" "$dir/mysql-variables")"
 
1188
   if [ -n "${semisync_enabled_master}" ]; then
 
1189
      section "Semisynchronous Replication"
 
1190
      if [ "$semisync_enabled_master" = "OFF" -o "$semisync_enabled_master" = "0" -o -z "$semisync_enabled_master" ]; then
 
1191
         name_val "Master" "Disabled"
 
1192
      else
 
1193
         _semi_sync_stats_for "master" "$dir/mysql-variables"
 
1194
      fi
 
1195
      local semisync_enabled_slave="$(get_var rpl_semi_sync_slave_enabled "$dir/mysql-variables")"
 
1196
      if    [ "$semisync_enabled_slave" = "OFF" -o "$semisync_enabled_slave" = "0" -o -z "$semisync_enabled_slave" ]; then
 
1197
         name_val "Slave" "Disabled"
 
1198
      else
 
1199
         _semi_sync_stats_for "slave" "$dir/mysql-variables"
 
1200
      fi
 
1201
   fi
 
1202
 
 
1203
   # ########################################################################
 
1204
   # Schema, databases, data type, other analysis.
 
1205
   # ########################################################################
 
1206
   section "Schema"
 
1207
   # Assume "no" if stdin or stdout is not a terminal, so this can be run and
 
1208
   # put into a file, or piped into a pager, or something else like that.
 
1209
   local reply="n"
 
1210
   # But dump no matter what if they passed in something through --databases,
 
1211
   # OR if --read-samples was set
 
1212
   if [ "${OPT_DATABASES}" ] || [ "${OPT_READ_SAMPLES}" ] \
 
1213
      || [ -e "$dir/mysqldump" -a -s "$dir/mysqldump" ]; then
 
1214
      reply="y"
 
1215
   elif [ -t 0 -a -t 1 ]; then
 
1216
      echo -n "Would you like to mysqldump -d the schema and analyze it? y/n "
 
1217
      read reply
 
1218
      reply=${reply:-n}
 
1219
   fi
 
1220
   if echo "${reply:-n}" | grep -i '^y' > /dev/null ; then
 
1221
      if [ -z "${OPT_DATABASES}" ] && [ -z "$OPT_READ_SAMPLES" ] \
 
1222
         && [ ! -e "$dir/mysqldump" ]; then
 
1223
         # If --dump-schemas wasn't used, ask what they want to dump
 
1224
         echo "There are ${num_dbs} databases.  Would you like to dump all, or just one?"
 
1225
         echo -n "Type the name of the database, or press Enter to dump all of them. "
 
1226
         local dbtodump=""
 
1227
         read dbtodump
 
1228
         local trg_arg="$( get_mysqldump_args "$dir/mysql-variables" )"
 
1229
         get_mysqldump_for "${trg_arg}" "${dbtodump}" > "$dir/mysqldump"
 
1230
      fi
 
1231
 
 
1232
      # Test the result by checking the file, not by the exit status, because we
 
1233
      # might get partway through and then die, and the info is worth analyzing
 
1234
      # anyway.
 
1235
      if [ -e "$dir/mysqldump" -a -s "$dir/mysqldump" ] \
 
1236
         && grep 'CREATE TABLE' "$dir/mysqldump" >/dev/null 2>&1; then
 
1237
            format_overall_db_stats "$dir/mysqldump"
 
1238
      elif [ ! -e "$dir/mysqldump" -a "$OPT_READ_SAMPLES" ]; then
 
1239
         echo "Skipping schema analysis as the directory passed in" \
 
1240
              "doesn't have a dump file"
 
1241
      else
 
1242
         echo "Skipping schema analysis due to apparent error in dump file"
 
1243
      fi
 
1244
   else
 
1245
      echo "Skipping schema analysis"
 
1246
   fi
 
1247
 
 
1248
   # ########################################################################
 
1249
   # Noteworthy Technologies
 
1250
   # ########################################################################
 
1251
   section "Noteworthy Technologies"
 
1252
   if [ -s "$dir/mysqldump" ]; then
 
1253
      if grep FULLTEXT "$dir/mysqldump" > /dev/null; then
 
1254
         name_val "Full Text Indexing" "Yes"
 
1255
      else
 
1256
         name_val "Full Text Indexing" "No"
 
1257
      fi
 
1258
      if grep 'GEOMETRY\|POINT\|LINESTRING\|POLYGON' "$dir/mysqldump" > /dev/null; then
 
1259
         name_val "Geospatial Types" "Yes"
 
1260
      else
 
1261
         name_val "Geospatial Types" "No"
 
1262
      fi
 
1263
      if grep 'FOREIGN KEY' "$dir/mysqldump" > /dev/null; then
 
1264
         name_val "Foreign Keys" "Yes"
 
1265
      else
 
1266
         name_val "Foreign Keys" "No"
 
1267
      fi
 
1268
      if grep 'PARTITION BY' "$dir/mysqldump" > /dev/null; then
 
1269
         name_val "Partitioning" "Yes"
 
1270
      else
 
1271
         name_val "Partitioning" "No"
 
1272
      fi
 
1273
      if grep -e 'ENGINE=InnoDB.*ROW_FORMAT' \
 
1274
         -e 'ENGINE=InnoDB.*KEY_BLOCK_SIZE' "$dir/mysqldump" > /dev/null; then
 
1275
         name_val "InnoDB Compression" "Yes"
 
1276
      else
 
1277
         name_val "InnoDB Compression" "No"
 
1278
      fi
 
1279
   fi
 
1280
   local ssl="$(get_var Ssl_accepts "$dir/mysql-status")"
 
1281
   if [ -n "$ssl" -a "${ssl:-0}" -gt 0 ]; then
 
1282
      name_val "SSL" "Yes"
 
1283
   else
 
1284
      name_val "SSL" "No"
 
1285
   fi
 
1286
   local lock_tables="$(get_var Com_lock_tables "$dir/mysql-status")"
 
1287
   if [ -n "$lock_tables" -a "${lock_tables:-0}" -gt 0 ]; then
 
1288
      name_val "Explicit LOCK TABLES" "Yes"
 
1289
   else
 
1290
      name_val "Explicit LOCK TABLES" "No"
 
1291
   fi
 
1292
   local delayed_insert="$(get_var Delayed_writes "$dir/mysql-status")"
 
1293
   if [ -n "$delayed_insert" -a "${delayed_insert:-0}" -gt 0 ]; then
 
1294
      name_val "Delayed Insert" "Yes"
 
1295
   else
 
1296
      name_val "Delayed Insert" "No"
 
1297
   fi
 
1298
   local xat="$(get_var Com_xa_start "$dir/mysql-status")"
 
1299
   if [ -n "$xat" -a "${xat:-0}" -gt 0 ]; then
 
1300
      name_val "XA Transactions" "Yes"
 
1301
   else
 
1302
      name_val "XA Transactions" "No"
 
1303
   fi
 
1304
   local ndb_cluster="$(get_var "Ndb_cluster_node_id" "$dir/mysql-status")"
 
1305
   if [ -n "$ndb_cluster" -a "${ndb_cluster:-0}" -gt 0 ]; then
 
1306
      name_val "NDB Cluster" "Yes"
 
1307
   else
 
1308
      name_val "NDB Cluster" "No"
 
1309
   fi
 
1310
   local prep=$(( $(get_var "Com_stmt_prepare" "$dir/mysql-status") + $(get_var "Com_prepare_sql" "$dir/mysql-status") ))
 
1311
   if [ "${prep}" -gt 0 ]; then
 
1312
      name_val "Prepared Statements" "Yes"
 
1313
   else
 
1314
      name_val "Prepared Statements" "No"
 
1315
   fi
 
1316
   local prep_count="$(get_var Prepared_stmt_count "$dir/mysql-status")"
 
1317
   if [ "${prep_count}" ]; then
 
1318
      name_val "Prepared statement count" "${prep_count}"
 
1319
   fi
 
1320
 
 
1321
   # ########################################################################
 
1322
   # InnoDB
 
1323
   # ########################################################################
 
1324
   section "InnoDB"
 
1325
   local have_innodb="$(get_var "have_innodb" "$dir/mysql-variables")"
 
1326
   if [ "${have_innodb}" = "YES" ]; then
 
1327
      section_innodb "$dir/mysql-variables" "$dir/mysql-status"
 
1328
 
 
1329
      if [ -s "$dir/innodb-status" ]; then
 
1330
         format_innodb_status "$dir/innodb-status"
 
1331
      fi
 
1332
   fi
 
1333
 
 
1334
   # ########################################################################
 
1335
   # MyISAM
 
1336
   # ########################################################################
 
1337
   section "MyISAM"
 
1338
   section_myisam "$dir/mysql-variables" "$dir/mysql-status"
 
1339
 
 
1340
   # ########################################################################
 
1341
   # Users & Security
 
1342
   # ########################################################################
 
1343
   section "Security"
 
1344
   local users="$( format_users "$dir/mysql-users" )"
 
1345
   name_val "Users" "${users}"
 
1346
   name_val "Old Passwords" "$(get_var old_passwords "$dir/mysql-variables")"
 
1347
 
 
1348
   # ########################################################################
 
1349
   # Binary Logging
 
1350
   # ########################################################################
 
1351
   section "Binary Logging"
 
1352
 
 
1353
   if    [ -s "$dir/mysql-master-logs" ] \
 
1354
      || [ -s "$dir/mysql-master-status" ]; then
 
1355
      summarize_binlogs "$dir/mysql-master-logs"
 
1356
      local format="$(get_var binlog_format "$dir/mysql-variables")"
 
1357
      name_val binlog_format "${format:-STATEMENT}"
 
1358
      name_val expire_logs_days "$(get_var expire_logs_days "$dir/mysql-variables")"
 
1359
      name_val sync_binlog "$(get_var sync_binlog "$dir/mysql-variables")"
 
1360
      name_val server_id "$(get_var server_id "$dir/mysql-variables")"
 
1361
      format_binlog_filters "$dir/mysql-master-status"
 
1362
   fi
 
1363
 
 
1364
# Replication: seconds behind, running, filters, skip_slave_start, skip_errors,
 
1365
# read_only, temp tables open, slave_net_timeout, slave_exec_mode
 
1366
 
 
1367
   # ########################################################################
 
1368
   # Interesting things that you just ought to know about.
 
1369
   # ########################################################################
 
1370
   section "Noteworthy Variables"
 
1371
   section_noteworthy_variables "$dir/mysql-variables"
 
1372
 
 
1373
   # ########################################################################
 
1374
   # If there is a my.cnf in a standard location, see if we can pretty-print it.
 
1375
   # ########################################################################
 
1376
   section "Configuration File"
 
1377
   local cnf_file="$(get_var "pt-summary-internal-Config_File_path" "$dir/mysql-variables")"
 
1378
   if [ -n "${cnf_file}" ]; then
 
1379
      name_val "Config File" "${cnf_file}"
 
1380
      pretty_print_cnf_file "$dir/mysql-config-file"
 
1381
   else
 
1382
      name_val "Config File" "Cannot autodetect or find, giving up"
 
1383
   fi
 
1384
 
 
1385
   # Make sure that we signal the end of the tool's output.
 
1386
   section "The End"
 
1387
}
 
1388
 
 
1389
# ###########################################################################
 
1390
# End report_mysql_info package
 
1391
# ###########################################################################