1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Added a separate lock for start/stop/reset slave.

This solves some possible dead locks when one calls stop slave while slave
is starting.
This commit is contained in:
Monty
2017-01-29 23:44:24 +02:00
committed by Sergei Golubchik
parent e65f667bb6
commit c5e25c8b40
9 changed files with 132 additions and 59 deletions

View File

@ -80,6 +80,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);
@ -117,6 +119,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);
@ -727,17 +730,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 */
lock_slave_threads(mi);
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);
unlock_slave_threads(mi);
mi->unlock_slave_threads();
delete mi;
mysql_mutex_lock(&LOCK_active_mi);
DBUG_VOID_RETURN;
}
@ -904,6 +918,7 @@ Master_info_index::Master_info_index()
void Master_info_index::free_connections()
{
mysql_mutex_assert_owner(&LOCK_active_mi);
my_hash_reset(&master_info_hash);
}
@ -936,7 +951,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,
@ -984,7 +998,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,
@ -999,6 +1012,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))
{
@ -1012,14 +1026,14 @@ 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(ER_CONNECTION_ALREADY_EXISTS),
(int) connection_name.length, connection_name.str);
unlock_slave_threads(mi);
mi->unlock_slave_threads();
delete mi;
}
continue;
@ -1036,7 +1050,7 @@ bool Master_info_index::init_all_master_info()
/* Master_info was already registered */
sql_print_error(ER(ER_CONNECTION_ALREADY_EXISTS),
(int) connection_name.length, connection_name.str);
unlock_slave_threads(mi);
mi->unlock_slave_threads();
delete mi;
continue;
}
@ -1065,7 +1079,7 @@ bool Master_info_index::init_all_master_info()
(int) connection_name.length,
connection_name.str);
}
unlock_slave_threads(mi);
mi->unlock_slave_threads();
}
}
@ -1268,7 +1282,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",
@ -1392,23 +1411,31 @@ bool give_error_if_slave_running(bool already_locked)
@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 any_slave_sql_running()
{
uint count= 0;
HASH *hash;
DBUG_ENTER("any_slave_sql_running");
mysql_mutex_lock(&LOCK_active_mi);
if (likely(master_info_index)) // Not shutdown
if (unlikely(shutdown_in_progress || !master_info_index))
{
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);
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);