Commit e65f667b authored by Monty's avatar Monty Committed by Sergei Golubchik

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.
parent d5c54f39
......@@ -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);
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;
......
This diff is collapsed.
......@@ -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 @@ class Master_info_index
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 @@ class rpl_io_thread_info
};
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 @@ rpl_parallel_change_thread_count(rpl_parallel_thread_pool *pool,
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);
......
......@@ -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,10 +953,7 @@ 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(
error= start_slave_thread(
#ifdef HAVE_PSI_INTERFACE
key_thread_slave_sql,
#endif
......@@ -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 @@ log '%s' at position %s, relay log '%s' position: %s%s", RPL_LOG_NAME,
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 @@ static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables)
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 @@ case SQLCOM_PREPARE:
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 @@ case SQLCOM_PREPARE:
}
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 @@ case SQLCOM_PREPARE:
}
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:
......@@ -4317,11 +4331,13 @@ case SQLCOM_PREPARE:
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);
......
......@@ -174,24 +174,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
......@@ -349,27 +345,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)
......
......@@ -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,
Sql_condition::WARN_LEVEL_ERROR)))
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 @@ bool mysql_show_binlog_events(THD* thd)
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);
......
......@@ -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,19 +4069,16 @@ 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,
Sql_condition::WARN_LEVEL_ERROR);
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,
Sql_condition::WARN_LEVEL_WARN);
mi= get_master_info(&var->base,
Sql_condition::WARN_LEVEL_WARN);
}
if (mi)
......@@ -4132,17 +4086,17 @@ bool Sys_var_rpl_filter::global_update(THD *thd, set_var *var)
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;
}
......@@ -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,
Sql_condition::WARN_LEVEL_ERROR);
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment