MDEV-9573 'Stop slave' hangs on replication slave
The reason for this is that stop slave takes LOCK_active_mi over the whole operation while some slave operations will also need LOCK_active_mi which causes deadlocks. Fixed by introducing object counting for Master_info and not taking LOCK_active_mi over stop slave or even stop_all_slaves() Another benefit of this approach is that it allows: - Multiple threads can run SHOW SLAVE STATUS at the same time - START/STOP/RESET/SLAVE STATUS on a slave will not block other slaves - Simpler interface for handling get_master_info() - Added some missing unlock of 'log_lock' in error condtions - Moved rpl_parallel_inactivate_pool(&global_rpl_thread_pool) to end of stop_slave() to not have to use LOCK_active_mi inside terminate_slave_threads() - Changed argument for remove_master_info() to Master_info, as we always have this available - Fixed core dump when doing FLUSH TABLES WITH READ LOCK and parallel replication. Problem was that waiting for pause_for_ftwrl was not done when deleting rpt->current_owner after a force_abort.
This commit is contained in:
parent
d5c54f3990
commit
e65f667bb6
@ -1815,6 +1815,7 @@ int my_b_flush_io_cache(IO_CACHE *info,
|
||||
It's currently safe to call this if one has called init_io_cache()
|
||||
on the 'info' object, even if init_io_cache() failed.
|
||||
This function is also safe to call twice with the same handle.
|
||||
Note that info->file is not reset as the caller may still use ut for my_close()
|
||||
|
||||
RETURN
|
||||
0 ok
|
||||
@ -1850,10 +1851,12 @@ int end_io_cache(IO_CACHE *info)
|
||||
if (info->type == SEQ_READ_APPEND)
|
||||
{
|
||||
/* Destroy allocated mutex */
|
||||
info->type= TYPE_NOT_SET;
|
||||
mysql_mutex_destroy(&info->append_buffer_lock);
|
||||
}
|
||||
info->share= 0;
|
||||
info->type= TYPE_NOT_SET; /* Ensure that flush_io_cache() does nothing */
|
||||
info->write_end= 0; /* Ensure that my_b_write() fails */
|
||||
info->write_function= 0; /* my_b_write will crash if used */
|
||||
DBUG_RETURN(error);
|
||||
} /* end_io_cache */
|
||||
|
||||
|
@ -3958,12 +3958,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)
|
||||
@ -3971,6 +3966,7 @@ longlong Item_master_pos_wait::val_int()
|
||||
null_value = 1;
|
||||
event_count=0;
|
||||
}
|
||||
mi->release();
|
||||
#endif
|
||||
return event_count;
|
||||
|
||||
|
@ -702,12 +702,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_init;
|
||||
|
||||
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
|
||||
@ -1651,7 +1654,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.
|
||||
@ -1700,6 +1703,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);
|
||||
@ -7214,17 +7218,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);
|
||||
mi->release();
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_active_mi);
|
||||
if (mi)
|
||||
*((my_bool *)buff)= tmp;
|
||||
else
|
||||
@ -7256,38 +7257,26 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
static int show_slave_received_heartbeats(THD *thd, SHOW_VAR *var, char *buff)
|
||||
{
|
||||
Master_info *mi= NULL;
|
||||
longlong tmp;
|
||||
LINT_INIT(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;
|
||||
@ -7297,23 +7286,16 @@ 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)
|
||||
{
|
||||
Master_info *mi= NULL;
|
||||
float tmp;
|
||||
LINT_INIT(tmp);
|
||||
|
||||
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;
|
||||
|
249
sql/rpl_mi.cc
249
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;
|
||||
@ -87,8 +89,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();
|
||||
rpl_filters.delete_element(connection_name.str, connection_name.length,
|
||||
(void (*)(const char*, uchar*)) free_rpl_filter);
|
||||
my_free(connection_name.str);
|
||||
@ -709,8 +730,13 @@ uchar *get_key_master_info(Master_info *mi, size_t *length,
|
||||
void free_key_master_info(Master_info *mi)
|
||||
{
|
||||
DBUG_ENTER("free_key_master_info");
|
||||
/* Ensure that we are not in reset_slave while this is done */
|
||||
lock_slave_threads(mi);
|
||||
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);
|
||||
unlock_slave_threads(mi);
|
||||
delete mi;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -867,9 +893,27 @@ 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()
|
||||
{
|
||||
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)
|
||||
@ -1001,7 +1045,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)
|
||||
{
|
||||
@ -1022,6 +1065,7 @@ bool Master_info_index::init_all_master_info()
|
||||
(int) connection_name.length,
|
||||
connection_name.str);
|
||||
}
|
||||
unlock_slave_threads(mi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1072,6 +1116,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(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
|
||||
|
||||
@ -1094,8 +1203,6 @@ 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);
|
||||
|
||||
/* Make name lower case for comparison */
|
||||
res= strmake(buff, connection_name->str, connection_name->length);
|
||||
my_casedn_str(system_charset_info, buff);
|
||||
@ -1187,13 +1294,11 @@ 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))
|
||||
{
|
||||
@ -1229,63 +1334,83 @@ bool Master_info_index::remove_master_info(LEX_STRING *name)
|
||||
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));
|
||||
}
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
Master_info *mi;
|
||||
mi= (Master_info *) my_hash_element(&master_info_hash, i);
|
||||
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);
|
||||
DBUG_RETURN(TRUE);
|
||||
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
|
||||
*/
|
||||
|
||||
uint Master_info_index::any_slave_sql_running()
|
||||
uint any_slave_sql_running()
|
||||
{
|
||||
uint count= 0;
|
||||
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 (likely(master_info_index)) // Not shutdown
|
||||
{
|
||||
Master_info *mi= (Master_info *)my_hash_element(&master_info_hash, i);
|
||||
HASH *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);
|
||||
}
|
||||
|
||||
@ -1298,15 +1423,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;
|
||||
@ -1316,10 +1451,23 @@ 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)))
|
||||
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",
|
||||
@ -1334,7 +1482,9 @@ bool Master_info_index::start_all_slaves(THD *thd)
|
||||
ER_SLAVE_STARTED, ER(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);
|
||||
}
|
||||
@ -1348,23 +1498,46 @@ 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);
|
||||
|
||||
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)))
|
||||
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",
|
||||
@ -1379,7 +1552,9 @@ bool Master_info_index::stop_all_slaves(THD *thd)
|
||||
ER_SLAVE_STOPPED, ER(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);
|
||||
}
|
||||
|
16
sql/rpl_mi.h
16
sql/rpl_mi.h
@ -79,6 +79,8 @@ class Master_info : public Slave_reporting_capability
|
||||
{
|
||||
return opt_slave_parallel_threads > 0;
|
||||
}
|
||||
void release();
|
||||
void wait_until_free();
|
||||
|
||||
/* the variables below are needed because we can change masters on the fly */
|
||||
char master_log_name[FN_REFLEN+6]; /* Room for multi-*/
|
||||
@ -182,7 +184,11 @@ 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;
|
||||
};
|
||||
|
||||
int init_master_info(Master_info* mi, const char* master_info_fname,
|
||||
const char* slave_info_fname,
|
||||
bool abort_if_no_master_info_file,
|
||||
@ -218,13 +224,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(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();
|
||||
};
|
||||
|
||||
|
||||
@ -237,6 +242,8 @@ public:
|
||||
};
|
||||
|
||||
|
||||
Master_info *get_master_info(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,
|
||||
@ -246,7 +253,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 */
|
||||
|
@ -1312,6 +1312,29 @@ 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) &&
|
||||
@ -1369,6 +1392,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)
|
||||
{
|
||||
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
|
||||
@ -1382,7 +1427,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)
|
||||
@ -1503,6 +1548,20 @@ 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() &&
|
||||
master_info_index)
|
||||
return rpl_parallel_inactivate_pool(&global_rpl_thread_pool);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
rpl_parallel_activate_pool(rpl_parallel_thread_pool *pool)
|
||||
@ -1814,6 +1873,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);
|
||||
|
@ -342,6 +342,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);
|
||||
|
77
sql/slave.cc
77
sql/slave.cc
@ -614,6 +614,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();
|
||||
|
||||
@ -633,24 +634,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"));
|
||||
@ -661,25 +657,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);
|
||||
}
|
||||
|
||||
|
||||
@ -956,9 +953,6 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
|
||||
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(
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
key_thread_slave_sql,
|
||||
@ -975,10 +969,18 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
|
||||
|
||||
|
||||
/*
|
||||
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()
|
||||
@ -996,7 +998,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;
|
||||
@ -2657,7 +2662,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);
|
||||
@ -4493,6 +4500,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))
|
||||
{
|
||||
/*
|
||||
@ -4862,17 +4879,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);
|
||||
delete thd;
|
||||
|
@ -213,6 +213,7 @@ 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);
|
||||
|
@ -2207,7 +2207,7 @@ err:
|
||||
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) */
|
||||
@ -2702,10 +2702,17 @@ case SQLCOM_PREPARE:
|
||||
|
||||
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);
|
||||
@ -2734,7 +2741,7 @@ case SQLCOM_PREPARE:
|
||||
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;
|
||||
}
|
||||
@ -2752,22 +2759,24 @@ case SQLCOM_PREPARE:
|
||||
/* 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:
|
||||
@ -3091,22 +3100,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
|
||||
@ -3114,8 +3124,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:
|
||||
@ -3145,13 +3155,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:
|
||||
@ -4322,6 +4336,8 @@ end_with_restore_list:
|
||||
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);
|
||||
|
@ -174,11 +174,8 @@ 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= (master_info_index->
|
||||
get_master_info(&connection_name,
|
||||
|
||||
if (!(mi= (get_master_info(&connection_name,
|
||||
Sql_condition::WARN_LEVEL_ERROR))))
|
||||
{
|
||||
result= 1;
|
||||
@ -189,9 +186,8 @@ bool reload_acl_and_cache(THD *thd, unsigned long long options,
|
||||
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
|
||||
@ -349,28 +345,34 @@ 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= (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)))
|
||||
{
|
||||
result= 1;
|
||||
}
|
||||
else if (reset_slave(thd, mi))
|
||||
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();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (options & REFRESH_USER_RESOURCES)
|
||||
reset_mqh((LEX_USER *) NULL, 0); /* purecov: inspected */
|
||||
|
@ -3265,8 +3265,8 @@ 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);
|
||||
mysql_mutex_assert_owner(&LOCK_active_mi);
|
||||
|
||||
*master_info_added= false;
|
||||
/*
|
||||
@ -3646,7 +3646,6 @@ bool mysql_show_binlog_events(THD* thd)
|
||||
int old_max_allowed_packet= thd->variables.max_allowed_packet;
|
||||
Master_info *mi= 0;
|
||||
LOG_INFO linfo;
|
||||
|
||||
DBUG_ENTER("mysql_show_binlog_events");
|
||||
|
||||
Log_event::init_show_field_list(&field_list);
|
||||
@ -3674,13 +3673,9 @@ bool mysql_show_binlog_events(THD* thd)
|
||||
}
|
||||
else /* showing relay log contents */
|
||||
{
|
||||
mysql_mutex_lock(&LOCK_active_mi);
|
||||
if (!master_info_index ||
|
||||
!(mi= master_info_index->
|
||||
get_master_info(&thd->variables.default_master_connection,
|
||||
if (!(mi= get_master_info(&thd->variables.default_master_connection,
|
||||
Sql_condition::WARN_LEVEL_ERROR)))
|
||||
{
|
||||
mysql_mutex_unlock(&LOCK_active_mi);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
binary_log= &(mi->rli.relay_log);
|
||||
@ -3700,7 +3695,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;
|
||||
}
|
||||
|
||||
@ -3722,6 +3717,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);
|
||||
@ -3799,7 +3795,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");
|
||||
@ -3820,8 +3816,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);
|
||||
|
120
sql/sys_vars.cc
120
sql/sys_vars.cc
@ -1527,7 +1527,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);
|
||||
|
||||
@ -1538,11 +1537,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;
|
||||
@ -1580,7 +1575,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,
|
||||
@ -1766,16 +1761,7 @@ Sys_var_last_gtid::session_value_ptr(THD *thd, 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
|
||||
@ -1784,10 +1770,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;
|
||||
@ -1810,16 +1793,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
|
||||
@ -1828,13 +1802,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;
|
||||
}
|
||||
|
||||
|
||||
@ -1865,16 +1836,7 @@ static Sys_var_ulong Sys_slave_parallel_max_queued(
|
||||
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
|
||||
@ -1883,13 +1845,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;
|
||||
}
|
||||
|
||||
|
||||
@ -2837,10 +2796,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);
|
||||
}
|
||||
@ -4112,18 +4069,15 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
|
||||
Master_info *mi;
|
||||
|
||||
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||
mysql_mutex_lock(&LOCK_active_mi);
|
||||
|
||||
if (!var->base.length) // no base name
|
||||
{
|
||||
mi= master_info_index->
|
||||
get_master_info(&thd->variables.default_master_connection,
|
||||
mi= get_master_info(&thd->variables.default_master_connection,
|
||||
Sql_condition::WARN_LEVEL_ERROR);
|
||||
}
|
||||
else // has base name
|
||||
{
|
||||
mi= master_info_index->
|
||||
get_master_info(&var->base,
|
||||
mi= get_master_info(&var->base,
|
||||
Sql_condition::WARN_LEVEL_WARN);
|
||||
}
|
||||
|
||||
@ -4140,9 +4094,9 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@ -4150,8 +4104,10 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
|
||||
bool Sys_var_rpl_filter::set_filter_value(const char *value, Master_info *mi)
|
||||
{
|
||||
bool status= true;
|
||||
Rpl_filter* rpl_filter= mi ? mi->rpl_filter : global_rpl_filter;
|
||||
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);
|
||||
@ -4172,7 +4128,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;
|
||||
}
|
||||
|
||||
@ -4185,29 +4141,24 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base)
|
||||
Rpl_filter *rpl_filter;
|
||||
|
||||
mysql_mutex_unlock(&LOCK_global_system_variables);
|
||||
mysql_mutex_lock(&LOCK_active_mi);
|
||||
if (!base->length) // no base name
|
||||
{
|
||||
mi= master_info_index->
|
||||
get_master_info(&thd->variables.default_master_connection,
|
||||
mi= get_master_info(&thd->variables.default_master_connection,
|
||||
Sql_condition::WARN_LEVEL_ERROR);
|
||||
}
|
||||
else // has base name
|
||||
{
|
||||
mi= master_info_index->
|
||||
get_master_info(base,
|
||||
Sql_condition::WARN_LEVEL_WARN);
|
||||
}
|
||||
mysql_mutex_lock(&LOCK_global_system_variables);
|
||||
mi= get_master_info(base, 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);
|
||||
@ -4228,9 +4179,12 @@ uchar *Sys_var_rpl_filter::global_value_ptr(THD *thd, LEX_STRING *base)
|
||||
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;
|
||||
}
|
||||
@ -4301,17 +4255,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;
|
||||
}
|
||||
@ -4326,19 +4275,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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user