7 mysql_ - Munin plugin to display misc MySQL server status
9 =head1 APPLICABLE SYSTEMS
11 Any MySQL platform, tested by the authors on:
13 * MySQL 5.5.32, 5.5.37
17 * MariaDB-5.5.39(galera).
20 * MariaDB-10 Query Response Time: https://mariadb.com/kb/en/mariadb/query_response_time-plugin/
22 Information Schema tables:
23 * User statistics - MariaDB-5.2+, OurDelta, Percona Server - https://mariadb.com/kb/en/mariadb/user-statistics
27 This script is used to generate data for several graphs. To generate
28 data for one specific graph, you need to create a symbolic link with a
29 name like mysql_<GRAPH> to this script.
31 If you need to run against multiple MySQL instances on the same host,
32 create your symlinks with names like mysql<N>_<GRAPH> where N is any
33 non-negative integer. You must also set the env.cachenamespace variable
34 to a unique value for each group of symlinks.
36 To get a list of symlinks that can be created, run:
40 In addition you might need to specify connection parameters in the
41 plugin configuration to override the defaults. These are the defaults:
44 env.mysqlconnection DBI:mysql:information_schema
50 env.mysqlconnection DBI:mysql:information_schema;host=127.0.0.1;port=3306
52 env.mysqlpassword geheim
53 env.cachenamespace munin_mysql_pri
55 env.mysqlconnection DBI:mysql:information_schema;host=127.0.0.1;port=13306
57 env.mysqlpassword ryuWyawEv
58 env.cachenamespace munin_mysql_alt
62 env.mysqlconnection DBI:mysql:information_schema;mysql_read_default_file=/etc/munin/.my-10.cnf
63 env.cachenamespace munin_mysql_10
64 # here the [client] section of /etc/munin/.my-10.cnf is read. socket= can
67 Creating a munin user:
69 CREATE USER 'munin'@'localhost' IDENTIFIED BY 'ryuWyawEv';
71 or with a unix_socket plugin (INSTALL PLUGIN unix_socket SONAME 'auth_socket')
73 CREATE USER 'munin'@'localhost' IDENTIFIED WITH unix_socket;
75 Note: requires 'user munin' in the configuration.
77 The minimum required priviledges of the munin database user is:
79 GRANT PROCESS, REPLICATION CLIENT ON *.* TO 'munin'@'localhost';
82 Warning and critical values can be set via the environment in the usual way.
86 env.slave_io_running_warning 0.5
87 env.slave_sql_running_warning 0.5
88 env.seconds_behind_master_warning 300
89 env.seconds_behind_master_critical 600
97 The plugin uses shared memory to cache the statistics gathered from
98 MySQL. This ensures minimal inpact on the MySQL server.
104 =head1 INTERPRETATION
108 The statistics from innodb are mainly collected from the command
110 SHOW ENGINE INNODB STATUS
112 A nice walk through is found at
113 L<http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/>
116 L<http://blog.jcole.us/2014/04/16/the-basics-of-the-innodb-undo-logging-and-history-system/>
120 FIX point to relevant sections in the MySQL manual and other www
121 resources for each graph
125 =item mysql_replication
127 slave_io_running and slave_sql_running both translate the "Yes" values to 0 and
128 anything else to 1 for their respective fields in the "SHOW SLAVE STATUS" output.
129 This can be used to warn on slave failure if the warning and critical values
130 are set as seen in a previous section.
132 =item wsrep_cluster_status
134 "Primary" is translated 0 and "non-Primary" to 1.
140 Copyright (C) 2008,2009 Kjell-Magne Øierud, 2014 Open Query
142 This program is free software; you can redistribute it and/or modify
143 it under the terms of the GNU General Public License as published by
144 the Free Software Foundation; version 2 dated June, 1991.
146 This program is distributed in the hope that it will be useful, but
147 WITHOUT ANY WARRANTY; without even the implied warranty of
148 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
149 General Public License for more details.
151 You should have received a copy of the GNU General Public License along
152 with this program; if not, write to the Free Software Foundation, Inc.,
153 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
157 git-master + a few munin modifications
159 This plugin was downloaded from L<http://github.com/kjellm/munin-mysql/>
161 =head1 MAGICK MARKERS
164 #%# capabilities=suggest autoconf
174 use Math::BigInt; # Used to append "=> lib 'GMP'" here, but GMP caused
175 # segfault on some occasions. Removed as I don't
176 # think the tiny performance boost is worth the
178 use Storable qw(nfreeze thaw);
185 eval 'require Cache::SharedMemoryCache';
186 $has_cache = $@ ? 0 : 1;
190 #---------------------------------------------------------------------
192 #---------------------------------------------------------------------
195 'dsn' => $ENV{'mysqlconnection'} || 'DBI:mysql:information_schema',
196 'user' => $ENV{'mysqluser'} || 'root',
197 'password' => $ENV{'mysqlpassword'} || '',
198 'cache_namespace' => $ENV{'cachenamespace'} || 'munin_mysql',
202 #---------------------------------------------------------------------
204 #---------------------------------------------------------------------
206 my %cache_options = (
207 'namespace' => $config{cache_namespace},
208 'default_expires_in' => 60,
211 my $shared_memory_cache ;
214 $shared_memory_cache = Cache::SharedMemoryCache->new(\%cache_options)
215 or die("Couldn't instantiate SharedMemoryCache");
218 #---------------------------------------------------------------------
219 # G R A P H D E F I N I T I O N S
220 #---------------------------------------------------------------------
222 # These are defaults to save typing in the graph definitions
225 args => '--base 1000',
227 data_source_attrs => {
234 # %graphs contains the graph definitions, it is indexed on the graph
235 # name. The information stored for each graph is used for both showing
236 # data source values and for printing the graph configuration. Each
237 # graph follows the followingformat:
241 # # The global attributes for this graph
243 # # Attributes common to all data sources in this graph
244 # data_source_attrs => {}
247 # # NAME - The name of the data source (e.g. variable names
248 # # from SHOW STATUS)
249 # # DATA_SOURCE_ATTRS - key-value pairs with data source
251 # {name => 'NAME', (DATA_SOURCE_ATTRS)},
256 #---------------------------------------------------------------------
259 $graphs{wsrep_cluster_status} = {
262 title => 'Galera Status',
265 data_source_attrs => {
272 {name => 'wsrep_cluster_status', label => '0-Primary, 1-Non-Primary',
273 info => 'If the host is primary',
279 $graphs{wsrep_cluster_size} = {
282 title => 'Galera cluster size',
285 data_source_attrs => {
290 {name => 'wsrep_cluster_size', label => 'Cluster size',
291 info => 'The number of hosts in the cluster.',
297 # http://www.codership.com/wiki/doku.php?id=galera_node_fsm
298 $graphs{wsrep_local_state} = {
301 title => 'Galera node state',
302 vlabel => 'State (galera_node_fsm)',
303 args => '--lower-limit 0 --upper-limit 6',
305 data_source_attrs => {
312 {name => 'wsrep_local_state', label => '1-Joining, 2-Donor, 3-Joined, 4-Synced, 5-Donor, 6-Join after Donor ',
313 info => 'The state of the node in the cluster.',
315 warning => '3.5:4.5'},
319 #---------------------------------------------------------------------
321 $graphs{wsrep_transactions} = {
324 title => 'Galera transactions',
326 data_source_attrs => {
331 {name => 'wsrep_last_committed', label => 'Committed transactions',
332 info => '# of committed transactions.',
335 {name => 'wsrep_local_commits', label => 'Locally Committed transactions',
336 info => '# of locally committed transactions.',
342 #---------------------------------------------------------------------
344 $graphs{wsrep_writesets} = {
347 title => 'Galera writesets',
349 data_source_attrs => {
354 {name => 'wsrep_replicated', label => 'Writesets sent',
355 info => '# of writesets sent to other nodes',
359 {name => 'wsrep_received', label => 'Writesets received',
360 info => '# of writesets received from other nodes',
363 negative => 'wsrep_replicated'},
367 #-------------------------
370 $graphs{wsrep_writesetbytes} = {
373 title => 'Galera writesets bytes/sec',
375 data_source_attrs => {
379 {name => 'wsrep_received_bytes', label => 'Writesets bytes received',
380 info => '# of bytes in writesets received from other nodes',
384 {name => 'wsrep_replicated_bytes', label => 'Writesets bytes sent',
385 info => '# of bytes in writesets sent to other nodes',
389 negative => 'wsrep_received_bytes'},
390 {name => 'wsrep_repl_keys_bytes', label => 'Writeset key size sent',
391 info => '# of bytes in writesets of keys sent to other nodes',
394 {name => 'wsrep_repl_data_bytes', label => 'Writeset data size sent',
395 info => '# of bytes in writesets of data sent to other nodes',
398 {name => 'wsrep_repl_other_bytes', label => 'Writeset other size sent',
399 info => '# of bytes in writesets of other data sent to other nodes',
406 #-------------------------
408 $graphs{wsrep_errors} = {
411 title => 'Galera transaction problems'
413 data_source_attrs => {
418 {name => 'wsrep_local_cert_failures', label => 'Certification failures',
421 {name => 'wsrep_local_bf_aborts', label => 'Aborted local transactions',
424 {name => 'wsrep_local_replays', label => 'Replays',
430 #-------------------------
432 $graphs{wsrep_queue} = {
435 title => 'Galera queues',
436 vlabel => 'queue length received (-) / sent (+) per ${graph_period}',
438 data_source_attrs => {
443 {name => 'wsrep_local_recv_queue', label => 'Receive queue length',
446 {name => 'wsrep_local_recv_queue_min', label => 'Receive queue length min',
449 {name => 'wsrep_local_recv_queue_avg', label => 'Average receive queue length',
452 {name => 'wsrep_local_recv_queue_max', label => 'Receive queue length max',
455 {name => 'wsrep_local_send_queue', label => 'Send queue length',
457 negative => 'wsrep_local_recv_queue'},
458 {name => 'wsrep_local_send_queue_min', label => 'Send queue length min',
460 negative => 'wsrep_local_recv_queue_min'},
461 {name => 'wsrep_local_send_queue_avg', label => 'Average send queue length',
463 negative => 'wsrep_local_recv_queue_avg'},
464 {name => 'wsrep_local_send_queue_max', label => 'Send queue length max',
466 negative => 'wsrep_local_recv_queue_max'},
470 #-------------------------
472 $graphs{wsrep_concurrency} = {
475 title => 'Galera Performance - Apply to Commit',
476 vlabel => 'commit + / apply - '
478 data_source_attrs => {
484 {name => 'wsrep_apply_window', label => 'apply window',
486 {name => 'wsrep_apply_oooe', label => 'apply out of order',
488 {name => 'wsrep_apply_oool', label => 'apply out of order (slowness)',
490 {name => 'wsrep_commit_window', label => 'commit window',
491 negative => 'wsrep_apply_window'},
492 {name => 'wsrep_commit_oooe', label => 'commit out of order',
493 negative => 'wsrep_apply_oooe'},
494 {name => 'wsrep_commit_oool', label => 'commit out of order (slowness)',
495 negative => 'wsrep_apply_oool'},
499 #-------------------------
501 $graphs{wsrep_flow} = {
504 title => 'Galera flow control',
505 vlabel => 'events received (-) / sent (+) per ${graph_period}',
507 data_source_attrs => {
512 {name => 'wsrep_flow_control_recv', label => 'Pause events received',
516 {name => 'wsrep_flow_control_sent', label => 'Pause events sent',
519 negative => 'wsrep_flow_control_recv'},
525 #-------------------------
527 $graphs{wsrep_flow_paused} = {
530 title => 'Galera flow control paused ratio',
532 data_source_attrs => {
537 {name => 'wsrep_flow_control_paused', label => 'Ratio flow control was paused',
546 #-------------------------
548 $graphs{wsrep_flow_paused_ns} = {
551 title => 'Galera flow control paused time',
552 vlabel => 'nanoseconds',
554 data_source_attrs => {
559 {name => 'wsrep_flow_control_paused_ns', label => 'Time flow control was paused (ns)',
562 critical => 1000000},
566 #-------------------------
568 $graphs{wsrep_distance} = {
571 title => 'Galera distance',
573 data_source_attrs => {
578 {name => 'wsrep_cert_deps_distance', label => 'cert_deps_distance',
580 {name => 'wsrep_cert_index_size', label => 'wsrep_cert_index_size',
582 {name => 'wsrep_slave_threads', label => 'wsrep_slave_threads',
584 {name => 'wsrep_commit_window', label => 'commit_window',
589 #-------------------------
590 $graphs{bin_relay_log} = {
593 title => 'Binary/Relay Logs',
594 vlabel => 'Log activity',
596 data_source_attrs => {
601 {name => 'Binlog_cache_disk_use', label => 'Binlog Cache Disk Use'},
602 {name => 'Binlog_cache_use', label => 'Binlog Cache Use'},
603 {name => 'Binlog_stmt_cache_disk_use', label => 'Binlog Statement Cache Disk Use'},
604 {name => 'Binlog_stmt_cache_use', label => 'Binlog Statement Cache Use'},
605 {name => 'ma_binlog_size', label => 'Binary Log Space'},
606 {name => 'relay_log_space', label => 'Relay Log Space'},
610 #---------------------------------------------------------------------
612 $graphs{commands} = {
615 title => 'Command Counters',
616 vlabel => 'Commands per ${graph_period}',
617 total => 'Questions',
619 data_source_attrs => {},
622 {name => 'Com_delete', label => 'Delete'},
623 {name => 'Com_insert', label => 'Insert'},
624 {name => 'Com_insert_select', label => 'Insert select'},
625 {name => 'Com_load', label => 'Load Data'},
626 {name => 'Com_replace', label => 'Replace'},
627 {name => 'Com_replace_select', label => 'Replace select'},
628 {name => 'Com_select', label => 'Select'},
629 {name => 'Com_update', label => 'Update'},
630 {name => 'Com_update_multi', label => 'Update multi'},
634 #---------------------------------------------------------------------
636 $graphs{connections} = {
639 title => 'Connections',
640 vlabel => 'Connections per ${graph_period}',
642 data_source_attrs => {
647 {name => 'max_connections', label => 'Max connections',
651 {name => 'Max_used_connections', label => 'Max used',
655 {name => 'Aborted_clients', label => 'Aborted clients'},
656 {name => 'Aborted_connects', label => 'Aborted connects'},
657 {name => 'Threads_connected', label => 'Threads connected',
659 {name => 'Threads_running', label => 'Threads running',
661 {name => 'Connections', label => 'New connections'},
665 #---------------------------------------------------------------------
672 data_source_attrs => {
678 {name => 'open_files_limit', label => 'File Limit',
681 {name => 'Open_files', label => 'Open files',
687 #---------------------------------------------------------------------
694 data_source_attrs => {
700 {name => 'table_open_cache', label => 'Table cache',
703 {name => 'innodb_open_files', label => 'Innodb Table Cache Limit',
706 {name => 'Open_tables', label => 'Open tables'},
707 {name => 'Slave_open_temp_tables', label => 'Open Slave Temp Tables'},
708 {name => 'Opened_tables', label => 'Opened tables',
711 {name => 'Opened_views', label => 'Opened Views',
717 #---------------------------------------------------------------------
719 $graphs{table_definitions} = {
722 title => 'Tables Definitions',
724 data_source_attrs => {
730 {name => 'table_definition_cache', label => 'Cache Limit',
733 {name => 'Open_table_definitions', label => 'Open'},
734 {name => 'Opened_table_definitions', label => 'Opened',
740 #---------------------------------------------------------------------
742 $graphs{innodb_bpool} = {
745 title => 'InnoDB Buffer Pool',
747 args => '--base 1024',
749 data_source_attrs => {
755 {name => 'ib_bpool_size', label => 'Buffer pool size',
758 {name => 'ib_bpool_dbpages', label => 'Database pages',
761 {name => 'ib_bpool_free', label => 'Free pages'},
762 {name => 'ib_bpool_modpages', label => 'Modified pages'},
763 {name => 'ib_bpool_oldpages', label => 'Old pages'},
767 #---------------------------------------------------------------------
769 $graphs{innodb_bpool_act} = {
772 title => 'InnoDB Buffer Pool Activity',
773 vlabel => 'Pages per ${graph_period}',
776 data_source_attrs => {
781 {name => 'ib_bpool_read', label => 'Read'},
782 {name => 'ib_bpool_created', label => 'Created'},
783 {name => 'ib_bpool_written', label => 'Written'},
784 {name => 'ib_bpool_made_young', label => 'Made young'},
785 {name => 'ib_bpool_made_not_young', label => 'Made not young'},
789 #---------------------------------------------------------------------
791 $graphs{innodb_bpool_internal_breakdown} = {
794 title => 'InnoDB Buffer Pool Internal breakdown',
795 args => '--base 1024 --lower-limit 0',
798 data_source_attrs => {
805 {name => 'ib_bpool_internal_adaptive_hash_size_const', label => 'Adaptive Hash const'},
806 {name => 'ib_bpool_internal_adaptive_hash_size_var', label => 'Adaptive Hash var'},
807 {name => 'ib_bpool_internal_page_hash_size_total', label => 'Page Hash'},
808 {name => 'ib_bpool_internal_dictionary_cache_size_const', label => 'Dictionary const'},
809 {name => 'ib_bpool_internal_dictionary_cache_size_var', label => 'Dictionary var'},
810 {name => 'ib_bpool_internal_file_system_size_const', label => 'Filesystem const'},
811 {name => 'ib_bpool_internal_file_system_size_var', label => 'Filesystem var'},
812 {name => 'ib_bpool_internal_lock_system_size_const', label => 'Lock system const'},
813 {name => 'ib_bpool_internal_lock_system_size_var', label => 'Lock system var'},
814 {name => 'ib_bpool_internal_recovery_system_size_const', label => 'Recovery system const'},
815 {name => 'ib_bpool_internal_recovery_system_size_var', label => 'Recovery system var'},
819 #---------------------------------------------------------------------
821 $graphs{innodb_insert_buf} = {
824 title => 'InnoDB Insert Buffer',
825 vlabel => 'Activity per ${graph_period}',
827 data_source_attrs => {
832 {name => 'ib_ibuf_inserts', label => 'Merge Inserts'},
833 {name => 'ib_ibuf_delete', label => 'Merge Deletes'},
834 {name => 'ib_ibuf_merged_rec', label => 'Merged Records'},
835 {name => 'ib_ibuf_merges', label => 'Merges'},
836 {name => 'ib_ibuf_discard_inserts', label => 'Discard Inserts'},
837 {name => 'ib_ibuf_discard_delete', label => 'Discard Deletes'},
841 #---------------------------------------------------------------------
843 $graphs{innodb_adaptive_hash} = {
846 title => 'InnoDB Adaptive Hash Optimiser',
848 data_source_attrs => {
853 {name => 'Innodb_adaptive_hash_hash_searches', label => 'Hash Searches'},
854 {name => 'Innodb_adaptive_hash_non_hash_searches', label => 'Nonhash Searches'},
858 #---------------------------------------------------------------------
860 $graphs{innodb_io} = {
863 title => 'InnoDB IO',
864 vlabel => 'IO operations per ${graph_period}',
866 data_source_attrs => {
871 {name => 'ib_io_read', label => 'File reads'},
872 {name => 'ib_io_write', label => 'File writes'},
873 {name => 'ib_io_log', label => 'Log writes'},
874 {name => 'ib_io_fsync', label => 'File syncs'},
878 #---------------------------------------------------------------------
880 $graphs{innodb_io_pend} = {
883 title => 'InnoDB IO Pending',
884 vlabel => 'Pending operations',
886 data_source_attrs => {
891 {name => 'ib_iop_log', label => 'AIO Log'},
892 {name => 'ib_iop_sync', label => 'AIO Sync'},
893 {name => 'ib_iop_flush_bpool', label => 'Buf Pool Flush'},
894 {name => 'ib_iop_flush_log', label => 'Log Flushes'},
895 {name => 'ib_iop_ibuf_aio', label => 'Insert Buf AIO Read'},
896 {name => 'ib_iop_aioread', label => 'Normal AIO Reads'},
897 {name => 'ib_iop_aiowrite', label => 'Normal AIO Writes'},
901 #---------------------------------------------------------------------
903 $graphs{innodb_log} = {
906 title => 'InnoDB Log',
907 vlabel => 'Log activity per ${graph_period}',
909 data_source_attrs => {
914 {name => 'innodb_log_buffer_size', label => 'Buffer Size',
918 {name => 'ib_log_flush', label => 'KB Flushed'},
919 {name => 'ib_log_written', label => 'KB Written'},
923 #---------------------------------------------------------------------
925 $graphs{innodb_rows} = {
928 title => 'InnoDB Row Operations',
929 vlabel => 'Operations per ${graph_period}',
932 data_source_attrs => {},
935 {name => 'Innodb_rows_deleted', label => 'Deletes'},
936 {name => 'Innodb_rows_inserted', label => 'Inserts'},
937 {name => 'Innodb_rows_read', label => 'Reads'},
938 {name => 'Innodb_rows_updated', label => 'Updates'},
942 #---------------------------------------------------------------------
944 $graphs{innodb_semaphores} = {
947 title => 'InnoDB Semaphores',
948 vlabel => 'Semaphores per ${graph_period}',
950 data_source_attrs => {
955 {name => 'ib_spin_rounds', label => 'Spin Rounds'},
956 {name => 'ib_spin_waits', label => 'Spin Waits'},
957 {name => 'ib_os_waits', label => 'OS Waits'},
958 {name => 'ib_rw_shared_rounds', label => 'RW/S Rounds'},
959 {name => 'ib_rw_shared_waits', label => 'RW/S Waits'},
960 {name => 'ib_rw_shared_os_waits', label => 'RW/S OS Waits'},
961 {name => 'ib_rw_excl_rounds', label => 'RW/X Rounds'},
962 {name => 'ib_rw_excl_waits', label => 'RW/X Waits'},
963 {name => 'ib_rw_excl_os_waits', label => 'RW/X OS Waits'},
967 #---------------------------------------------------------------------
969 $graphs{innodb_tnx} = {
972 title => 'InnoDB Transactions',
973 vlabel => 'Transactions per ${graph_period}',
975 data_source_attrs => {
980 {name => 'ib_tnx', label => 'Transactions created'},
984 #---------------------------------------------------------------------
986 $graphs{innodb_history_list_length} = {
989 title => 'InnoDB History List Length',
990 vlabel => 'Undo log units',
992 data_source_attrs => {
998 {name => 'ib_tnx_hist', label => 'History List Length'},
1002 #---------------------------------------------------------------------
1004 $graphs{innodb_srv_master_thread} = {
1007 title => 'InnoDB Master Thread',
1009 data_source_attrs => {
1011 draw => 'AREASTACK',
1015 {name => 'ib_srv_main_flush_loops', label => 'Flush Loop'},
1016 {name => 'ib_srv_main_background_loops', label => 'Background Loop'},
1017 {name => 'ib_srv_main_flushs_writes', label => 'Flushes/Writes', draw => 'LINE1'},
1021 #---------------------------------------------------------------------
1023 $graphs{innodb_queries} = {
1026 title => 'InnoDB Engine Queries and Transactions',
1027 args => '--lower-limit 0',
1029 data_source_attrs => {
1034 {name => 'ib_innodb_queries', label => 'Active'},
1035 {name => 'ib_innodb_transactions_active', label => 'Transactions'},
1036 {name => 'ib_innodb_query_queue_len', label => 'Queued'},
1040 #---------------------------------------------------------------------
1042 $graphs{innodb_read_views} = {
1045 title => 'InnoDB Read Views',
1046 args => '--lower-limit 0',
1048 data_source_attrs => {
1053 {name => 'ib_innodb_read_views', label => 'Views'},
1057 #---------------------------------------------------------------------
1059 $graphs{innodb_descriptors} = {
1062 title => 'InnoDB Descriptors',
1063 args => '--lower-limit 0',
1065 data_source_attrs => {
1070 {name => 'ib_innodb_descriptors', label => 'Descriptors'},
1071 {name => 'ib_innodb_descriptors_max', label => 'Max', draw => 'AREA', colour => 'ffd660'},
1075 #---------------------------------------------------------------------
1077 $graphs{performance} = {
1080 title => 'Performance Schema Losses',
1082 data_source_attrs => {
1087 {name => 'Performance_schema_cond_classes_lost', label => 'Condition classes'},
1088 {name => 'Performance_schema_cond_instances_lost', label => 'Condition instances'},
1089 {name => 'Performance_schema_file_classes_lost', label => 'File classes'},
1090 {name => 'Performance_schema_file_handles_lost', label => 'File handles'},
1091 {name => 'Performance_schema_file_instances_lost', label => 'File instances'},
1092 {name => 'Performance_schema_locker_lost', label => 'Locker'},
1093 {name => 'Performance_schema_mutex_classes_lost', label => 'Mutex classes'},
1094 {name => 'Performance_schema_mutex_instances_lost', label => 'Mutex instances'},
1095 {name => 'Performance_schema_rwlock_classes_lost', label => 'Read/Write lock classes'},
1096 {name => 'Performance_schema_rwlock_instances_lost', label => 'Read/Write lock instances'},
1097 {name => 'Performance_schema_table_handles_lost', label => 'Table handles'},
1098 {name => 'Performance_schema_table_instances_lost', label => 'Table instances'},
1099 {name => 'Performance_schema_thread_classes_lost', label => 'Thread classes'},
1100 {name => 'Performance_schema_thread_instances_lost', label => 'Thread instances'},
1104 #---------------------------------------------------------------------
1106 $graphs{myisam_indexes} = {
1109 title => 'MyISAM Indexes',
1110 vlabel => 'Requests per ${graph_period}',
1112 data_source_attrs => {
1117 {name => 'Key_read_requests', label => 'Key read requests'},
1118 {name => 'Key_reads', label => 'Key reads'},
1119 {name => 'Key_write_requests', label => 'Key write requests'},
1120 {name => 'Key_writes', label => 'Key writes'},
1124 #---------------------------------------------------------------------
1126 $graphs{network_traffic} = {
1129 title => 'Network Traffic',
1130 args => '--base 1024',
1131 vlabel => 'Bytes received (-) / sent (+) per ${graph_period}',
1133 data_source_attrs => {
1138 {name => 'Bytes_received', label => 'Bytes transferred',
1140 {name => 'Bytes_sent', label => 'Bytes transferred',
1141 negative => 'Bytes_received'},
1145 #---------------------------------------------------------------------
1150 title => 'Query Cache',
1151 vlabel => 'Commands per ${graph_period}',
1153 data_source_attrs => {
1158 {name => 'Qcache_queries_in_cache', label => 'Queries in cache', type => 'GAUGE'},
1159 {name => 'Qcache_hits', label => 'Cache hits'},
1160 {name => 'Subquery_cache_hit', label => 'Subquery Cache hits'},
1161 {name => 'Subquery_cache_miss', label => 'Subquery Cache misses'},
1162 {name => 'Qcache_inserts', label => 'Inserts'},
1163 {name => 'Qcache_not_cached', label => 'Not cached'},
1164 {name => 'Qcache_lowmem_prunes', label => 'Low-memory prunes'},
1168 #---------------------------------------------------------------------
1170 $graphs{qcache_mem} = {
1173 title => 'Query Cache Memory',
1175 args => '--base 1024 --lower-limit 0',
1177 data_source_attrs => {
1183 {name => 'query_cache_size', label => 'Cache size'},
1184 {name => 'Qcache_free_memory', label => 'Free mem'},
1189 #---------------------------------------------------------------------
1191 $graphs{max_mem} = {
1194 title => 'Maximum memory that Mysql could use',
1196 args => '--base 1024 --lower-limit 0',
1198 data_source_attrs => {
1199 draw => 'AREASTACK',
1204 {name => 'mysql_connection_memory', label => 'Connection Memory'},
1205 {name => 'mysql_base_memory', label => 'Base MYSQL Memory'},
1210 #---------------------------------------------------------------------
1212 $graphs{replication} = {
1215 title => 'Replication',
1216 vlabel => 'Activity',
1218 data_source_attrs => {
1223 {name => 'slave_io_running', label => 'Slave IO Running',
1226 {name => 'slave_sql_running', label => 'Slave SQL Running',
1229 {name => 'Slave_retried_transactions', label => 'Retried Transactions'},
1230 {name => 'Slave_open_temp_tables', label => 'Open Temp Tables'},
1231 {name => 'seconds_behind_master', label => 'Secs Behind Master',
1236 #---------------------------------------------------------------------
1238 $graphs{select_types} = {
1241 title => 'Select types',
1242 vlabel => 'Commands per ${graph_period}',
1245 data_source_attrs => {},
1248 {name => 'Select_full_join', label => 'Full join'},
1249 {name => 'Select_full_range_join', label => 'Full range'},
1250 {name => 'Select_range', label => 'Range'},
1251 {name => 'Select_range_check', label => 'Range check'},
1252 {name => 'Select_scan', label => 'Scan'},
1256 #---------------------------------------------------------------------
1261 title => 'Slow Queries',
1262 vlabel => 'Slow queries per ${graph_period}',
1264 data_source_attrs => {
1269 {name => 'Slow_queries', label => 'Slow queries'},
1273 #---------------------------------------------------------------------
1279 vlabel => 'Sorts / ${graph_period}',
1281 data_source_attrs => {
1286 {name => 'Sort_rows', label => 'Rows sorted'},
1287 {name => 'Sort_range', label => 'Range'},
1288 {name => 'Sort_merge_passes', label => 'Merge passes'},
1289 {name => 'Sort_scan', label => 'Scan'},
1293 #---------------------------------------------------------------------
1295 $graphs{table_locks} = {
1298 title => 'Table locks',
1299 vlabel => 'locks per ${graph_period}',
1301 data_source_attrs => {
1306 {name => 'Table_locks_immediate', label => 'Table locks immed'},
1307 {name => 'Table_locks_waited', label => 'Table locks waited'},
1311 #---------------------------------------------------------------------
1313 $graphs{tmp_tables} = {
1316 title => 'Temporary objects',
1317 vlabel => 'Objects per ${graph_period}',
1319 data_source_attrs => {
1324 {name => 'Created_tmp_disk_tables', label => 'Temp disk tables'},
1325 {name => 'Created_tmp_tables', label => 'Temp tables'},
1326 {name => 'Created_tmp_files', label => 'Temp files'},
1331 #---------------------------------------------------------------------
1338 data_source_attrs => {
1344 {name => 'Rows_read', label => 'Read'},
1345 {name => 'Rows_sent', label => 'Sent'},
1346 {name => 'Rows_tmp_read', label => 'Temp Read'},
1350 #---------------------------------------------------------------------
1352 $graphs{handler_read} = {
1355 title => 'Read Handler',
1357 data_source_attrs => {
1358 draw => 'AREASTACK',
1363 {name => 'Handler_read_first', label => 'Key First'},
1364 {name => 'Handler_read_key', label => 'Key Read'},
1365 {name => 'Handler_read_last', label => 'Key Last'},
1366 {name => 'Handler_read_prev', label => 'Key Prev'},
1367 {name => 'Handler_read_rnd', label => 'Row position'},
1368 {name => 'Handler_read_rnd_deleted', label => 'Row position delete'},
1369 {name => 'Handler_read_rnd_next', label => 'Row position next'},
1373 #---------------------------------------------------------------------
1375 $graphs{handler_transaction} = {
1378 title => 'Transactions Handler',
1380 data_source_attrs => {
1381 draw => 'AREASTACK',
1386 {name => 'Handler_commit', label => 'Commit'},
1387 {name => 'Handler_rollback', label => 'Rollback'},
1388 {name => 'Handler_savepoint', label => 'Savepoint'},
1389 {name => 'Handler_savepoint_rollback', label => 'Savepoint Rollback'},
1393 #---------------------------------------------------------------------
1395 $graphs{handler_write} = {
1398 title => 'Write/Update Handler',
1400 data_source_attrs => {
1406 {name => 'Handler_write', label => 'Writes'},
1407 {name => 'Handler_update', label => 'Updates'},
1411 #---------------------------------------------------------------------
1413 $graphs{handler_tmp} = {
1416 title => 'Temporary Write/Update Handler',
1418 data_source_attrs => {
1424 {name => 'Handler_tmp_write', label => 'Writes'},
1425 {name => 'Handler_tmp_update', label => 'Updates'},
1429 #---------------------------------------------------------------------
1431 $graphs{execution} = {
1434 title => 'Execution Events',
1436 data_source_attrs => {
1442 {name => 'Executed_events', label => 'Events'},
1443 {name => 'Executed_triggers', label => 'Triggers'},
1447 #---------------------------------------------------------------------
1452 title => 'Index Condition Pushdown',
1454 data_source_attrs => {
1460 {name => 'Handler_icp_attempts', label => 'Attempts'},
1461 {name => 'Handler_icp_match', label => 'Matches'},
1465 #---------------------------------------------------------------------
1470 title => 'Multi Range Read optimizations',
1472 data_source_attrs => {
1478 {name => 'Handler_mrr_init', label => 'Uses'},
1479 {name => 'Handler_mrr_key_refills', label => 'Key refills'},
1480 {name => 'Handler_mrr_rowid_refills', label => 'Row refills'},
1484 #---------------------------------------------------------------------
1486 # These are mysql plugins of type INFORMATION SCHEMA
1488 # These will be added to $graphs if available
1489 #---------------------------------------------------------------------
1491 my %graph_plugins = ();
1493 $graph_plugins{query_response_time} = {
1497 title => 'Query Response Time Count',
1498 vlabel => 'queries per ${graph_period}',
1500 data_source_attrs => {
1505 # data_sources are populated by sub plugin_query_response_time
1512 title => 'Query Response Time Total',
1513 vlabel => 'query time (microseconds) per ${graph_period}',
1515 data_source_attrs => {
1520 # data_sources are populated by sub plugin_query_response_time
1526 $graph_plugins{user_statistics} = {
1530 title => 'User Connections',
1531 vlabel => 'connections per ${graph_period}',
1533 data_source_attrs => {
1538 cols => { 'total_connections' => {}, 'concurrent_connections' => {}, 'denied_connections' => {}, 'lost_connections' => {}},
1545 title => 'User Time',
1546 vlabel => 'seconds',
1548 data_source_attrs => {
1553 cols => { 'connected_time' => {}, 'busy_time' => {}, 'cpu_time' => {} },
1560 title => 'User Bytes',
1563 data_source_attrs => {
1568 cols => { 'bytes_received' => {}, 'bytes_sent' => {}, 'binlog_bytes_written' => {} },
1575 title => 'User Rows',
1578 data_source_attrs => {
1583 cols => { 'rows_read' => {}, 'rows_sent' => {}, 'rows_deleted' => {}, 'rows_inserted' => {}, 'rows_updated' => {} },
1590 title => 'Command breakdown by user',
1591 vlabel => 'commands',
1593 data_source_attrs => {
1598 cols => { 'select_commands' => {}, 'update_commands' => {}, 'other_commands' => {}, 'commit_transactions' => {}, 'rollback_transactions' => {} },
1604 #---------------------------------------------------------------------
1606 #---------------------------------------------------------------------
1610 # Global hash holding the data collected from mysql.
1612 our $data; # Was 'my'. Changed to 'our' to facilitate testing.
1616 my $graph = basename($0);
1617 $graph =~ s/^mysql[0-9]*_//g; # allow multiple instances
1618 my $command = $ARGV[0] || 'show';
1621 'autoconf' => \&autoconf,
1622 'config' => \&config,
1624 'suggest' => \&suggest,
1627 die "Unknown command: $command"
1628 unless exists $command_map{$command};
1630 die "Missing dependency Cache::Cache"
1631 unless $has_cache || $command eq 'autoconf';
1633 return $command_map{$command}->($graph);
1637 #---------------------------------------------------------------------
1638 # C O M M A N D H A N D L E R S
1639 #---------------------------------------------------------------------
1641 # Each command handler should return an appropriate exit code
1644 # http://munin-monitoring.org/wiki/ConcisePlugins#autoconf
1646 unless ($has_cache) {
1647 print "no (Missing dependency Cache::Cache)\n";
1656 $err =~ s{\s at \s \S+ \s line .*}{}xms;
1657 print "no ($err)\n";
1665 # http://munin-monitoring.org/wiki/ConcisePlugins#suggest
1668 # What is the best way to decide which graphs is applicable to a
1671 # Use lack of variables to indicate that the capability doesn't exist
1672 # Use variable values to indicate some graph isn't currently used.
1673 # update_data() now does this.
1678 foreach my $graph (sort keys(%graphs)) {
1679 next if $graph =~ /innodb_/ && $data->{_innodb_disabled};
1680 next if $graph =~ /wsrep_/ && $data->{_galera_disabled};
1689 my $graph_name = shift;
1691 # In MySQL 5.1 (and probably erlier versions as well) status
1692 # variables are unique when looking at the last 19 characters.
1694 # SELECT RIGHT(variable_name, 19), COUNT(*)
1695 # FROM information_schema.global_status
1696 # GROUP BY RIGHT(variable_name, 19)
1697 # HAVING COUNT(*) > 1;
1699 # Empty set (0.06 sec)
1701 # There is one duplicate when looking at server variables
1703 # SELECT RIGHT(variable_name, 19), COUNT(*)
1704 # FROM information_schema.global_variables
1705 # GROUP BY RIGHT(variable_name, 19)
1706 # HAVING COUNT(*) > 1;
1708 # +--------------------------+----------+
1709 # | RIGHT(variable_name, 19) | COUNT(*) |
1710 # +--------------------------+----------+
1711 # | OW_PRIORITY_UPDATES | 2 |
1712 # +--------------------------+----------+
1713 # 1 row in set (0.05 sec)
1715 # show global variables like '%OW_PRIORITY_UPDATES';
1717 # +--------------------------+-------+
1718 # | Variable_name | Value |
1719 # +--------------------------+-------+
1720 # | low_priority_updates | OFF |
1721 # | sql_low_priority_updates | OFF |
1722 # +--------------------------+-------+
1723 # 2 rows in set (0.00 sec)
1725 # Not a problem since we don't graph these
1729 die 'Unknown graph ' . ($graph_name ? $graph_name : '')
1730 unless $graphs{$graph_name};
1732 my $graph = $graphs{$graph_name};
1734 my %conf = (%{$defaults{global_attrs}}, %{$graph->{config}{global_attrs}});
1735 while (my ($k, $v) = each %conf) {
1736 print "graph_$k $v\n";
1738 if ($graph_name =~ /wsrep_/) {
1739 print "graph_category galera\n";
1741 print "graph_category mysql\n";
1745 for my $ds (@{$graph->{data_sources}}) {
1747 %{$defaults{data_source_attrs}},
1748 %{$graph->{config}{data_source_attrs}},
1751 while (my ($k, $v) = each %ds_spec) {
1752 # 'name' is only used internally in this script, not
1753 # understood by munin.
1754 next if ($k eq 'name');
1756 # AREASTACK is part of munin as of version 1.3.3 (not
1757 # released yet). Until then ...
1758 if ($k eq 'draw' && $v eq 'AREASTACK') {
1759 printf("%s.%s %s\n",
1760 clean_fieldname($ds->{name}), $k, ($i ? 'STACK' : 'AREA'));
1763 printf("%s.%s %s\n", clean_fieldname($ds->{name}), $k, $v);
1767 print_thresholds(clean_fieldname($ds->{name}));
1774 my $graph_name = shift;
1778 die 'Unknown graph ' . ($graph_name ? $graph_name : '')
1779 unless $graphs{$graph_name};
1781 my $graph = $graphs{$graph_name};
1783 die "Can't show data for '$graph_name' because InnoDB is disabled."
1784 if $graph_name =~ /innodb_/ && $data->{_innodb_disabled};
1786 die "Can't show data for '$graph_name' because not a Galera mysql version."
1787 if $graph_name =~ /wsrep_/ && $data->{_galera_disabled};
1789 for my $ds (@{$graph->{data_sources}}) {
1790 printf "%s.value %s\n",
1791 clean_fieldname($ds->{name}),
1792 defined $data->{$ds->{name}} ? $data->{$ds->{name}} : 'U';
1800 #---------------------------------------------------------------------
1801 # U T I L I T Y S U B S
1802 #---------------------------------------------------------------------
1806 my $dsn = "$config{dsn};mysql_connect_timeout=5";
1808 return DBI->connect($dsn, $config{user}, $config{password}, {
1811 FetchHashKeyName => 'NAME_lc',
1817 $data = $shared_memory_cache->get('data');
1818 my $graphs_stored = $shared_memory_cache->get('graphs');
1819 %graphs = %{thaw($graphs_stored)} if $graphs_stored;
1824 my $dbh = db_connect();
1826 update_variables($dbh);
1827 update_plugins($dbh);
1828 update_innodb($dbh);
1829 update_master($dbh);
1830 delete $graphs{replication} if update_slave($dbh)==1;
1832 delete $graphs{bin_relay_log} if not defined $data->{relay_log_space}
1833 && not defined $data->{ma_binlog_size};
1835 delete $graphs{execution} if not defined $data->{Executed_events}
1836 && not defined $data->{Executed_triggers};
1838 delete $graphs{icp} if not defined $data->{Handler_icp_attempts}
1839 && not defined $data->{Handler_icp_matches};
1841 delete $graphs{innodb_adaptive_hash}
1842 if not defined $data->{Innodb_adaptive_hash_hash_searches}
1843 && not defined $data->{Innodb_adaptive_hash_non_hash_searches};
1845 delete $graphs{innodb_bpool_internal_breakdown}
1846 if not defined $data->{ib_bpool_internal_adaptive_hash_size_const};
1848 delete $graphs{innodb_descriptors}
1849 if not defined $data->{ib_innodb_descriptors};
1851 delete $graphs{mrr} if not defined $data->{Handler_mrr_init};
1853 delete $graphs{rows} if not defined $data->{Rows_sent};
1855 delete $graphs{handler_temp} if not defined $data->{Handler_tmp_write};
1857 $shared_memory_cache->set('data', $data);
1858 $shared_memory_cache->set('graphs', nfreeze(\%graphs));
1862 sub update_plugins {
1866 'query_response_time' => \&plugin_query_response_time,
1870 my ($f, $sec, $dbh, %g) = @_;
1871 if ($f->($dbh) == 0) {
1872 while (my ($k, $v) = each %g) {
1873 $graphs{$sec . '_' . $k} = $v;
1878 my $sth = $dbh->prepare("SHOW PLUGINS");
1880 while (my $row = $sth->fetchrow_hashref()) {
1881 next if $row->{'type'} ne 'INFORMATION SCHEMA';
1882 my $sec = lc $row->{'name'};
1883 next if not exists $plugin_map{$sec};
1884 add_graphs($plugin_map{$sec}, $sec, $dbh, %{$graph_plugins{$sec}});
1889 'user_statistics' => \&is_user_statistics,
1892 $sth = $dbh->prepare("SHOW TABLES IN INFORMATION_SCHEMA");
1894 while (my $row = $sth->fetchrow_hashref()) {
1895 my $sec = lc $row->{'tables_in_information_schema'};
1896 next if not exists $is_map{$sec};
1897 add_graphs($is_map{$sec}, $sec, $dbh, %{$graph_plugins{$sec}});
1902 sub update_variables {
1905 'SHOW GLOBAL STATUS',
1906 'SHOW GLOBAL VARIABLES',
1909 my %variable_name_map = (
1910 table_cache => 'table_open_cache', # table_open_cache was
1911 # previously known as
1912 # table_cache in MySQL
1913 # 5.1.2 and earlier.
1915 my %wsrep_cluster_status_map = (
1920 for my $query (@queries) {
1921 $data->{$query} = {};
1923 my $sth = $dbh->prepare($query);
1925 while (my $row = $sth->fetch) {
1926 my $var = $variable_name_map{$row->[0]} || $row->[0];
1927 $data->{$var} = $row->[1];
1932 $data->{'mysql_base_memory'} = $data->{'key_buffer_size'}
1933 + $data->{'query_cache_size'}
1934 + $data->{'innodb_buffer_pool_size'}
1935 + ( $data->{'innodb_additional_mem_pool_size'} || 0 )
1936 + $data->{'innodb_log_buffer_size'}
1937 + ( $data->{'tokudb_cache_size'} || 0 );
1939 my $tmp_table_size = $data->{'tmp_table_size'};
1940 my $max_heap_table_size = $data->{'max_heap_table_size'};
1941 $data->{'mysql_connection_memory'} = $data->{'read_buffer_size'}
1942 + $data->{'read_rnd_buffer_size'}
1943 + $data->{'sort_buffer_size'}
1944 + $data->{'join_buffer_size'}
1945 + $data->{'binlog_cache_size'}
1946 + $data->{'thread_stack'}
1947 + ( $tmp_table_size >= $max_heap_table_size ? $tmp_table_size : $max_heap_table_size )
1948 + ( $data->{'tokudb_read_buf_size'} || 0 );
1950 # wsrep_thread_count was separated from max_connections for mariadb-5.5.38 https://mariadb.atlassian.net/browse/MDEV-6206
1951 $data->{'mysql_connection_memory'} *= $data->{'max_connections'} + ( $data->{'wsrep_thread_count'} || 0 );
1953 if ($data->{wsrep_cluster_status}) {
1954 my $var = $wsrep_cluster_status_map{$data->{wsrep_cluster_status}};
1955 $data->{wsrep_cluster_status} = $var;
1957 $data->{_galera_disabled} = 1 unless ($data->{wsrep_provider_name});
1964 my $sth = $dbh->prepare('SHOW /*!50000 ENGINE*/ INNODB STATUS');
1969 if ($@ =~ /Unknown (storage|table) engine 'INNODB'|Cannot call SHOW INNODB STATUS because skip-innodb is defined/i) {
1970 $data->{_innodb_disabled} = 1;
1975 my $row = $sth->fetchrow_hashref();
1976 my $status = $row->{'status'};
1979 parse_innodb_status($status);
1986 my $sth = $dbh->prepare('SHOW MASTER LOGS');
1991 # SHOW MASTER LOGS failed because binlog is not enabled
1992 return if $@ =~ /You are not using binary logging/;
1996 while (my $row = $sth->fetch) {
1997 $data->{ma_binlog_size} += $row->[1];
2007 my $sth = $dbh->prepare('SHOW SLAVE STATUS');
2009 my $row = $sth->fetchrow_hashref();
2010 return 1 unless $row;
2011 while (my ($k, $v) = each %$row) {
2016 # We choose master_host here as a stopped slave
2017 # may not indicate that we have reset all slave capability
2018 # however the minimium requirement is a master_host
2019 return 1 if not defined $data->{master_host};
2021 # undef when slave is stopped, or when MySQL fails to calculate
2022 # the lag (which happens depresingly often). (mk-heartbeat fixes
2024 $data->{seconds_behind_master} ||= 0;
2026 # Track these two fields so we can trigger warnings if the slave stops
2028 $data->{slave_sql_running} = ($data->{slave_sql_running} eq 'Yes')
2030 $data->{slave_io_running} = ($data->{slave_io_running} eq 'Yes')
2036 #---------------------------------------------------------------------
2037 # Information SCHEMA tables represent data to be processed
2038 #---------------------------------------------------------------------
2041 sub plugin_query_response_time {
2044 return 1 if not defined $data->{query_response_time_stats};
2045 return 1 if $data->{query_response_time_stats} eq 'OFF';
2047 my $sth = $dbh->prepare("SELECT * FROM INFORMATION_SCHEMA.QUERY_RESPONSE_TIME");
2049 while (my $row = $sth->fetchrow_hashref()) {
2050 my $time = $row->{'time'};
2051 $data->{'query_response_time_count_' . $time} = $row->{'count'};
2052 push @{$graph_plugins{query_response_time}->{count}->{data_sources}}, {name => 'query_response_time_count_' . $time, label => $time };
2053 next if $row->{'total'} eq 'TOO LONG';
2054 $data->{'query_response_time_total_' . $time} = $row->{'total'} * 1e6;
2055 push @{$graph_plugins{query_response_time}->{total}->{data_sources}}, {name => 'query_response_time_total_' . $time, label => $time };
2062 sub is_user_statistics {
2065 return 1 if not defined $data->{userstat};
2066 return 1 if $data->{userstat} eq 'OFF';
2068 my $sth = $dbh->prepare("SELECT * FROM INFORMATION_SCHEMA.USER_STATISTICS");
2070 while (my $row = $sth->fetchrow_hashref()) {
2071 my $user = $row->{'user'};
2073 while (my ($g, $v) = each %{$graph_plugins{user_statistics}}) {
2074 while (my ($userstat,$conf) = each %{$v->{cols}}) {
2075 $var = 'user_stats_' . $user . '_' . $userstat;
2076 $data->{$var} = int $row->{$userstat};
2077 my $ds = { %$conf };
2079 $ds->{label} = $user . ' ' . $userstat;
2080 push @{$graph_plugins{user_statistics}->{$g}->{data_sources}}, $ds;
2089 # In 'SHOW ENGINE INNODB STATUS' 64 bit integers are not formated as
2090 # plain integers. They are either:
2092 # - split in two and needs to be shifted together,
2099 ? Math::BigInt->new($x)->blsft(32) + $y
2100 : Math::BigInt->new("0x$x");
2103 #---------------------------------------------------------------------
2104 # P A R S E 'SHOW ENGINE INNODB STATUS' O U T P U T
2105 #---------------------------------------------------------------------
2108 # A nice walk through
2109 # http://www.mysqlperformanceblog.com/2006/07/17/show-innodb-status-walk-through/
2111 # The parsing is split in one subrutine per section. Each subroutine
2112 # should parse a block with the following structure
2118 sub parse_innodb_status {
2121 # Add a dummy section to the end in case the innodb status output
2122 # has been truncated (Happens for status > 64K characters)
2123 $_ .= "\n----------\nDUMMY\n----------\n";
2127 'BUFFER POOL AND MEMORY' => \&parse_buffer_pool_and_memory,
2128 'INDIVIDUAL BUFFER POOL INFO' => \&parse_individual_buffer_pool,
2129 'FILE I/O' => \&parse_file_io,
2130 'INSERT BUFFER AND ADAPTIVE HASH INDEX'
2131 => \&parse_insert_buffer_and_adaptive_hash_index,
2132 'LATEST DETECTED DEADLOCK' => \&skip,
2133 'LATEST FOREIGN KEY ERROR' => \&skip,
2134 'LOG' => \&parse_log,
2135 'ROW OPERATIONS' => \&parse_row_operations,
2136 'SEMAPHORES' => \&parse_semaphores,
2137 'TRANSACTIONS' => \&parse_transactions,
2138 'BACKGROUND THREAD' => \&parse_background_thread,
2142 parse_header_seconds();
2147 last if $sec eq 'END OF INNODB MONITOR OUTPUT';
2148 if ($sec eq 'DUMMY') {
2149 handle_incomplete_innodb_status();
2153 if (exists $section_map{$sec}) {
2154 $section_map{$sec}->();
2156 #warn "Unknown section: $1";
2163 # This regular expression handles the different formating of 64-bit
2164 # integers in different versions of the innodb engine. Either two
2165 # decimal 32-bit integers separated by a space, or a single
2166 # hexadecimal 64-bit integer.
2167 my $innodb_bigint_rx = qr{([[a-fA-F\d]+)(?: (\d+))?};
2170 sub match_new_section {
2172 -+\n # ---------------------------
2173 (?= [A-Z\/ ]+\n # SECTION NAME
2174 [=-]+\n)/gcx; # --------------------------- ('=' on end of output)
2178 sub skip_line { return m/\G.*\n/gc; }
2182 # Heading is 3 lines
2183 for my $foo (1...3) {
2184 skip_line or die('Parse error');
2192 #warn substr($_, pos(), 10);
2194 return if match_new_section;
2195 next if $parser->();
2201 sub skip { parse_section(sub {}); }
2204 sub parse_header_seconds {
2207 m/\GPer second averages calculated from the last (\d+) seconds\n/gc && do {
2208 $data->{innodb_engine_status_seconds} = $1;
2216 sub parse_background_thread {
2219 m/\Gsrv_master_thread loops: \d+ 1_second, \d+ sleeps, \d+ 10_second, (\d+) background, (\d+) flush\n/gc && do {
2220 $data->{ib_srv_main_flush_loops} = $1;
2221 $data->{ib_srv_main_background_loops} = $2;
2224 m/\Gsrv_master_thread log flush and writes: (\d+)\n/gc && do {
2225 $data->{ib_srv_main_flushs_writes} = $1;
2232 sub parse_row_operations {
2235 m/\G(\d+) queries inside InnoDB, (\d+) queries in queue\n/gc && do {
2236 $data->{ib_innodb_queries} = $1;
2237 $data->{ib_innodb_query_queue_len} = $2;
2240 m/\G(\d+) read views open inside InnoDB\n/gc && do {
2241 $data->{ib_innodb_read_views} = $1;
2244 m/\G(\d+) transactions active inside InnoDB\n/gc && do {
2245 $data->{ib_innodb_transactions_active} = $1;
2248 m/\G(\d+) out of (\d+) descriptors used\n/gc && do {
2249 $data->{ib_innodb_descriptors} = $1;
2250 $data->{ib_innodb_descriptors_max} = $2;
2253 # no need for this - its exposed as status variables
2254 # m/\GNumber of rows inserted (\d+), updated (\d+), deleted (\d+), read (\d+)\n/gc && do {
2255 # $data->{ib_innodb_rows_inserted} = $1;
2256 # $data->{ib_innodb_rows_updated} = $2;
2257 # $data->{ib_innodb_rows_deleted} = $3;
2258 # $data->{ib_innodb_rows_read} = $4;
2265 sub parse_semaphores {
2268 m/\GMutex spin waits (\d+), rounds (\d+), OS waits (\d+)\n/gc && do {
2269 $data->{ib_spin_waits} = $1;
2270 $data->{ib_spin_rounds} = $2;
2271 $data->{ib_os_waits} = $3;
2274 m/\GRW-shared spins (\d+), rounds (\d+), OS waits (\d+)\n/gc && do {
2275 $data->{ib_rw_shared_waits} = $1;
2276 $data->{ib_rw_shared_rounds} = $2;
2277 $data->{ib_rw_shared_os_waits} = $3;
2280 m/\GRW-excl spins (\d+), rounds (\d+), OS waits (\d+)\n/gc && do {
2281 $data->{ib_rw_excl_waits} = $1;
2282 $data->{ib_rw_excl_rounds} = $2;
2283 $data->{ib_rw_excl_os_waits} = $3;
2291 sub parse_transactions {
2294 m/\GTrx id counter $innodb_bigint_rx\n/gc && do {
2295 $data->{ib_tnx} = innodb_bigint($1, $2);
2298 m/\GPurge done for trx's n:o < $innodb_bigint_rx undo n:o < $innodb_bigint_rx\n/gc && do {
2301 $data->{ib_tnx_prg} = innodb_bigint($1, $2);
2302 # FIX add to data? innodb_bigint($3, $4);
2306 $data->{ib_tnx_prg} = innodb_bigint($1);
2307 # FIX add to data? innodb_bigint($2);
2311 m/\GHistory list length (\d+)\n/gc && do {
2312 $data->{ib_tnx_hist} = $1;
2324 m/\GPending normal aio reads: (\d+)(?: \[(?:\d+, )*\d+\] )?, aio writes: (\d+)(?: \[(?:\d+, )*\d+\] )?,\n\s*ibuf aio reads: (\d+), log i\/o's: (\d+), sync i\/o's: (\d+)\n/gc && do {
2325 $data->{ib_iop_aioread} = $1;
2326 $data->{ib_iop_aiowrite} = $2;
2327 $data->{ib_iop_ibuf_aio} = $3;
2328 $data->{ib_iop_log} = $4;
2329 $data->{ib_iop_sync} = $5;
2332 m/\GPending flushes \(fsync\) log: (\d+); buffer pool: (\d+)\n/gc && do {
2333 $data->{ib_iop_flush_log} = $1;
2334 $data->{ib_iop_flush_bpool} = $2;
2337 m/\G(\d+) OS file reads, (\d+) OS file writes, (\d+) OS fsyncs\n/gc && do {
2338 $data->{ib_io_read} = $1;
2339 $data->{ib_io_write} = $2;
2340 $data->{ib_io_fsync} = $3;
2348 sub parse_insert_buffer_and_adaptive_hash_index {
2352 m/\G(\d+) inserts, (\d+) merged recs, (\d+) merges\n/gc && do {
2353 $data->{ib_ibuf_inserts} = $1;
2354 $data->{ib_ibuf_merged_rec} = $2;
2355 $data->{ib_ibuf_merges} = $3;
2359 m/\Gmerged operations:\n insert (\d+), delete mark (\d+), delete (\d+)\ndiscarded operations:\n insert (\d+), delete mark (\d+), delete (\d+)\n/gc && do {
2360 $data->{ib_ibuf_inserts} = $1;
2361 $data->{ib_ibuf_delete_mark} = $2;
2362 $data->{ib_ibuf_delete} = $3;
2363 $data->{ib_ibuf_discard_inserts} = $4;
2364 $data->{ib_ibuf_discard_delete_mark} = $5;
2365 $data->{ib_ibuf_discard_delete} = $6;
2366 $data->{ib_ibuf_merged_rec} = $data->{ib_ibuf_inserts} + $data->{ib_ibuf_discard_inserts};
2370 m/\GIbuf: size (\d+), free list len (\d+), seg size (\d+),(?: (\d+) merges)?\n/gc && do {
2371 $data->{ib_ibuf_size} = $1;
2372 $data->{ib_ibuf_free_len} = $2;
2373 $data->{ib_ibuf_seg_size} = $3;
2374 $data->{ib_ibuf_merges} = $4 if defined $4; # MySQL >= 5.5
2385 m/\GLog sequence number $innodb_bigint_rx\n/gc && do {
2386 $data->{ib_log_written} = innodb_bigint($1, $2);
2389 m/\GLog flushed up to\s+$innodb_bigint_rx\n/gc && do {
2390 $data->{ib_log_flush} = innodb_bigint($1, $2);
2393 m/\G(\d+) log i\/o's done.*\n/gc && do {
2394 $data->{ib_io_log} = $1;
2402 sub parse_buffer_pool_and_memory {
2405 m/\GBuffer pool size\s+(\d+)\n/gc && do {
2406 $data->{ib_bpool_size} = $1;
2409 m/\GBuffer pool size, bytes\s+(\d+)\n/gc && do {
2410 $data->{ib_bpool_size_bytes} = $1;
2413 m/\GFree buffers\s+(\d+)\n/gc && do {
2414 $data->{ib_bpool_free} = $1;
2417 m/\GDatabase pages\s+(\d+)\n/gc && do {
2418 $data->{ib_bpool_dbpages} = $1;
2421 m/\GModified db pages\s+(\d+)\n/gc && do {
2422 $data->{ib_bpool_modpages} = $1;
2425 m/\GOld database pages\s+(\d+)\n/gc && do {
2426 $data->{ib_bpool_oldpages} = $1;
2429 m/\GPages made young (\d+), not young (\d+)\n/gc && do {
2430 $data->{ib_bpool_made_young} = $1;
2431 $data->{ib_bpool_made_not_young} = $2;
2434 m/\GPages read (\d+), created (\d+), written (\d+)\n/gc && do {
2435 $data->{ib_bpool_read} = $1;
2436 $data->{ib_bpool_created} = $2;
2437 $data->{ib_bpool_written} = $3;
2441 m/\GInternal hash tables \(constant factor \+ variable factor\)\n\s*Adaptive hash index\s*(\d+)\s*\((\d+) \+ (\d+)\) *\n\s+Page hash +(\d+) +\(buffer pool \d+ only\) *\n\s+Dictionary cache\s*(\d+)\s+\((\d+) \+ (\d+)\) *\n\s+File system\s+(\d+)\s+\((\d+) \+ (\d+)\) *\n\s+Lock system\s+(\d+)\s+\((\d+) \+ (\d+)\) *\n\s+Recovery system\s*(\d+)\s+\((\d+) \+ (\d+)\) *\n/gc
2443 $data->{ib_bpool_internal_adaptive_hash_size_total} = $1;
2444 $data->{ib_bpool_internal_adaptive_hash_size_const} = $2;
2445 $data->{ib_bpool_internal_adaptive_hash_size_var} = $3;
2446 $data->{ib_bpool_internal_page_hash_size_total} = $4;
2447 $data->{ib_bpool_internal_dictionary_cache_size_total} = $5;
2448 $data->{ib_bpool_internal_dictionary_cache_size_const} = $6;
2449 $data->{ib_bpool_internal_dictionary_cache_size_var} = $7;
2450 $data->{ib_bpool_internal_file_system_size_total} = $8;
2451 $data->{ib_bpool_internal_file_system_size_const} = $9;
2452 $data->{ib_bpool_internal_file_system_size_var} = $10;
2453 $data->{ib_bpool_internal_lock_system_size_total} = $11;
2454 $data->{ib_bpool_internal_lock_system_size_const} = $12;
2455 $data->{ib_bpool_internal_lock_system_size_var} = $13;
2456 $data->{ib_bpool_internal_recovery_system_size_total} = $14;
2457 $data->{ib_bpool_internal_recovery_system_size_const} = $15;
2458 $data->{ib_bpool_internal_recovery_system_size_var} = $16;
2466 sub parse_individual_buffer_pool {
2469 m/\G---BUFFER POOL (\d+)\n/gc && do {
2471 $data->{ib_bpool_individual_pool_count} = $pool + 1;
2472 m/\GBuffer pool size\s+(\d+)\n/gc && do {
2473 $data->{"ib_bpool_individual_pool_${pool}_size"} = $1;
2475 m/\GBuffer pool size, bytes\s+(\d+)\n/gc && do {
2476 $data->{"ib_bpool_individual_pool_${pool}_size_bytes"} = $1;
2478 m/\GFree buffers\s+(\d+)\nDatabase pages\s+(\d+)\nOld database pages\s+(\d+)\nModified db pages\s+(\d+)\nPending reads\s+(\d+)\nPending writes: LRU\s+(\d+), flush list\s+(\d+), single page\s+(\d+)\n/gc && do {
2479 $data->{"ib_bpool_individual_pool_${pool}_free"} = $1;
2480 $data->{"ib_bpool_individual_pool_${pool}_dbpages"} = $2;
2481 $data->{"ib_bpool_individual_pool_${pool}_oldpages"} = $3;
2482 $data->{"ib_bpool_individual_pool_${pool}_modpages"} = $4;
2483 $data->{"ib_bpool_individual_pool_${pool}_pending_reads"} = $5;
2484 $data->{"ib_bpool_individual_pool_${pool}_pending_writes_lru"} = $6;
2485 $data->{"ib_bpool_individual_pool_${pool}_pending_writes_flush"} = $7;
2486 $data->{"ib_bpool_individual_pool_${pool}_pending_writes_single"} = $8;
2489 m/\GPages read (\d+), created (\d+), written (\d+)\n/gc && do {
2490 $data->{"ib_bpool_individual_pool_${pool}_read"} = $1;
2491 $data->{"ib_bpool_individual_pool_${pool}_created"} = $2;
2492 $data->{"ib_bpool_individual_pool_${pool}_written"} = $3;
2500 sub handle_incomplete_innodb_status {
2502 warn "Output from SHOW ENGINE INNODB STATUS was truncated. "
2503 . "This happens if the output of STATUS exceeds 64KB. "
2504 . "Several of the InnoDB graphs might be affected by this.";
2506 # FIX Is it possible to find some of the missing values from SHOW
2511 exit main() unless caller;