Skip to content

Commit 626f2a1

Browse files
committed
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.
1 parent 242a28c commit 626f2a1

File tree

6 files changed

+152
-144
lines changed

6 files changed

+152
-144
lines changed

storage/innobase/buf/buf0lru.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4-
Copyright (c) 2017, 2018, MariaDB Corporation.
4+
Copyright (c) 2017, 2019, MariaDB Corporation.
55
66
This program is free software; you can redistribute it and/or modify it under
77
the terms of the GNU General Public License as published by the Free Software
@@ -2243,8 +2243,8 @@ buf_LRU_old_ratio_update_instance(
22432243
buf_pool_t* buf_pool,/*!< in: buffer pool instance */
22442244
uint old_pct,/*!< in: Reserve this percentage of
22452245
the buffer pool for "old" blocks. */
2246-
ibool adjust) /*!< in: TRUE=adjust the LRU list;
2247-
FALSE=just assign buf_pool->LRU_old_ratio
2246+
bool adjust) /*!< in: true=adjust the LRU list;
2247+
false=just assign buf_pool->LRU_old_ratio
22482248
during the initialization of InnoDB */
22492249
{
22502250
uint ratio;
@@ -2282,17 +2282,17 @@ buf_LRU_old_ratio_update_instance(
22822282
Updates buf_pool->LRU_old_ratio.
22832283
@return updated old_pct */
22842284
UNIV_INTERN
2285-
ulint
2285+
uint
22862286
buf_LRU_old_ratio_update(
22872287
/*=====================*/
22882288
uint old_pct,/*!< in: Reserve this percentage of
22892289
the buffer pool for "old" blocks. */
2290-
ibool adjust) /*!< in: TRUE=adjust the LRU list;
2291-
FALSE=just assign buf_pool->LRU_old_ratio
2290+
bool adjust) /*!< in: true=adjust the LRU list;
2291+
false=just assign buf_pool->LRU_old_ratio
22922292
during the initialization of InnoDB */
22932293
{
22942294
ulint i;
2295-
ulint new_ratio = 0;
2295+
uint new_ratio = 0;
22962296

22972297
for (i = 0; i < srv_buf_pool_instances; i++) {
22982298
buf_pool_t* buf_pool;

storage/innobase/handler/ha_innodb.cc

Lines changed: 65 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -17166,11 +17166,13 @@ innodb_adaptive_hash_index_update(
1716617166
const void* save) /*!< in: immediate result
1716717167
from check function */
1716817168
{
17169+
mysql_mutex_unlock(&LOCK_global_system_variables);
1716917170
if (*(my_bool*) save) {
1717017171
btr_search_enable();
1717117172
} else {
1717217173
btr_search_disable();
1717317174
}
17175+
mysql_mutex_lock(&LOCK_global_system_variables);
1717417176
}
1717517177

1717617178
/****************************************************************//**
@@ -17191,7 +17193,9 @@ innodb_cmp_per_index_update(
1719117193
/* Reset the stats whenever we enable the table
1719217194
INFORMATION_SCHEMA.innodb_cmp_per_index. */
1719317195
if (!srv_cmp_per_index_enabled && *(my_bool*) save) {
17196+
mysql_mutex_unlock(&LOCK_global_system_variables);
1719417197
page_zip_reset_stat_per_index();
17198+
mysql_mutex_lock(&LOCK_global_system_variables);
1719517199
}
1719617200

1719717201
srv_cmp_per_index_enabled = !!(*(my_bool*) save);
@@ -17212,9 +17216,11 @@ innodb_old_blocks_pct_update(
1721217216
const void* save) /*!< in: immediate result
1721317217
from check function */
1721417218
{
17215-
innobase_old_blocks_pct = static_cast<uint>(
17216-
buf_LRU_old_ratio_update(
17217-
*static_cast<const uint*>(save), TRUE));
17219+
mysql_mutex_unlock(&LOCK_global_system_variables);
17220+
uint ratio = buf_LRU_old_ratio_update(*static_cast<const uint*>(save),
17221+
true);
17222+
mysql_mutex_lock(&LOCK_global_system_variables);
17223+
innobase_old_blocks_pct = ratio;
1721817224
}
1721917225

1722017226
/****************************************************************//**
@@ -17232,9 +17238,10 @@ innodb_change_buffer_max_size_update(
1723217238
const void* save) /*!< in: immediate result
1723317239
from check function */
1723417240
{
17235-
innobase_change_buffer_max_size =
17236-
(*static_cast<const uint*>(save));
17241+
innobase_change_buffer_max_size = *static_cast<const uint*>(save);
17242+
mysql_mutex_unlock(&LOCK_global_system_variables);
1723717243
ibuf_max_size_update(innobase_change_buffer_max_size);
17244+
mysql_mutex_lock(&LOCK_global_system_variables);
1723817245
}
1723917246

1724017247
#ifdef UNIV_DEBUG
@@ -17278,6 +17285,7 @@ innodb_make_page_dirty(
1727817285
{
1727917286
mtr_t mtr;
1728017287
ulong space_id = *static_cast<const ulong*>(save);
17288+
mysql_mutex_unlock(&LOCK_global_system_variables);
1728117289

1728217290
mtr_start(&mtr);
1728317291

@@ -17295,6 +17303,7 @@ innodb_make_page_dirty(
1729517303
MLOG_2BYTES, &mtr);
1729617304
}
1729717305
mtr_commit(&mtr);
17306+
mysql_mutex_lock(&LOCK_global_system_variables);
1729817307
}
1729917308
#endif // UNIV_DEBUG
1730017309

@@ -17933,8 +17942,11 @@ innodb_buffer_pool_evict_update(
1793317942
{
1793417943
if (const char* op = *static_cast<const char*const*>(save)) {
1793517944
if (!strcmp(op, "uncompressed")) {
17945+
mysql_mutex_unlock(&LOCK_global_system_variables);
1793617946
for (uint tries = 0; tries < 10000; tries++) {
1793717947
if (innodb_buffer_pool_evict_uncompressed()) {
17948+
mysql_mutex_lock(
17949+
&LOCK_global_system_variables);
1793817950
return;
1793917951
}
1794017952

@@ -18237,7 +18249,9 @@ purge_run_now_set(
1823718249
check function */
1823818250
{
1823918251
if (*(my_bool*) save && trx_purge_state() != PURGE_STATE_DISABLED) {
18252+
mysql_mutex_unlock(&LOCK_global_system_variables);
1824018253
trx_purge_run();
18254+
mysql_mutex_lock(&LOCK_global_system_variables);
1824118255
}
1824218256
}
1824318257

@@ -18260,7 +18274,9 @@ purge_stop_now_set(
1826018274
check function */
1826118275
{
1826218276
if (*(my_bool*) save && trx_purge_state() != PURGE_STATE_DISABLED) {
18277+
mysql_mutex_unlock(&LOCK_global_system_variables);
1826318278
trx_purge_stop();
18279+
mysql_mutex_lock(&LOCK_global_system_variables);
1826418280
}
1826518281
}
1826618282

@@ -18282,6 +18298,8 @@ checkpoint_now_set(
1828218298
check function */
1828318299
{
1828418300
if (*(my_bool*) save) {
18301+
mysql_mutex_unlock(&LOCK_global_system_variables);
18302+
1828518303
while (log_sys->last_checkpoint_lsn < log_sys->lsn) {
1828618304
log_make_checkpoint_at(LSN_MAX, TRUE);
1828718305
fil_flush_file_spaces(FIL_LOG);
@@ -18295,6 +18313,8 @@ checkpoint_now_set(
1829518313
"system tablespace at checkpoint err=%s",
1829618314
ut_strerr(err));
1829718315
}
18316+
18317+
mysql_mutex_lock(&LOCK_global_system_variables);
1829818318
}
1829918319
}
1830018320

@@ -18316,8 +18336,10 @@ buf_flush_list_now_set(
1831618336
check function */
1831718337
{
1831818338
if (*(my_bool*) save) {
18339+
mysql_mutex_unlock(&LOCK_global_system_variables);
1831918340
buf_flush_list(ULINT_MAX, LSN_MAX, NULL);
1832018341
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
18342+
mysql_mutex_lock(&LOCK_global_system_variables);
1832118343
}
1832218344
}
1832318345
#endif /* UNIV_DEBUG */
@@ -18419,7 +18441,9 @@ buffer_pool_dump_now(
1841918441
check function */
1842018442
{
1842118443
if (*(my_bool*) save && !srv_read_only_mode) {
18444+
mysql_mutex_unlock(&LOCK_global_system_variables);
1842218445
buf_dump_start();
18446+
mysql_mutex_lock(&LOCK_global_system_variables);
1842318447
}
1842418448
}
1842518449

@@ -18442,7 +18466,9 @@ buffer_pool_load_now(
1844218466
check function */
1844318467
{
1844418468
if (*(my_bool*) save && !srv_read_only_mode) {
18469+
mysql_mutex_unlock(&LOCK_global_system_variables);
1844518470
buf_load_start();
18471+
mysql_mutex_lock(&LOCK_global_system_variables);
1844618472
}
1844718473
}
1844818474

@@ -18465,96 +18491,71 @@ buffer_pool_load_abort(
1846518491
check function */
1846618492
{
1846718493
if (*(my_bool*) save && !srv_read_only_mode) {
18494+
mysql_mutex_unlock(&LOCK_global_system_variables);
1846818495
buf_load_abort();
18496+
mysql_mutex_lock(&LOCK_global_system_variables);
1846918497
}
1847018498
}
1847118499

1847218500
/** Update innodb_status_output or innodb_status_output_locks,
1847318501
which control InnoDB "status monitor" output to the error log.
18474-
@param[in] thd thread handle
18475-
@param[in] var system variable
18476-
@param[out] var_ptr current value
18502+
@param[out] var current value
1847718503
@param[in] save to-be-assigned value */
1847818504
static
1847918505
void
18480-
innodb_status_output_update(
18481-
/*========================*/
18482-
THD* thd __attribute__((unused)),
18483-
struct st_mysql_sys_var* var __attribute__((unused)),
18484-
void* var_ptr __attribute__((unused)),
18485-
const void* save __attribute__((unused)))
18506+
innodb_status_output_update(THD*,st_mysql_sys_var*,void*var,const void*save)
1848618507
{
18487-
*static_cast<my_bool*>(var_ptr) = *static_cast<const my_bool*>(save);
18508+
*static_cast<my_bool*>(var) = *static_cast<const my_bool*>(save);
18509+
mysql_mutex_unlock(&LOCK_global_system_variables);
1848818510
/* Wakeup server monitor thread. */
1848918511
os_event_set(srv_monitor_event);
18512+
mysql_mutex_lock(&LOCK_global_system_variables);
1849018513
}
1849118514

18492-
/******************************************************************
18493-
Update the system variable innodb_encryption_threads */
18515+
/** Update the system variable innodb_encryption_threads.
18516+
@param[in] save to-be-assigned value */
1849418517
static
1849518518
void
18496-
innodb_encryption_threads_update(
18497-
/*=============================*/
18498-
THD* thd, /*!< in: thread handle */
18499-
struct st_mysql_sys_var* var, /*!< in: pointer to
18500-
system variable */
18501-
void* var_ptr,/*!< out: where the
18502-
formal string goes */
18503-
const void* save) /*!< in: immediate result
18504-
from check function */
18519+
innodb_encryption_threads_update(THD*,st_mysql_sys_var*,void*,const void*save)
1850518520
{
18521+
mysql_mutex_unlock(&LOCK_global_system_variables);
1850618522
fil_crypt_set_thread_cnt(*static_cast<const uint*>(save));
18523+
mysql_mutex_lock(&LOCK_global_system_variables);
1850718524
}
1850818525

18509-
/******************************************************************
18510-
Update the system variable innodb_encryption_rotate_key_age */
18526+
/** Update the system variable innodb_encryption_rotate_key_age.
18527+
@param[in] save to-be-assigned value */
1851118528
static
1851218529
void
18513-
innodb_encryption_rotate_key_age_update(
18514-
/*====================================*/
18515-
THD* thd, /*!< in: thread handle */
18516-
struct st_mysql_sys_var* var, /*!< in: pointer to
18517-
system variable */
18518-
void* var_ptr,/*!< out: where the
18519-
formal string goes */
18520-
const void* save) /*!< in: immediate result
18521-
from check function */
18530+
innodb_encryption_rotate_key_age_update(THD*,st_mysql_sys_var*,void*,
18531+
const void*save)
1852218532
{
18533+
mysql_mutex_unlock(&LOCK_global_system_variables);
1852318534
fil_crypt_set_rotate_key_age(*static_cast<const uint*>(save));
18535+
mysql_mutex_lock(&LOCK_global_system_variables);
1852418536
}
1852518537

18526-
/******************************************************************
18527-
Update the system variable innodb_encryption_rotation_iops */
18538+
/** Update the system variable innodb_encryption_rotation_iops.
18539+
@param[in] save to-be-assigned value */
1852818540
static
1852918541
void
18530-
innodb_encryption_rotation_iops_update(
18531-
/*===================================*/
18532-
THD* thd, /*!< in: thread handle */
18533-
struct st_mysql_sys_var* var, /*!< in: pointer to
18534-
system variable */
18535-
void* var_ptr,/*!< out: where the
18536-
formal string goes */
18537-
const void* save) /*!< in: immediate result
18538-
from check function */
18542+
innodb_encryption_rotation_iops_update(THD*,st_mysql_sys_var*,void*,
18543+
const void*save)
1853918544
{
18545+
mysql_mutex_unlock(&LOCK_global_system_variables);
1854018546
fil_crypt_set_rotation_iops(*static_cast<const uint*>(save));
18547+
mysql_mutex_lock(&LOCK_global_system_variables);
1854118548
}
1854218549

18543-
/******************************************************************
18544-
Update the system variable innodb_encrypt_tables*/
18550+
/** Update the system variable innodb_encrypt_tables.
18551+
@param[in] save to-be-assigned value */
1854518552
static
1854618553
void
18547-
innodb_encrypt_tables_update(
18548-
/*=========================*/
18549-
THD* thd, /*!< in: thread handle */
18550-
struct st_mysql_sys_var* var, /*!< in: pointer to
18551-
system variable */
18552-
void* var_ptr,/*!< out: where the
18553-
formal string goes */
18554-
const void* save) /*!< in: immediate result
18555-
from check function */
18554+
innodb_encrypt_tables_update(THD*,st_mysql_sys_var*,void*,const void*save)
1855618555
{
18556+
mysql_mutex_unlock(&LOCK_global_system_variables);
1855718557
fil_crypt_set_encrypt_tables(*static_cast<const ulong*>(save));
18558+
mysql_mutex_lock(&LOCK_global_system_variables);
1855818559
}
1855918560

1856018561
static SHOW_VAR innodb_status_variables_export[]= {
@@ -19736,12 +19737,15 @@ innobase_disallow_writes_update(
1973619737
variable */
1973719738
const void* save) /* in: temporary storage */
1973819739
{
19739-
*(my_bool*)var_ptr = *(my_bool*)save;
19740+
const my_bool val = *static_cast<const my_bool*>(save);
19741+
*static_cast<my_bool*>(var_ptr) = val;
1974019742
ut_a(srv_allow_writes_event);
19741-
if (*(my_bool*)var_ptr)
19743+
mysql_mutex_unlock(&LOCK_global_system_variables);
19744+
if (val)
1974219745
os_event_reset(srv_allow_writes_event);
1974319746
else
1974419747
os_event_set(srv_allow_writes_event);
19748+
mysql_mutex_lock(&LOCK_global_system_variables);
1974519749
}
1974619750

1974719751
static MYSQL_SYSVAR_BOOL(disallow_writes, innobase_disallow_writes,

storage/innobase/include/buf0lru.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*****************************************************************************
22
33
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
4-
Copyright (c) 2017, 2018, MariaDB Corporation.
4+
Copyright (c) 2017, 2019, MariaDB Corporation.
55
66
This program is free software; you can redistribute it and/or modify it under
77
the terms of the GNU General Public License as published by the Free Software
@@ -202,13 +202,13 @@ buf_LRU_make_block_old(
202202
Updates buf_pool->LRU_old_ratio.
203203
@return updated old_pct */
204204
UNIV_INTERN
205-
ulint
205+
uint
206206
buf_LRU_old_ratio_update(
207207
/*=====================*/
208208
uint old_pct,/*!< in: Reserve this percentage of
209209
the buffer pool for "old" blocks. */
210-
ibool adjust);/*!< in: TRUE=adjust the LRU list;
211-
FALSE=just assign buf_pool->LRU_old_ratio
210+
bool adjust);/*!< in: true=adjust the LRU list;
211+
false=just assign buf_pool->LRU_old_ratio
212212
during the initialization of InnoDB */
213213
/********************************************************************//**
214214
Update the historical stats that we are collecting for LRU eviction

0 commit comments

Comments
 (0)