From 558583d04ff65f5bf823ff0a16bf95b7daa4bef5 Mon Sep 17 00:00:00 2001 From: Santosh Praneeth Banda Date: Wed, 26 Feb 2014 14:33:33 -0800 Subject: [PATCH] add histogram for rpl_semi_sync_master_trx_wait Summary: add histogram for rpl_semi_sync_master_trx_wait. 8.0 porting notes: Keeps the same histogram status variables as before since these are already being read by various applications. We should eventually remove this. Reference Patch: https://github.com/facebook/mysql-5.6/commit/d1a1394 Reference Patch: https://github.com/facebook/mysql-5.6/commit/15333b2e6f9 Differential Revision: D21832889 ---------------------------------------------------------------------- Fix semi_sync histogram reporting Summary: Fix a porting bug with semi_sync histograms. Reviewed By: george-reynya Differential Revision: D40964563 ---------------------------------------------------------------------- Semisync histogram double free (#1290) Summary: Avoid double free on latency histogram data Before this fix, rpl.rpl_semi_sync_alias test under ASan with ``` ================================================================= ==65389==ERROR: AddressSanitizer: heap-use-after-free on address 0x0001742e17d4 at pc 0x000107febaf0 bp 0x00016ea8f710 sp 0x00016ea8f708 READ of size 4 at 0x0001742e17d4 thread T80 #0 0x107febaec in my_free(void*) my_malloc.cc:135 https://github.com/facebook/mysql-5.6/issues/1 0x103cb9828 in free_latency_histogram_sysvars(SHOW_VAR*) mysqld.cc:4668 https://github.com/facebook/mysql-5.6/issues/2 0x103cb99bc in prepare_latency_histogram_vars(latency_histogram*, SHOW_VAR*, unsigned long long*) mysqld.cc:4692 https://github.com/facebook/mysql-5.6/issues/3 0x17c65826c in rpl_semi_sync_master_trx_wait_histogram(THD*, SHOW_VAR*, char*) semisync_source_plugin.cc:581 https://github.com/facebook/mysql-5.6/issues/4 0x10be1b4cc in PFS_status_variable_cache::manifest(THD*, SHOW_VAR const*, System_status_var*, char const*, bool, bool) pfs_variable.cc:1366 https://github.com/facebook/mysql-5.6/issues/5 0x10be1ba90 in PFS_status_variable_cache::do_materialize_all(THD*) pfs_variable.cc:1172 https://github.com/facebook/mysql-5.6/issues/6 0x10c0ab33c in PFS_variable_cache::materialize_all(THD*) pfs_variable.h:536 https://github.com/facebook/mysql-5.6/issues/7 0x10c0ab294 in table_session_status::rnd_init(bool) table_session_status.cc:111 https://github.com/facebook/mysql-5.6/issues/8 0x10bceb790 in ha_perfschema::rnd_init(bool) ha_perfschema.cc:1686 https://github.com/facebook/mysql-5.6/issues/9 0x1033c7cec in handler::ha_rnd_init(bool) handler.cc:3157 https://github.com/facebook/mysql-5.6/issues/10 0x103975380 in TableScanIterator::Init() basic_row_iterators.cc:230 https://github.com/facebook/mysql-5.6/issues/11 0x103a33a18 in FilterIterator::Init() composite_iterators.h:82 https://github.com/facebook/mysql-5.6/issues/12 0x103982ec0 in MaterializeIterator::MaterializeQueryBlock(MaterializeIterator::QueryBlock const&, unsigned long long*) composite_iterators.cc:845 https://github.com/facebook/mysql-5.6/issues/13 0x103981410 in MaterializeIterator::Init() composite_iterators.cc:660 https://github.com/facebook/mysql-5.6/issues/14 0x1049fc518 in Query_expression::ExecuteIteratorQuery(THD*) sql_union.cc:1293 https://github.com/facebook/mysql-5.6/issues/15 0x1049fd358 in Query_expression::execute(THD*) sql_union.cc:1355 https://github.com/facebook/mysql-5.6/issues/16 0x1047ae7ac in Sql_cmd_dml::execute_inner(THD*) sql_select.cc:870 https://github.com/facebook/mysql-5.6/issues/17 0x1047ac344 in Sql_cmd_dml::execute(THD*) sql_select.cc:618 https://github.com/facebook/mysql-5.6/issues/18 0x1047ffcc8 in Sql_cmd_show::execute(THD*) sql_show.cc:232 https://github.com/facebook/mysql-5.6/issues/19 0x10480ab58 in Sql_cmd_show_status::execute(THD*) sql_show.cc:894 https://github.com/facebook/mysql-5.6/issues/20 0x1045cea6c in mysql_execute_command(THD*, bool, unsigned long long*) sql_parse.cc:5323 https://github.com/facebook/mysql-5.6/issues/21 0x1045c5dcc in dispatch_sql_command(THD*, Parser_state*, unsigned long long*) sql_parse.cc:6093 https://github.com/facebook/mysql-5.6/issues/22 0x1045bb92c in dispatch_command(THD*, COM_DATA const*, enum_server_command) sql_parse.cc:2444 https://github.com/facebook/mysql-5.6/issues/23 0x1045c06f8 in do_command(THD*) sql_parse.cc:1636 https://github.com/facebook/mysql-5.6/issues/24 0x104cc4cc4 in handle_connection(void*) connection_handler_per_thread.cc:307 https://github.com/facebook/mysql-5.6/issues/25 0x10bd130d4 in pfs_spawn_thread(void*) pfs.cc:2983 https://github.com/facebook/mysql-5.6/issues/26 0x18ad47fa4 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x6fa4) https://github.com/facebook/mysql-5.6/issues/27 0x18ad42d9c in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d9c) 0x0001742e17d4 is located 4 bytes inside of 40-byte region [0x0001742e17d0,0x0001742e17f8) freed by thread T80 here: #0 0x139ff6de4 in wrap_free+0x98 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x3ede4) https://github.com/facebook/mysql-5.6/issues/1 0x107febcfc in my_raw_free(void*) my_malloc.cc:269 https://github.com/facebook/mysql-5.6/issues/2 0x107feba48 in my_free(void*) my_malloc.cc:141 https://github.com/facebook/mysql-5.6/issues/3 0x103cb9828 in free_latency_histogram_sysvars(SHOW_VAR*) mysqld.cc:4668 https://github.com/facebook/mysql-5.6/issues/4 0x17c6231e8 in ReplSemiSyncMaster::~ReplSemiSyncMaster() semisync_source.cc:517 https://github.com/facebook/mysql-5.6/issues/5 0x17c623488 in ReplSemiSyncMaster::~ReplSemiSyncMaster() semisync_source.cc:516 https://github.com/facebook/mysql-5.6/issues/6 0x17c651484 in semi_sync_master_plugin_deinit(void*) semisync_source_plugin.cc:833 https://github.com/facebook/mysql-5.6/issues/7 0x10467aa90 in plugin_deinitialize(st_plugin_int*, bool) sql_plugin.cc:1123 https://github.com/facebook/mysql-5.6/issues/8 0x1046730b0 in reap_plugins() sql_plugin.cc:1192 https://github.com/facebook/mysql-5.6/issues/9 0x1046863b4 in mysql_uninstall_plugin(THD*, MYSQL_LEX_CSTRING) sql_plugin.cc:2602 https://github.com/facebook/mysql-5.6/issues/10 0x104685374 in Sql_cmd_uninstall_plugin::execute(THD*) sql_plugin.cc:3731 https://github.com/facebook/mysql-5.6/issues/11 0x1045cea6c in mysql_execute_command(THD*, bool, unsigned long long*) sql_parse.cc:5323 https://github.com/facebook/mysql-5.6/issues/12 0x1045c5dcc in dispatch_sql_command(THD*, Parser_state*, unsigned long long*) sql_parse.cc:6093 https://github.com/facebook/mysql-5.6/issues/13 0x1045bb92c in dispatch_command(THD*, COM_DATA const*, enum_server_command) sql_parse.cc:2444 https://github.com/facebook/mysql-5.6/issues/14 0x1045c06f8 in do_command(THD*) sql_parse.cc:1636 https://github.com/facebook/mysql-5.6/issues/15 0x104cc4cc4 in handle_connection(void*) connection_handler_per_thread.cc:307 https://github.com/facebook/mysql-5.6/issues/16 0x10bd130d4 in pfs_spawn_thread(void*) pfs.cc:2983 https://github.com/facebook/mysql-5.6/issues/17 0x18ad47fa4 in _pthread_start+0x90 (libsystem_pthread.dylib:arm64e+0x6fa4) https://github.com/facebook/mysql-5.6/issues/18 0x18ad42d9c in thread_start+0x4 (libsystem_pthread.dylib:arm64e+0x1d9c) ``` It seems that the double invocation of `free_latency_histogram_sysvars` is correct in this case, thus protect against the double free with resetting the pointers to nullptr. Pull Request resolved: https://github.com/facebook/mysql-5.6/pull/1290 Reviewed By: sunshine-Chun Differential Revision: D45277600 Pulled By: hermanlee --- .../r/binlog_persist_only_variables.result | 2 + .../r/binlog_persist_variables.result | 2 + .../suite/rpl_nogtid/r/rpl_semi_sync.result | 12 + ...c_optimize_for_static_plugin_config.result | 12 + ...emi_sync_sender_observe_commit_only.result | 12 + .../suite/rpl_nogtid/t/rpl_semi_sync.test | 1 + ..._histogram_trx_wait_step_size_basic.result | 75 ++++++ ...togram_trx_wait_step_size_basic-master.opt | 1 + ...ce_histogram_trx_wait_step_size_basic.test | 73 ++++++ plugin/semisync/semisync_source.cc | 22 ++ plugin/semisync/semisync_source.h | 15 ++ plugin/semisync/semisync_source_plugin.cc | 86 +++++++ sql/mysqld.cc | 240 ++++++++++++++++++ sql/mysqld.h | 116 +++++++++ 14 files changed, 669 insertions(+) create mode 100644 mysql-test/suite/sys_vars/r/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.result create mode 100644 mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic-master.opt create mode 100644 mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.test diff --git a/mysql-test/suite/binlog_nogtid/r/binlog_persist_only_variables.result b/mysql-test/suite/binlog_nogtid/r/binlog_persist_only_variables.result index 1b43adf10560..b2bc9eebbcbd 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_persist_only_variables.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_persist_only_variables.result @@ -193,6 +193,7 @@ SET PERSIST_ONLY rpl_receive_buffer_size = @@GLOBAL.rpl_receive_buffer_size; SET PERSIST_ONLY rpl_semi_sync_replica_enabled = @@GLOBAL.rpl_semi_sync_replica_enabled; SET PERSIST_ONLY rpl_semi_sync_replica_trace_level = @@GLOBAL.rpl_semi_sync_replica_trace_level; SET PERSIST_ONLY rpl_semi_sync_source_enabled = @@GLOBAL.rpl_semi_sync_source_enabled; +SET PERSIST_ONLY rpl_semi_sync_source_histogram_trx_wait_step_size = @@GLOBAL.rpl_semi_sync_source_histogram_trx_wait_step_size; SET PERSIST_ONLY rpl_semi_sync_source_timeout = @@GLOBAL.rpl_semi_sync_source_timeout; SET PERSIST_ONLY rpl_semi_sync_source_trace_level = @@GLOBAL.rpl_semi_sync_source_trace_level; SET PERSIST_ONLY rpl_semi_sync_source_wait_for_replica_count = @@GLOBAL.rpl_semi_sync_source_wait_for_replica_count; @@ -413,6 +414,7 @@ RESET PERSIST rpl_receive_buffer_size; RESET PERSIST rpl_semi_sync_replica_enabled; RESET PERSIST rpl_semi_sync_replica_trace_level; RESET PERSIST rpl_semi_sync_source_enabled; +RESET PERSIST rpl_semi_sync_source_histogram_trx_wait_step_size; RESET PERSIST rpl_semi_sync_source_timeout; RESET PERSIST rpl_semi_sync_source_trace_level; RESET PERSIST rpl_semi_sync_source_wait_for_replica_count; diff --git a/mysql-test/suite/binlog_nogtid/r/binlog_persist_variables.result b/mysql-test/suite/binlog_nogtid/r/binlog_persist_variables.result index ad7f9a83194c..9d035beae518 100644 --- a/mysql-test/suite/binlog_nogtid/r/binlog_persist_variables.result +++ b/mysql-test/suite/binlog_nogtid/r/binlog_persist_variables.result @@ -172,6 +172,7 @@ SET PERSIST rpl_receive_buffer_size = @@GLOBAL.rpl_receive_buffer_size; SET PERSIST rpl_semi_sync_replica_enabled = @@GLOBAL.rpl_semi_sync_replica_enabled; SET PERSIST rpl_semi_sync_replica_trace_level = @@GLOBAL.rpl_semi_sync_replica_trace_level; SET PERSIST rpl_semi_sync_source_enabled = @@GLOBAL.rpl_semi_sync_source_enabled; +SET PERSIST rpl_semi_sync_source_histogram_trx_wait_step_size = @@GLOBAL.rpl_semi_sync_source_histogram_trx_wait_step_size; SET PERSIST rpl_semi_sync_source_timeout = @@GLOBAL.rpl_semi_sync_source_timeout; SET PERSIST rpl_semi_sync_source_trace_level = @@GLOBAL.rpl_semi_sync_source_trace_level; SET PERSIST rpl_semi_sync_source_wait_for_replica_count = @@GLOBAL.rpl_semi_sync_source_wait_for_replica_count; @@ -426,6 +427,7 @@ RESET PERSIST IF EXISTS rpl_receive_buffer_size; RESET PERSIST IF EXISTS rpl_semi_sync_replica_enabled; RESET PERSIST IF EXISTS rpl_semi_sync_replica_trace_level; RESET PERSIST IF EXISTS rpl_semi_sync_source_enabled; +RESET PERSIST IF EXISTS rpl_semi_sync_source_histogram_trx_wait_step_size; RESET PERSIST IF EXISTS rpl_semi_sync_source_timeout; RESET PERSIST IF EXISTS rpl_semi_sync_source_trace_level; RESET PERSIST IF EXISTS rpl_semi_sync_source_wait_for_replica_count; diff --git a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync.result b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync.result index fb6e4129c231..8d1cefecb420 100644 --- a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync.result +++ b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync.result @@ -36,6 +36,18 @@ Rpl_semi_sync_source_status ON show status like 'Rpl_semi_sync_source_yes_tx'; Variable_name Value Rpl_semi_sync_source_yes_tx 0 +show status like 'Rpl_semi_sync_master_trx_wait_histogram%'; +Variable_name Value +Rpl_semi_sync_master_trx_wait_histogram_0-500us 0 +Rpl_semi_sync_master_trx_wait_histogram_500-1500us 0 +Rpl_semi_sync_master_trx_wait_histogram_1500-3500us 0 +Rpl_semi_sync_master_trx_wait_histogram_3500-7500us 0 +Rpl_semi_sync_master_trx_wait_histogram_7500-15500us 0 +Rpl_semi_sync_master_trx_wait_histogram_15500-31500us 0 +Rpl_semi_sync_master_trx_wait_histogram_31500-63500us 0 +Rpl_semi_sync_master_trx_wait_histogram_63500-127500us 0 +Rpl_semi_sync_master_trx_wait_histogram_127500-255500us 0 +Rpl_semi_sync_master_trx_wait_histogram_255500-MAXus 0 # # BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed # BUG#45673 Semisync reports correct operation even if no slave is connected diff --git a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_optimize_for_static_plugin_config.result b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_optimize_for_static_plugin_config.result index 3bfd59f16e54..4afff7a6385b 100644 --- a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_optimize_for_static_plugin_config.result +++ b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_optimize_for_static_plugin_config.result @@ -36,6 +36,18 @@ Rpl_semi_sync_source_status ON show status like 'Rpl_semi_sync_source_yes_tx'; Variable_name Value Rpl_semi_sync_source_yes_tx 0 +show status like 'Rpl_semi_sync_master_trx_wait_histogram%'; +Variable_name Value +Rpl_semi_sync_master_trx_wait_histogram_0-500us 0 +Rpl_semi_sync_master_trx_wait_histogram_500-1500us 0 +Rpl_semi_sync_master_trx_wait_histogram_1500-3500us 0 +Rpl_semi_sync_master_trx_wait_histogram_3500-7500us 0 +Rpl_semi_sync_master_trx_wait_histogram_7500-15500us 0 +Rpl_semi_sync_master_trx_wait_histogram_15500-31500us 0 +Rpl_semi_sync_master_trx_wait_histogram_31500-63500us 0 +Rpl_semi_sync_master_trx_wait_histogram_63500-127500us 0 +Rpl_semi_sync_master_trx_wait_histogram_127500-255500us 0 +Rpl_semi_sync_master_trx_wait_histogram_255500-MAXus 0 # # BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed # BUG#45673 Semisync reports correct operation even if no slave is connected diff --git a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_sender_observe_commit_only.result b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_sender_observe_commit_only.result index fb6e4129c231..8d1cefecb420 100644 --- a/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_sender_observe_commit_only.result +++ b/mysql-test/suite/rpl_nogtid/r/rpl_semi_sync_sender_observe_commit_only.result @@ -36,6 +36,18 @@ Rpl_semi_sync_source_status ON show status like 'Rpl_semi_sync_source_yes_tx'; Variable_name Value Rpl_semi_sync_source_yes_tx 0 +show status like 'Rpl_semi_sync_master_trx_wait_histogram%'; +Variable_name Value +Rpl_semi_sync_master_trx_wait_histogram_0-500us 0 +Rpl_semi_sync_master_trx_wait_histogram_500-1500us 0 +Rpl_semi_sync_master_trx_wait_histogram_1500-3500us 0 +Rpl_semi_sync_master_trx_wait_histogram_3500-7500us 0 +Rpl_semi_sync_master_trx_wait_histogram_7500-15500us 0 +Rpl_semi_sync_master_trx_wait_histogram_15500-31500us 0 +Rpl_semi_sync_master_trx_wait_histogram_31500-63500us 0 +Rpl_semi_sync_master_trx_wait_histogram_63500-127500us 0 +Rpl_semi_sync_master_trx_wait_histogram_127500-255500us 0 +Rpl_semi_sync_master_trx_wait_histogram_255500-MAXus 0 # # BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed # BUG#45673 Semisync reports correct operation even if no slave is connected diff --git a/mysql-test/suite/rpl_nogtid/t/rpl_semi_sync.test b/mysql-test/suite/rpl_nogtid/t/rpl_semi_sync.test index 4136d6691490..09332bc0b356 100644 --- a/mysql-test/suite/rpl_nogtid/t/rpl_semi_sync.test +++ b/mysql-test/suite/rpl_nogtid/t/rpl_semi_sync.test @@ -90,6 +90,7 @@ echo [ status of semi-sync on master should be ON even without any semi-sync sla show status like 'Rpl_semi_sync_source_clients'; show status like 'Rpl_semi_sync_source_status'; show status like 'Rpl_semi_sync_source_yes_tx'; +show status like 'Rpl_semi_sync_master_trx_wait_histogram%'; --echo # --echo # BUG#45672 Semisync repl: ActiveTranx:insert_tranx_node: transaction node allocation failed diff --git a/mysql-test/suite/sys_vars/r/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.result b/mysql-test/suite/sys_vars/r/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.result new file mode 100644 index 000000000000..8e5cc2987c74 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.result @@ -0,0 +1,75 @@ +SELECT COUNT(@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size); +COUNT(@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size) +1 +1 Expected +SET @start_global_value = @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +SELECT @start_global_value; +@start_global_value +500us +16ms Expected +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='16us'; +select @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size +16us +16us Expected +select * from performance_schema.global_variables where variable_name='rpl_semi_sync_master_histogram_trx_wait_step_size'; +VARIABLE_NAME VARIABLE_VALUE +rpl_semi_sync_master_histogram_trx_wait_step_size 16us +SELECT @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='rpl_semi_sync_master_histogram_trx_wait_step_size'; +@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size = VARIABLE_VALUE +1 +1 Expected +SELECT COUNT(@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size); +COUNT(@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size) +1 +1 Expected +SELECT COUNT(VARIABLE_VALUE) +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='rpl_semi_sync_master_histogram_trx_wait_step_size'; +COUNT(VARIABLE_VALUE) +1 +1 Expected +SELECT COUNT(@@local.rpl_semi_sync_master_histogram_trx_wait_step_size); +ERROR HY000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SELECT COUNT(@@SESSION.rpl_semi_sync_master_histogram_trx_wait_step_size); +ERROR HY000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' is a GLOBAL variable +Expected error 'Variable is a GLOBAL variable' +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of '32' +Expected error 'Variable cannot be set to this value'; +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='0'; +select @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size +0 +0 Expected +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='ms32'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of 'ms32' +Expected error 'Variable cannot be set to this value'; +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32ps'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of '32ps' +Expected error 'Variable cannot be set to this value'; +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='3s2'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of '3s2' +Expected error 'Variable cannot be set to this value'; +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32@s'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of '32@s' +Expected error 'Variable cannot be set to this value'; +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32s.'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of '32s.' +Expected error 'Variable cannot be set to this value'; +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='s'; +ERROR 42000: Variable 'rpl_semi_sync_master_histogram_trx_wait_step_size' can't be set to the value of 's' +Expected error 'Variable cannot be set to this value' +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='16.5us'; +select @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size +16.5us +16.5us Expected +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size = @start_global_value; +SELECT @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size +500us +16ms Expected diff --git a/mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic-master.opt b/mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic-master.opt new file mode 100644 index 000000000000..8c9e13fe2c4a --- /dev/null +++ b/mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic-master.opt @@ -0,0 +1 @@ +$SEMISYNC_MASTER_PLUGIN_OPT $SEMISYNC_MASTER_PLUGIN_LOAD diff --git a/mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.test b/mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.test new file mode 100644 index 000000000000..5838a3de3fd5 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/rpl_semi_sync_source_histogram_trx_wait_step_size_basic.test @@ -0,0 +1,73 @@ +SELECT COUNT(@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size); +--echo 1 Expected + +SET @start_global_value = @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +SELECT @start_global_value; +--echo 16ms Expected + +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='16us'; +select @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +--echo 16us Expected + +select * from performance_schema.global_variables where variable_name='rpl_semi_sync_master_histogram_trx_wait_step_size'; + +SELECT @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size = VARIABLE_VALUE +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='rpl_semi_sync_master_histogram_trx_wait_step_size'; +--echo 1 Expected + +SELECT COUNT(@@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size); +--echo 1 Expected + +SELECT COUNT(VARIABLE_VALUE) +FROM performance_schema.global_variables +WHERE VARIABLE_NAME='rpl_semi_sync_master_histogram_trx_wait_step_size'; +--echo 1 Expected + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@local.rpl_semi_sync_master_histogram_trx_wait_step_size); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_INCORRECT_GLOBAL_LOCAL_VAR +SELECT COUNT(@@SESSION.rpl_semi_sync_master_histogram_trx_wait_step_size); +--echo Expected error 'Variable is a GLOBAL variable' + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32'; +--echo Expected error 'Variable cannot be set to this value'; + +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='0'; +select @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +--echo 0 Expected + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='ms32'; +--echo Expected error 'Variable cannot be set to this value'; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32ps'; +--echo Expected error 'Variable cannot be set to this value'; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='3s2'; +--echo Expected error 'Variable cannot be set to this value'; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32@s'; +--echo Expected error 'Variable cannot be set to this value'; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='32s.'; +--echo Expected error 'Variable cannot be set to this value'; + +--Error ER_WRONG_VALUE_FOR_VAR +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='s'; +--echo Expected error 'Variable cannot be set to this value' + +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size='16.5us'; +select @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +--echo 16.5us Expected + +SET @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size = @start_global_value; +SELECT @@GLOBAL.rpl_semi_sync_master_histogram_trx_wait_step_size; +--echo 16ms Expected diff --git a/plugin/semisync/semisync_source.cc b/plugin/semisync/semisync_source.cc index 8959d1749533..033104eaf9d4 100644 --- a/plugin/semisync/semisync_source.cc +++ b/plugin/semisync/semisync_source.cc @@ -66,6 +66,10 @@ unsigned long long rpl_semi_sync_source_net_wait_time = 0; unsigned long long rpl_semi_sync_source_trx_wait_time = 0; bool rpl_semi_sync_source_wait_no_replica = true; unsigned int rpl_semi_sync_source_wait_for_replica_count = 1; +char *histogram_trx_wait_step_size = 0; +latency_histogram histogram_trx_wait; +SHOW_VAR latency_histogram_trx_wait[NUMBER_OF_HISTOGRAM_BINS + 1]; +ulonglong histogram_trx_wait_values[NUMBER_OF_HISTOGRAM_BINS]; resource_blocker::Resource &get_dump_thread_resource(); @@ -441,6 +445,7 @@ int ReplSemiSyncMaster::initObject() { else result = disableMaster(); + latency_histogram_init(&histogram_trx_wait, histogram_trx_wait_step_size); return result; } @@ -511,6 +516,7 @@ int ReplSemiSyncMaster::disableMaster() { } ReplSemiSyncMaster::~ReplSemiSyncMaster() { + free_latency_histogram_sysvars(latency_histogram_trx_wait); if (init_done_) { mysql_mutex_destroy(&LOCK_binlog_); } @@ -849,6 +855,10 @@ int ReplSemiSyncMaster::commitTrx(const char *trx_wait_binlog_name, } else { rpl_semi_sync_source_trx_wait_num++; rpl_semi_sync_source_trx_wait_time += wait_time; + if (histogram_trx_wait_step_size) + latency_histogram_increment( + &histogram_trx_wait, + microseconds_to_my_timer((double)wait_time), 1); } } } @@ -1215,6 +1225,11 @@ void ReplSemiSyncMaster::setExportStats() { ((double)rpl_semi_sync_source_net_wait_num)) : 0); + for (size_t i_bins = 0; i_bins < NUMBER_OF_HISTOGRAM_BINS; ++i_bins) { + histogram_trx_wait_values[i_bins] = + latency_histogram_get_count(&histogram_trx_wait, i_bins); + } + unlock(); } @@ -1340,3 +1355,10 @@ static int getWaitTime(const struct timespec &start_ts) { return (int)(end_usecs - start_usecs); } + +void ReplSemiSyncMaster::update_histogram_trx_wait_step_size( + const char *step_size) { + lock(); + latency_histogram_init(&histogram_trx_wait, step_size); + unlock(); +} diff --git a/plugin/semisync/semisync_source.h b/plugin/semisync/semisync_source.h index ebdc63b740b6..379da0bb60d5 100644 --- a/plugin/semisync/semisync_source.h +++ b/plugin/semisync/semisync_source.h @@ -32,6 +32,7 @@ #include "my_io.h" #include "my_psi_config.h" #include "plugin/semisync/semisync.h" +#include "sql/mysqld.h" extern PSI_memory_key key_ss_memory_TranxNodeAllocator_block; @@ -833,6 +834,14 @@ class ReplSemiSyncMaster : public ReplSemiSyncBase { } unlock(); } + + /* Reinitializes the latency histogram when trx_wait_step_size + * is updated. + * + * Input: + * step_size - (IN) updated step_size + */ + void update_histogram_trx_wait_step_size(const char *step_size); }; /* System and status variables for the master component */ @@ -856,6 +865,12 @@ extern unsigned long long rpl_semi_sync_source_trx_wait_num; extern unsigned long long rpl_semi_sync_source_net_wait_time; extern unsigned long long rpl_semi_sync_source_trx_wait_time; +extern char *histogram_trx_wait_step_size; +extern latency_histogram histogram_trx_wait; +/* status variables for trx_wait_time histogram */ +extern SHOW_VAR latency_histogram_trx_wait[NUMBER_OF_HISTOGRAM_BINS + 1]; +extern ulonglong histogram_trx_wait_values[NUMBER_OF_HISTOGRAM_BINS]; + /* This indicates whether we should keep waiting if no semi-sync slave is available. diff --git a/plugin/semisync/semisync_source_plugin.cc b/plugin/semisync/semisync_source_plugin.cc index 57ad899040da..e3aab4141390 100644 --- a/plugin/semisync/semisync_source_plugin.cc +++ b/plugin/semisync/semisync_source_plugin.cc @@ -277,6 +277,63 @@ static void update_whitelist(THD *, SYS_VAR *, void *var_ptr, ack_receiver->unlock(); } +/* + Checks whether a valid argument is given to + rpl_semi_sync_master_trx_wait_step_size sys_var. + + @return 0 valid step size + >0 invalid step size + + @param thd thread handler + @param var pointer to the system variable + @return save Output value is stored here. This is the immediate result + for sys_var update function + @param value input value +*/ +static int check_histogram_step_size(MYSQL_THD, SYS_VAR *, void *save, + struct st_mysql_value *value) { + int len = 0; + const char *step_size_local = value->val_str(value, nullptr, &len); + + size_t length = 0; + if (step_size_local) length = strlen(step_size_local); + + if (length == 0) { + *static_cast(save) = nullptr; + return 0; + } + + /* + Validating if the string (non empty) ends with ms/us/s and the + rest of it is a valid floating point number + */ + int ret = histogram_validate_step_size_string(step_size_local); + if (!ret) *static_cast(save) = step_size_local; + + return ret; +} + +/* + Reinitializes the latency histogram when the trx_wait_step_size is + updated. + + @param thd thread handler + @param var pointer to system variable + @result var_ptr output value of the system variable + @param save input string value. This is the immediate result from + sys_var check function. +*/ +static void update_histogram_trx_wait_step_size(MYSQL_THD, SYS_VAR *, + void *var_ptr, + const void *save) { + const char *step_size_local = *static_cast(save); + + if (step_size_local) + repl_semisync->update_histogram_trx_wait_step_size(step_size_local); + + *static_cast(var_ptr) = step_size_local; +} + static MYSQL_SYSVAR_BOOL( enabled, rpl_semi_sync_source_enabled, PLUGIN_VAR_OPCMDARG, "Enable semi-synchronous replication source (disabled by default). ", @@ -390,6 +447,13 @@ static MYSQL_SYSVAR_STR( "list will lead to discarding all ACKs.", nullptr, update_whitelist, "ANY"); +static MYSQL_SYSVAR_STR(histogram_trx_wait_step_size, + histogram_trx_wait_step_size, + PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_MEMALLOC, + "Histogram step size for transaction wait time. ", + check_histogram_step_size, + update_histogram_trx_wait_step_size, "500us"); + static SYS_VAR *semi_sync_master_system_vars[] = { MYSQL_SYSVAR(enabled), MYSQL_SYSVAR(timeout), @@ -399,6 +463,7 @@ static SYS_VAR *semi_sync_master_system_vars[] = { MYSQL_SYSVAR(wait_point), MYSQL_SYSVAR(WAIT_FOR_REPLICA_COUNT_NAME), MYSQL_SYSVAR(whitelist), + MYSQL_SYSVAR(histogram_trx_wait_step_size), nullptr, }; static void fix_rpl_semi_sync_source_timeout(MYSQL_THD, SYS_VAR *, void *ptr, @@ -506,6 +571,24 @@ DEF_SHOW_FUNC(net_wait_num, SHOW_LONGLONG) DEF_SHOW_FUNC(avg_net_wait_time, SHOW_LONG) DEF_SHOW_FUNC(avg_trx_wait_time, SHOW_LONG) +static SHOW_VAR semisync_histogram_status_variables[] = { + {"Rpl_semi_sync_master_trx_wait_histogram", + (char *)&latency_histogram_trx_wait, SHOW_ARRAY, SHOW_SCOPE_GLOBAL}, + {NULL, NULL, SHOW_LONG, SHOW_SCOPE_GLOBAL}}; + +static int rpl_semi_sync_master_trx_wait_histogram(MYSQL_THD, SHOW_VAR *var, + char *) { + prepare_latency_histogram_vars(&histogram_trx_wait, + latency_histogram_trx_wait, + histogram_trx_wait_values); + + repl_semisync->setExportStats(); + var->type = SHOW_ARRAY; + var->value = (char *)&semisync_histogram_status_variables; + var->scope = SHOW_SCOPE_GLOBAL; + return 0; +} + /* plugin status variables */ static SHOW_VAR semi_sync_master_status_vars[] = { {STATUS_VAR_PREFIX "status", (char *)&SHOW_FNAME(status), SHOW_FUNC, @@ -538,6 +621,9 @@ static SHOW_VAR semi_sync_master_status_vars[] = { SHOW_FUNC, SHOW_SCOPE_GLOBAL}, {STATUS_VAR_PREFIX "net_avg_wait_time", (char *)&SHOW_FNAME(avg_net_wait_time), SHOW_FUNC, SHOW_SCOPE_GLOBAL}, + {"Rpl_semi_sync_master_trx_wait_histogram", + (char *)&rpl_semi_sync_master_trx_wait_histogram, SHOW_FUNC, + SHOW_SCOPE_GLOBAL}, {nullptr, nullptr, SHOW_LONG, SHOW_SCOPE_GLOBAL}, }; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 7632fcbbdfc2..374fd64a11bd 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4170,6 +4170,246 @@ void init_my_timer(void) { } } +/** + Create a new Histogram. + + @param current_histogram The histogram being initialized. + @param step_size_with_unit Configurable system variable containing + step size and unit of the Histogram. +*/ +void latency_histogram_init(latency_histogram *current_histogram, + const char *step_size_with_unit) { + assert(current_histogram != 0); + + double step_size_base_time = 0.0; + current_histogram->num_bins = NUMBER_OF_HISTOGRAM_BINS; + + // this can potentially be made configurable later. + current_histogram->step_ratio = 2.0; + current_histogram->step_size = 0; + char *histogram_unit = NULL; + + for (int i = 0; i < NUMBER_OF_HISTOGRAM_BINS; i++) + current_histogram->count_per_bin[i].store(0); + + if (!step_size_with_unit) return; + + step_size_base_time = strtod(step_size_with_unit, &histogram_unit); + if (histogram_unit) { + if (!strcmp(histogram_unit, "s")) { + current_histogram->step_size = + microseconds_to_my_timer(step_size_base_time * 1000000.0); + } else if (!strcmp(histogram_unit, "ms")) { + current_histogram->step_size = + microseconds_to_my_timer(step_size_base_time * 1000.0); + } else if (!strcmp(histogram_unit, "us")) { + current_histogram->step_size = + microseconds_to_my_timer(step_size_base_time); + } + /* Special case when step size is passed to be '0' */ + else if (*histogram_unit == '\0') { + if (step_size_base_time == 0.0) { + current_histogram->step_size = 0; + } else + current_histogram->step_size = + microseconds_to_my_timer(step_size_base_time); + } else { + sql_print_error("Invalid units given to histogram step size."); + return; + } + } else { + /* NO_LINT_DEBUG */ + sql_print_error("Invalid histogram step size."); + return; + } +} + +/** + Search a value in the histogram bins. + + @param current_histogram The current histogram. + @param value Value to be searched. + + @return Returns the bin that contains this value. + -1 if Step Size is 0 +*/ +static int latency_histogram_bin_search(latency_histogram *current_histogram, + ulonglong value) { + if (current_histogram->step_size == 0 || value == 0 || + current_histogram->step_ratio <= 0.0) + return -1; + + double dbin_no = std::log2((double)value / current_histogram->step_size) / + std::log2(current_histogram->step_ratio); + + int ibin_no = (int)dbin_no; + if (ibin_no < 0) return 0; + + return min(ibin_no, (int)current_histogram->num_bins - 1); +} + +/** + Increment the count of a bin in Histogram. + + @param current_histogram The current histogram. + @param value Value of which corresponding bin has to be found. + @param count Amount by which the count of a bin has to be + increased. + +*/ +void latency_histogram_increment(latency_histogram *current_histogram, + ulonglong value, ulonglong count) { + int index = latency_histogram_bin_search(current_histogram, value); + if (index < 0) return; + current_histogram->count_per_bin[index] += count; +} + +/** + Get the count corresponding to a bin of the Histogram. + + @param current_histogram The current histogram. + @param bin_num The bin whose count has to be returned. + + @return Returns the count of that bin. +*/ +ulonglong latency_histogram_get_count(latency_histogram *current_histogram, + size_t bin_num) { + return (current_histogram->count_per_bin)[bin_num]; +} + +/** + Validate if the string passed to the configurable histogram step size + conforms to proper syntax. + + @param step_size_with_unit The configurable step size string to be checked. + + @return 1 if invalid, 0 if valid. +*/ +int histogram_validate_step_size_string(const char *step_size_with_unit) { + if (step_size_with_unit == nullptr) return 0; + + int ret = 0; + char *histogram_unit = NULL; + double histogram_step_size = strtod(step_size_with_unit, &histogram_unit); + if (histogram_step_size && histogram_unit) { + if (strcmp(histogram_unit, "ms") && strcmp(histogram_unit, "us") && + strcmp(histogram_unit, "s")) + ret = 1; + } + /* Special case when step size is passed to be '0' */ + else if (*histogram_unit == '\0' && histogram_step_size == 0.0) + return 0; + else + ret = 1; + return ret; +} + +/** + This function is called to convert the histogram bucket ranges in system time + units to a string and calculates units on the fly, which can be displayed in + the output of SHOW GLOBAL STATUS. + The string has the following form: + + _- + + @param bucket_lower_display Lower Range value of the Histogram Bucket + @param bucket_upper_display Upper Range value of the Histogram Bucket + @param is_last_bucket Flag to denote last bucket in the histogram + + @return The display string for the Histogram Bucket +*/ +histogram_display_string histogram_bucket_to_display_string( + ulonglong bucket_lower_display, ulonglong bucket_upper_display, + bool is_last_bucket) { + struct histogram_display_string histogram_bucket_name; + + std::string time_unit_suffix; + ulonglong time_factor = 1; + + if ((bucket_upper_display % 1000000) == 0 && + (bucket_lower_display % 1000000) == 0) { + time_unit_suffix = "s"; + time_factor = 1000000; + } else if ((bucket_upper_display % 1000) == 0 && + (bucket_lower_display % 1000) == 0) { + time_unit_suffix = "ms"; + time_factor = 1000; + } else { + time_unit_suffix = "us"; + } + + std::string bucket_display_format; + if (is_last_bucket) { + bucket_display_format = "%llu-MAX" + time_unit_suffix; + snprintf(histogram_bucket_name.name, HISTOGRAM_BUCKET_NAME_MAX_SIZE, + bucket_display_format.c_str(), bucket_lower_display / time_factor); + } else { + bucket_display_format = "%llu-%llu" + time_unit_suffix; + snprintf(histogram_bucket_name.name, HISTOGRAM_BUCKET_NAME_MAX_SIZE, + bucket_display_format.c_str(), bucket_lower_display / time_factor, + bucket_upper_display / time_factor); + } + + return histogram_bucket_name; +} + +/** + Frees old histogram bucket display strings before assigning new ones. +*/ +void free_latency_histogram_sysvars(SHOW_VAR *latency_histogram_data) { + size_t i; + for (i = 0; i < NUMBER_OF_HISTOGRAM_BINS; ++i) { + if (latency_histogram_data[i].name) { + my_free(const_cast(latency_histogram_data[i].name)); + latency_histogram_data[i].name = nullptr; + } + } +} + +/** + This function is called by the plugin callback function + to add entries into the latency_histogram_xxxx array, by forming + the appropriate display string and fetching the histogram bin + counts. + + @param current_histogram Histogram whose values are currently added + in the SHOW_VAR array + @param latency_histogram_data SHOW_VAR array for the corresponding Histogram + @param histogram_values Values to be exported to Innodb status. + This array contains the bin counts of the + respective Histograms. +*/ +void prepare_latency_histogram_vars(latency_histogram *current_histogram, + SHOW_VAR *latency_histogram_data, + ulonglong *histogram_values) { + size_t i; + ulonglong bucket_lower_display, bucket_upper_display; + const SHOW_VAR temp_last = {NullS, NullS, SHOW_LONG, SHOW_SCOPE_GLOBAL}; + + free_latency_histogram_sysvars(latency_histogram_data); + + ulonglong itr_step_size = current_histogram->step_size; + for (i = 0, bucket_lower_display = 0; i < NUMBER_OF_HISTOGRAM_BINS; ++i) { + bucket_upper_display = my_timer_to_microseconds_ulonglong(itr_step_size) + + bucket_lower_display; + + struct histogram_display_string histogram_bucket_name = + histogram_bucket_to_display_string(bucket_lower_display, + bucket_upper_display, + i == NUMBER_OF_HISTOGRAM_BINS - 1); + + const SHOW_VAR temp = {my_strdup(key_memory_global_system_variables, + histogram_bucket_name.name, MYF(0)), + (char *)&(histogram_values[i]), SHOW_LONGLONG, + SHOW_SCOPE_GLOBAL}; + latency_histogram_data[i] = temp; + + bucket_lower_display = bucket_upper_display; + itr_step_size *= current_histogram->step_ratio; + } + latency_histogram_data[NUMBER_OF_HISTOGRAM_BINS] = temp_last; +} + /** Initialize one of the global date/time format variables. diff --git a/sql/mysqld.h b/sql/mysqld.h index fb7776eb2024..c4e8e7db65c1 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -1007,6 +1007,122 @@ extern SERVICE_TYPE_NO_CONST(registry) * srv_registry; extern SERVICE_TYPE(dynamic_loader_scheme_file) * scheme_file_srv; extern SERVICE_TYPE(dynamic_loader) * dynamic_loader_srv; +/* Histogram struct to track various latencies */ +#define NUMBER_OF_HISTOGRAM_BINS 10 +struct latency_histogram { + size_t num_bins; + ulonglong step_size; + double step_ratio; + std::atomic count_per_bin[NUMBER_OF_HISTOGRAM_BINS]; +}; + +/* Convert native timer units in a ulonglong into microseconds in a ulonglong */ +inline ulonglong my_timer_to_microseconds_ulonglong(ulonglong when) { + ulonglong ret = (ulonglong)(when); + ret *= 1000000; + ret = (ulonglong)((ret + my_timer.frequency - 1) / my_timer.frequency); + return ret; +} + +/** Compression statistics for a fil_space */ +/** + Create a new Histogram. + + @param current_histogram The histogram being initialized. + @param step_size_with_unit Configurable system variable containing + step size and unit of the Histogram. +*/ +void latency_histogram_init(latency_histogram *current_histogram, + const char *step_size_with_unit); + +/** + Increment the count of a bin in Histogram. + + @param current_histogram The current histogram. + @param value Value of which corresponding bin has to be found. + @param count Amount by which the count of a bin has to be + increased. + +*/ +void latency_histogram_increment(latency_histogram *current_histogram, + ulonglong value, ulonglong count); + +/** + Get the count corresponding to a bin of the Histogram. + + @param current_histogram The current histogram. + @param bin_num The bin whose count has to be returned. + + @return Returns the count of that bin. +*/ +ulonglong latency_histogram_get_count(latency_histogram *current_histogram, + size_t bin_num); + +/** + Validate if the string passed to the configurable histogram step size + conforms to proper syntax. + + @param step_size_with_unit The configurable step size string to be checked. + + @return 1 if invalid, 0 if valid. +*/ +int histogram_validate_step_size_string(const char *step_size_with_unit); + +#define HISTOGRAM_BUCKET_NAME_MAX_SIZE \ + 64 /**< This is the maximum size \ + of the string: \ + "LowerBucketValue-" \ + "UpperBucketValue" \ + where bucket is the latency \ + histogram bucket and units \ + can be us,ms or s */ + +/** To return the displayable histogram name from + my_timer_to_display_string() */ +struct histogram_display_string { + char name[HISTOGRAM_BUCKET_NAME_MAX_SIZE]; +}; + +/** + This function is called to convert the histogram bucket ranges in system time + units to a string and calculates units on the fly, which can be displayed in + the output of SHOW GLOBAL STATUS. + The string has the following form: + + _- + + @param bucket_lower_display Lower Range value of the Histogram Bucket + @param bucket_upper_display Upper Range value of the Histogram Bucket + @param is_last_bucket Flag to denote last bucket in the histogram + + @return The display string for the Histogram Bucket +*/ +histogram_display_string histogram_bucket_to_display_string( + ulonglong bucket_lower_display, ulonglong bucket_upper_display, + bool is_last_bucket = false); + +/** + This function is called by the plugin callback function + to add entries into the latency_histogram_xxxx array, by forming + the appropriate display string and fetching the histogram bin + counts. + + @param current_histogram Histogram whose values are currently added + in the SHOW_VAR array + @param latency_histogram_data SHOW_VAR array for the corresponding Histogram + @param histogram_values Values to be exported to Innodb status. + This array contains the bin counts of the + respective Histograms. +*/ +void prepare_latency_histogram_vars(latency_histogram *current_histogram, + SHOW_VAR *latency_histogram_data, + ulonglong *histogram_values); + +/** + Frees old histogram bucket display strings before assigning new ones. +*/ +void free_latency_histogram_sysvars(SHOW_VAR *latency_histogram_data); + class Deployed_components; extern Deployed_components *g_deployed_components;