Commit e5c8240a authored by unknown's avatar unknown

BUG#29968 (rpl_ndb_circular.test and rpl_ndb_log.test fail):

Removing unguarded read of slave_running field from inside
terminate_slave_threads(). This could cause premature exit in the event
that the slave thread already were shutting down, but isn't finished yet.

The fields slave_running, io_thd, and sql_thread are guarded by an
associated run_lock. A read of these fields were not guarded inside
terminate_slave_threads(), which caused an assertion to fire. The
assertion was removed, and the code reorganized slightly.


sql/slave.cc:
  Changing signature of terminate_slave_thread() to accept a skip_lock
  parameter instead of two mutexes. This mimics the signature of the
  terminate_slave_threads() function. Code is also changed as a result
  of this.
  
  Removing unguarded check of slave_running field in the master info and
  relay log info structure since that could cause premature exit of
  terminate_slave_threads().
  
  The thread variable for each of the slave threads can change before
  acquiring the run_lock mutex inside terminate_slave_thread(). Hence
  an assertion was removed that read the variable without guarding it
  with run_lock.
  
  Code that checked *slave_running status inside terminate_slave_thread()
  was reorganized slightly.
sql/slave.h:
  Moving terminate_slave_thread() to use internal linkage.
parent cd7d837b
...@@ -132,6 +132,11 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db, ...@@ -132,6 +132,11 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name, bool overwrite); const char* table_name, bool overwrite);
static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi); static int get_master_version_and_clock(MYSQL* mysql, MASTER_INFO* mi);
static Log_event* next_event(RELAY_LOG_INFO* rli); static Log_event* next_event(RELAY_LOG_INFO* rli);
static int terminate_slave_thread(THD *thd,
pthread_mutex_t* term_lock,
pthread_cond_t* term_cond,
volatile uint *slave_running,
bool skip_lock);
/* /*
Find out which replications threads are running Find out which replications threads are running
...@@ -312,35 +317,26 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) ...@@ -312,35 +317,26 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
DBUG_RETURN(0); /* successfully do nothing */ DBUG_RETURN(0); /* successfully do nothing */
int error,force_all = (thread_mask & SLAVE_FORCE_ALL); int error,force_all = (thread_mask & SLAVE_FORCE_ALL);
pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock; pthread_mutex_t *sql_lock = &mi->rli.run_lock, *io_lock = &mi->run_lock;
pthread_mutex_t *sql_cond_lock,*io_cond_lock;
sql_cond_lock=sql_lock; if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)))
io_cond_lock=io_lock;
if (skip_lock)
{
sql_lock = io_lock = 0;
}
if ((thread_mask & (SLAVE_IO|SLAVE_FORCE_ALL)) && mi->slave_running)
{ {
DBUG_PRINT("info",("Terminating IO thread")); DBUG_PRINT("info",("Terminating IO thread"));
mi->abort_slave=1; mi->abort_slave=1;
if ((error=terminate_slave_thread(mi->io_thd,io_lock, if ((error=terminate_slave_thread(mi->io_thd,io_lock,
io_cond_lock,
&mi->stop_cond, &mi->stop_cond,
&mi->slave_running)) && &mi->slave_running,
skip_lock)) &&
!force_all) !force_all)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)) && mi->rli.slave_running) if ((thread_mask & (SLAVE_SQL|SLAVE_FORCE_ALL)))
{ {
DBUG_PRINT("info",("Terminating SQL thread")); DBUG_PRINT("info",("Terminating SQL thread"));
DBUG_ASSERT(mi->rli.sql_thd != 0) ;
mi->rli.abort_slave=1; mi->rli.abort_slave=1;
if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock, if ((error=terminate_slave_thread(mi->rli.sql_thd,sql_lock,
sql_cond_lock,
&mi->rli.stop_cond, &mi->rli.stop_cond,
&mi->rli.slave_running)) && &mi->rli.slave_running,
skip_lock)) &&
!force_all) !force_all)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -348,23 +344,60 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) ...@@ -348,23 +344,60 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock)
} }
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, /**
pthread_mutex_t *cond_lock, Wait for a slave thread to terminate.
pthread_cond_t* term_cond,
volatile uint *slave_running) This function is called after requesting the thread to terminate
(by setting @c abort_slave member of @c Relay_log_info or @c
Master_info structure to 1). Termination of the thread is
controlled with the the predicate <code>*slave_running</code>.
Function will acquire @c term_lock before waiting on the condition
unless @c skip_lock is true in which case the mutex should be owned
by the caller of this function and will remain acquired after
return from the function.
@param term_lock
Associated lock to use when waiting for @c term_cond
@param term_cond
Condition that is signalled when the thread has terminated
@param slave_running
Pointer to predicate to check for slave thread termination
@param skip_lock
If @c true the lock will not be acquired before waiting on
the condition. In this case, it is assumed that the calling
function acquires the lock before calling this function.
@retval 0 All OK
*/
static int
terminate_slave_thread(THD *thd,
pthread_mutex_t* term_lock,
pthread_cond_t* term_cond,
volatile uint *slave_running,
bool skip_lock)
{ {
int error;
DBUG_ENTER("terminate_slave_thread"); DBUG_ENTER("terminate_slave_thread");
if (term_lock)
{ if (!skip_lock)
pthread_mutex_lock(term_lock); pthread_mutex_lock(term_lock);
if (!*slave_running)
{ safe_mutex_assert_owner(term_lock);
if (!*slave_running)
{
if (!skip_lock)
pthread_mutex_unlock(term_lock); pthread_mutex_unlock(term_lock);
DBUG_RETURN(ER_SLAVE_NOT_RUNNING); DBUG_RETURN(ER_SLAVE_NOT_RUNNING);
}
} }
DBUG_ASSERT(thd != 0); DBUG_ASSERT(thd != 0);
THD_CHECK_SENTRY(thd); THD_CHECK_SENTRY(thd);
/* /*
Is is critical to test if the slave is running. Otherwise, we might Is is critical to test if the slave is running. Otherwise, we might
be referening freed memory trying to kick it be referening freed memory trying to kick it
...@@ -380,9 +413,13 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, ...@@ -380,9 +413,13 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock,
*/ */
struct timespec abstime; struct timespec abstime;
set_timespec(abstime,2); set_timespec(abstime,2);
pthread_cond_timedwait(term_cond, cond_lock, &abstime); error= pthread_cond_timedwait(term_cond, term_lock, &abstime);
DBUG_ASSERT(error == ETIMEDOUT || error == 0);
} }
if (term_lock)
DBUG_ASSERT(*slave_running == 0);
if (!skip_lock)
pthread_mutex_unlock(term_lock); pthread_mutex_unlock(term_lock);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -133,10 +133,6 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli); ...@@ -133,10 +133,6 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli);
int register_slave_on_master(MYSQL* mysql); int register_slave_on_master(MYSQL* mysql);
int terminate_slave_threads(MASTER_INFO* mi, int thread_mask, int terminate_slave_threads(MASTER_INFO* mi, int thread_mask,
bool skip_lock = 0); bool skip_lock = 0);
int terminate_slave_thread(THD* thd, pthread_mutex_t* term_mutex,
pthread_mutex_t* cond_lock,
pthread_cond_t* term_cond,
volatile uint* slave_running);
int start_slave_threads(bool need_slave_mutex, bool wait_for_start, int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
MASTER_INFO* mi, const char* master_info_fname, MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname, int thread_mask); const char* slave_info_fname, int thread_mask);
......
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