# name : innodb_thread_concurrency_timer_based.patch # introduced : 11 or before # maintainer : Yasufumi # #!!! notice !!! # Any small change to this file in the main branch # should be done or reviewed by the maintainer! --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -148,6 +148,7 @@ static ulong innobase_write_io_threads; static long innobase_buffer_pool_instances = 1; +static my_bool innobase_thread_concurrency_timer_based; static long long innobase_buffer_pool_size, innobase_log_file_size; /** Percentage of the buffer pool to reserve for 'old' blocks. @@ -2577,6 +2578,9 @@ srv_n_log_files = (ulint) innobase_log_files_in_group; srv_log_file_size = (ulint) innobase_log_file_size; + srv_thread_concurrency_timer_based = + (ibool) innobase_thread_concurrency_timer_based; + #ifdef UNIV_LOG_ARCHIVE srv_log_archive_on = (ulint) innobase_log_archive; #endif /* UNIV_LOG_ARCHIVE */ @@ -11601,6 +11605,12 @@ "Maximum delay between polling for a spin lock (6 by default)", NULL, NULL, 6L, 0L, ~0L, 0); +static MYSQL_SYSVAR_BOOL(thread_concurrency_timer_based, + innobase_thread_concurrency_timer_based, + PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY, + "Use InnoDB timer based concurrency throttling. ", + NULL, NULL, FALSE); + static MYSQL_SYSVAR_ULONG(thread_concurrency, srv_thread_concurrency, 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.", @@ -11859,6 +11869,7 @@ MYSQL_SYSVAR(spin_wait_delay), MYSQL_SYSVAR(table_locks), MYSQL_SYSVAR(thread_concurrency), + MYSQL_SYSVAR(thread_concurrency_timer_based), MYSQL_SYSVAR(thread_sleep_delay), MYSQL_SYSVAR(autoinc_lock_mode), MYSQL_SYSVAR(show_verbose_locks), --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -165,6 +165,8 @@ extern ulint srv_mem_pool_size; extern ulint srv_lock_table_size; +extern ibool srv_thread_concurrency_timer_based; + extern ulint srv_n_file_io_threads; extern my_bool srv_random_read_ahead; extern ulong srv_read_ahead_threshold; --- a/storage/innobase/srv/srv0srv.c +++ b/storage/innobase/srv/srv0srv.c @@ -349,6 +349,7 @@ computer. Bigger computers need bigger values. Value 0 will disable the concurrency check. */ +UNIV_INTERN ibool srv_thread_concurrency_timer_based = FALSE; UNIV_INTERN ulong srv_thread_concurrency = 0; /* this mutex protects srv_conc data structures */ @@ -1148,6 +1149,75 @@ /*********************************************************************//** 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. */ + +#ifdef HAVE_ATOMIC_BUILTINS +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) { + 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); + } +retry: + if (srv_conc_n_threads < (lint) srv_thread_concurrency) { + conc_n_threads = os_atomic_increment_lint(&srv_conc_n_threads, 1); + if (conc_n_threads <= (lint) srv_thread_concurrency) { + enter_innodb_with_tickets(trx); + return; + } + (void) os_atomic_increment_lint(&srv_conc_n_threads, -1); + } + if (!has_yielded) + { + has_yielded = TRUE; + os_thread_yield(); + goto retry; + } + if (trx->has_search_latch + || NULL != UT_LIST_GET_FIRST(trx->trx_locks)) { + + conc_n_threads = os_atomic_increment_lint(&srv_conc_n_threads, 1); + 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++; + } + conc_n_threads = os_atomic_increment_lint(&srv_conc_n_threads, 1); + enter_innodb_with_tickets(trx); + return; +} + +static void +srv_conc_exit_innodb_timer_based(trx_t* trx) +{ + (void) os_atomic_increment_lint(&srv_conc_n_threads, -1); + trx->declared_to_be_inside_innodb = FALSE; + trx->n_tickets_to_enter_innodb = 0; + return; +} +#endif + UNIV_INTERN void srv_conc_enter_innodb( @@ -1182,6 +1252,13 @@ return; } +#ifdef HAVE_ATOMIC_BUILTINS + if (srv_thread_concurrency_timer_based) { + srv_conc_enter_innodb_timer_based(trx); + return; + } +#endif + os_fast_mutex_lock(&srv_conc_mutex); retry: if (trx->declared_to_be_inside_innodb) { @@ -1335,6 +1412,14 @@ } ut_ad(srv_conc_n_threads >= 0); +#ifdef HAVE_ATOMIC_BUILTINS + if (srv_thread_concurrency_timer_based) { + (void) os_atomic_increment_lint(&srv_conc_n_threads, 1); + trx->declared_to_be_inside_innodb = TRUE; + trx->n_tickets_to_enter_innodb = 1; + return; + } +#endif os_fast_mutex_lock(&srv_conc_mutex); @@ -1368,6 +1453,13 @@ return; } +#ifdef HAVE_ATOMIC_BUILTINS + if (srv_thread_concurrency_timer_based) { + srv_conc_exit_innodb_timer_based(trx); + return; + } +#endif + os_fast_mutex_lock(&srv_conc_mutex); ut_ad(srv_conc_n_threads > 0);