Commit 5d615366 authored by Mikael Ronstrom's avatar Mikael Ronstrom

Introduced a new timer based innodb thread concurrency. A new

parameter innodb_thread_concurrency_timer_based is used to
get this new feature (it is set by default). The new feature
is only available on platforms where atomic instructions are
available.
parent aefc0aca
...@@ -148,6 +148,9 @@ long innobase_max_merged_io = 64; ...@@ -148,6 +148,9 @@ long innobase_max_merged_io = 64;
/* Number of background IO threads for read and write. */ /* Number of background IO threads for read and write. */
long innobase_read_io_threads, innobase_write_io_threads; long innobase_read_io_threads, innobase_write_io_threads;
/* Use timer based InnoDB concurrency throttling flag */
static my_bool innobase_thread_concurrency_timer_based;
/* The following counter is used to convey information to InnoDB /* The following counter is used to convey information to InnoDB
about server activity: in selects it is not sensible to call about server activity: in selects it is not sensible to call
srv_active_wake_master_thread after each fetch or search, we only do srv_active_wake_master_thread after each fetch or search, we only do
...@@ -1602,6 +1605,9 @@ innobase_init( ...@@ -1602,6 +1605,9 @@ innobase_init(
srv_n_log_files = (ulint) innobase_log_files_in_group; srv_n_log_files = (ulint) innobase_log_files_in_group;
srv_log_file_size = (ulint) innobase_log_file_size; srv_log_file_size = (ulint) innobase_log_file_size;
srv_thread_concurrency_timer_based =
(ibool) innobase_thread_concurrency_timer_based;
#ifdef UNIV_LOG_ARCHIVE #ifdef UNIV_LOG_ARCHIVE
srv_log_archive_on = (ulint) innobase_log_archive; srv_log_archive_on = (ulint) innobase_log_archive;
#endif /* UNIV_LOG_ARCHIVE */ #endif /* UNIV_LOG_ARCHIVE */
...@@ -8236,6 +8242,12 @@ static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds, ...@@ -8236,6 +8242,12 @@ static MYSQL_SYSVAR_ULONG(sync_spin_loops, srv_n_spin_wait_rounds,
"Count of spin-loop rounds in InnoDB mutexes", "Count of spin-loop rounds in InnoDB mutexes",
NULL, NULL, 20L, 0L, ~0L, 0); NULL, NULL, 20L, 0L, ~0L, 0);
static MYSQL_SYSVAR_BOOL(thread_concurrency_timer_based,
innobase_thread_concurrency_timer_based,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Use InnoDB timer based concurrency throttling. ",
NULL, NULL, TRUE);
static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency,
PLUGIN_VAR_RQCMDARG, PLUGIN_VAR_RQCMDARG,
"Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.", "Helps in performance tuning in heavily concurrent environments. Sets the maximum number of threads allowed inside InnoDB. Value 0 will disable the thread throttling.",
...@@ -8278,6 +8290,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { ...@@ -8278,6 +8290,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(read_io_threads), MYSQL_SYSVAR(read_io_threads),
MYSQL_SYSVAR(write_io_threads), MYSQL_SYSVAR(write_io_threads),
MYSQL_SYSVAR(max_merged_io), MYSQL_SYSVAR(max_merged_io),
MYSQL_SYSVAR(thread_concurrency_timer_based),
MYSQL_SYSVAR(file_per_table), MYSQL_SYSVAR(file_per_table),
MYSQL_SYSVAR(flush_log_at_trx_commit), MYSQL_SYSVAR(flush_log_at_trx_commit),
MYSQL_SYSVAR(flush_method), MYSQL_SYSVAR(flush_method),
......
...@@ -89,6 +89,8 @@ extern ulint srv_awe_window_size; ...@@ -89,6 +89,8 @@ extern ulint srv_awe_window_size;
extern ulint srv_mem_pool_size; extern ulint srv_mem_pool_size;
extern ulint srv_lock_table_size; extern ulint srv_lock_table_size;
extern ibool srv_thread_concurrency_timer_based;
extern ulint srv_n_file_io_threads; extern ulint srv_n_file_io_threads;
/* Number of background IO threads for read and write. Replaces /* Number of background IO threads for read and write. Replaces
* srv_n_file_io_threads. */ * srv_n_file_io_threads. */
......
...@@ -171,6 +171,7 @@ ulint srv_awe_window_size = 0; /* size in pages; MySQL inits ...@@ -171,6 +171,7 @@ ulint srv_awe_window_size = 0; /* size in pages; MySQL inits
ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */ ulint srv_mem_pool_size = ULINT_MAX; /* size in bytes */
ulint srv_lock_table_size = ULINT_MAX; ulint srv_lock_table_size = ULINT_MAX;
ulint srv_io_capacity = ULINT_MAX; /* Number of IO operations per ulint srv_io_capacity = ULINT_MAX; /* Number of IO operations per
second the server can do */ second the server can do */
...@@ -288,6 +289,7 @@ Value 10 should be good if there are less than 4 processors + 4 disks in the ...@@ -288,6 +289,7 @@ Value 10 should be good if there are less than 4 processors + 4 disks in the
computer. Bigger computers need bigger values. Value 0 will disable the computer. Bigger computers need bigger values. Value 0 will disable the
concurrency check. */ concurrency check. */
ibool srv_thread_concurrency_timer_based = TRUE;
ulong srv_thread_concurrency = 0; ulong srv_thread_concurrency = 0;
ulong srv_commit_concurrency = 0; ulong srv_commit_concurrency = 0;
...@@ -1061,6 +1063,91 @@ ulong srv_max_purge_lag = 0; ...@@ -1061,6 +1063,91 @@ ulong srv_max_purge_lag = 0;
Puts an OS thread to wait if there are too many concurrent threads Puts an OS thread to wait if there are too many concurrent threads
(>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */ (>= srv_thread_concurrency) inside InnoDB. The threads wait in a FIFO queue. */
static void
inc_srv_conc_n_threads(lint *n_threads)
{
*n_threads = os_atomic_increment(&srv_conc_n_threads, 1);
}
static void
dec_srv_conc_n_threads()
{
os_atomic_increment(&srv_conc_n_threads, -1);
}
static void
print_already_in_error(trx_t* trx)
{
ut_print_timestamp(stderr);
fputs(" InnoDB: Error: trying to declare trx"
" to enter InnoDB, but\n"
"InnoDB: it already is declared.\n", stderr);
trx_print(stderr, trx, 0);
putc('\n', stderr);
return;
}
static void
enter_innodb_with_tickets(trx_t* trx)
{
trx->declared_to_be_inside_innodb = TRUE;
trx->n_tickets_to_enter_innodb = SRV_FREE_TICKETS_TO_ENTER;
return;
}
static void
srv_conc_enter_innodb_timer_based(trx_t* trx)
{
lint conc_n_threads;
ibool has_yielded = FALSE;
ulint has_slept = 0;
if (trx->declared_to_be_inside_innodb) {
print_already_in_error(trx);
}
retry:
if (srv_conc_n_threads < (lint) srv_thread_concurrency) {
inc_srv_conc_n_threads(&conc_n_threads);
if (conc_n_threads <= srv_thread_concurrency) {
enter_innodb_with_tickets(trx);
return;
}
dec_srv_conc_n_threads(&conc_n_threads);
}
if (!has_yielded)
{
has_yielded = TRUE;
os_thread_yield();
goto retry;
}
if (trx->has_search_latch
|| NULL != UT_LIST_GET_FIRST(trx->trx_locks)) {
inc_srv_conc_n_threads(&conc_n_threads);
enter_innodb_with_tickets(trx);
return;
}
if (has_slept < 2)
{
trx->op_info = "sleeping before entering InnoDB";
os_thread_sleep(10000);
trx->op_info = "";
has_slept++;
}
inc_srv_conc_n_threads(&conc_n_threads);
enter_innodb_with_tickets(trx);
return;
}
static void
srv_conc_exit_innodb_timer_based(trx_t* trx)
{
dec_srv_conc_n_threads();
trx->declared_to_be_inside_innodb = FALSE;
trx->n_tickets_to_enter_innodb = 0;
return;
}
void void
srv_conc_enter_innodb( srv_conc_enter_innodb(
/*==================*/ /*==================*/
...@@ -1091,15 +1178,17 @@ srv_conc_enter_innodb( ...@@ -1091,15 +1178,17 @@ srv_conc_enter_innodb(
return; return;
} }
#ifdef UNIV_SYNC_ATOMIC
if (srv_thread_concurrency_timer_based) {
srv_conc_enter_innodb_timer_based(trx);
return;
}
#endif
os_fast_mutex_lock(&srv_conc_mutex); os_fast_mutex_lock(&srv_conc_mutex);
retry: retry:
if (trx->declared_to_be_inside_innodb) { if (trx->declared_to_be_inside_innodb) {
ut_print_timestamp(stderr); print_already_in_error(trx);
fputs(" InnoDB: Error: trying to declare trx"
" to enter InnoDB, but\n"
"InnoDB: it already is declared.\n", stderr);
trx_print(stderr, trx, 0);
putc('\n', stderr);
os_fast_mutex_unlock(&srv_conc_mutex); os_fast_mutex_unlock(&srv_conc_mutex);
return; return;
...@@ -1226,17 +1315,25 @@ srv_conc_force_enter_innodb( ...@@ -1226,17 +1315,25 @@ srv_conc_force_enter_innodb(
trx_t* trx) /* in: transaction object associated with the trx_t* trx) /* in: transaction object associated with the
thread */ thread */
{ {
lint conc_n_threads;
if (UNIV_LIKELY(!srv_thread_concurrency)) { if (UNIV_LIKELY(!srv_thread_concurrency)) {
return; return;
} }
#ifdef UNIV_SYNC_ATOMIC
if (srv_thread_concurrency_timer_based) {
inc_srv_conc_n_threads(&conc_n_threads);
trx->declared_to_be_inside_innodb = TRUE;
trx->n_tickets_to_enter_innodb = 1;
return;
}
#endif
os_fast_mutex_lock(&srv_conc_mutex); os_fast_mutex_lock(&srv_conc_mutex);
srv_conc_n_threads++; srv_conc_n_threads++;
trx->declared_to_be_inside_innodb = TRUE; trx->declared_to_be_inside_innodb = TRUE;
trx->n_tickets_to_enter_innodb = 1; trx->n_tickets_to_enter_innodb = 1;
os_fast_mutex_unlock(&srv_conc_mutex); os_fast_mutex_unlock(&srv_conc_mutex);
} }
...@@ -1268,6 +1365,14 @@ srv_conc_force_exit_innodb( ...@@ -1268,6 +1365,14 @@ srv_conc_force_exit_innodb(
return; return;
} }
#ifdef UNIV_SYNC_ATOMIC
if (srv_thread_concurrency_timer_based)
{
srv_conc_exit_innodb_timer_based(trx);
return;
}
#endif
os_fast_mutex_lock(&srv_conc_mutex); os_fast_mutex_lock(&srv_conc_mutex);
srv_conc_n_threads--; srv_conc_n_threads--;
......
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