summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2017-03-03 13:27:12 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2017-03-03 13:27:12 +0200
commitadc91387e3add6d9c850b7c2a44760deaceb3638 (patch)
treec772c6339d2f715a1a50766e30790307e0658f3e /sql
parentbc28b305e538774eae4152b300cd323e9a724393 (diff)
parent29c776cfd1e560846e394f39d79ae43ff7d70c61 (diff)
downloadmariadb-git-adc91387e3add6d9c850b7c2a44760deaceb3638.tar.gz
Merge 10.0 into 10.1
Diffstat (limited to 'sql')
-rw-r--r--sql/contributors.h14
-rw-r--r--sql/event_scheduler.cc40
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/item_func.cc8
-rw-r--r--sql/log.cc42
-rw-r--r--sql/log_event.cc17
-rw-r--r--sql/log_event_old.cc4
-rw-r--r--sql/mysql_install_db.cc4
-rw-r--r--sql/mysqld.cc101
-rw-r--r--sql/mysqld.h6
-rw-r--r--sql/nt_servc.cc2
-rw-r--r--sql/nt_servc.h2
-rw-r--r--sql/rpl_mi.cc412
-rw-r--r--sql/rpl_mi.h19
-rw-r--r--sql/rpl_parallel.cc126
-rw-r--r--sql/rpl_parallel.h1
-rw-r--r--sql/rpl_rli.cc15
-rw-r--r--sql/rpl_rli.h2
-rw-r--r--sql/slave.cc137
-rw-r--r--sql/slave.h3
-rw-r--r--sql/sql_alter.h35
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_class.cc6
-rw-r--r--sql/sql_parse.cc66
-rw-r--r--sql/sql_reload.cc56
-rw-r--r--sql/sql_repl.cc78
-rw-r--r--sql/sql_table.cc3
-rw-r--r--sql/sql_yacc.yy2
-rw-r--r--sql/sys_vars.cc127
29 files changed, 792 insertions, 540 deletions
diff --git a/sql/contributors.h b/sql/contributors.h
index 0359ec54022..3a771e2b493 100644
--- a/sql/contributors.h
+++ b/sql/contributors.h
@@ -37,16 +37,18 @@ struct show_table_contributors_st {
struct show_table_contributors_st show_table_contributors[]= {
/* MariaDB foundation sponsors, in contribution, size , time order */
- {"Booking.com", "http://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
+ {"Booking.com", "https://www.booking.com", "Founding member, Platinum Sponsor of the MariaDB Foundation"},
+ {"Alibaba Cloud", "https://intl.aliyun.com", "Platinum Sponsor of the MariaDB Foundation"},
{"MariaDB Corporation", "https://mariadb.com", "Founding member, Gold Sponsor of the MariaDB Foundation"},
- {"Visma", "http://visma.com", "Gold Sponsor of the MariaDB Foundation"},
- {"DBS", "http://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"Visma", "https://visma.com", "Gold Sponsor of the MariaDB Foundation"},
+ {"DBS", "https://dbs.com", "Gold Sponsor of the MariaDB Foundation"},
{"Nexedi", "https://www.nexedi.com", "Silver Sponsor of the MariaDB Foundation"},
{"Acronis", "http://www.acronis.com", "Silver Sponsor of the MariaDB Foundation"},
{"Auttomattic", "https://automattic.com", "Bronze Sponsor of the MariaDB Foundation"},
- {"Verkkokauppa.com", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
- {"Virtuozzo", "https://virtuozzo.com/", "Bronze Sponsor of the MariaDB Foundation"},
- {"Tencent Game DBA", "http://tencentdba.com/about/", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Verkkokauppa.com", "https://www.verkkokauppa.com", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Virtuozzo", "https://virtuozzo.com", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Tencent Game DBA", "http://tencentdba.com/about", "Bronze Sponsor of the MariaDB Foundation"},
+ {"Tencent TDSQL", "http://tdsql.org", "Bronze Sponsor of the MariaDB Foundation"},
/* Sponsors of important features */
{"Google", "USA", "Sponsoring encryption, parallel replication and GTID"},
diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc
index 95c5f6d9047..e02b618a80a 100644
--- a/sql/event_scheduler.cc
+++ b/sql/event_scheduler.cc
@@ -133,12 +133,6 @@ post_init_event_thread(THD *thd)
thd->cleanup();
return TRUE;
}
-
- thread_safe_increment32(&thread_count);
- mysql_mutex_lock(&LOCK_thread_count);
- threads.append(thd);
- mysql_mutex_unlock(&LOCK_thread_count);
- inc_thread_running();
return FALSE;
}
@@ -157,7 +151,13 @@ deinit_event_thread(THD *thd)
thd->proc_info= "Clearing";
DBUG_PRINT("exit", ("Event thread finishing"));
- delete_running_thd(thd);
+ mysql_mutex_lock(&LOCK_thread_count);
+ thd->unlink();
+ mysql_mutex_unlock(&LOCK_thread_count);
+
+ delete thd;
+ thread_safe_decrement32(&thread_count);
+ signal_thd_deleted();
}
@@ -191,8 +191,10 @@ pre_init_event_thread(THD* thd)
thd->net.read_timeout= slave_net_timeout;
thd->variables.option_bits|= OPTION_AUTO_IS_NULL;
thd->client_capabilities|= CLIENT_MULTI_RESULTS;
+ thread_safe_increment32(&thread_count);
mysql_mutex_lock(&LOCK_thread_count);
thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
+ threads.append(thd);
mysql_mutex_unlock(&LOCK_thread_count);
/*
@@ -240,13 +242,8 @@ event_scheduler_thread(void *arg)
my_free(arg);
if (!res)
scheduler->run(thd);
- else
- {
- thd->proc_info= "Clearing";
- net_end(&thd->net);
- delete thd;
- }
+ deinit_event_thread(thd);
DBUG_LEAVE; // Against gcc warnings
my_thread_end();
return 0;
@@ -310,6 +307,7 @@ Event_worker_thread::run(THD *thd, Event_queue_element_for_exec *event)
DBUG_ENTER("Event_worker_thread::run");
DBUG_PRINT("info", ("Time is %ld, THD: 0x%lx", (long) my_time(0), (long) thd));
+ inc_thread_running();
if (res)
goto end;
@@ -338,6 +336,7 @@ end:
event->name.str));
delete event;
+ dec_thread_running();
deinit_event_thread(thd);
DBUG_VOID_RETURN;
@@ -442,13 +441,9 @@ Event_scheduler::start(int *err_no)
" Can not create thread for event scheduler (errno=%d)",
*err_no);
- new_thd->proc_info= "Clearing";
- DBUG_ASSERT(new_thd->net.buff != 0);
- net_end(&new_thd->net);
-
state= INITIALIZED;
scheduler_thd= NULL;
- delete new_thd;
+ deinit_event_thread(new_thd);
delete scheduler_param_value;
ret= true;
@@ -515,7 +510,6 @@ Event_scheduler::run(THD *thd)
}
LOCK_DATA();
- deinit_event_thread(thd);
scheduler_thd= NULL;
state= INITIALIZED;
DBUG_PRINT("info", ("Broadcasting COND_state back to the stoppers"));
@@ -575,10 +569,7 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
sql_print_error("Event_scheduler::execute_top: Can not create event worker"
" thread (errno=%d). Stopping event scheduler", res);
- new_thd->proc_info= "Clearing";
- DBUG_ASSERT(new_thd->net.buff != 0);
- net_end(&new_thd->net);
-
+ deinit_event_thread(new_thd);
goto error;
}
@@ -590,9 +581,6 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
error:
DBUG_PRINT("error", ("Event_scheduler::execute_top() res: %d", res));
- if (new_thd)
- delete new_thd;
-
delete event_name;
DBUG_RETURN(TRUE);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index cca77eece48..7ac8dd63e9e 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -4200,7 +4200,7 @@ enum_alter_inplace_result
handler::check_if_supported_inplace_alter(TABLE *altered_table,
Alter_inplace_info *ha_alter_info)
{
- DBUG_ENTER("check_if_supported_alter");
+ DBUG_ENTER("handler::check_if_supported_inplace_alter");
HA_CREATE_INFO *create_info= ha_alter_info->create_info;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 623ff1128f3..ee3fd2f6026 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -3932,12 +3932,7 @@ longlong Item_master_pos_wait::val_int()
else
connection_name= thd->variables.default_master_connection;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index) // master_info_index is set to NULL on shutdown.
- mi= master_info_index->get_master_info(&connection_name,
- Sql_condition::WARN_LEVEL_WARN);
- mysql_mutex_unlock(&LOCK_active_mi);
- if (!mi)
+ if (!(mi= get_master_info(&connection_name, Sql_condition::WARN_LEVEL_WARN)))
goto err;
if ((event_count = mi->rli.wait_for_pos(thd, log_name, pos, timeout)) == -2)
@@ -3945,6 +3940,7 @@ longlong Item_master_pos_wait::val_int()
null_value = 1;
event_count=0;
}
+ mi->release();
#endif
return event_count;
diff --git a/sql/log.cc b/sql/log.cc
index 5a4f883b0ac..4a1e9f26c4c 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -2789,16 +2789,16 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name,
void MYSQL_QUERY_LOG::reopen_file()
{
char *save_name;
-
DBUG_ENTER("MYSQL_LOG::reopen_file");
+
+ mysql_mutex_lock(&LOCK_log);
if (!is_open())
{
DBUG_PRINT("info",("log is closed"));
+ mysql_mutex_unlock(&LOCK_log);
DBUG_VOID_RETURN;
}
- mysql_mutex_lock(&LOCK_log);
-
save_name= name;
name= 0; // Don't free name
close(LOG_CLOSE_TO_BE_OPENED);
@@ -2957,13 +2957,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
DBUG_ENTER("MYSQL_QUERY_LOG::write");
mysql_mutex_lock(&LOCK_log);
-
- if (!is_open())
- {
- mysql_mutex_unlock(&LOCK_log);
- DBUG_RETURN(0);
- }
-
if (is_open())
{ // Safety agains reopen
int tmp_errno= 0;
@@ -3207,7 +3200,9 @@ void MYSQL_BIN_LOG::cleanup()
}
inited= 0;
+ mysql_mutex_lock(&LOCK_log);
close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
+ mysql_mutex_unlock(&LOCK_log);
delete description_event_for_queue;
delete description_event_for_exec;
@@ -3374,6 +3369,8 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
+ mysql_mutex_assert_owner(&LOCK_log);
+
if (!is_relay_log)
{
if (!binlog_state_recover_done)
@@ -4329,7 +4326,7 @@ void MYSQL_BIN_LOG::wait_for_last_checkpoint_event()
int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
{
- int error;
+ int error, errcode;
char *to_purge_if_included= NULL;
inuse_relaylog *ir;
ulonglong log_space_reclaimed= 0;
@@ -4397,7 +4394,8 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
}
/* Store where we are in the new file for the execution thread */
- flush_relay_log_info(rli);
+ if (flush_relay_log_info(rli))
+ error= LOG_INFO_IO;
DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_SUICIDE(););
@@ -4413,10 +4411,10 @@ int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
* Need to update the log pos because purge logs has been called
* after fetching initially the log pos at the begining of the method.
*/
- if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
+ if ((errcode= find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
{
sql_print_error("next log error: %d offset: %llu log: %s included: %d",
- error, rli->linfo.index_file_offset,
+ errcode, rli->linfo.index_file_offset,
rli->group_relay_log_name, included);
goto err;
}
@@ -5040,19 +5038,19 @@ int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
File UNINIT_VAR(old_file);
DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
+ if (need_lock)
+ mysql_mutex_lock(&LOCK_log);
+ mysql_mutex_assert_owner(&LOCK_log);
+
if (!is_open())
{
DBUG_PRINT("info",("log is closed"));
+ mysql_mutex_unlock(&LOCK_log);
DBUG_RETURN(error);
}
- if (need_lock)
- mysql_mutex_lock(&LOCK_log);
mysql_mutex_lock(&LOCK_index);
- mysql_mutex_assert_owner(&LOCK_log);
- mysql_mutex_assert_owner(&LOCK_index);
-
/* Reuse old name if not binlog and not update log */
new_name_ptr= name;
@@ -5189,9 +5187,9 @@ end:
new_name_ptr, errno);
}
+ mysql_mutex_unlock(&LOCK_index);
if (need_lock)
mysql_mutex_unlock(&LOCK_log);
- mysql_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@@ -8133,9 +8131,11 @@ int MYSQL_BIN_LOG::wait_for_update_binlog_end_pos(THD* thd,
void MYSQL_BIN_LOG::close(uint exiting)
{ // One can't set log_type here!
bool failed_to_save_state= false;
-
DBUG_ENTER("MYSQL_BIN_LOG::close");
DBUG_PRINT("enter",("exiting: %d", (int) exiting));
+
+ mysql_mutex_assert_owner(&LOCK_log);
+
if (log_state == LOG_OPENED)
{
#ifdef HAVE_REPLICATION
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 21b5de2725e..13a271d98da 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6405,9 +6405,11 @@ bool Rotate_log_event::write()
@retval
0 ok
+ 1 error
*/
int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
{
+ int error= 0;
Relay_log_info *rli= rgi->rli;
DBUG_ENTER("Rotate_log_event::do_update_pos");
@@ -6456,7 +6458,7 @@ int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
(ulong) rli->group_master_log_pos));
mysql_mutex_unlock(&rli->data_lock);
rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
- flush_relay_log_info(rli);
+ error= flush_relay_log_info(rli);
/*
Reset thd->variables.option_bits and sql_mode etc, because this could
@@ -6474,8 +6476,7 @@ int Rotate_log_event::do_update_pos(rpl_group_info *rgi)
else
rgi->inc_event_relay_log_pos();
-
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
@@ -8235,6 +8236,7 @@ void Stop_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
int Stop_log_event::do_update_pos(rpl_group_info *rgi)
{
+ int error= 0;
Relay_log_info *rli= rgi->rli;
DBUG_ENTER("Stop_log_event::do_update_pos");
/*
@@ -8250,9 +8252,10 @@ int Stop_log_event::do_update_pos(rpl_group_info *rgi)
{
rpl_global_gtid_slave_state->record_and_update_gtid(thd, rgi);
rli->inc_group_relay_log_pos(0, rgi);
- flush_relay_log_info(rli);
+ if (flush_relay_log_info(rli))
+ error= 1;
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
#endif /* !MYSQL_CLIENT */
@@ -10298,8 +10301,8 @@ int
Rows_log_event::do_update_pos(rpl_group_info *rgi)
{
Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Rows_log_event::do_update_pos");
int error= 0;
+ DBUG_ENTER("Rows_log_event::do_update_pos");
DBUG_PRINT("info", ("flags: %s",
get_flags(STMT_END_F) ? "STMT_END_F " : ""));
@@ -10311,7 +10314,7 @@ Rows_log_event::do_update_pos(rpl_group_info *rgi)
Step the group log position if we are not in a transaction,
otherwise increase the event log position.
*/
- rli->stmt_done(log_pos, thd, rgi);
+ error= rli->stmt_done(log_pos, thd, rgi);
/*
Clear any errors in thd->net.last_err*. It is not known if this is
needed or not. It is believed that any errors that may exist in
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 0502f20d2b1..59f704d8474 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1746,8 +1746,8 @@ int
Old_rows_log_event::do_update_pos(rpl_group_info *rgi)
{
Relay_log_info *rli= rgi->rli;
- DBUG_ENTER("Old_rows_log_event::do_update_pos");
int error= 0;
+ DBUG_ENTER("Old_rows_log_event::do_update_pos");
DBUG_PRINT("info", ("flags: %s",
get_flags(STMT_END_F) ? "STMT_END_F " : ""));
@@ -1759,7 +1759,7 @@ Old_rows_log_event::do_update_pos(rpl_group_info *rgi)
Step the group log position if we are not in a transaction,
otherwise increase the event log position.
*/
- rli->stmt_done(log_pos, thd, rgi);
+ error= rli->stmt_done(log_pos, thd, rgi);
/*
Clear any errors in thd->net.last_err*. It is not known if this is
needed or not. It is believed that any errors that may exist in
diff --git a/sql/mysql_install_db.cc b/sql/mysql_install_db.cc
index c23a20ebac9..de799874a8f 100644
--- a/sql/mysql_install_db.cc
+++ b/sql/mysql_install_db.cc
@@ -386,8 +386,8 @@ static int register_service()
CloseServiceHandle(sc_manager);
die("CreateService failed (%u)", GetLastError());
}
-
- SERVICE_DESCRIPTION sd= { "MariaDB database server" };
+ char description[] = "MariaDB database server";
+ SERVICE_DESCRIPTION sd= { description };
ChangeServiceConfig2(sc_service, SERVICE_CONFIG_DESCRIPTION, &sd);
CloseServiceHandle(sc_service);
CloseServiceHandle(sc_manager);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5ff56daf7c2..90607882aa4 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -714,12 +714,15 @@ mysql_mutex_t
LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create,
LOCK_crypt,
LOCK_global_system_variables,
- LOCK_user_conn, LOCK_slave_list, LOCK_active_mi,
+ LOCK_user_conn, LOCK_slave_list,
LOCK_connection_count, LOCK_error_messages, LOCK_slave_background;
mysql_mutex_t LOCK_stats, LOCK_global_user_client_stats,
LOCK_global_table_stats, LOCK_global_index_stats;
+/* This protects against changes in master_info_index */
+mysql_mutex_t LOCK_active_mi;
+
/**
The below lock protects access to two global server variables:
max_prepared_stmt_count and prepared_stmt_count. These variables
@@ -877,7 +880,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_system_variables_hash, key_LOCK_thd_data,
key_LOCK_user_conn, key_LOCK_uuid_short_generator, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
- key_master_info_sleep_lock,
+ key_master_info_sleep_lock, key_master_info_start_stop_lock,
key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock,
key_rpl_group_info_sleep_lock,
key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
@@ -949,6 +952,7 @@ static PSI_mutex_info all_server_mutexes[]=
{ &key_LOCK_uuid_short_generator, "LOCK_uuid_short_generator", PSI_FLAG_GLOBAL},
{ &key_LOG_LOCK_log, "LOG::LOCK_log", 0},
{ &key_master_info_data_lock, "Master_info::data_lock", 0},
+ { &key_master_info_start_stop_lock, "Master_info::start_stop_lock", 0},
{ &key_master_info_run_lock, "Master_info::run_lock", 0},
{ &key_master_info_sleep_lock, "Master_info::sleep_lock", 0},
{ &key_mutex_slave_reporting_capability_err_lock, "Slave_reporting_capability::err_lock", 0},
@@ -1434,7 +1438,7 @@ ulong query_cache_min_res_unit= QUERY_CACHE_MIN_RESULT_DATA_SIZE;
Query_cache query_cache;
#endif
#ifdef HAVE_SMEM
-char *shared_memory_base_name= default_shared_memory_base_name;
+const char *shared_memory_base_name= default_shared_memory_base_name;
my_bool opt_enable_shared_memory;
HANDLE smem_event_connect_request= 0;
#endif
@@ -1675,7 +1679,7 @@ static void close_connections(void)
mysql_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::deinit();
- end_slave();
+ slave_prepare_for_shutdown();
/*
Give threads time to die.
@@ -1752,6 +1756,7 @@ static void close_connections(void)
DBUG_PRINT("quit",("Unlocking LOCK_thread_count"));
mysql_mutex_unlock(&LOCK_thread_count);
}
+ end_slave();
/* All threads has now been aborted */
DBUG_PRINT("quit",("Waiting for threads to die (count=%u)",thread_count));
mysql_mutex_lock(&LOCK_thread_count);
@@ -2769,22 +2774,6 @@ void dec_connection_count(THD *thd)
/*
- Delete THD and decrement thread counters, including thread_running
-*/
-
-void delete_running_thd(THD *thd)
-{
- mysql_mutex_lock(&LOCK_thread_count);
- thd->unlink();
- mysql_mutex_unlock(&LOCK_thread_count);
-
- delete thd;
- dec_thread_running();
- thread_safe_decrement32(&thread_count);
- signal_thd_deleted();
-}
-
-/*
Send a signal to unblock close_conneciton() if there is no more
threads running with a THD attached
@@ -5294,15 +5283,13 @@ static int init_server_components()
if (opt_bin_log)
{
- /**
- * mutex lock is not needed here.
- * but to be able to have mysql_mutex_assert_owner() in code,
- * we do it anyway */
- mysql_mutex_lock(mysql_bin_log.get_log_lock());
- int r= mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0, 0,
+ int error;
+ mysql_mutex_t *log_lock= mysql_bin_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
+ error= mysql_bin_log.open(opt_bin_logname, LOG_BIN, 0, 0,
WRITE_CACHE, max_binlog_size, 0, TRUE);
- mysql_mutex_unlock(mysql_bin_log.get_log_lock());
- if (r)
+ mysql_mutex_unlock(log_lock);
+ if (error)
unireg_abort(1);
}
@@ -7652,17 +7639,14 @@ static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff,
var->type= SHOW_MY_BOOL;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_NOTE)))
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_NOTE);
- if (mi)
- tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_READING &&
- mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN);
+ tmp= (my_bool) (mi->slave_running == MYSQL_SLAVE_RUN_READING &&
+ mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
if (mi)
*((my_bool *)buff)= tmp;
else
@@ -7694,14 +7678,9 @@ static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff)
{
var->type= SHOW_LONGLONG;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
- *((longlong *)buff)= master_info_index->any_slave_sql_running();
- else
- *((longlong *)buff)= 0;
+ *((longlong *)buff)= any_slave_sql_running();
- mysql_mutex_unlock(&LOCK_active_mi);
return 0;
}
@@ -7709,23 +7688,17 @@ static int show_slaves_running(THD *thd, SHOW_VAR *var, char *buff)
static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope)
{
- Master_info *mi= NULL;
- longlong UNINIT_VAR(tmp);
+ Master_info *mi;
var->type= SHOW_LONGLONG;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_NOTE)))
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_NOTE);
- if (mi)
- tmp= mi->received_heartbeats;
+ *((longlong *)buff)= mi->received_heartbeats;
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
- if (mi)
- *((longlong *)buff)= tmp;
else
var->type= SHOW_UNDEF;
return 0;
@@ -7735,23 +7708,17 @@ static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff,
static int show_heartbeat_period(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope)
{
- Master_info *mi= NULL;
- float UNINIT_VAR(tmp);
+ Master_info *mi;
var->type= SHOW_CHAR;
var->value= buff;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_NOTE)))
{
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_NOTE);
- if (mi)
- tmp= mi->heartbeat_period;
+ sprintf(buff, "%.3f", mi->heartbeat_period);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
- if (mi)
- sprintf(buff, "%.3f", tmp);
else
var->type= SHOW_UNDEF;
return 0;
diff --git a/sql/mysqld.h b/sql/mysqld.h
index 52a4da77367..0e21b0f020a 100644
--- a/sql/mysqld.h
+++ b/sql/mysqld.h
@@ -83,7 +83,6 @@ void kill_mysql(void);
void close_connection(THD *thd, uint sql_errno= 0);
void handle_connection_in_main_thread(THD *thd);
void create_thread_to_handle_connection(THD *thd);
-void delete_running_thd(THD *thd);
void signal_thd_deleted();
void unlink_thd(THD *thd);
bool one_thread_per_connection_end(THD *thd, bool put_in_cache);
@@ -139,7 +138,8 @@ extern my_bool sp_automatic_privileges, opt_noacl;
extern ulong use_stat_tables;
extern my_bool opt_old_style_user_limits, trust_function_creators;
extern uint opt_crash_binlog_innodb;
-extern char *shared_memory_base_name, *mysqld_unix_port;
+extern const char *shared_memory_base_name;
+extern char *mysqld_unix_port;
extern my_bool opt_enable_shared_memory;
extern ulong opt_replicate_events_marked_for_skip;
extern char *default_tz_name;
@@ -293,7 +293,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_index, key_BINLOG_LOCK_xid_list,
key_LOCK_thd_data,
key_LOCK_user_conn, key_LOG_LOCK_log,
key_master_info_data_lock, key_master_info_run_lock,
- key_master_info_sleep_lock,
+ key_master_info_sleep_lock, key_master_info_start_stop_lock,
key_mutex_slave_reporting_capability_err_lock, key_relay_log_info_data_lock,
key_relay_log_info_log_space_lock, key_relay_log_info_run_lock,
key_rpl_group_info_sleep_lock,
diff --git a/sql/nt_servc.cc b/sql/nt_servc.cc
index d6a8eac7ed5..e05e43a0a59 100644
--- a/sql/nt_servc.cc
+++ b/sql/nt_servc.cc
@@ -508,7 +508,7 @@ BOOL NTService::IsService(LPCSTR ServiceName)
}
/* ------------------------------------------------------------------------
-------------------------------------------------------------------------- */
-BOOL NTService::got_service_option(char **argv, char *service_option)
+BOOL NTService::got_service_option(char **argv, const char *service_option)
{
char *option;
for (option= argv[1]; *option; option++)
diff --git a/sql/nt_servc.h b/sql/nt_servc.h
index 949499d8d7f..6781fe0ddfa 100644
--- a/sql/nt_servc.h
+++ b/sql/nt_servc.h
@@ -61,7 +61,7 @@ class NTService
BOOL SeekStatus(LPCSTR szInternName, int OperationType);
BOOL Remove(LPCSTR szInternName);
BOOL IsService(LPCSTR ServiceName);
- BOOL got_service_option(char **argv, char *service_option);
+ BOOL got_service_option(char **argv, const char *service_option);
BOOL is_super_user();
/*
diff --git a/sql/rpl_mi.cc b/sql/rpl_mi.cc
index 6048d26998b..3e73d80ef48 100644
--- a/sql/rpl_mi.cc
+++ b/sql/rpl_mi.cc
@@ -40,7 +40,9 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
sync_counter(0), heartbeat_period(0), received_heartbeats(0),
master_id(0), prev_master_id(0),
using_gtid(USE_GTID_NO), events_queued_since_last_gtid(0),
- gtid_reconnect_event_skip_count(0), gtid_event_seen(false)
+ gtid_reconnect_event_skip_count(0), gtid_event_seen(false),
+ in_start_all_slaves(0), in_stop_all_slaves(0),
+ users(0), killed(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
ssl_ca[0]= 0; ssl_capath[0]= 0; ssl_cert[0]= 0;
@@ -81,6 +83,8 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
bzero((char*) &file, sizeof(file));
mysql_mutex_init(key_master_info_run_lock, &run_lock, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_master_info_data_lock, &data_lock, MY_MUTEX_INIT_FAST);
+ mysql_mutex_init(key_master_info_start_stop_lock, &start_stop_lock,
+ MY_MUTEX_INIT_SLOW);
mysql_mutex_setflags(&run_lock, MYF_NO_DEADLOCK_DETECTION);
mysql_mutex_setflags(&data_lock, MYF_NO_DEADLOCK_DETECTION);
mysql_mutex_init(key_master_info_sleep_lock, &sleep_lock, MY_MUTEX_INIT_FAST);
@@ -90,8 +94,27 @@ Master_info::Master_info(LEX_STRING *connection_name_arg,
mysql_cond_init(key_master_info_sleep_cond, &sleep_cond, NULL);
}
+
+/**
+ Wait until no one is using Master_info
+*/
+
+void Master_info::wait_until_free()
+{
+ mysql_mutex_lock(&sleep_lock);
+ killed= 1;
+ while (users)
+ mysql_cond_wait(&sleep_cond, &sleep_lock);
+ mysql_mutex_unlock(&sleep_lock);
+}
+
+/**
+ Delete master_info
+*/
+
Master_info::~Master_info()
{
+ wait_until_free();
#ifdef WITH_WSREP
/*
Do not free "wsrep" rpl_filter. It will eventually be freed by
@@ -106,6 +129,7 @@ Master_info::~Master_info()
mysql_mutex_destroy(&run_lock);
mysql_mutex_destroy(&data_lock);
mysql_mutex_destroy(&sleep_lock);
+ mysql_mutex_destroy(&start_stop_lock);
mysql_cond_destroy(&data_cond);
mysql_cond_destroy(&start_cond);
mysql_cond_destroy(&stop_cond);
@@ -841,12 +865,28 @@ uchar *get_key_master_info(Master_info *mi, size_t *length,
return (uchar*) mi->cmp_connection_name.str;
}
+/*
+ Delete a master info
+
+ Called from my_hash_delete(&master_info_hash)
+ Stops associated slave threads and frees master_info
+*/
+
void free_key_master_info(Master_info *mi)
{
DBUG_ENTER("free_key_master_info");
+ mysql_mutex_unlock(&LOCK_active_mi);
+
+ /* Ensure that we are not in reset_slave while this is done */
+ mi->lock_slave_threads();
terminate_slave_threads(mi,SLAVE_FORCE_ALL);
+ /* We use 2 here instead of 1 just to make it easier when debugging */
+ mi->killed= 2;
end_master_info(mi);
+ mi->unlock_slave_threads();
delete mi;
+
+ mysql_mutex_lock(&LOCK_active_mi);
DBUG_VOID_RETURN;
}
@@ -1002,9 +1042,28 @@ Master_info_index::Master_info_index()
index_file.file= -1;
}
+
+/**
+ Free all connection threads
+
+ This is done during early stages of shutdown
+ to give connection threads and slave threads time
+ to die before ~Master_info_index is called
+*/
+
+void Master_info_index::free_connections()
+{
+ mysql_mutex_assert_owner(&LOCK_active_mi);
+ my_hash_reset(&master_info_hash);
+}
+
+
+/**
+ Free all connection threads and free structures
+*/
+
Master_info_index::~Master_info_index()
{
- /* This will close connection for all objects in the cache */
my_hash_free(&master_info_hash);
end_io_cache(&index_file);
if (index_file.file >= 0)
@@ -1027,7 +1086,6 @@ 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,
@@ -1075,7 +1133,6 @@ bool Master_info_index::init_all_master_info()
DBUG_RETURN(1);
}
- lock_slave_threads(mi);
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
create_logfile_name_with_suffix(buf_master_info_file,
@@ -1090,6 +1147,7 @@ bool Master_info_index::init_all_master_info()
sql_print_information("Reading Master_info: '%s' Relay_info:'%s'",
buf_master_info_file, buf_relay_log_info_file);
+ mi->lock_slave_threads();
if (init_master_info(mi, buf_master_info_file, buf_relay_log_info_file,
0, thread_mask))
{
@@ -1103,15 +1161,16 @@ bool Master_info_index::init_all_master_info()
if (master_info_index->add_master_info(mi, FALSE))
DBUG_RETURN(1);
succ_num++;
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
}
else
{
/* Master_info already in HASH */
sql_print_error(ER_THD_OR_DEFAULT(current_thd,
ER_CONNECTION_ALREADY_EXISTS),
+ (int) connection_name.length, connection_name.str,
(int) connection_name.length, connection_name.str);
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
delete mi;
}
continue;
@@ -1128,8 +1187,9 @@ bool Master_info_index::init_all_master_info()
/* Master_info was already registered */
sql_print_error(ER_THD_OR_DEFAULT(current_thd,
ER_CONNECTION_ALREADY_EXISTS),
+ (int) connection_name.length, connection_name.str,
(int) connection_name.length, connection_name.str);
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
delete mi;
continue;
}
@@ -1138,7 +1198,6 @@ bool Master_info_index::init_all_master_info()
if (master_info_index->add_master_info(mi, FALSE))
DBUG_RETURN(1);
succ_num++;
- unlock_slave_threads(mi);
if (!opt_skip_slave_start)
{
@@ -1160,6 +1219,7 @@ bool Master_info_index::init_all_master_info()
(int) connection_name.length,
connection_name.str);
}
+ mi->unlock_slave_threads();
}
}
@@ -1211,6 +1271,71 @@ bool Master_info_index::write_master_name_to_index_file(LEX_STRING *name,
/**
+ Get Master_info for a connection and lock the object from deletion
+
+ @param
+ connection_name Connection name
+ warning WARN_LEVEL_NOTE -> Don't print anything
+ WARN_LEVEL_WARN -> Issue warning if not exists
+ WARN_LEVEL_ERROR-> Issue error if not exists
+*/
+
+Master_info *get_master_info(const LEX_STRING *connection_name,
+ Sql_condition::enum_warning_level warning)
+{
+ Master_info *mi;
+ DBUG_ENTER("get_master_info");
+
+ /* Protect against inserts into hash */
+ mysql_mutex_lock(&LOCK_active_mi);
+ /*
+ The following can only be true during shutdown when slave has been killed
+ but some other threads are still trying to access slave statistics.
+ */
+ if (unlikely(!master_info_index))
+ {
+ if (warning != Sql_condition::WARN_LEVEL_NOTE)
+ my_error(WARN_NO_MASTER_INFO,
+ MYF(warning == Sql_condition::WARN_LEVEL_WARN ?
+ ME_JUST_WARNING : 0),
+ (int) connection_name->length, connection_name->str);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(0);
+ }
+ if ((mi= master_info_index->get_master_info(connection_name, warning)))
+ {
+ /*
+ We have to use sleep_lock here. If we would use LOCK_active_mi
+ then we would take locks in wrong order in Master_info::release()
+ */
+ mysql_mutex_lock(&mi->sleep_lock);
+ mi->users++;
+ DBUG_PRINT("info",("users: %d", mi->users));
+ mysql_mutex_unlock(&mi->sleep_lock);
+ }
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(mi);
+}
+
+
+/**
+ Release master info.
+ Signals ~Master_info that it's now safe to delete it
+*/
+
+void Master_info::release()
+{
+ mysql_mutex_lock(&sleep_lock);
+ if (!--users && killed)
+ {
+ /* Signal ~Master_info that it's ok to now free it */
+ mysql_cond_signal(&sleep_cond);
+ }
+ mysql_mutex_unlock(&sleep_lock);
+}
+
+
+/**
Get Master_info for a connection
@param
@@ -1232,8 +1357,6 @@ Master_info_index::get_master_info(const LEX_STRING *connection_name,
("connection_name: '%.*s'", (int) connection_name->length,
connection_name->str));
- mysql_mutex_assert_owner(&LOCK_active_mi);
-
/* Make name lower case for comparison */
res= strmake(buff, connection_name->str, connection_name->length);
my_casedn_str(system_charset_info, buff);
@@ -1299,7 +1422,12 @@ bool Master_info_index::check_duplicate_master_info(LEX_STRING *name_arg,
/* Add a Master_info class to Hash Table */
bool Master_info_index::add_master_info(Master_info *mi, bool write_to_file)
{
- if (!my_hash_insert(&master_info_hash, (uchar*) mi))
+ /*
+ We have to protect against shutdown to ensure we are not calling
+ my_hash_insert() while my_hash_free() is in progress
+ */
+ if (unlikely(shutdown_in_progress) ||
+ !my_hash_insert(&master_info_hash, (uchar*) mi))
{
if (global_system_variables.log_warnings > 1)
sql_print_information("Added new Master_info '%.*s' to hash table",
@@ -1325,105 +1453,131 @@ bool Master_info_index::add_master_info(Master_info *mi, bool write_to_file)
atomic
*/
-bool Master_info_index::remove_master_info(LEX_STRING *name)
+bool Master_info_index::remove_master_info(Master_info *mi)
{
- Master_info* mi;
DBUG_ENTER("remove_master_info");
+ mysql_mutex_assert_owner(&LOCK_active_mi);
- if ((mi= get_master_info(name, Sql_condition::WARN_LEVEL_WARN)))
+ // Delete Master_info and rewrite others to file
+ if (!my_hash_delete(&master_info_hash, (uchar*) mi))
{
- // Delete Master_info and rewrite others to file
- if (!my_hash_delete(&master_info_hash, (uchar*) mi))
+ File index_file_nr;
+
+ // Close IO_CACHE and FILE handler fisrt
+ end_io_cache(&index_file);
+ my_close(index_file.file, MYF(MY_WME));
+
+ // Reopen File and truncate it
+ if ((index_file_nr= my_open(index_file_name,
+ O_RDWR | O_CREAT | O_TRUNC | O_BINARY ,
+ MYF(MY_WME))) < 0 ||
+ init_io_cache(&index_file, index_file_nr,
+ IO_SIZE, WRITE_CACHE,
+ my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
+ 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
{
- File index_file_nr;
-
- // Close IO_CACHE and FILE handler fisrt
- end_io_cache(&index_file);
- my_close(index_file.file, MYF(MY_WME));
-
- // Reopen File and truncate it
- if ((index_file_nr= my_open(index_file_name,
- O_RDWR | O_CREAT | O_TRUNC | O_BINARY ,
- MYF(MY_WME))) < 0 ||
- init_io_cache(&index_file, index_file_nr,
- IO_SIZE, WRITE_CACHE,
- my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
- 0, MYF(MY_WME | MY_WAIT_IF_FULL)))
- {
- int error= my_errno;
- if (index_file_nr >= 0)
- my_close(index_file_nr,MYF(0));
-
- sql_print_error("Create of Master Info Index file '%s' failed with "
- "error: %M",
- index_file_name, error);
- DBUG_RETURN(TRUE);
- }
+ int error= my_errno;
+ if (index_file_nr >= 0)
+ my_close(index_file_nr,MYF(0));
- // Rewrite Master_info.index
- for (uint i= 0; i< master_info_hash.records; ++i)
- {
- Master_info *tmp_mi;
- tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i);
- write_master_name_to_index_file(&tmp_mi->connection_name, 0);
- }
- my_sync(index_file_nr, MYF(MY_WME));
+ sql_print_error("Create of Master Info Index file '%s' failed with "
+ "error: %M",
+ index_file_name, error);
+ DBUG_RETURN(TRUE);
+ }
+
+ // Rewrite Master_info.index
+ for (uint i= 0; i< master_info_hash.records; ++i)
+ {
+ Master_info *tmp_mi;
+ tmp_mi= (Master_info *) my_hash_element(&master_info_hash, i);
+ write_master_name_to_index_file(&tmp_mi->connection_name, 0);
}
+ if (my_sync(index_file_nr, MYF(MY_WME)))
+ DBUG_RETURN(TRUE);
}
DBUG_RETURN(FALSE);
}
/**
- Master_info_index::give_error_if_slave_running()
+ give_error_if_slave_running()
+
+ @param
+ already_locked 0 if we need to lock, 1 if we have LOCK_active_mi_locked
@return
TRUE If some slave is running. An error is printed
FALSE No slave is running
*/
-bool Master_info_index::give_error_if_slave_running()
+bool give_error_if_slave_running(bool already_locked)
{
+ bool ret= 0;
DBUG_ENTER("give_error_if_slave_running");
- mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ if (!already_locked)
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (!master_info_index)
{
- Master_info *mi;
- mi= (Master_info *) my_hash_element(&master_info_hash, i);
- if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
+ my_error(ER_SERVER_SHUTDOWN, MYF(0));
+ ret= 1;
+ }
+ else
+ {
+ HASH *hash= &master_info_index->master_info_hash;
+ for (uint i= 0; i< hash->records; ++i)
{
- my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length,
- mi->connection_name.str);
- DBUG_RETURN(TRUE);
+ Master_info *mi;
+ mi= (Master_info *) my_hash_element(hash, i);
+ if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
+ {
+ my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length,
+ mi->connection_name.str);
+ ret= 1;
+ break;
+ }
}
}
- DBUG_RETURN(FALSE);
+ if (!already_locked)
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(ret);
}
/**
- Master_info_index::any_slave_sql_running()
-
- The LOCK_active_mi must be held while calling this function.
+ any_slave_sql_running()
@return
0 No Slave SQL thread is running
# Number of slave SQL thread running
+
+ Note that during shutdown we return 1. This is needed to ensure we
+ don't try to resize thread pool during shutdown as during shutdown
+ master_info_hash may be freeing the hash and during that time
+ hash entries can't be accessed.
*/
-uint Master_info_index::any_slave_sql_running()
+uint any_slave_sql_running()
{
uint count= 0;
+ HASH *hash;
DBUG_ENTER("any_slave_sql_running");
- mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (unlikely(shutdown_in_progress || !master_info_index))
{
- Master_info *mi= (Master_info *)my_hash_element(&master_info_hash, i);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ DBUG_RETURN(1);
+ }
+ hash= &master_info_index->master_info_hash;
+ for (uint i= 0; i< hash->records; ++i)
+ {
+ Master_info *mi= (Master_info *)my_hash_element(hash, i);
if (mi->rli.slave_running != MYSQL_SLAVE_NOT_RUN)
count++;
}
+ mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(count);
}
@@ -1436,15 +1590,25 @@ uint Master_info_index::any_slave_sql_running()
@return
TRUE Error
FALSE Everything ok.
+
+ This code is written so that we don't keep LOCK_active_mi active
+ while we are starting a slave.
*/
bool Master_info_index::start_all_slaves(THD *thd)
{
bool result= FALSE;
- DBUG_ENTER("warn_if_slave_running");
+ DBUG_ENTER("start_all_slaves");
mysql_mutex_assert_owner(&LOCK_active_mi);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ for (uint i= 0; i< master_info_hash.records; i++)
+ {
+ Master_info *mi;
+ mi= (Master_info *) my_hash_element(&master_info_hash, i);
+ mi->in_start_all_slaves= 0;
+ }
+
+ for (uint i= 0; i< master_info_hash.records; )
{
int error;
Master_info *mi;
@@ -1454,25 +1618,40 @@ bool Master_info_index::start_all_slaves(THD *thd)
Try to start all slaves that are configured (host is defined)
and are not already running
*/
- if ((mi->slave_running == MYSQL_SLAVE_NOT_RUN ||
- !mi->rli.slave_running) && *mi->host)
+ if (!((mi->slave_running == MYSQL_SLAVE_NOT_RUN ||
+ !mi->rli.slave_running) && *mi->host) ||
+ mi->in_start_all_slaves)
{
- if ((error= start_slave(thd, mi, 1)))
- {
- my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
- "START",
- (int) mi->connection_name.length,
- mi->connection_name.str);
- result= 1;
- if (error < 0) // fatal error
- break;
- }
- else if (thd)
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SLAVE_STARTED, ER_THD(thd, ER_SLAVE_STARTED),
- (int) mi->connection_name.length,
- mi->connection_name.str);
+ i++;
+ continue;
}
+ mi->in_start_all_slaves= 1;
+
+ mysql_mutex_lock(&mi->sleep_lock);
+ mi->users++; // Mark used
+ mysql_mutex_unlock(&mi->sleep_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ error= start_slave(thd, mi, 1);
+ mi->release();
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (error)
+ {
+ my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
+ "START",
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ result= 1;
+ if (error < 0) // fatal error
+ break;
+ }
+ else if (thd)
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SLAVE_STARTED, ER_THD(thd, ER_SLAVE_STARTED),
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ /* Restart from first element as master_info_hash may have changed */
+ i= 0;
+ continue;
}
DBUG_RETURN(result);
}
@@ -1488,39 +1667,64 @@ bool Master_info_index::start_all_slaves(THD *thd)
@return
TRUE Error
FALSE Everything ok.
+
+ This code is written so that we don't keep LOCK_active_mi active
+ while we are stopping a slave.
*/
bool Master_info_index::stop_all_slaves(THD *thd)
{
bool result= FALSE;
- DBUG_ENTER("warn_if_slave_running");
+ DBUG_ENTER("stop_all_slaves");
mysql_mutex_assert_owner(&LOCK_active_mi);
DBUG_ASSERT(thd);
- for (uint i= 0; i< master_info_hash.records; ++i)
+ for (uint i= 0; i< master_info_hash.records; i++)
+ {
+ Master_info *mi;
+ mi= (Master_info *) my_hash_element(&master_info_hash, i);
+ mi->in_stop_all_slaves= 0;
+ }
+
+ for (uint i= 0; i< master_info_hash.records ;)
{
int error;
Master_info *mi;
mi= (Master_info *) my_hash_element(&master_info_hash, i);
- if ((mi->slave_running != MYSQL_SLAVE_NOT_RUN ||
- mi->rli.slave_running))
+ if (!(mi->slave_running != MYSQL_SLAVE_NOT_RUN ||
+ mi->rli.slave_running) ||
+ mi->in_stop_all_slaves)
{
- if ((error= stop_slave(thd, mi, 1)))
- {
- my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
- "STOP",
- (int) mi->connection_name.length,
- mi->connection_name.str);
- result= 1;
- if (error < 0) // Fatal error
- break;
- }
- else
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
- ER_SLAVE_STOPPED, ER_THD(thd, ER_SLAVE_STOPPED),
- (int) mi->connection_name.length,
- mi->connection_name.str);
+ i++;
+ continue;
}
+ mi->in_stop_all_slaves= 1; // Protection for loops
+
+ mysql_mutex_lock(&mi->sleep_lock);
+ mi->users++; // Mark used
+ mysql_mutex_unlock(&mi->sleep_lock);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ error= stop_slave(thd, mi, 1);
+ mi->release();
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (error)
+ {
+ my_error(ER_CANT_START_STOP_SLAVE, MYF(0),
+ "STOP",
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ result= 1;
+ if (error < 0) // Fatal error
+ break;
+ }
+ else
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
+ ER_SLAVE_STOPPED, ER_THD(thd, ER_SLAVE_STOPPED),
+ (int) mi->connection_name.length,
+ mi->connection_name.str);
+ /* Restart from first element as master_info_hash may have changed */
+ i= 0;
+ continue;
}
DBUG_RETURN(result);
}
diff --git a/sql/rpl_mi.h b/sql/rpl_mi.h
index 9365c065ea9..31c0f280ac1 100644
--- a/sql/rpl_mi.h
+++ b/sql/rpl_mi.h
@@ -187,6 +187,10 @@ class Master_info : public Slave_reporting_capability
return opt_slave_parallel_threads > 0 &&
parallel_mode > SLAVE_PARALLEL_NONE;
}
+ void release();
+ void wait_until_free();
+ void lock_slave_threads();
+ void unlock_slave_threads();
/* the variables below are needed because we can change masters on the fly */
char master_log_name[FN_REFLEN+6]; /* Room for multi-*/
@@ -205,7 +209,7 @@ class Master_info : public Slave_reporting_capability
File fd; // we keep the file open, so we need to remember the file pointer
IO_CACHE file;
- mysql_mutex_t data_lock, run_lock, sleep_lock;
+ mysql_mutex_t data_lock, run_lock, sleep_lock, start_stop_lock;
mysql_cond_t data_cond, start_cond, stop_cond, sleep_cond;
THD *io_thd;
MYSQL* mysql;
@@ -297,6 +301,9 @@ class Master_info : public Slave_reporting_capability
uint64 gtid_reconnect_event_skip_count;
/* gtid_event_seen is false until we receive first GTID event from master. */
bool gtid_event_seen;
+ bool in_start_all_slaves, in_stop_all_slaves;
+ uint users; /* Active user for object */
+ uint killed;
/* domain-id based filter */
Domain_id_filter domain_id_filter;
@@ -341,13 +348,12 @@ public:
bool check_duplicate_master_info(LEX_STRING *connection_name,
const char *host, uint port);
bool add_master_info(Master_info *mi, bool write_to_file);
- bool remove_master_info(LEX_STRING *connection_name);
+ bool remove_master_info(Master_info *mi);
Master_info *get_master_info(const LEX_STRING *connection_name,
Sql_condition::enum_warning_level warning);
- bool give_error_if_slave_running();
- uint any_slave_sql_running();
bool start_all_slaves(THD *thd);
bool stop_all_slaves(THD *thd);
+ void free_connections();
};
@@ -360,6 +366,8 @@ public:
};
+Master_info *get_master_info(const LEX_STRING *connection_name,
+ Sql_condition::enum_warning_level warning);
bool check_master_connection_name(LEX_STRING *name);
void create_logfile_name_with_suffix(char *res_file_name, size_t length,
const char *info_file,
@@ -369,5 +377,8 @@ void create_logfile_name_with_suffix(char *res_file_name, size_t length,
uchar *get_key_master_info(Master_info *mi, size_t *length,
my_bool not_used __attribute__((unused)));
void free_key_master_info(Master_info *mi);
+uint any_slave_sql_running();
+bool give_error_if_slave_running(bool already_lock);
+
#endif /* HAVE_REPLICATION */
#endif /* RPL_MI_H */
diff --git a/sql/rpl_parallel.cc b/sql/rpl_parallel.cc
index 1959f6bc4bb..a814628e72c 100644
--- a/sql/rpl_parallel.cc
+++ b/sql/rpl_parallel.cc
@@ -1313,39 +1313,16 @@ handle_rpl_parallel_thread(void *arg)
*/
rpt->batch_free();
- for (;;)
+ if ((events= rpt->event_queue) != NULL)
{
- if ((events= rpt->event_queue) != NULL)
- {
- /*
- Take next group of events from the replication pool.
- This is faster than having to wakeup the pool manager thread to give
- us a new event.
- */
- rpt->dequeue1(events);
- mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
- goto more_events;
- }
- if (!rpt->pause_for_ftwrl ||
- (in_event_group && !group_rgi->parallel_entry->force_abort))
- break;
/*
- We are currently in the delicate process of pausing parallel
- replication while FLUSH TABLES WITH READ LOCK is starting. We must
- not de-allocate the thread (setting rpt->current_owner= NULL) until
- rpl_unpause_after_ftwrl() has woken us up.
+ Take next group of events from the replication pool.
+ This is faster than having to wakeup the pool manager thread to give
+ us a new event.
*/
- mysql_mutex_lock(&rpt->current_entry->LOCK_parallel_entry);
+ rpt->dequeue1(events);
mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
- if (rpt->pause_for_ftwrl)
- mysql_cond_wait(&rpt->current_entry->COND_parallel_entry,
- &rpt->current_entry->LOCK_parallel_entry);
- mysql_mutex_unlock(&rpt->current_entry->LOCK_parallel_entry);
- mysql_mutex_lock(&rpt->LOCK_rpl_thread);
- /*
- Now loop to check again for more events available, since we released
- and re-aquired the LOCK_rpl_thread mutex.
- */
+ goto more_events;
}
rpt->inuse_relaylog_refcount_update();
@@ -1372,11 +1349,36 @@ handle_rpl_parallel_thread(void *arg)
}
if (!in_event_group)
{
+ /* If we are in a FLUSH TABLES FOR READ LOCK, wait for it */
+ while (rpt->current_entry && rpt->pause_for_ftwrl)
+ {
+ /*
+ We are currently in the delicate process of pausing parallel
+ replication while FLUSH TABLES WITH READ LOCK is starting. We must
+ not de-allocate the thread (setting rpt->current_owner= NULL) until
+ rpl_unpause_after_ftwrl() has woken us up.
+ */
+ rpl_parallel_entry *e= rpt->current_entry;
+ /*
+ Ensure that we will unblock rpl_pause_for_ftrwl()
+ e->pause_sub_id may be LONGLONG_MAX if rpt->current_entry has changed
+ */
+ DBUG_ASSERT(e->pause_sub_id == (uint64)ULONGLONG_MAX ||
+ e->last_committed_sub_id >= e->pause_sub_id);
+ mysql_mutex_lock(&e->LOCK_parallel_entry);
+ mysql_mutex_unlock(&rpt->LOCK_rpl_thread);
+ if (rpt->pause_for_ftwrl)
+ mysql_cond_wait(&e->COND_parallel_entry, &e->LOCK_parallel_entry);
+ mysql_mutex_unlock(&e->LOCK_parallel_entry);
+ mysql_mutex_lock(&rpt->LOCK_rpl_thread);
+ }
+
rpt->current_owner= NULL;
/* Tell wait_for_done() that we are done, if it is waiting. */
if (likely(rpt->current_entry) &&
unlikely(rpt->current_entry->force_abort))
mysql_cond_broadcast(&rpt->COND_rpl_thread_stop);
+
rpt->current_entry= NULL;
if (!rpt->stop)
rpt->pool->release_thread(rpt);
@@ -1416,10 +1418,24 @@ dealloc_gco(group_commit_orderer *gco)
my_free(gco);
}
+/**
+ Change thread count for global parallel worker threads
+
+ @param pool parallel thread pool
+ @param new_count Number of threads to be in pool. 0 in shutdown
+ @param force Force thread count to new_count even if slave
+ threads are running
+
+ By default we don't resize pool of there are running threads.
+ However during shutdown we will always do it.
+ This is needed as any_slave_sql_running() returns 1 during shutdown
+ as we don't want to access master_info while
+ Master_info_index::free_connections are running.
+*/
static int
rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
- uint32 new_count)
+ uint32 new_count, bool force)
{
uint32 i;
rpl_parallel_thread **old_list= NULL;
@@ -1431,6 +1447,28 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
if ((res= pool_mark_busy(pool, current_thd)))
return res;
+ /* Protect against parallel pool resizes */
+ if (pool->count == new_count)
+ {
+ pool_mark_not_busy(pool);
+ return 0;
+ }
+
+ /*
+ If we are about to delete pool, do an extra check that there are no new
+ slave threads running since we marked pool busy
+ */
+ if (!new_count && !force)
+ {
+ if (any_slave_sql_running())
+ {
+ DBUG_PRINT("warning",
+ ("SQL threads running while trying to reset parallel pool"));
+ pool_mark_not_busy(pool);
+ return 0; // Ok to not resize pool
+ }
+ }
+
/*
Allocate the new list of threads up-front.
That way, if we fail half-way, we only need to free whatever we managed
@@ -1444,7 +1482,7 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
{
my_error(ER_OUTOFMEMORY, MYF(0), (int(new_count*sizeof(*new_list) +
new_count*sizeof(*rpt_array))));
- goto err;;
+ goto err;
}
for (i= 0; i < new_count; ++i)
@@ -1569,12 +1607,26 @@ err:
return 1;
}
+/*
+ Deactivate the parallel replication thread pool, if there are now no more
+ SQL threads running.
+*/
+
+int rpl_parallel_resize_pool_if_no_slaves(void)
+{
+ /* master_info_index is set to NULL on shutdown */
+ if (opt_slave_parallel_threads > 0 && !any_slave_sql_running())
+ return rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
+ return 0;
+}
+
int
rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
{
if (!pool->count)
- return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads);
+ return rpl_parallel_change_thread_count(pool, opt_slave_parallel_threads,
+ 0);
return 0;
}
@@ -1582,7 +1634,7 @@ rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
int
rpl_parallel_inactivate_pool(rpl_parallel_thread_pool *pool)
{
- return rpl_parallel_change_thread_count(pool, 0);
+ return rpl_parallel_change_thread_count(pool, 0, 0);
}
@@ -1860,7 +1912,7 @@ rpl_parallel_thread_pool::destroy()
{
if (!inited)
return;
- rpl_parallel_change_thread_count(this, 0);
+ rpl_parallel_change_thread_count(this, 0, 1);
mysql_mutex_destroy(&LOCK_rpl_thread_pool);
mysql_cond_destroy(&COND_rpl_thread_pool);
inited= false;
@@ -1879,6 +1931,7 @@ rpl_parallel_thread_pool::get_thread(rpl_parallel_thread **owner,
{
rpl_parallel_thread *rpt;
+ DBUG_ASSERT(count > 0);
mysql_mutex_lock(&LOCK_rpl_thread_pool);
while (unlikely(busy) || !(rpt= free_list))
mysql_cond_wait(&COND_rpl_thread_pool, &LOCK_rpl_thread_pool);
@@ -2107,6 +2160,11 @@ rpl_parallel::find(uint32 domain_id)
return e;
}
+/**
+ Wait until all sql worker threads has stopped processing
+
+ This is called when sql thread has been killed/stopped
+*/
void
rpl_parallel::wait_for_done(THD *thd, Relay_log_info *rli)
diff --git a/sql/rpl_parallel.h b/sql/rpl_parallel.h
index c6f77b0144c..a0faeae815c 100644
--- a/sql/rpl_parallel.h
+++ b/sql/rpl_parallel.h
@@ -365,6 +365,7 @@ struct rpl_parallel {
extern struct rpl_parallel_thread_pool global_rpl_thread_pool;
+extern int rpl_parallel_resize_pool_if_no_slaves(void);
extern int rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool);
extern int rpl_parallel_inactivate_pool(rpl_parallel_thread_pool *pool);
extern bool process_gtid_for_restart_pos(Relay_log_info *rli, rpl_gtid *gtid);
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index 03f0f4fdf53..1b969fb4257 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -208,6 +208,7 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
Master_info* mi= rli->mi;
char buf_relay_logname[FN_REFLEN], buf_relaylog_index_name_buff[FN_REFLEN];
char *buf_relaylog_index_name= opt_relaylog_index_name;
+ mysql_mutex_t *log_lock;
create_logfile_name_with_suffix(buf_relay_logname,
sizeof(buf_relay_logname),
@@ -227,14 +228,18 @@ a file name for --relay-log-index option", opt_relaylog_index_name);
note, that if open() fails, we'll still have index file open
but a destructor will take care of that
*/
+ log_lock= rli->relay_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
if (rli->relay_log.open_index_file(buf_relaylog_index_name, ln, TRUE) ||
rli->relay_log.open(ln, LOG_BIN, 0, 0, SEQ_READ_APPEND,
mi->rli.max_relay_log_size, 1, TRUE))
{
+ mysql_mutex_unlock(log_lock);
mysql_mutex_unlock(&rli->data_lock);
sql_print_error("Failed when trying to open logs for '%s' in init_relay_log_info(). Error: %M", ln, my_errno);
DBUG_RETURN(1);
}
+ mysql_mutex_unlock(log_lock);
}
/* if file does not exist */
@@ -424,7 +429,7 @@ Failed to open the existing relay log info file '%s' (errno %d)",
}
rli->inited= 1;
mysql_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(error);
+ DBUG_RETURN(0);
err:
sql_print_error("%s", msg);
@@ -1289,9 +1294,10 @@ bool Relay_log_info::is_until_satisfied(my_off_t master_beg_pos)
}
-void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
+bool Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
rpl_group_info *rgi)
{
+ int error= 0;
DBUG_ENTER("Relay_log_info::stmt_done");
DBUG_ASSERT(rgi->rli == this);
@@ -1343,10 +1349,11 @@ void Relay_log_info::stmt_done(my_off_t event_master_log_pos, THD *thd,
}
DBUG_EXECUTE_IF("inject_crash_before_flush_rli", DBUG_SUICIDE(););
if (mi->using_gtid == Master_info::USE_GTID_NO)
- flush_relay_log_info(this);
+ if (flush_relay_log_info(this))
+ error= 1;
DBUG_EXECUTE_IF("inject_crash_after_flush_rli", DBUG_SUICIDE(););
}
- DBUG_VOID_RETURN;
+ DBUG_RETURN(error);
}
diff --git a/sql/rpl_rli.h b/sql/rpl_rli.h
index 96c3e7c3fac..b9fc2127440 100644
--- a/sql/rpl_rli.h
+++ b/sql/rpl_rli.h
@@ -416,7 +416,7 @@ public:
relay log info and used to produce information for <code>SHOW
SLAVE STATUS</code>.
*/
- void stmt_done(my_off_t event_log_pos, THD *thd, rpl_group_info *rgi);
+ bool stmt_done(my_off_t event_log_pos, THD *thd, rpl_group_info *rgi);
int alloc_inuse_relaylog(const char *name);
void free_inuse_relaylog(inuse_relaylog *ir);
void reset_inuse_relaylog();
diff --git a/sql/slave.cc b/sql/slave.cc
index 717d37a7907..47bdf5eb3e8 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -232,16 +232,14 @@ void init_thread_mask(int* mask,Master_info* mi,bool inverse)
/*
- lock_slave_threads()
+ lock_slave_threads() against other threads doing STOP, START or RESET SLAVE
+
*/
-void lock_slave_threads(Master_info* mi)
+void Master_info::lock_slave_threads()
{
DBUG_ENTER("lock_slave_threads");
-
- //TODO: see if we can do this without dual mutex
- mysql_mutex_lock(&mi->run_lock);
- mysql_mutex_lock(&mi->rli.run_lock);
+ mysql_mutex_lock(&start_stop_lock);
DBUG_VOID_RETURN;
}
@@ -250,13 +248,10 @@ void lock_slave_threads(Master_info* mi)
unlock_slave_threads()
*/
-void unlock_slave_threads(Master_info* mi)
+void Master_info::unlock_slave_threads()
{
DBUG_ENTER("unlock_slave_threads");
-
- //TODO: see if we can do this without dual mutex
- mysql_mutex_unlock(&mi->rli.run_lock);
- mysql_mutex_unlock(&mi->run_lock);
+ mysql_mutex_unlock(&start_stop_lock);
DBUG_VOID_RETURN;
}
@@ -472,7 +467,6 @@ int init_slave()
accepted. However bootstrap may conflict with us if it does START SLAVE.
So it's safer to take the lock.
*/
- mysql_mutex_lock(&LOCK_active_mi);
if (pthread_key_create(&RPL_MASTER_INFO, NULL))
goto err;
@@ -481,7 +475,6 @@ int init_slave()
if (!master_info_index || master_info_index->init_all_master_info())
{
sql_print_error("Failed to initialize multi master structures");
- mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(1);
}
if (!(active_mi= new Master_info(&default_master_connection_name,
@@ -540,7 +533,6 @@ int init_slave()
}
end:
- mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(error);
err:
@@ -713,6 +705,7 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
if (!mi->inited)
DBUG_RETURN(0); /* successfully do nothing */
int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
+ int retval= 0;
mysql_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
mysql_mutex_t *log_lock= mi->rli.relay_log.get_log_lock();
@@ -732,24 +725,19 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
+ retval= error;
mysql_mutex_lock(log_lock);
DBUG_PRINT("info",("Flushing relay-log info file."));
if (current_thd)
THD_STAGE_INFO(current_thd, stage_flushing_relay_log_info_file);
- if (flush_relay_log_info(&mi->rli))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
-
- if (my_sync(mi->rli.info_fd, MYF(MY_WME)))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+ if (flush_relay_log_info(&mi->rli) ||
+ my_sync(mi->rli.info_fd, MYF(MY_WME)))
+ retval= ER_ERROR_DURING_FLUSH_LOGS;
mysql_mutex_unlock(log_lock);
}
- if (opt_slave_parallel_threads > 0 &&
- master_info_index &&// master_info_index is set to NULL on server shutdown
- !master_info_index->any_slave_sql_running())
- rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
if (thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL))
{
DBUG_PRINT("info",("Terminating IO thread"));
@@ -760,25 +748,26 @@ int terminate_slave_threads(Master_info* mi,int thread_mask,bool skip_lock)
skip_lock)) &&
!force_all)
DBUG_RETURN(error);
+ if (!retval)
+ retval= error;
mysql_mutex_lock(log_lock);
DBUG_PRINT("info",("Flushing relay log and master info file."));
if (current_thd)
THD_STAGE_INFO(current_thd, stage_flushing_relay_log_and_master_info_repository);
- if (flush_master_info(mi, TRUE, FALSE))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
-
+ if (likely(mi->fd >= 0))
+ {
+ if (flush_master_info(mi, TRUE, FALSE) || my_sync(mi->fd, MYF(MY_WME)))
+ retval= ER_ERROR_DURING_FLUSH_LOGS;
+ }
if (mi->rli.relay_log.is_open() &&
my_sync(mi->rli.relay_log.get_log_file()->file, MYF(MY_WME)))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
-
- if (my_sync(mi->fd, MYF(MY_WME)))
- DBUG_RETURN(ER_ERROR_DURING_FLUSH_LOGS);
+ retval= ER_ERROR_DURING_FLUSH_LOGS;
mysql_mutex_unlock(log_lock);
}
- DBUG_RETURN(0);
+ DBUG_RETURN(retval);
}
@@ -941,6 +930,15 @@ int start_slave_thread(
mysql_mutex_unlock(start_lock);
DBUG_RETURN(ER_SLAVE_THREAD);
}
+
+ /*
+ In the following loop we can't check for thd->killed as we have to
+ wait until THD structures for the slave thread are created
+ before we can return.
+ This should be ok as there is no major work done in the slave
+ threads before they signal that we can stop waiting.
+ */
+
if (start_cond && cond_lock) // caller has cond_lock
{
THD* thd = current_thd;
@@ -958,16 +956,9 @@ int start_slave_thread(
registered, we could otherwise go waiting though thd->killed is
set.
*/
- if (!thd->killed)
- mysql_cond_wait(start_cond, cond_lock);
+ mysql_cond_wait(start_cond, cond_lock);
thd->EXIT_COND(& saved_stage);
mysql_mutex_lock(cond_lock); // re-acquire it as exit_cond() released
- if (thd->killed)
- {
- if (start_lock)
- mysql_mutex_unlock(start_lock);
- DBUG_RETURN(thd->killed_errno());
- }
}
}
if (start_lock)
@@ -1056,10 +1047,7 @@ int start_slave_threads(THD *thd,
mi);
if (!error && (thread_mask & SLAVE_SQL))
{
- if (opt_slave_parallel_threads > 0)
- error= rpl_parallel_activate_pool(&global_rpl_thread_pool);
- if (!error)
- error= start_slave_thread(
+ error= start_slave_thread(
#ifdef HAVE_PSI_INTERFACE
key_thread_slave_sql,
#endif
@@ -1075,10 +1063,18 @@ int start_slave_threads(THD *thd,
/*
- Release slave threads at time of executing shutdown.
+ Kill slaves preparing for shutdown
+*/
- SYNOPSIS
- end_slave()
+void slave_prepare_for_shutdown()
+{
+ mysql_mutex_lock(&LOCK_active_mi);
+ master_info_index->free_connections();
+ mysql_mutex_unlock(&LOCK_active_mi);
+}
+
+/*
+ Release slave threads at time of executing shutdown.
*/
void end_slave()
@@ -1096,7 +1092,10 @@ void end_slave()
startup parameter to the server was wrong.
*/
mysql_mutex_lock(&LOCK_active_mi);
- /* This will call terminate_slave_threads() on all connections */
+ /*
+ master_info_index should not have any threads anymore as they where
+ killed as part of slave_prepare_for_shutdown()
+ */
delete master_info_index;
master_info_index= 0;
active_mi= 0;
@@ -2867,7 +2866,9 @@ static bool send_show_master_info_data(THD *thd, Master_info *mi, bool full,
mysql_mutex_lock(&mi->data_lock);
mysql_mutex_lock(&mi->rli.data_lock);
+ /* err_lock is to protect mi->last_error() */
mysql_mutex_lock(&mi->err_lock);
+ /* err_lock is to protect mi->rli.last_error() */
mysql_mutex_lock(&mi->rli.err_lock);
protocol->store(mi->host, &my_charset_bin);
protocol->store(mi->user, &my_charset_bin);
@@ -4715,6 +4716,16 @@ pthread_handler_t handle_slave_sql(void *arg)
rli->slave_running= MYSQL_SLAVE_RUN_NOT_CONNECT;
pthread_detach_this_thread();
+
+ if (opt_slave_parallel_threads > 0 &&
+ rpl_parallel_activate_pool(&global_rpl_thread_pool))
+ {
+ mysql_cond_broadcast(&rli->start_cond);
+ rli->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR, NULL,
+ "Failed during parallel slave pool activation");
+ goto err_during_init;
+ }
+
if (init_slave_thread(thd, mi, SLAVE_THD_SQL))
{
/*
@@ -5016,8 +5027,15 @@ pthread_handler_t handle_slave_sql(void *arg)
if (rli->mi->using_gtid != Master_info::USE_GTID_NO)
{
ulong domain_count;
+ my_bool save_log_all_errors= thd->log_all_errors;
+ /*
+ We don't need to check return value for flush_relay_log_info()
+ as any errors should be logged to stderr
+ */
+ thd->log_all_errors= 1;
flush_relay_log_info(rli);
+ thd->log_all_errors= save_log_all_errors;
if (mi->using_parallel())
{
/*
@@ -5126,17 +5144,7 @@ err_during_init:
DBUG_EXECUTE_IF("simulate_slave_delay_at_terminate_bug38694", sleep(5););
mysql_mutex_unlock(&rli->run_lock); // tell the world we are done
- /*
- Deactivate the parallel replication thread pool, if there are now no more
- SQL threads running. Do this here, when we have released all locks, but
- while our THD (and current_thd) is still valid.
- */
- mysql_mutex_lock(&LOCK_active_mi);
- if (opt_slave_parallel_threads > 0 &&
- master_info_index &&// master_info_index is set to NULL on server shutdown
- !master_info_index->any_slave_sql_running())
- rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
- mysql_mutex_unlock(&LOCK_active_mi);
+ rpl_parallel_resize_pool_if_no_slaves();
mysql_mutex_lock(&LOCK_thread_count);
thd->unlink();
@@ -6295,6 +6303,7 @@ err:
void end_relay_log_info(Relay_log_info* rli)
{
+ mysql_mutex_t *log_lock;
DBUG_ENTER("end_relay_log_info");
if (!rli->inited)
@@ -6312,8 +6321,11 @@ void end_relay_log_info(Relay_log_info* rli)
rli->cur_log_fd = -1;
}
rli->inited = 0;
+ log_lock= rli->relay_log.get_log_lock();
+ mysql_mutex_lock(log_lock);
rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
rli->relay_log.harvest_bytes_written(&rli->log_space_total);
+ mysql_mutex_unlock(log_lock);
/*
Delete the slave's temporary tables from memory.
In the future there will be other actions than this, to ensure persistance
@@ -6464,7 +6476,7 @@ static int connect_to_master(THD* thd, MYSQL* mysql, Master_info* mi,
suppress_warnings= 0;
mi->report(ERROR_LEVEL, last_errno, NULL,
"error %s to master '%s@%s:%d'"
- " - retry-time: %d retries: %lu message: %s",
+ " - retry-time: %d maximum-retries: %lu message: %s",
(reconnect ? "reconnecting" : "connecting"),
mi->user, mi->host, mi->port,
mi->connect_retry, master_retry_count,
@@ -7026,9 +7038,12 @@ static Log_event* next_event(rpl_group_info *rgi, ulonglong *event_size)
}
rli->event_relay_log_pos = BIN_LOG_HEADER_SIZE;
strmake_buf(rli->event_relay_log_name,rli->linfo.log_file_name);
- flush_relay_log_info(rli);
+ if (flush_relay_log_info(rli))
+ {
+ errmsg= "error flushing relay log";
+ goto err;
+ }
}
-
/*
Now we want to open this next log. To know if it's a hot log (the one
being written by the I/O thread now) or a cold log, we can use
diff --git a/sql/slave.h b/sql/slave.h
index a78ae4cff6f..58c8106614d 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -220,13 +220,12 @@ bool rpl_master_erroneous_autoinc(THD* thd);
const char *print_slave_db_safe(const char *db);
void skip_load_data_infile(NET* net);
+void slave_prepare_for_shutdown();
void end_slave(); /* release slave threads */
void close_active_mi(); /* clean up slave threads data */
void clear_until_condition(Relay_log_info* rli);
void clear_slave_error(Relay_log_info* rli);
void end_relay_log_info(Relay_log_info* rli);
-void lock_slave_threads(Master_info* mi);
-void unlock_slave_threads(Master_info* mi);
void init_thread_mask(int* mask,Master_info* mi,bool inverse);
Format_description_log_event *
read_relay_log_description_event(IO_CACHE *cur_log, ulonglong start_pos,
diff --git a/sql/sql_alter.h b/sql/sql_alter.h
index 526442e83e2..7114694124b 100644
--- a/sql/sql_alter.h
+++ b/sql/sql_alter.h
@@ -70,59 +70,56 @@ public:
// Set for DISABLE KEYS | ENABLE KEYS
static const uint ALTER_KEYS_ONOFF = 1L << 9;
- // Set for CONVERT TO CHARACTER SET
- static const uint ALTER_CONVERT = 1L << 10;
-
// Set for FORCE
// Set for ENGINE(same engine)
// Set by mysql_recreate_table()
- static const uint ALTER_RECREATE = 1L << 11;
+ static const uint ALTER_RECREATE = 1L << 10;
// Set for ADD PARTITION
- static const uint ALTER_ADD_PARTITION = 1L << 12;
+ static const uint ALTER_ADD_PARTITION = 1L << 11;
// Set for DROP PARTITION
- static const uint ALTER_DROP_PARTITION = 1L << 13;
+ static const uint ALTER_DROP_PARTITION = 1L << 12;
// Set for COALESCE PARTITION
- static const uint ALTER_COALESCE_PARTITION = 1L << 14;
+ static const uint ALTER_COALESCE_PARTITION = 1L << 13;
// Set for REORGANIZE PARTITION ... INTO
- static const uint ALTER_REORGANIZE_PARTITION = 1L << 15;
+ static const uint ALTER_REORGANIZE_PARTITION = 1L << 14;
// Set for partition_options
- static const uint ALTER_PARTITION = 1L << 16;
+ static const uint ALTER_PARTITION = 1L << 15;
// Set for LOAD INDEX INTO CACHE ... PARTITION
// Set for CACHE INDEX ... PARTITION
- static const uint ALTER_ADMIN_PARTITION = 1L << 17;
+ static const uint ALTER_ADMIN_PARTITION = 1L << 16;
// Set for REORGANIZE PARTITION
- static const uint ALTER_TABLE_REORG = 1L << 18;
+ static const uint ALTER_TABLE_REORG = 1L << 17;
// Set for REBUILD PARTITION
- static const uint ALTER_REBUILD_PARTITION = 1L << 19;
+ static const uint ALTER_REBUILD_PARTITION = 1L << 18;
// Set for partitioning operations specifying ALL keyword
- static const uint ALTER_ALL_PARTITION = 1L << 20;
+ static const uint ALTER_ALL_PARTITION = 1L << 19;
// Set for REMOVE PARTITIONING
- static const uint ALTER_REMOVE_PARTITIONING = 1L << 21;
+ static const uint ALTER_REMOVE_PARTITIONING = 1L << 20;
// Set for ADD FOREIGN KEY
- static const uint ADD_FOREIGN_KEY = 1L << 22;
+ static const uint ADD_FOREIGN_KEY = 1L << 21;
// Set for DROP FOREIGN KEY
- static const uint DROP_FOREIGN_KEY = 1L << 23;
+ static const uint DROP_FOREIGN_KEY = 1L << 22;
// Set for EXCHANGE PARITION
- static const uint ALTER_EXCHANGE_PARTITION = 1L << 24;
+ static const uint ALTER_EXCHANGE_PARTITION = 1L << 23;
// Set by Sql_cmd_alter_table_truncate_partition::execute()
- static const uint ALTER_TRUNCATE_PARTITION = 1L << 25;
+ static const uint ALTER_TRUNCATE_PARTITION = 1L << 24;
// Set for ADD [COLUMN] FIRST | AFTER
- static const uint ALTER_COLUMN_ORDER = 1L << 26;
+ static const uint ALTER_COLUMN_ORDER = 1L << 25;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 860a2c52ab5..9c56b7d8f22 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -6674,7 +6674,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
if (!table_ref->belong_to_view &&
!table_ref->belong_to_derived)
{
- SELECT_LEX *current_sel= thd->lex->current_select;
+ SELECT_LEX *current_sel= item->context->select_lex;
SELECT_LEX *last_select= table_ref->select_lex;
bool all_merged= TRUE;
for (SELECT_LEX *sl= current_sel; sl && sl!=last_select;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 7585e49390f..fb58519b816 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -7066,7 +7066,13 @@ wait_for_commit::reinit()
So in this case, do a re-init of the mutex. In release builds, we want to
avoid the overhead of a re-init though.
+
+ To ensure that no one is locking the mutex, we take a lock of it first.
+ For full explanation, see wait_for_commit::~wait_for_commit()
*/
+ mysql_mutex_lock(&LOCK_wait_commit);
+ mysql_mutex_unlock(&LOCK_wait_commit);
+
mysql_mutex_destroy(&LOCK_wait_commit);
mysql_mutex_init(key_LOCK_wait_commit, &LOCK_wait_commit, MY_MUTEX_INIT_FAST);
#endif
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index dadb03abfff..45815fe7a02 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2446,7 +2446,7 @@ static bool do_execute_sp(THD *thd, sp_head *sp)
int
mysql_execute_command(THD *thd)
{
- int res= FALSE;
+ int res= 0;
int up_result= 0;
LEX *lex= thd->lex;
/* first SELECT_LEX (have special meaning for many of non-SELECTcommands) */
@@ -3119,10 +3119,17 @@ mysql_execute_command(THD *thd)
if (check_global_access(thd, SUPER_ACL))
goto error;
+ /*
+ In this code it's ok to use LOCK_active_mi as we are adding new things
+ into master_info_index
+ */
mysql_mutex_lock(&LOCK_active_mi);
-
if (!master_info_index)
+ {
+ mysql_mutex_unlock(&LOCK_active_mi);
+ my_error(ER_SERVER_SHUTDOWN, MYF(0));
goto error;
+ }
mi= master_info_index->get_master_info(&lex_mi->connection_name,
Sql_condition::WARN_LEVEL_NOTE);
@@ -3151,7 +3158,7 @@ mysql_execute_command(THD *thd)
If new master was not added, we still need to free mi.
*/
if (master_info_added)
- master_info_index->remove_master_info(&lex_mi->connection_name);
+ master_info_index->remove_master_info(mi);
else
delete mi;
}
@@ -3169,22 +3176,24 @@ mysql_execute_command(THD *thd)
/* Accept one of two privileges */
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
- mysql_mutex_lock(&LOCK_active_mi);
if (lex->verbose)
+ {
+ mysql_mutex_lock(&LOCK_active_mi);
res= show_all_master_info(thd);
+ mysql_mutex_unlock(&LOCK_active_mi);
+ }
else
{
LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
Master_info *mi;
- mi= master_info_index->get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR);
- if (mi != NULL)
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
res= show_master_info(thd, mi, 0);
+ mi->release();
}
}
- mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SHOW_MASTER_STAT:
@@ -3528,22 +3537,23 @@ end_with_restore_list:
load_error= rpl_load_gtid_slave_state(thd);
- mysql_mutex_lock(&LOCK_active_mi);
-
- if ((mi= (master_info_index->
- get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR))))
+ /*
+ We don't need to ensure that only one user is using master_info
+ as start_slave is protected against simultaneous usage
+ */
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
if (load_error)
{
/*
- We cannot start a slave using GTID if we cannot load the GTID position
- from the mysql.gtid_slave_pos table. But we can allow non-GTID
- replication (useful eg. during upgrade).
+ We cannot start a slave using GTID if we cannot load the
+ GTID position from the mysql.gtid_slave_pos table. But we
+ can allow non-GTID replication (useful eg. during upgrade).
*/
if (mi->using_gtid != Master_info::USE_GTID_NO)
{
- mysql_mutex_unlock(&LOCK_active_mi);
+ mi->release();
break;
}
else
@@ -3551,8 +3561,8 @@ end_with_restore_list:
}
if (!start_slave(thd, mi, 1 /* net report*/))
my_ok(thd);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
break;
}
case SQLCOM_SLAVE_STOP:
@@ -3582,13 +3592,17 @@ end_with_restore_list:
}
lex_mi= &thd->lex->mi;
- mysql_mutex_lock(&LOCK_active_mi);
- if ((mi= (master_info_index->
- get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR))))
- if (!stop_slave(thd, mi, 1/* net report*/))
+ if ((mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
+ {
+ if (stop_slave(thd, mi, 1/* net report*/))
+ res= 1;
+ mi->release();
+ if (rpl_parallel_resize_pool_if_no_slaves())
+ res= 1;
+ if (!res)
my_ok(thd);
- mysql_mutex_unlock(&LOCK_active_mi);
+ }
break;
}
case SQLCOM_SLAVE_ALL_START:
@@ -4900,11 +4914,13 @@ end_with_restore_list:
reload_acl_and_cache binlog interactions failed
*/
res= 1;
- }
+ }
if (!res)
my_ok(thd);
}
+ else
+ res= 1; // reload_acl_and_cache failed
#ifdef HAVE_REPLICATION
if (lex->type & REFRESH_READ_LOCK)
rpl_unpause_after_ftwrl(thd);
diff --git a/sql/sql_reload.cc b/sql/sql_reload.cc
index e361ed8b6e6..995c4c0a838 100644
--- a/sql/sql_reload.cc
+++ b/sql/sql_reload.cc
@@ -181,24 +181,20 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
slave is not likely to have the same connection names.
*/
tmp_write_to_binlog= 0;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if (!(mi= (get_master_info(&connection_name,
+ Sql_condition::WARN_LEVEL_ERROR))))
{
- 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);
- }
+ result= 1;
+ }
+ else
+ {
+ mysql_mutex_lock(&mi->data_lock);
+ if (rotate_relay_log(mi))
+ *write_to_binlog= -1;
+ mysql_mutex_unlock(&mi->data_lock);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
#endif
}
#ifdef HAVE_QUERY_CACHE
@@ -375,27 +371,33 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
Master_info *mi;
tmp_write_to_binlog= 0;
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index)
+
+ if (!(mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
- 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))
+ result= 1;
+ }
+ else
+ {
+ /* The following will fail if slave is running */
+ if (reset_slave(thd, mi))
{
+ mi->release();
/* 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);
+ mi->release();
+ mysql_mutex_lock(&LOCK_active_mi);
+ if (master_info_index->remove_master_info(mi))
+ result= 1;
+ mysql_mutex_unlock(&LOCK_active_mi);
}
+ else
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
}
#endif
if (options & REFRESH_USER_RESOURCES)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 0dd4c59ce56..6fedda95959 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -3041,7 +3041,16 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
relay_log_info_file, 0,
&mi->cmp_connection_name);
- lock_slave_threads(mi); // this allows us to cleanly read slave_running
+ mi->lock_slave_threads();
+ if (mi->killed)
+ {
+ /* connection was deleted while we waited for lock_slave_threads */
+ mi->unlock_slave_threads();
+ my_error(WARN_NO_MASTER_INFO, mi->connection_name.length,
+ mi->connection_name.str);
+ DBUG_RETURN(-1);
+ }
+
// Get a mask of _stopped_ threads
init_thread_mask(&thread_mask,mi,1 /* inverse */);
@@ -3176,7 +3185,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
if (!slave_errno)
slave_errno = start_slave_threads(thd,
- 0 /*no mutex */,
+ 1,
1 /* wait for start */,
mi,
master_info_file_tmp,
@@ -3192,7 +3201,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
}
err:
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
thd_proc_info(thd, 0);
if (slave_errno)
@@ -3233,8 +3242,12 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
DBUG_RETURN(-1);
THD_STAGE_INFO(thd, stage_killing_slave);
int thread_mask;
- lock_slave_threads(mi);
- // Get a mask of _running_ threads
+ mi->lock_slave_threads();
+ /*
+ Get a mask of _running_ threads.
+ We don't have to test for mi->killed as the thread_mask will take care
+ of checking if threads exists
+ */
init_thread_mask(&thread_mask,mi,0 /* not inverse*/);
/*
Below we will stop all running threads.
@@ -3247,8 +3260,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
if (thread_mask)
{
- slave_errno= terminate_slave_threads(mi,thread_mask,
- 1 /*skip lock */);
+ slave_errno= terminate_slave_threads(mi,thread_mask, 0 /* get lock */);
}
else
{
@@ -3257,7 +3269,8 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
push_warning(thd, Sql_condition::WARN_LEVEL_NOTE, ER_SLAVE_WAS_NOT_RUNNING,
ER_THD(thd, ER_SLAVE_WAS_NOT_RUNNING));
}
- unlock_slave_threads(mi);
+
+ mi->unlock_slave_threads();
if (slave_errno)
{
@@ -3292,11 +3305,20 @@ int reset_slave(THD *thd, Master_info* mi)
char relay_log_info_file_tmp[FN_REFLEN];
DBUG_ENTER("reset_slave");
- lock_slave_threads(mi);
+ mi->lock_slave_threads();
+ if (mi->killed)
+ {
+ /* connection was deleted while we waited for lock_slave_threads */
+ mi->unlock_slave_threads();
+ my_error(WARN_NO_MASTER_INFO, mi->connection_name.length,
+ mi->connection_name.str);
+ DBUG_RETURN(-1);
+ }
+
init_thread_mask(&thread_mask,mi,0 /* not inverse */);
if (thread_mask) // We refuse if any slave thread is running
{
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
my_error(ER_SLAVE_MUST_STOP, MYF(0), (int) mi->connection_name.length,
mi->connection_name.str);
DBUG_RETURN(ER_SLAVE_MUST_STOP);
@@ -3359,7 +3381,7 @@ int reset_slave(THD *thd, Master_info* mi)
RUN_HOOK(binlog_relay_io, after_reset_slave, (thd, mi));
err:
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
if (error)
my_error(sql_errno, MYF(0), errmsg);
DBUG_RETURN(error);
@@ -3474,8 +3496,8 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
DBUG_ENTER("change_master");
- mysql_mutex_assert_owner(&LOCK_active_mi);
DBUG_ASSERT(master_info_index);
+ mysql_mutex_assert_owner(&LOCK_active_mi);
*master_info_added= false;
/*
@@ -3495,7 +3517,16 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
lex_mi->port))
DBUG_RETURN(TRUE);
- lock_slave_threads(mi);
+ mi->lock_slave_threads();
+ if (mi->killed)
+ {
+ /* connection was deleted while we waited for lock_slave_threads */
+ mi->unlock_slave_threads();
+ my_error(WARN_NO_MASTER_INFO, mi->connection_name.length,
+ mi->connection_name.str);
+ DBUG_RETURN(TRUE);
+ }
+
init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
if (thread_mask) // We refuse if any slave thread is running
{
@@ -3816,12 +3847,13 @@ bool change_master(THD* thd, Master_info* mi, bool *master_info_added)
in-memory value at restart (thus causing errors, as the old relay log does
not exist anymore).
*/
- flush_relay_log_info(&mi->rli);
+ if (flush_relay_log_info(&mi->rli))
+ ret= 1;
mysql_cond_broadcast(&mi->data_cond);
mysql_mutex_unlock(&mi->rli.data_lock);
err:
- unlock_slave_threads(mi);
+ mi->unlock_slave_threads();
if (ret == FALSE)
my_ok(thd);
DBUG_RETURN(ret);
@@ -3901,13 +3933,9 @@ bool mysql_show_binlog_events(THD* thd)
{
if (!lex_mi->connection_name.str)
lex_mi->connection_name= thd->variables.default_master_connection;
- mysql_mutex_lock(&LOCK_active_mi);
- if (!master_info_index ||
- !(mi= master_info_index->
- get_master_info(&lex_mi->connection_name,
- Sql_condition::WARN_LEVEL_ERROR)))
+ if (!(mi= get_master_info(&lex_mi->connection_name,
+ Sql_condition::WARN_LEVEL_ERROR)))
{
- mysql_mutex_unlock(&LOCK_active_mi);
DBUG_RETURN(TRUE);
}
binary_log= &(mi->rli.relay_log);
@@ -3926,7 +3954,7 @@ bool mysql_show_binlog_events(THD* thd)
if (mi)
{
/* We can unlock the mutex as we have a lock on the file */
- mysql_mutex_unlock(&LOCK_active_mi);
+ mi->release();
mi= 0;
}
@@ -3948,6 +3976,7 @@ bool mysql_show_binlog_events(THD* thd)
goto err;
}
+ /* These locks is here to enable syncronization with log_in_use() */
mysql_mutex_lock(&LOCK_thread_count);
thd->current_linfo = &linfo;
mysql_mutex_unlock(&LOCK_thread_count);
@@ -4061,7 +4090,7 @@ bool mysql_show_binlog_events(THD* thd)
mysql_mutex_unlock(log_lock);
}
else if (mi)
- mysql_mutex_unlock(&LOCK_active_mi);
+ mi->release();
// Check that linfo is still on the function scope.
DEBUG_SYNC(thd, "after_show_binlog_events");
@@ -4082,8 +4111,9 @@ err:
else
my_eof(thd);
+ /* These locks is here to enable syncronization with log_in_use() */
mysql_mutex_lock(&LOCK_thread_count);
- thd->current_linfo = 0;
+ thd->current_linfo= 0;
mysql_mutex_unlock(&LOCK_thread_count);
thd->variables.max_allowed_packet= old_max_allowed_packet;
DBUG_RETURN(ret);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index ebbec8c4c83..27d1b96886c 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6450,6 +6450,9 @@ static bool fill_alter_inplace_info(THD *thd,
new_key->user_defined_key_parts))
goto index_changed;
+ if (table_key->block_size != new_key->block_size)
+ goto index_changed;
+
if (engine_options_differ(table_key->option_struct, new_key->option_struct,
table->file->ht->index_options))
goto index_changed;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 09dda0809de..efbc896b94a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -7533,7 +7533,7 @@ alter_list_item:
$5->name, $4->csname));
if (Lex->create_info.add_alter_list_item_convert_to_charset($5))
MYSQL_YYABORT;
- Lex->alter_info.flags|= Alter_info::ALTER_CONVERT;
+ Lex->alter_info.flags|= Alter_info::ALTER_OPTIONS;
}
| create_table_options_space_separated
{
diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc
index 02dad1d1ca7..1a6bb9a4e54 100644
--- a/sql/sys_vars.cc
+++ b/sql/sys_vars.cc
@@ -1586,7 +1586,6 @@ bool
Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var)
{
String str, *res;
- bool running;
DBUG_ASSERT(var->type == OPT_GLOBAL);
@@ -1597,11 +1596,7 @@ Sys_var_gtid_slave_pos::do_check(THD *thd, set_var *var)
return true;
}
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
+ if (give_error_if_slave_running(0))
return true;
if (!(res= var->value->val_str(&str)))
return true;
@@ -1639,7 +1634,7 @@ Sys_var_gtid_slave_pos::global_update(THD *thd, set_var *var)
mysql_mutex_unlock(&LOCK_global_system_variables);
mysql_mutex_lock(&LOCK_active_mi);
- if (!master_info_index || master_info_index->give_error_if_slave_running())
+ if (give_error_if_slave_running(1))
err= true;
else
err= rpl_gtid_pos_update(thd, var->save_result.string_value.str,
@@ -1825,16 +1820,7 @@ Sys_var_last_gtid::session_value_ptr(THD *thd, const LEX_STRING *base)
static bool
check_slave_parallel_threads(sys_var *self, THD *thd, set_var *var)
{
- bool running;
-
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
- return true;
-
- return false;
+ return give_error_if_slave_running(0);
}
static bool
@@ -1843,10 +1829,7 @@ fix_slave_parallel_threads(sys_var *self, THD *thd, enum_var_type type)
bool err;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- err= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
+ err= give_error_if_slave_running(0);
mysql_mutex_lock(&LOCK_global_system_variables);
return err;
@@ -1869,16 +1852,7 @@ static Sys_var_ulong Sys_slave_parallel_threads(
static bool
check_slave_domain_parallel_threads(sys_var *self, THD *thd, set_var *var)
{
- bool running;
-
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
- return true;
-
- return false;
+ return give_error_if_slave_running(0);
}
static bool
@@ -1887,13 +1861,10 @@ fix_slave_domain_parallel_threads(sys_var *self, THD *thd, enum_var_type type)
bool running;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
+ running= give_error_if_slave_running(0);
mysql_mutex_lock(&LOCK_global_system_variables);
- return running ? true : false;
+ return running;
}
@@ -2036,16 +2007,7 @@ static Sys_var_bit Sys_skip_parallel_replication(
static bool
check_gtid_ignore_duplicates(sys_var *self, THD *thd, set_var *var)
{
- bool running;
-
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
- if (running)
- return true;
-
- return false;
+ return give_error_if_slave_running(0);
}
static bool
@@ -2054,13 +2016,10 @@ fix_gtid_ignore_duplicates(sys_var *self, THD *thd, enum_var_type type)
bool running;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- running= (!master_info_index ||
- master_info_index->give_error_if_slave_running());
- mysql_mutex_unlock(&LOCK_active_mi);
+ running= give_error_if_slave_running(0);
mysql_mutex_lock(&LOCK_global_system_variables);
- return running ? true : false;
+ return running;
}
@@ -2969,10 +2928,8 @@ Sys_var_replicate_events_marked_for_skip::global_update(THD *thd, set_var *var)
DBUG_ENTER("Sys_var_replicate_events_marked_for_skip::global_update");
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- if (master_info_index && !master_info_index->give_error_if_slave_running())
+ if (!give_error_if_slave_running(0))
result= Sys_var_enum::global_update(thd, var);
- mysql_mutex_unlock(&LOCK_active_mi);
mysql_mutex_lock(&LOCK_global_system_variables);
DBUG_RETURN(result);
}
@@ -4294,35 +4251,31 @@ static Sys_var_mybool Sys_relay_log_recovery(
bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
{
bool result= true; // Assume error
- Master_info *mi;
LEX_STRING *base_name= &var->base;
if (!base_name->length)
base_name= &thd->variables.default_master_connection;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
-
- mi= master_info_index->
- get_master_info(base_name, !base_name->length ?
- Sql_condition::WARN_LEVEL_ERROR :
- Sql_condition::WARN_LEVEL_WARN);
- if (mi)
+
+ if (Master_info *mi= get_master_info(base_name, !var->base.length ?
+ Sql_condition::WARN_LEVEL_ERROR :
+ Sql_condition::WARN_LEVEL_WARN))
{
if (mi->rli.slave_running)
{
my_error(ER_SLAVE_MUST_STOP, MYF(0),
- mi->connection_name.length,
- mi->connection_name.str);
+ mi->connection_name.length,
+ mi->connection_name.str);
result= true;
}
else
{
result= set_filter_value(var->save_result.string_value.str, mi);
}
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
mysql_mutex_lock(&LOCK_global_system_variables);
return result;
}
@@ -4332,6 +4285,8 @@ bool Sys_var_rpl_filter::set_filter_value(const char *value, Master_info *mi)
bool status= true;
Rpl_filter* rpl_filter= mi->rpl_filter;
+ /* Proctect against other threads */
+ mysql_mutex_lock(&LOCK_active_mi);
switch (opt_id) {
case OPT_REPLICATE_DO_DB:
status= rpl_filter->set_do_db(value);
@@ -4352,7 +4307,7 @@ bool Sys_var_rpl_filter::set_filter_value(const char *value, Master_info *mi)
status= rpl_filter->set_wild_ignore_table(value);
break;
}
-
+ mysql_mutex_unlock(&LOCK_active_mi);
return status;
}
@@ -4366,23 +4321,20 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd,
Rpl_filter *rpl_filter;
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
-
- mi= master_info_index->
- get_master_info(base_name, !base_name->length ?
- Sql_condition::WARN_LEVEL_ERROR :
- Sql_condition::WARN_LEVEL_WARN);
-
- mysql_mutex_lock(&LOCK_global_system_variables);
+ mi= get_master_info(base_name, !base_name->length ?
+ Sql_condition::WARN_LEVEL_ERROR :
+ Sql_condition::WARN_LEVEL_WARN);
if (!mi)
{
- mysql_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_global_system_variables);
return 0;
}
+
rpl_filter= mi->rpl_filter;
tmp.length(0);
+ mysql_mutex_lock(&LOCK_active_mi);
switch (opt_id) {
case OPT_REPLICATE_DO_DB:
rpl_filter->get_do_db(&tmp);
@@ -4403,9 +4355,12 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd,
rpl_filter->get_wild_ignore_table(&tmp);
break;
}
+ mysql_mutex_unlock(&LOCK_active_mi);
+ mysql_mutex_lock(&LOCK_global_system_variables);
+
+ mi->release();
ret= (uchar *) thd->strmake(tmp.ptr(), tmp.length());
- mysql_mutex_unlock(&LOCK_active_mi);
return ret;
}
@@ -4474,17 +4429,12 @@ get_master_info_ulonglong_value(THD *thd, ptrdiff_t offset)
Master_info *mi;
ulonglong res= 0; // Default value
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_WARN);
- if (mi)
+ if ((mi= get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_WARN)))
{
- mysql_mutex_lock(&mi->rli.data_lock);
res= *((ulonglong*) (((uchar*) mi) + master_info_offset));
- mysql_mutex_unlock(&mi->rli.data_lock);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
mysql_mutex_lock(&LOCK_global_system_variables);
return res;
}
@@ -4499,19 +4449,16 @@ bool update_multi_source_variable(sys_var *self_var, THD *thd,
if (type == OPT_GLOBAL)
mysql_mutex_unlock(&LOCK_global_system_variables);
- mysql_mutex_lock(&LOCK_active_mi);
- mi= master_info_index->
- get_master_info(&thd->variables.default_master_connection,
- Sql_condition::WARN_LEVEL_ERROR);
- if (mi)
+ if ((mi= (get_master_info(&thd->variables.default_master_connection,
+ Sql_condition::WARN_LEVEL_ERROR))))
{
mysql_mutex_lock(&mi->rli.run_lock);
mysql_mutex_lock(&mi->rli.data_lock);
result= self->update_variable(thd, mi);
mysql_mutex_unlock(&mi->rli.data_lock);
mysql_mutex_unlock(&mi->rli.run_lock);
+ mi->release();
}
- mysql_mutex_unlock(&LOCK_active_mi);
if (type == OPT_GLOBAL)
mysql_mutex_lock(&LOCK_global_system_variables);
return result;