Skip to content

Commit

Permalink
MDEV-11026 Make InnoDB number of IO write/read threads dynamic
Browse files Browse the repository at this point in the history
Resize the read/write slots, and recreate the io_context (for Linux libaio)
  • Loading branch information
vaintroub committed Jun 27, 2022
1 parent ada8280 commit 49e660b
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 11 additions & 3 deletions mysql-test/suite/sys_vars/r/innodb_read_io_threads_basic.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
12 changes: 9 additions & 3 deletions mysql-test/suite/sys_vars/r/innodb_write_io_threads_basic.result
Original file line number Diff line number Diff line change
Expand Up @@ -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;
4 changes: 2 additions & 2 deletions mysql-test/suite/sys_vars/r/sysvars_innodb.result
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
7 changes: 0 additions & 7 deletions mysql-test/suite/sys_vars/t/innodb_file_io_threads_basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
16 changes: 12 additions & 4 deletions mysql-test/suite/sys_vars/t/innodb_read_io_threads_basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -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;

16 changes: 12 additions & 4 deletions mysql-test/suite/sys_vars/t/innodb_write_io_threads_basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -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

37 changes: 33 additions & 4 deletions storage/innobase/handler/ha_innodb.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
75 changes: 75 additions & 0 deletions storage/innobase/os/os0file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down
14 changes: 14 additions & 0 deletions tpool/tpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
34 changes: 28 additions & 6 deletions tpool/tpool_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ template<typename T> class cache
return ret;
}

std::mutex& mutex()
{
return m_mtx;
}

void put(T *ele)
{
Expand All @@ -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];
}
};

Expand Down

0 comments on commit 49e660b

Please sign in to comment.