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)
1
1 Expected
'#---------------------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);
COUNT(@@GLOBAL.innodb_read_io_threads)
1
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);
COUNT(@@GLOBAL.innodb_write_io_threads)
1
......
......@@ -15,7 +15,15 @@ INNODB_READ_IO_THREADS 2
select * from information_schema.session_variables where variable_name='innodb_read_io_threads';
VARIABLE_NAME VARIABLE_VALUE
INNODB_READ_IO_THREADS 2
set global innodb_read_io_threads=1;
ERROR HY000: Variable 'innodb_read_io_threads' is a read only variable
select @@innodb_read_io_threads into @n;
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;
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
select * from information_schema.session_variables where variable_name='innodb_write_io_threads';
VARIABLE_NAME VARIABLE_VALUE
INNODB_WRITE_IO_THREADS 2
select @@innodb_write_io_threads into @n;
set global innodb_write_io_threads=1;
ERROR HY000: Variable 'innodb_write_io_threads' is a read only variable
set session innodb_write_io_threads=1;
ERROR HY000: Variable 'innodb_write_io_threads' is a read only variable
select @@innodb_write_io_threads;
@@innodb_write_io_threads
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
NUMERIC_MAX_VALUE 64
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY YES
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME INNODB_READ_ONLY
SESSION_VALUE NULL
......@@ -1697,5 +1697,5 @@ NUMERIC_MIN_VALUE 2
NUMERIC_MAX_VALUE 64
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL
READ_ONLY YES
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
......@@ -39,17 +39,10 @@ SELECT COUNT(@@GLOBAL.innodb_write_io_threads);
# 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);
--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);
--echo 1 Expected
......
......@@ -19,10 +19,18 @@ select * from information_schema.session_variables where variable_name='innodb_r
--enable_warnings
#
# show that it's read-only
# show that it's not read-only
#
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
set global innodb_read_io_threads=1;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
select @@innodb_read_io_threads into @n;
--disable_warnings
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 global innodb_read_io_threads=@n;
......@@ -19,10 +19,18 @@ select * from information_schema.session_variables where variable_name='innodb_w
--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;
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
set session innodb_write_io_threads=1;
--enable_warnings
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,
"Only optimize the Fulltext index of the table",
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,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
PLUGIN_VAR_RQCMDARG,
"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,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
PLUGIN_VAR_RQCMDARG,
"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,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
......
......@@ -106,6 +106,11 @@ class io_slots
}
/* Wait for completions of all AIO operations */
void wait(std::unique_lock<std::mutex> &lk)
{
m_cache.wait(lk);
}
void wait()
{
m_cache.wait();
......@@ -125,6 +130,24 @@ class io_slots
{
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;
......@@ -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()
{
srv_thread_pool->disable_aio();
......
......@@ -231,6 +231,20 @@ class thread_pool
m_aio.reset(create_simulated_aio(this));
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()
{
m_aio.reset();
......
......@@ -94,6 +94,10 @@ template<typename T> class cache
return ret;
}
std::mutex& mutex()
{
return m_mtx;
}
void put(T *ele)
{
......@@ -112,19 +116,37 @@ template<typename T> class cache
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++;
while(!is_full())
while (!is_full())
m_cv.wait(lk);
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