diff options
author | Sergei Golubchik <sergii@pisem.net> | 2014-09-06 08:33:56 +0200 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2014-09-06 08:33:56 +0200 |
commit | 3da761912a6b243b1361a27d5b796cc53dfff3ec (patch) | |
tree | c566c164d2499b28b18ffee1dc4f3c32f5c8a8bd | |
parent | 9392d0e280c622c56d1b533762d8b577ed5b82c6 (diff) | |
download | mariadb-git-3da761912a6b243b1361a27d5b796cc53dfff3ec.tar.gz |
MDEV-6616 Server crashes in my_hash_first if shutdown is performed when FLUSH LOGS is running
master_info_index becomes zero during shutdown.
check that it's valid (under a mutex) before dereferencing.
-rw-r--r-- | sql/item_func.cc | 8 | ||||
-rw-r--r-- | sql/rpl_mi.cc | 12 | ||||
-rw-r--r-- | sql/slave.cc | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_reload.cc | 57 | ||||
-rw-r--r-- | sql/sql_repl.cc | 6 |
6 files changed, 61 insertions, 32 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc index 51a85e71f20..098845d372e 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3961,9 +3961,13 @@ longlong Item_master_pos_wait::val_int() else connection_name= thd->variables.default_master_connection; - if (!(mi= master_info_index->get_master_info(&connection_name, - Sql_condition::WARN_LEVEL_WARN))) + mysql_mutex_lock(&LOCK_active_mi); + mi= master_info_index->get_master_info(&connection_name, + Sql_condition::WARN_LEVEL_WARN); + mysql_mutex_unlock(&LOCK_active_mi); + if (!mi) goto err; + if ((event_count = mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2) { null_value = 1; diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc index f2c39ea7f8d..78218e0418e 100644 --- a/sql/rpl_mi.cc +++ b/sql/rpl_mi.cc @@ -891,6 +891,9 @@ bool Master_info_index::init_all_master_info() File index_file_nr; DBUG_ENTER("init_all_master_info"); + mysql_mutex_assert_owner(&LOCK_active_mi); + DBUG_ASSERT(master_info_index); + if ((index_file_nr= my_open(index_file_name, O_RDWR | O_CREAT | O_BINARY , MYF(MY_WME | ME_NOREFRESH))) < 0 || @@ -1090,6 +1093,10 @@ Master_info_index::get_master_info(LEX_STRING *connection_name, ("connection_name: '%.*s'", (int) connection_name->length, connection_name->str)); + mysql_mutex_assert_owner(&LOCK_active_mi); + if (!this) // master_info_index is set to NULL on server shutdown + return NULL; + /* Make name lower case for comparison */ res= strmake(buff, connection_name->str, connection_name->length); my_casedn_str(system_charset_info, buff); @@ -1117,6 +1124,9 @@ bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg, Master_info *mi; DBUG_ENTER("check_duplicate_master_info"); + mysql_mutex_assert_owner(&LOCK_active_mi); + DBUG_ASSERT(master_info_index); + /* Get full host and port name */ if ((mi= master_info_index->get_master_info(name_arg, Sql_condition::WARN_LEVEL_NOTE))) @@ -1239,6 +1249,8 @@ bool Master_info_index::give_error_if_slave_running() { DBUG_ENTER("warn_if_slave_running"); mysql_mutex_assert_owner(&LOCK_active_mi); + if (!this) // master_info_index is set to NULL on server shutdown + return TRUE; for (uint i= 0; i< master_info_hash.records; ++i) { diff --git a/sql/slave.cc b/sql/slave.cc index 9422ecc7f22..b9f06c15fd4 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2858,7 +2858,8 @@ bool show_all_master_info(THD* thd) if (send_show_master_info_header(thd, 1, gtid_pos.length())) DBUG_RETURN(TRUE); - if (!(elements= master_info_index->master_info_hash.records)) + if (!master_info_index || + !(elements= master_info_index->master_info_hash.records)) goto end; /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 30fcac6e12a..4edbd3ba5be 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2693,6 +2693,9 @@ case SQLCOM_PREPARE: goto error; mysql_mutex_lock(&LOCK_active_mi); + if (!master_info_index) + goto error; + mi= master_info_index->get_master_info(&lex_mi->connection_name, Sql_condition::WARN_LEVEL_NOTE); @@ -3150,7 +3153,7 @@ end_with_restore_list: case SQLCOM_SLAVE_ALL_START: { mysql_mutex_lock(&LOCK_active_mi); - if (!master_info_index->start_all_slaves(thd)) + if (master_info_index && !master_info_index->start_all_slaves(thd)) my_ok(thd); mysql_mutex_unlock(&LOCK_active_mi); break; @@ -3166,7 +3169,7 @@ end_with_restore_list: goto error; } mysql_mutex_lock(&LOCK_active_mi); - if (!master_info_index->stop_all_slaves(thd)) + if (master_info_index && !master_info_index->stop_all_slaves(thd)) my_ok(thd); mysql_mutex_unlock(&LOCK_active_mi); break; diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc index bb3d5bb899a..95e06ddbbd5 100644 --- a/sql/sql_reload.cc +++ b/sql/sql_reload.cc @@ -174,18 +174,21 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, */ tmp_write_to_binlog= 0; mysql_mutex_lock(&LOCK_active_mi); - if (!(mi= (master_info_index-> - get_master_info(&connection_name, - Sql_condition::WARN_LEVEL_ERROR)))) + if (master_info_index) { - result= 1; - } - else - { - mysql_mutex_lock(&mi->data_lock); - if (rotate_relay_log(mi)) - *write_to_binlog= -1; - mysql_mutex_unlock(&mi->data_lock); + if (!(mi= (master_info_index-> + get_master_info(&connection_name, + Sql_condition::WARN_LEVEL_ERROR)))) + { + result= 1; + } + else + { + mysql_mutex_lock(&mi->data_lock); + if (rotate_relay_log(mi)) + *write_to_binlog= -1; + mysql_mutex_unlock(&mi->data_lock); + } } mysql_mutex_unlock(&LOCK_active_mi); #endif @@ -346,22 +349,24 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options, Master_info *mi; tmp_write_to_binlog= 0; mysql_mutex_lock(&LOCK_active_mi); - - if (!(mi= (master_info_index-> - get_master_info(&lex_mi->connection_name, - Sql_condition::WARN_LEVEL_ERROR)))) + if (master_info_index) { - result= 1; - } - else if (reset_slave(thd, mi)) - { - /* NOTE: my_error() has been already called by reset_slave(). */ - result= 1; - } - else if (mi->connection_name.length && thd->lex->reset_slave_info.all) - { - /* If not default connection and 'all' is used */ - master_info_index->remove_master_info(&mi->connection_name); + if (!(mi= (master_info_index-> + get_master_info(&lex_mi->connection_name, + Sql_condition::WARN_LEVEL_ERROR)))) + { + result= 1; + } + else if (reset_slave(thd, mi)) + { + /* NOTE: my_error() has been already called by reset_slave(). */ + result= 1; + } + else if (mi->connection_name.length && thd->lex->reset_slave_info.all) + { + /* If not default connection and 'all' is used */ + master_info_index->remove_master_info(&mi->connection_name); + } } mysql_mutex_unlock(&LOCK_active_mi); } diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 0f4a7c5133e..8a441dd2737 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -3226,6 +3226,9 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added) LEX_MASTER_INFO* lex_mi= &thd->lex->mi; DBUG_ENTER("change_master"); + mysql_mutex_assert_owner(&LOCK_active_mi); + DBUG_ASSERT(master_info_index); + *master_info_added= false; /* We need to check if there is an empty master_host. Otherwise @@ -3632,7 +3635,8 @@ bool mysql_show_binlog_events(THD* thd) else /* showing relay log contents */ { mysql_mutex_lock(&LOCK_active_mi); - if (!(mi= master_info_index-> + if (!master_info_index || + !(mi= master_info_index-> get_master_info(&thd->variables.default_master_connection, Sql_condition::WARN_LEVEL_ERROR))) { |