mirror of
https://github.com/MariaDB/server.git
synced 2025-12-28 08:10:14 +00:00
MDEV-11026 Make InnoDB number of IO write/read threads dynamic
Resize the read/write slots, and recreate the io_context (for Linux libaio)
This commit is contained in:
parent
ada82805da
commit
49e660bb12
@ -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 @@ public:
|
||||
}
|
||||
|
||||
/* 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 @@ public:
|
||||
{
|
||||
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 @@ disable:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::mutex& mutex()
|
||||
{
|
||||
return m_mtx;
|
||||
}
|
||||
|
||||
void put(T *ele)
|
||||
{
|
||||
@ -112,20 +116,38 @@ public:
|
||||
return ele >= &m_base[0] && ele <= &m_base[m_base.size() -1];
|
||||
}
|
||||
|
||||
/* Wait until cache is full.*/
|
||||
void wait()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mtx);
|
||||
m_waiters++;
|
||||
while(!is_full())
|
||||
m_cv.wait(lk);
|
||||
m_waiters--;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
m_waiters++;
|
||||
while (!is_full())
|
||||
m_cv.wait(lk);
|
||||
m_waiters--;
|
||||
}
|
||||
|
||||
/* Wait until cache is full.*/
|
||||
void wait()
|
||||
{
|
||||
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];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user