diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-28 10:50:17 +0300 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2019-05-28 10:54:30 +0300 |
commit | 626f2a1c170e615c7866c1041746159dc3f709af (patch) | |
tree | 1ba9bf9348d2a78d212a1790b48321242d5792bc /storage/xtradb | |
parent | 242a28c320ae8b16144c5e91cbcf8806ce1e5d68 (diff) | |
download | mariadb-git-626f2a1c170e615c7866c1041746159dc3f709af.tar.gz |
MDEV-19614 SET GLOBAL innodb_ deadlock due to LOCK_global_system_variables
The update callback functions for several settable global InnoDB variables
are acquiring InnoDB latches while holding LOCK_global_system_variables.
On the other hand, some InnoDB code is invoking THDVAR() while holding
InnoDB latches. An example of this is thd_lock_wait_timeout() that is
called by lock_rec_enqueue_waiting(). In some cases, the
intern_sys_var_ptr() that is invoked by THDVAR() may acquire
LOCK_global_system_variables, via sync_dynamic_session_variables().
In lock_rec_enqueue_waiting(), we really must be holding some InnoDB
latch while invoking THDVAR(). This implies that
LOCK_global_system_variables must conceptually reside below any InnoDB
latch in the latching order. That in turns implies that the various
update callback functions must release LOCK_global_system_variables
before acquiring any InnoDB mutexes or rw-locks, and reacquire
LOCK_global_system_variables later. The validate functions are being
invoked while not holding LOCK_global_system_variables and thus they
do not need any changes.
The following statements are affected by this:
SET GLOBAL innodb_adaptive_hash_index = …;
SET GLOBAL innodb_cmp_per_index_enabled = 1;
SET GLOBAL innodb_old_blocks_pct = …;
SET GLOBAL innodb_fil_make_page_dirty_debug = …; -- debug builds only
SET GLOBAL innodb_buffer_pool_evict = uncompressed; -- debug builds only
SET GLOBAL innodb_purge_run_now = 1; -- debug builds only
SET GLOBAL innodb_purge_stop_now = 1; -- debug builds only
SET GLOBAL innodb_log_checkpoint_now = 1; -- debug builds only
SET GLOBAL innodb_buf_flush_list_now = 1; -- debug builds only
SET GLOBAL innodb_buffer_pool_dump_now = 1;
SET GLOBAL innodb_buffer_pool_load_now = 1;
SET GLOBAL innodb_buffer_pool_load_abort = 1;
SET GLOBAL innodb_status_output = …;
SET GLOBAL innodb_status_output_locks = …;
SET GLOBAL innodb_encryption_threads = …;
SET GLOBAL innodb_encryption_rotate_key_age = …;
SET GLOBAL innodb_encryption_rotation_iops = …;
SET GLOBAL innodb_encrypt_tables = …;
SET GLOBAL innodb_disallow_writes = …;
buf_LRU_old_ratio_update(): Correct the return type.
Diffstat (limited to 'storage/xtradb')
-rw-r--r-- | storage/xtradb/buf/buf0lru.cc | 14 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.cc | 126 | ||||
-rw-r--r-- | storage/xtradb/include/buf0lru.h | 8 |
3 files changed, 76 insertions, 72 deletions
diff --git a/storage/xtradb/buf/buf0lru.cc b/storage/xtradb/buf/buf0lru.cc index 5f3a8627055..13bf5e79f2d 100644 --- a/storage/xtradb/buf/buf0lru.cc +++ b/storage/xtradb/buf/buf0lru.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -2408,8 +2408,8 @@ buf_LRU_old_ratio_update_instance( buf_pool_t* buf_pool,/*!< in: buffer pool instance */ uint old_pct,/*!< in: Reserve this percentage of the buffer pool for "old" blocks. */ - ibool adjust) /*!< in: TRUE=adjust the LRU list; - FALSE=just assign buf_pool->LRU_old_ratio + bool adjust) /*!< in: true=adjust the LRU list; + false=just assign buf_pool->LRU_old_ratio during the initialization of InnoDB */ { uint ratio; @@ -2447,17 +2447,17 @@ buf_LRU_old_ratio_update_instance( Updates buf_pool->LRU_old_ratio. @return updated old_pct */ UNIV_INTERN -ulint +uint buf_LRU_old_ratio_update( /*=====================*/ uint old_pct,/*!< in: Reserve this percentage of the buffer pool for "old" blocks. */ - ibool adjust) /*!< in: TRUE=adjust the LRU list; - FALSE=just assign buf_pool->LRU_old_ratio + bool adjust) /*!< in: true=adjust the LRU list; + false=just assign buf_pool->LRU_old_ratio during the initialization of InnoDB */ { ulint i; - ulint new_ratio = 0; + uint new_ratio = 0; for (i = 0; i < srv_buf_pool_instances; i++) { buf_pool_t* buf_pool; diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index aa17eb6a5ea..0cdd5ac2452 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -17887,11 +17887,13 @@ innodb_adaptive_hash_index_update( const void* save) /*!< in: immediate result from check function */ { + mysql_mutex_unlock(&LOCK_global_system_variables); if (*(my_bool*) save) { btr_search_enable(); } else { btr_search_disable(); } + mysql_mutex_lock(&LOCK_global_system_variables); } /****************************************************************//** @@ -17912,7 +17914,9 @@ innodb_cmp_per_index_update( /* Reset the stats whenever we enable the table INFORMATION_SCHEMA.innodb_cmp_per_index. */ if (!srv_cmp_per_index_enabled && *(my_bool*) save) { + mysql_mutex_unlock(&LOCK_global_system_variables); page_zip_reset_stat_per_index(); + mysql_mutex_lock(&LOCK_global_system_variables); } srv_cmp_per_index_enabled = !!(*(my_bool*) save); @@ -17933,9 +17937,11 @@ innodb_old_blocks_pct_update( const void* save) /*!< in: immediate result from check function */ { - innobase_old_blocks_pct = static_cast<uint>( - buf_LRU_old_ratio_update( - *static_cast<const uint*>(save), TRUE)); + mysql_mutex_unlock(&LOCK_global_system_variables); + uint ratio = buf_LRU_old_ratio_update(*static_cast<const uint*>(save), + true); + mysql_mutex_lock(&LOCK_global_system_variables); + innobase_old_blocks_pct = ratio; } /****************************************************************//** @@ -17953,9 +17959,10 @@ innodb_change_buffer_max_size_update( const void* save) /*!< in: immediate result from check function */ { - innobase_change_buffer_max_size = - (*static_cast<const uint*>(save)); + innobase_change_buffer_max_size = *static_cast<const uint*>(save); + mysql_mutex_unlock(&LOCK_global_system_variables); ibuf_max_size_update(innobase_change_buffer_max_size); + mysql_mutex_lock(&LOCK_global_system_variables); } #ifdef UNIV_DEBUG @@ -17999,6 +18006,7 @@ innodb_make_page_dirty( { mtr_t mtr; ulong space_id = *static_cast<const ulong*>(save); + mysql_mutex_unlock(&LOCK_global_system_variables); mtr_start(&mtr); @@ -18016,6 +18024,7 @@ innodb_make_page_dirty( MLOG_2BYTES, &mtr); } mtr_commit(&mtr); + mysql_mutex_lock(&LOCK_global_system_variables); } #endif // UNIV_DEBUG @@ -18661,8 +18670,11 @@ innodb_buffer_pool_evict_update( { if (const char* op = *static_cast<const char*const*>(save)) { if (!strcmp(op, "uncompressed")) { + mysql_mutex_unlock(&LOCK_global_system_variables); for (uint tries = 0; tries < 10000; tries++) { if (innodb_buffer_pool_evict_uncompressed()) { + mysql_mutex_lock( + &LOCK_global_system_variables); return; } @@ -19199,7 +19211,9 @@ purge_run_now_set( check function */ { if (*(my_bool*) save && trx_purge_state() != PURGE_STATE_DISABLED) { + mysql_mutex_unlock(&LOCK_global_system_variables); trx_purge_run(); + mysql_mutex_lock(&LOCK_global_system_variables); } } @@ -19222,7 +19236,9 @@ purge_stop_now_set( check function */ { if (*(my_bool*) save && trx_purge_state() != PURGE_STATE_DISABLED) { + mysql_mutex_unlock(&LOCK_global_system_variables); trx_purge_stop(); + mysql_mutex_lock(&LOCK_global_system_variables); } } @@ -19244,6 +19260,8 @@ checkpoint_now_set( check function */ { if (*(my_bool*) save) { + mysql_mutex_unlock(&LOCK_global_system_variables); + while (log_sys->last_checkpoint_lsn < log_sys->lsn) { log_make_checkpoint_at(LSN_MAX, TRUE); fil_flush_file_spaces(FIL_LOG); @@ -19257,6 +19275,8 @@ checkpoint_now_set( "system tablespace at checkpoint err=%s", ut_strerr(err)); } + + mysql_mutex_lock(&LOCK_global_system_variables); } } @@ -19278,8 +19298,10 @@ buf_flush_list_now_set( check function */ { if (*(my_bool*) save) { + mysql_mutex_unlock(&LOCK_global_system_variables); buf_flush_list(ULINT_MAX, LSN_MAX, NULL); buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST); + mysql_mutex_lock(&LOCK_global_system_variables); } } @@ -19406,7 +19428,9 @@ buffer_pool_dump_now( check function */ { if (*(my_bool*) save && !srv_read_only_mode) { + mysql_mutex_unlock(&LOCK_global_system_variables); buf_dump_start(); + mysql_mutex_lock(&LOCK_global_system_variables); } } @@ -19429,7 +19453,9 @@ buffer_pool_load_now( check function */ { if (*(my_bool*) save && !srv_read_only_mode) { + mysql_mutex_unlock(&LOCK_global_system_variables); buf_load_start(); + mysql_mutex_lock(&LOCK_global_system_variables); } } @@ -19452,96 +19478,71 @@ buffer_pool_load_abort( check function */ { if (*(my_bool*) save && !srv_read_only_mode) { + mysql_mutex_unlock(&LOCK_global_system_variables); buf_load_abort(); + mysql_mutex_lock(&LOCK_global_system_variables); } } /** Update innodb_status_output or innodb_status_output_locks, which control InnoDB "status monitor" output to the error log. -@param[in] thd thread handle -@param[in] var system variable -@param[out] var_ptr current value +@param[out] var current value @param[in] save to-be-assigned value */ static void -innodb_status_output_update( -/*========================*/ - THD* thd __attribute__((unused)), - struct st_mysql_sys_var* var __attribute__((unused)), - void* var_ptr __attribute__((unused)), - const void* save __attribute__((unused))) +innodb_status_output_update(THD*,st_mysql_sys_var*,void*var,const void*save) { - *static_cast<my_bool*>(var_ptr) = *static_cast<const my_bool*>(save); + *static_cast<my_bool*>(var) = *static_cast<const my_bool*>(save); + mysql_mutex_unlock(&LOCK_global_system_variables); /* Wakeup server monitor thread. */ os_event_set(srv_monitor_event); + mysql_mutex_lock(&LOCK_global_system_variables); } -/****************************************************************** -Update the system variable innodb_encryption_threads */ +/** Update the system variable innodb_encryption_threads. +@param[in] save to-be-assigned value */ static void -innodb_encryption_threads_update( -/*=============================*/ - THD* thd, /*!< in: thread handle */ - struct st_mysql_sys_var* var, /*!< in: pointer to - system variable */ - void* var_ptr,/*!< out: where the - formal string goes */ - const void* save) /*!< in: immediate result - from check function */ +innodb_encryption_threads_update(THD*,st_mysql_sys_var*,void*,const void*save) { + mysql_mutex_unlock(&LOCK_global_system_variables); fil_crypt_set_thread_cnt(*static_cast<const uint*>(save)); + mysql_mutex_lock(&LOCK_global_system_variables); } -/****************************************************************** -Update the system variable innodb_encryption_rotate_key_age */ +/** Update the system variable innodb_encryption_rotate_key_age. +@param[in] save to-be-assigned value */ static void -innodb_encryption_rotate_key_age_update( -/*====================================*/ - THD* thd, /*!< in: thread handle */ - struct st_mysql_sys_var* var, /*!< in: pointer to - system variable */ - void* var_ptr,/*!< out: where the - formal string goes */ - const void* save) /*!< in: immediate result - from check function */ +innodb_encryption_rotate_key_age_update(THD*,st_mysql_sys_var*,void*, + const void*save) { + mysql_mutex_unlock(&LOCK_global_system_variables); fil_crypt_set_rotate_key_age(*static_cast<const uint*>(save)); + mysql_mutex_lock(&LOCK_global_system_variables); } -/****************************************************************** -Update the system variable innodb_encryption_rotation_iops */ +/** Update the system variable innodb_encryption_rotation_iops. +@param[in] save to-be-assigned value */ static void -innodb_encryption_rotation_iops_update( -/*===================================*/ - THD* thd, /*!< in: thread handle */ - struct st_mysql_sys_var* var, /*!< in: pointer to - system variable */ - void* var_ptr,/*!< out: where the - formal string goes */ - const void* save) /*!< in: immediate result - from check function */ +innodb_encryption_rotation_iops_update(THD*,st_mysql_sys_var*,void*, + const void*save) { + mysql_mutex_unlock(&LOCK_global_system_variables); fil_crypt_set_rotation_iops(*static_cast<const uint*>(save)); + mysql_mutex_lock(&LOCK_global_system_variables); } -/****************************************************************** -Update the system variable innodb_encrypt_tables*/ +/** Update the system variable innodb_encrypt_tables. +@param[in] save to-be-assigned value */ static void -innodb_encrypt_tables_update( -/*=========================*/ - THD* thd, /*!< in: thread handle */ - struct st_mysql_sys_var* var, /*!< in: pointer to - system variable */ - void* var_ptr,/*!< out: where the - formal string goes */ - const void* save) /*!< in: immediate result - from check function */ +innodb_encrypt_tables_update(THD*,st_mysql_sys_var*,void*,const void*save) { + mysql_mutex_unlock(&LOCK_global_system_variables); fil_crypt_set_encrypt_tables(*static_cast<const ulong*>(save)); + mysql_mutex_lock(&LOCK_global_system_variables); } static SHOW_VAR innodb_status_variables_export[]= { @@ -20979,12 +20980,15 @@ innobase_disallow_writes_update( variable */ const void* save) /* in: temporary storage */ { - *(my_bool*)var_ptr = *(my_bool*)save; + const my_bool val = *static_cast<const my_bool*>(save); + *static_cast<my_bool*>(var_ptr) = val; ut_a(srv_allow_writes_event); - if (*(my_bool*)var_ptr) + mysql_mutex_unlock(&LOCK_global_system_variables); + if (val) os_event_reset(srv_allow_writes_event); else os_event_set(srv_allow_writes_event); + mysql_mutex_lock(&LOCK_global_system_variables); } static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes, diff --git a/storage/xtradb/include/buf0lru.h b/storage/xtradb/include/buf0lru.h index e0f2277b6a2..69ada4abb70 100644 --- a/storage/xtradb/include/buf0lru.h +++ b/storage/xtradb/include/buf0lru.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -208,13 +208,13 @@ buf_LRU_make_block_old( Updates buf_pool->LRU_old_ratio. @return updated old_pct */ UNIV_INTERN -ulint +uint buf_LRU_old_ratio_update( /*=====================*/ uint old_pct,/*!< in: Reserve this percentage of the buffer pool for "old" blocks. */ - ibool adjust);/*!< in: TRUE=adjust the LRU list; - FALSE=just assign buf_pool->LRU_old_ratio + bool adjust);/*!< in: true=adjust the LRU list; + false=just assign buf_pool->LRU_old_ratio during the initialization of InnoDB */ /********************************************************************//** Update the historical stats that we are collecting for LRU eviction |