Commit 49e660bb authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-11026 Make InnoDB number of IO write/read threads dynamic

Resize the read/write slots, and recreate the io_context (for Linux libaio)
parent ada82805
...@@ -8,16 +8,10 @@ COUNT(@@GLOBAL.innodb_write_io_threads) ...@@ -8,16 +8,10 @@ COUNT(@@GLOBAL.innodb_write_io_threads)
1 1
1 Expected 1 Expected
'#---------------------BS_STVARS_027_02----------------------#' '#---------------------BS_STVARS_027_02----------------------#'
SET @@GLOBAL.innodb_read_io_threads=1;
ERROR HY000: Variable 'innodb_read_io_threads' is a read only variable
Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_read_io_threads); SELECT COUNT(@@GLOBAL.innodb_read_io_threads);
COUNT(@@GLOBAL.innodb_read_io_threads) COUNT(@@GLOBAL.innodb_read_io_threads)
1 1
1 Expected 1 Expected
SET @@GLOBAL.innodb_write_io_threads=1;
ERROR HY000: Variable 'innodb_write_io_threads' is a read only variable
Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_write_io_threads); SELECT COUNT(@@GLOBAL.innodb_write_io_threads);
COUNT(@@GLOBAL.innodb_write_io_threads) COUNT(@@GLOBAL.innodb_write_io_threads)
1 1
......
...@@ -15,7 +15,15 @@ INNODB_READ_IO_THREADS 2 ...@@ -15,7 +15,15 @@ INNODB_READ_IO_THREADS 2
select * from information_schema.session_variables where variable_name='innodb_read_io_threads'; select * from information_schema.session_variables where variable_name='innodb_read_io_threads';
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
INNODB_READ_IO_THREADS 2 INNODB_READ_IO_THREADS 2
set global innodb_read_io_threads=1; select @@innodb_read_io_threads into @n;
ERROR HY000: Variable 'innodb_read_io_threads' is a read only variable set global innodb_read_io_threads = 1;
select @@innodb_read_io_threads;
@@innodb_read_io_threads
1
set global innodb_read_io_threads=64;
select @@innodb_read_io_threads;
@@innodb_read_io_threads
64
set session innodb_read_io_threads=1; set session innodb_read_io_threads=1;
ERROR HY000: Variable 'innodb_read_io_threads' is a read only variable ERROR HY000: Variable 'innodb_read_io_threads' is a GLOBAL variable and should be set with SET GLOBAL
set global innodb_read_io_threads=@n;
...@@ -15,7 +15,13 @@ INNODB_WRITE_IO_THREADS 2 ...@@ -15,7 +15,13 @@ INNODB_WRITE_IO_THREADS 2
select * from information_schema.session_variables where variable_name='innodb_write_io_threads'; select * from information_schema.session_variables where variable_name='innodb_write_io_threads';
VARIABLE_NAME VARIABLE_VALUE VARIABLE_NAME VARIABLE_VALUE
INNODB_WRITE_IO_THREADS 2 INNODB_WRITE_IO_THREADS 2
select @@innodb_write_io_threads into @n;
set global innodb_write_io_threads=1; set global innodb_write_io_threads=1;
ERROR HY000: Variable 'innodb_write_io_threads' is a read only variable select @@innodb_write_io_threads;
set session innodb_write_io_threads=1; @@innodb_write_io_threads
ERROR HY000: Variable 'innodb_write_io_threads' is a read only variable 2
set global innodb_write_io_threads=64;
select @@innodb_write_io_threads;
@@innodb_write_io_threads
64
set global innodb_write_io_threads=@n;
...@@ -1349,7 +1349,7 @@ NUMERIC_MIN_VALUE 1 ...@@ -1349,7 +1349,7 @@ NUMERIC_MIN_VALUE 1
NUMERIC_MAX_VALUE 64 NUMERIC_MAX_VALUE 64
NUMERIC_BLOCK_SIZE 0 NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY YES READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_READ_ONLY VARIABLE_NAME INNODB_READ_ONLY
SESSION_VALUE NULL SESSION_VALUE NULL
...@@ -1697,5 +1697,5 @@ NUMERIC_MIN_VALUE 2 ...@@ -1697,5 +1697,5 @@ NUMERIC_MIN_VALUE 2
NUMERIC_MAX_VALUE 64 NUMERIC_MAX_VALUE 64
NUMERIC_BLOCK_SIZE 0 NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL ENUM_VALUE_LIST NULL
READ_ONLY YES READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED COMMAND_LINE_ARGUMENT REQUIRED
...@@ -39,17 +39,10 @@ SELECT COUNT(@@GLOBAL.innodb_write_io_threads); ...@@ -39,17 +39,10 @@ SELECT COUNT(@@GLOBAL.innodb_write_io_threads);
# Check if Value can set # # Check if Value can set #
#################################################################### ####################################################################
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SET @@GLOBAL.innodb_read_io_threads=1;
--echo Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_read_io_threads); SELECT COUNT(@@GLOBAL.innodb_read_io_threads);
--echo 1 Expected --echo 1 Expected
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
SET @@GLOBAL.innodb_write_io_threads=1;
--echo Expected error 'Read only variable'
SELECT COUNT(@@GLOBAL.innodb_write_io_threads); SELECT COUNT(@@GLOBAL.innodb_write_io_threads);
--echo 1 Expected --echo 1 Expected
......
...@@ -19,10 +19,18 @@ select * from information_schema.session_variables where variable_name='innodb_r ...@@ -19,10 +19,18 @@ select * from information_schema.session_variables where variable_name='innodb_r
--enable_warnings --enable_warnings
# #
# show that it's read-only # show that it's not read-only
# #
--error ER_INCORRECT_GLOBAL_LOCAL_VAR select @@innodb_read_io_threads into @n;
set global innodb_read_io_threads=1; --disable_warnings
--error ER_INCORRECT_GLOBAL_LOCAL_VAR set global innodb_read_io_threads = 1;
--enable_warnings
select @@innodb_read_io_threads;
--disable_warnings
set global innodb_read_io_threads=64;
--enable_warnings
select @@innodb_read_io_threads;
--error ER_GLOBAL_VARIABLE
set session innodb_read_io_threads=1; set session innodb_read_io_threads=1;
set global innodb_read_io_threads=@n;
...@@ -19,10 +19,18 @@ select * from information_schema.session_variables where variable_name='innodb_w ...@@ -19,10 +19,18 @@ select * from information_schema.session_variables where variable_name='innodb_w
--enable_warnings --enable_warnings
# #
# show that it's read-only # show that it's not read-only
# #
--error ER_INCORRECT_GLOBAL_LOCAL_VAR select @@innodb_write_io_threads into @n;
--disable_warnings
set global innodb_write_io_threads=1; set global innodb_write_io_threads=1;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR --enable_warnings
set session innodb_write_io_threads=1; select @@innodb_write_io_threads;
--disable_warnings
set global innodb_write_io_threads=64;
--enable_warnings
select @@innodb_write_io_threads;
--disable_warnings
set global innodb_write_io_threads=@n;
--enable_warnings
...@@ -19261,15 +19261,44 @@ static MYSQL_SYSVAR_BOOL(optimize_fulltext_only, innodb_optimize_fulltext_only, ...@@ -19261,15 +19261,44 @@ static MYSQL_SYSVAR_BOOL(optimize_fulltext_only, innodb_optimize_fulltext_only,
"Only optimize the Fulltext index of the table", "Only optimize the Fulltext index of the table",
NULL, NULL, FALSE); NULL, NULL, FALSE);
extern int os_aio_resize(ulint n_reader_threads, ulint n_writer_threads);
static void innodb_update_io_thread_count(THD *thd,ulint n_read, ulint n_write)
{
int res = os_aio_resize(n_read, n_write);
if (res)
{
#ifndef __linux__
ut_ad(0);
#else
ut_a(srv_use_native_aio);
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR,
"Could not reserve max. number of concurrent ios."
"Increase the /proc/sys/fs/aio-max-nr to fix.");
#endif
}
}
static void innodb_read_io_threads_update(THD* thd, struct st_mysql_sys_var*, void*, const void* save)
{
srv_n_read_io_threads = *static_cast<const uint*>(save);
innodb_update_io_thread_count(thd, srv_n_read_io_threads, srv_n_write_io_threads);
}
static void innodb_write_io_threads_update(THD* thd, struct st_mysql_sys_var*, void*, const void* save)
{
srv_n_write_io_threads = *static_cast<const uint*>(save);
innodb_update_io_thread_count(thd, srv_n_read_io_threads, srv_n_write_io_threads);
}
static MYSQL_SYSVAR_UINT(read_io_threads, srv_n_read_io_threads, static MYSQL_SYSVAR_UINT(read_io_threads, srv_n_read_io_threads,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG,
"Number of background read I/O threads in InnoDB.", "Number of background read I/O threads in InnoDB.",
NULL, NULL, 4, 1, 64, 0); NULL, innodb_read_io_threads_update , 4, 1, 64, 0);
static MYSQL_SYSVAR_UINT(write_io_threads, srv_n_write_io_threads, static MYSQL_SYSVAR_UINT(write_io_threads, srv_n_write_io_threads,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG,
"Number of background write I/O threads in InnoDB.", "Number of background write I/O threads in InnoDB.",
NULL, NULL, 4, 2, 64, 0); NULL, innodb_write_io_threads_update, 4, 2, 64, 0);
static MYSQL_SYSVAR_ULONG(force_recovery, srv_force_recovery, static MYSQL_SYSVAR_ULONG(force_recovery, srv_force_recovery,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
......
...@@ -106,6 +106,11 @@ class io_slots ...@@ -106,6 +106,11 @@ class io_slots
} }
/* Wait for completions of all AIO operations */ /* Wait for completions of all AIO operations */
void wait(std::unique_lock<std::mutex> &lk)
{
m_cache.wait(lk);
}
void wait() void wait()
{ {
m_cache.wait(); m_cache.wait();
...@@ -125,6 +130,24 @@ class io_slots ...@@ -125,6 +130,24 @@ class io_slots
{ {
wait(); wait();
} }
std::mutex& mutex()
{
return m_cache.mutex();
}
void resize(int max_submitted_io, int max_callback_concurrency, std::unique_lock<std::mutex> &lk)
{
ut_a(lk.owns_lock());
m_cache.resize(max_submitted_io);
m_group.set_max_tasks(max_callback_concurrency);
m_max_aio = max_submitted_io;
}
tpool::task_group& task_group()
{
return m_group;
}
}; };
static std::unique_ptr<io_slots> read_slots; static std::unique_ptr<io_slots> read_slots;
...@@ -3698,6 +3721,58 @@ int os_aio_init() ...@@ -3698,6 +3721,58 @@ int os_aio_init()
} }
/**
Change reader or writer thread parameter on a running server.
This includes resizing the io slots, as we calculate
number of outstanding IOs based on the these variables.
It is trickier with when Linux AIO is involved (io_context
needs to be recreated to account for different number of
max_events). With Linux AIO, depending on fs-max-aio number
and user and system wide max-aio limitation, this can fail.
Otherwise, we just resize the slots, and allow for
more concurrent threads via thread_group setting.
@param[in] n_reader_threads - max number of concurrently
executing read callbacks
@param[in] n_writer_thread - max number of cuncurrently
executing write callbacks
@return 0 for success, !=0 for error.
*/
int os_aio_resize(ulint n_reader_threads, ulint n_writer_threads)
{
/* Lock the slots, and wait until all current IOs finish.*/
std::unique_lock<std::mutex> lk_read(read_slots->mutex());
std::unique_lock<std::mutex> lk_write(write_slots->mutex());
read_slots->wait(lk_read);
write_slots->wait(lk_write);
/* Now, all IOs have finished and no new ones can start, due to locks. */
int max_read_events= int(n_reader_threads * OS_AIO_N_PENDING_IOS_PER_THREAD);
int max_write_events= int(n_writer_threads * OS_AIO_N_PENDING_IOS_PER_THREAD);
int events= max_read_events + max_write_events;
/** Do the Linux AIO dance (this will try to create a new
io context with changed max_events ,etc*/
if (int ret= srv_thread_pool->reconfigure_aio(srv_use_native_aio, events))
{
/** Do the best effort. We can't change the parallel io number,
but we still can adjust the number of concurrent completion handlers.*/
read_slots->task_group().set_max_tasks(static_cast<int>(n_reader_threads));
write_slots->task_group().set_max_tasks(static_cast<int>(n_writer_threads));
return ret;
}
/* Allocation succeeded, resize the slots*/
read_slots->resize(max_read_events, static_cast<int>(n_reader_threads), lk_read);
write_slots->resize(max_write_events, static_cast<int>(n_writer_threads), lk_write);
return 0;
}
void os_aio_free() void os_aio_free()
{ {
srv_thread_pool->disable_aio(); srv_thread_pool->disable_aio();
......
...@@ -231,6 +231,20 @@ class thread_pool ...@@ -231,6 +231,20 @@ class thread_pool
m_aio.reset(create_simulated_aio(this)); m_aio.reset(create_simulated_aio(this));
return !m_aio ? -1 : 0; return !m_aio ? -1 : 0;
} }
int reconfigure_aio(bool use_native_aio, int max_io)
{
assert(m_aio);
if (use_native_aio)
{
auto new_aio = create_native_aio(max_io);
if (!new_aio)
return -1;
m_aio.reset(new_aio);
}
return 0;
}
void disable_aio() void disable_aio()
{ {
m_aio.reset(); m_aio.reset();
......
...@@ -94,6 +94,10 @@ template<typename T> class cache ...@@ -94,6 +94,10 @@ template<typename T> class cache
return ret; return ret;
} }
std::mutex& mutex()
{
return m_mtx;
}
void put(T *ele) void put(T *ele)
{ {
...@@ -112,19 +116,37 @@ template<typename T> class cache ...@@ -112,19 +116,37 @@ template<typename T> class cache
return ele >= &m_base[0] && ele <= &m_base[m_base.size() -1]; return ele >= &m_base[0] && ele <= &m_base[m_base.size() -1];
} }
/* Wait until cache is full.*/
void wait() TPOOL_SUPPRESS_TSAN size_t size()
{
return m_cache.size();
}
/** Wait until cache is full
@param[in] lk - lock for the cache mutex
(which can be obtained with mutex()) */
void wait(std::unique_lock<std::mutex> &lk)
{ {
std::unique_lock<std::mutex> lk(m_mtx);
m_waiters++; m_waiters++;
while(!is_full()) while (!is_full())
m_cv.wait(lk); m_cv.wait(lk);
m_waiters--; m_waiters--;
} }
TPOOL_SUPPRESS_TSAN size_t size() /* Wait until cache is full.*/
void wait()
{ {
return m_cache.size(); std::unique_lock<std::mutex> lk(m_mtx);
wait(lk);
}
void resize(size_t count)
{
assert(is_full());
m_base.resize(count);
m_cache.resize(count);
for (size_t i = 0; i < count; i++)
m_cache[i] = &m_base[i];
} }
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment