From 2bf3e416fedf9984296da9ff43c7ff54780010d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 29 Oct 2014 13:49:12 +0200 Subject: [PATCH] MDEV-6932: Enable Lazy Flushing Merge Facebook commit 4f3e0343fd2ac3fc7311d0ec9739a8f668274f0d authored by Steaphan Greene from https://github.com/facebook/mysql-5.6 Adds innodb_idle_flush_pct to enable tuning of the page flushing rate when the system is relatively idle. We care about this, since doing extra unnecessary flash writes shortens the lifespan of the flash. --- .../r/innodb_idle_flush_pct_basic.result | 77 +++++++++++++++++++ .../suite/sys_vars/r/sysvars_innodb.result | 14 ++++ .../t/innodb_idle_flush_pct_basic.test | 63 +++++++++++++++ storage/innobase/buf/buf0flu.cc | 17 ++-- storage/innobase/handler/ha_innodb.cc | 8 ++ storage/innobase/include/srv0srv.h | 2 + storage/innobase/srv/srv0srv.cc | 2 + storage/xtradb/buf/buf0flu.cc | 16 ++-- storage/xtradb/handler/ha_innodb.cc | 8 ++ storage/xtradb/include/srv0srv.h | 2 + storage/xtradb/srv/srv0srv.cc | 2 + 11 files changed, 189 insertions(+), 22 deletions(-) create mode 100644 mysql-test/suite/sys_vars/r/innodb_idle_flush_pct_basic.result create mode 100644 mysql-test/suite/sys_vars/t/innodb_idle_flush_pct_basic.test diff --git a/mysql-test/suite/sys_vars/r/innodb_idle_flush_pct_basic.result b/mysql-test/suite/sys_vars/r/innodb_idle_flush_pct_basic.result new file mode 100644 index 0000000000000..a2c328f38fd65 --- /dev/null +++ b/mysql-test/suite/sys_vars/r/innodb_idle_flush_pct_basic.result @@ -0,0 +1,77 @@ +SET @start_global_value = @@global.innodb_idle_flush_pct; +SELECT @start_global_value; +@start_global_value +100 +Valid values are between 0 and 100 +select @@global.innodb_idle_flush_pct between 0 and 100; +@@global.innodb_idle_flush_pct between 0 and 100 +1 +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +100 +select @@session.innodb_idle_flush_pct; +ERROR HY000: Variable 'innodb_idle_flush_pct' is a GLOBAL variable +show global variables like 'innodb_idle_flush_pct'; +Variable_name Value +innodb_idle_flush_pct 100 +show session variables like 'innodb_idle_flush_pct'; +Variable_name Value +innodb_idle_flush_pct 100 +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_IDLE_FLUSH_PCT 100 +select * from information_schema.session_variables where variable_name='innodb_idle_flush_pct'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_IDLE_FLUSH_PCT 100 +set global innodb_idle_flush_pct=10; +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +10 +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_IDLE_FLUSH_PCT 10 +select * from information_schema.session_variables where variable_name='innodb_idle_flush_pct'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_IDLE_FLUSH_PCT 10 +set session innodb_idle_flush_pct=1; +ERROR HY000: Variable 'innodb_idle_flush_pct' is a GLOBAL variable and should be set with SET GLOBAL +set global innodb_idle_flush_pct=1.1; +ERROR 42000: Incorrect argument type to variable 'innodb_idle_flush_pct' +set global innodb_idle_flush_pct=1e1; +ERROR 42000: Incorrect argument type to variable 'innodb_idle_flush_pct' +set global innodb_idle_flush_pct="bar"; +ERROR 42000: Incorrect argument type to variable 'innodb_idle_flush_pct' +set global innodb_idle_flush_pct=-7; +Warnings: +Warning 1292 Truncated incorrect innodb_idle_flush_pct value: '-7' +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +0 +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_IDLE_FLUSH_PCT 0 +set global innodb_idle_flush_pct=106; +Warnings: +Warning 1292 Truncated incorrect innodb_idle_flush_pct value: '106' +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +100 +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +VARIABLE_NAME VARIABLE_VALUE +INNODB_IDLE_FLUSH_PCT 100 +set global innodb_idle_flush_pct=0; +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +0 +set global innodb_idle_flush_pct=100; +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +100 +set global innodb_idle_flush_pct=DEFAULT; +select @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +100 +SET @@global.innodb_idle_flush_pct = @start_global_value; +SELECT @@global.innodb_idle_flush_pct; +@@global.innodb_idle_flush_pct +100 diff --git a/mysql-test/suite/sys_vars/r/sysvars_innodb.result b/mysql-test/suite/sys_vars/r/sysvars_innodb.result index f3bc9eead9c48..c1823ff7739a9 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_innodb.result +++ b/mysql-test/suite/sys_vars/r/sysvars_innodb.result @@ -1027,6 +1027,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT OPTIONAL +VARIABLE_NAME INNODB_IDLE_FLUSH_PCT +SESSION_VALUE NULL +GLOBAL_VALUE 100 +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE 100 +VARIABLE_SCOPE GLOBAL +VARIABLE_TYPE BIGINT UNSIGNED +VARIABLE_COMMENT Up to what percentage of dirty pages should be flushed when innodb finds it has spare resources to do so. +NUMERIC_MIN_VALUE 0 +NUMERIC_MAX_VALUE 100 +NUMERIC_BLOCK_SIZE 0 +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME INNODB_IO_CAPACITY SESSION_VALUE NULL GLOBAL_VALUE 200 diff --git a/mysql-test/suite/sys_vars/t/innodb_idle_flush_pct_basic.test b/mysql-test/suite/sys_vars/t/innodb_idle_flush_pct_basic.test new file mode 100644 index 0000000000000..7175a59e23850 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/innodb_idle_flush_pct_basic.test @@ -0,0 +1,63 @@ + +# +# 2013-04-01 - Added +# + +--source include/have_innodb.inc + +SET @start_global_value = @@global.innodb_idle_flush_pct; +SELECT @start_global_value; + +# +# exists as global only +# +--echo Valid values are between 0 and 100 +select @@global.innodb_idle_flush_pct between 0 and 100; +select @@global.innodb_idle_flush_pct; +--error ER_INCORRECT_GLOBAL_LOCAL_VAR +select @@session.innodb_idle_flush_pct; +show global variables like 'innodb_idle_flush_pct'; +show session variables like 'innodb_idle_flush_pct'; +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +select * from information_schema.session_variables where variable_name='innodb_idle_flush_pct'; + +# +# show that it's writable +# +set global innodb_idle_flush_pct=10; +select @@global.innodb_idle_flush_pct; +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +select * from information_schema.session_variables where variable_name='innodb_idle_flush_pct'; +--error ER_GLOBAL_VARIABLE +set session innodb_idle_flush_pct=1; + +# +# incorrect types +# +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_idle_flush_pct=1.1; +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_idle_flush_pct=1e1; +--error ER_WRONG_TYPE_FOR_VAR +set global innodb_idle_flush_pct="bar"; + +set global innodb_idle_flush_pct=-7; +select @@global.innodb_idle_flush_pct; +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; +set global innodb_idle_flush_pct=106; +select @@global.innodb_idle_flush_pct; +select * from information_schema.global_variables where variable_name='innodb_idle_flush_pct'; + +# +# min/max/DEFAULT values +# +set global innodb_idle_flush_pct=0; +select @@global.innodb_idle_flush_pct; +set global innodb_idle_flush_pct=100; +select @@global.innodb_idle_flush_pct; +set global innodb_idle_flush_pct=DEFAULT; +select @@global.innodb_idle_flush_pct; + + +SET @@global.innodb_idle_flush_pct = @start_global_value; +SELECT @@global.innodb_idle_flush_pct; diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 441fcfb4d9464..80b1ce0bb991b 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -2444,27 +2444,17 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( while (srv_shutdown_state == SRV_SHUTDOWN_NONE) { - /* The page_cleaner skips sleep if the server is - idle and there are no pending IOs in the buffer pool - and there is work to do. */ - if (srv_check_activity(last_activity) - || buf_get_n_pending_read_ios() - || n_flushed == 0) { - page_cleaner_sleep_if_needed(next_loop_time); - } + page_cleaner_sleep_if_needed(next_loop_time); next_loop_time = ut_time_ms() + 1000; if (srv_check_activity(last_activity)) { last_activity = srv_get_activity_count(); - /* Flush pages from end of LRU if required */ - n_flushed = buf_flush_LRU_tail(); - /* Flush pages from flush_list if required */ n_flushed += page_cleaner_flush_pages_if_needed(); - } else { + } else if (srv_idle_flush_pct) { n_flushed = page_cleaner_do_flush_batch( PCT_IO(100), LSN_MAX); @@ -2477,6 +2467,9 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( n_flushed); } } + + /* Flush pages from end of LRU if required */ + buf_flush_LRU_tail(); } ut_ad(srv_shutdown_state > 0); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ee06401be2452..ced6faba79b1a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -17891,6 +17891,13 @@ static MYSQL_SYSVAR_ULONG(io_capacity_max, srv_max_io_capacity, SRV_MAX_IO_CAPACITY_DUMMY_DEFAULT, 100, SRV_MAX_IO_CAPACITY_LIMIT, 0); +static MYSQL_SYSVAR_ULONG(idle_flush_pct, + srv_idle_flush_pct, + PLUGIN_VAR_RQCMDARG, + "Up to what percentage of dirty pages should be flushed when innodb " + "finds it has spare resources to do so.", + NULL, NULL, 100, 0, 100, 0); + #ifdef UNIV_DEBUG static MYSQL_SYSVAR_BOOL(purge_run_now, innodb_purge_run_now, PLUGIN_VAR_OPCMDARG, @@ -18920,6 +18927,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(read_only), MYSQL_SYSVAR(io_capacity), MYSQL_SYSVAR(io_capacity_max), + MYSQL_SYSVAR(idle_flush_pct), MYSQL_SYSVAR(monitor_enable), MYSQL_SYSVAR(monitor_disable), MYSQL_SYSVAR(monitor_reset), diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index 7ba69736271b7..e3ac49c50accd 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -359,6 +359,8 @@ extern double srv_defragment_fill_factor; extern uint srv_defragment_frequency; extern ulonglong srv_defragment_interval; +extern ulint srv_idle_flush_pct; + /* Number of IO operations per second the server can do */ extern ulong srv_io_capacity; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index ca5c22d8ee43a..5dfb38b53c7a0 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -257,6 +257,8 @@ UNIV_INTERN ulint srv_buf_pool_curr_size = 0; UNIV_INTERN ulint srv_mem_pool_size = ULINT_MAX; UNIV_INTERN ulint srv_lock_table_size = ULINT_MAX; +UNIV_INTERN ulint srv_idle_flush_pct = 100; + /* This parameter is deprecated. Use srv_n_io_[read|write]_threads instead. */ UNIV_INTERN ulint srv_n_file_io_threads = ULINT_MAX; diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc index ac614823bc1b6..4b160aea98842 100644 --- a/storage/xtradb/buf/buf0flu.cc +++ b/storage/xtradb/buf/buf0flu.cc @@ -2736,14 +2736,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( srv_current_thread_priority = srv_cleaner_thread_priority; - /* The page_cleaner skips sleep if the server is - idle and there are no pending IOs in the buffer pool - and there is work to do. */ - if (srv_check_activity(last_activity) - || buf_get_n_pending_read_ios() - || n_flushed == 0) { - page_cleaner_sleep_if_needed(next_loop_time); - } + page_cleaner_sleep_if_needed(next_loop_time); page_cleaner_sleep_time = page_cleaner_adapt_flush_sleep_time(); @@ -2761,8 +2754,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( } /* Flush pages from flush_list if required */ - n_flushed += page_cleaner_flush_pages_if_needed(); - } else { + page_cleaner_flush_pages_if_needed(); + } else if (srv_idle_flush_pct) { n_flushed = page_cleaner_do_flush_batch( PCT_IO(100), LSN_MAX); @@ -2775,6 +2768,9 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)( n_flushed); } } + + /* Flush pages from end of LRU if required */ + buf_flush_LRU_tail(); } ut_ad(srv_shutdown_state > 0); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 43349146c1411..93563b16c13d9 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -18970,6 +18970,13 @@ static MYSQL_SYSVAR_ULONG(io_capacity_max, srv_max_io_capacity, SRV_MAX_IO_CAPACITY_DUMMY_DEFAULT, 100, SRV_MAX_IO_CAPACITY_LIMIT, 0); +static MYSQL_SYSVAR_ULONG(idle_flush_pct, + srv_idle_flush_pct, + PLUGIN_VAR_RQCMDARG, + "Up to what percentage of dirty pages should be flushed when innodb " + "finds it has spare resources to do so.", + NULL, NULL, 100, 0, 100, 0); + #ifdef UNIV_DEBUG static MYSQL_SYSVAR_BOOL(purge_run_now, innodb_purge_run_now, PLUGIN_VAR_OPCMDARG, @@ -20224,6 +20231,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { MYSQL_SYSVAR(read_only), MYSQL_SYSVAR(io_capacity), MYSQL_SYSVAR(io_capacity_max), + MYSQL_SYSVAR(idle_flush_pct), MYSQL_SYSVAR(monitor_enable), MYSQL_SYSVAR(monitor_disable), MYSQL_SYSVAR(monitor_reset), diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h index 17c67ada04bd6..2825e37ba86f7 100644 --- a/storage/xtradb/include/srv0srv.h +++ b/storage/xtradb/include/srv0srv.h @@ -424,6 +424,8 @@ extern double srv_defragment_fill_factor; extern uint srv_defragment_frequency; extern ulonglong srv_defragment_interval; +extern ulint srv_idle_flush_pct; + /* Number of IO operations per second the server can do */ extern ulong srv_io_capacity; diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 16df97edd646b..a6035bdaa6c73 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -341,6 +341,8 @@ UNIV_INTERN ulong srv_cleaner_lsn_age_factor UNIV_INTERN ulong srv_empty_free_list_algorithm = SRV_EMPTY_FREE_LIST_BACKOFF; +UNIV_INTERN ulint srv_idle_flush_pct = 100; + /* This parameter is deprecated. Use srv_n_io_[read|write]_threads instead. */ UNIV_INTERN ulint srv_n_file_io_threads = ULINT_MAX;