* Gleb Shchepa <gshchepa@stripped> [09/06/11 02:56]:
> 2768 Gleb Shchepa 2009-06-11
> Bug #38816: kill + flush tables with read lock + stored
> procedures causes crashes!
>
> The problem of that bugreport was mostly fixed by the
> patch for bug 38691.
> However, attached test case focused on another crash or
> valgrind warning problem: SHOW PROCESSLIST query accesses
> freed memory of SP instruction that run in a parallel
> connection.
Your patch is OK, but I fixed or changed some more code:
1) (Matter of taste). I think that thd->set_query() is sufficient.
Having thd->reset_query(), thd->memdup_query_w_gap()
makes it harder to grep and understand what places
set thd->query. thd->memdup_query_w_gap() also had a change in
what is going on compared to the old code (an extra byte
allocated in one case, an extra assignment of
thd->query[query_length] in another). So I removed them.
We could discuss that on IRC.
2) Merged LOCK_delete and LOCK_query_string to LOCK_thd_data.
The semantics of LOCK_thd_data is to protect THD members that
are accessed concurrently. I wrote a description what it protects
in the comment for the lock.
3) Moved calls to thd->set_query() outside the critical section
protected by LOCK_thread_count. LOCK_thread_count protects the
global list of threads and a few other global variables. Now that
we have a separate mutex to protect thd->query there is no need
to keep the assignment inside LOCK_thread_count critical section.
Your patch fixed it, but not universally.
4) Moved thd->set_query() implementation from the end of
sql_class.cc closer to implementations of other THD methods.
5) Updated the comment for Statement::query.
A better solution, perhaps, would be to completely exclude
assignment of thd->query, thd->query_length from set_statement().
But it will increase the size of the patch even more.
6) I believe there is an unnecessary extra byte allocated
in many places by memdup_w_gap.
The query cache key consists of:
thd->query (query_length bytes)
trailing 0 (1 byte)
thd->db (thd->db_length bytes)
query cache flags.
Sometimes we pass, however, thd->query_length + thd->db_length + 2
+ query_cache_flags to thd->memdup_w_gap, which is a bug.
I didn't change anything there, however.
7) Updated innobase_mysql_print_thd, to take LOCK_thd_data
when accessing thd->query. Note, that with introduction of
LOCK_thd_data, using LOCK_thread_count has become insufficient,
but still mandatory:
- LOCK_thread_count still should be used to ensure that nobody
tries to delete the THD while we're looking at it
- LOCK_thd_data should be used to ensure that nobody
is changing THD members while we're looking at them.
In other words, innobase_mysql_print_thd() is very much similar to
SHOW PROCESSLIST.
One thing different, however, is that it is looking at many more
things. In particular, it is looking at thd->sctx (security
context). There is no guarantee it doesn't change while is being
looked at. It is, however, outside the scope of this bugfix.
8) Updated sql_show.cc to not use double-checked locking
and to always access thd->query under LOCK_thd_data. Upon merge
into 5.1 you will need to update another place that is looking at
it in sql_show.cc (fill_schema_processlist()).
Please see the diff below.
=== modified file 'sql/ha_innodb.cc'
--- sql/ha_innodb.cc 2009-06-25 09:50:26 +0000
+++ sql/ha_innodb.cc 2009-07-22 15:26:07 +0000
@@ -588,11 +588,11 @@ innobase_mysql_print_thd(
uint max_query_len) /* in: max query length to print, or 0 to
use the default max length */
{
- const THD* thd;
+ THD* thd;
const Security_context *sctx;
const char* s;
- thd = (const THD*) input_thd;
+ thd = (THD*) input_thd;
/* We probably want to have original user as part of debug output. */
sctx = &thd->main_security_ctx;
@@ -619,6 +619,7 @@ innobase_mysql_print_thd(
fputs(s, f);
}
+ VOID(pthread_mutex_lock(&thd->LOCK_thd_data));
if ((s = thd->query)) {
/* 3100 is chosen because currently 3000 is the maximum
max_query_len we ever give this. */
@@ -662,6 +663,7 @@ innobase_mysql_print_thd(
my_free(dyn_str, MYF(0));
}
}
+ VOID(pthread_mutex_unlock(&thd->LOCK_thd_data));
putc('\n', f);
}
=== modified file 'sql/ha_myisam.cc'
--- sql/ha_myisam.cc 2009-06-29 13:17:01 +0000
+++ sql/ha_myisam.cc 2009-07-22 14:27:33 +0000
@@ -1487,10 +1487,8 @@ bool ha_myisam::check_and_repair(THD *th
old_query= thd->query;
old_query_length= thd->query_length;
- pthread_mutex_lock(&LOCK_thread_count);
- thd->query= (char*) table->s->table_name;
- thd->query_length= (uint32) strlen(table->s->table_name);
- pthread_mutex_unlock(&LOCK_thread_count);
+ thd->set_query((char*) table->s->table_name,
+ (uint32) strlen(table->s->table_name));
if ((marked_crashed= mi_is_crashed(file)) || check(thd, &check_opt))
{
@@ -1503,10 +1501,7 @@ bool ha_myisam::check_and_repair(THD *th
if (repair(thd, &check_opt))
error=1;
}
- pthread_mutex_lock(&LOCK_thread_count);
- thd->query= old_query;
- thd->query_length= old_query_length;
- pthread_mutex_unlock(&LOCK_thread_count);
+ thd->set_query(old_query, old_query_length);
DBUG_RETURN(error);
}
=== modified file 'sql/log_event.cc'
--- sql/log_event.cc 2009-06-29 13:17:01 +0000
+++ sql/log_event.cc 2009-07-22 14:29:09 +0000
@@ -1960,8 +1960,7 @@ int Query_log_event::exec_event(struct s
db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->set_time((time_t)when);
- thd->query_length= q_len_arg;
- thd->query= (char*)query_arg;
+ thd->set_query((char*)query_arg, q_len_arg);
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -2164,7 +2163,6 @@ Default database: '%s'. Query: '%s'",
} /* End of if (db_ok(... */
end:
- VOID(pthread_mutex_lock(&LOCK_thread_count));
/*
Probably we have set thd->query, thd->db, thd->catalog to point to places
in the data_buf of this event. Now the event is going to be deleted
@@ -2177,10 +2175,8 @@ end:
*/
thd->catalog= 0;
thd->set_db(NULL, 0); /* will free the current database */
+ thd->set_query(NULL, 0);
DBUG_PRINT("info", ("end: query= 0"));
- thd->query= 0; // just to be sure
- thd->query_length= 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
close_thread_tables(thd);
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
/*
@@ -3259,8 +3255,7 @@ int Load_log_event::exec_event(NET* net,
print_query(FALSE, load_data_query, &end, (char
**)&thd->lex->fname_start,
(char **)&thd->lex->fname_end);
*end= 0;
- thd->query_length= (uint) (end - load_data_query);
- thd->query= load_data_query;
+ thd->set_query(load_data_query, (uint) (end - load_data_query));
if (sql_ex.opt_flags & REPLACE_FLAG)
{
@@ -3366,12 +3361,9 @@ int Load_log_event::exec_event(NET* net,
error:
thd->net.vio = 0;
const char *remember_db= thd->db;
- VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->catalog= 0;
thd->set_db(NULL, 0); /* will free the current database */
- thd->query= 0;
- thd->query_length= 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd->set_query(NULL, 0);
close_thread_tables(thd);
if (thd->query_error)
{
=== modified file 'sql/slave.cc'
--- sql/slave.cc 2009-06-29 13:17:01 +0000
+++ sql/slave.cc 2009-07-22 14:30:07 +0000
@@ -755,7 +755,7 @@ int terminate_slave_thread(THD* thd,
int error;
DBUG_PRINT("loop", ("killing slave thread"));
- pthread_mutex_lock(&thd->LOCK_delete);
+ pthread_mutex_lock(&thd->LOCK_thd_data);
#ifndef DONT_USE_THR_ALARM
/*
Error codes from pthread_kill are:
@@ -766,7 +766,7 @@ int terminate_slave_thread(THD* thd,
DBUG_ASSERT(err != EINVAL);
#endif
thd->awake(THD::NOT_KILLED);
- pthread_mutex_unlock(&thd->LOCK_delete);
+ pthread_mutex_unlock(&thd->LOCK_thd_data);
/*
There is a small chance that slave thread might miss the first
@@ -1608,15 +1608,13 @@ static int create_table_from_dump(THD* t
DBUG_RETURN(1);
}
thd->command = COM_TABLE_DUMP;
- thd->query_length= packet_len;
- /* Note that we should not set thd->query until the area is initalized */
if (!(query = thd->strmake((char*) net->read_pos, packet_len)))
{
sql_print_error("create_table_from_dump: out of memory");
my_message(ER_GET_ERRNO, "Out of memory", MYF(0));
DBUG_RETURN(1);
}
- thd->query= query;
+ thd->set_query(query, packet_len);
thd->query_error = 0;
thd->net.no_send_ok = 1;
@@ -3867,11 +3865,8 @@ err:
// print the current replication position
sql_print_information("Slave I/O thread exiting, read up to log '%s', position %s",
IO_RPL_LOG_NAME, llstr(mi->master_log_pos,llbuff));
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query= 0; // extra safety
- thd->query_length= 0;
+ thd->set_query(NULL, 0);
thd->reset_db(NULL, 0);
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
if (mysql)
{
/*
@@ -4105,17 +4100,14 @@ the slave SQL thread with \"SLAVE START\
RPL_LOG_NAME, llstr(rli->group_master_log_pos,llbuff));
err:
- VOID(pthread_mutex_lock(&LOCK_thread_count));
/*
Some extra safety, which should not been needed (normally, event deletion
should already have done these assignments (each event which sets these
variables is supposed to set them to 0 before terminating)).
*/
- thd->catalog= 0;
+ thd->catalog= 0;
+ thd->set_query(NULL, 0);
thd->reset_db(NULL, 0);
- thd->query= 0;
- thd->query_length= 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd_proc_info(thd, "Waiting for slave mutex on exit");
pthread_mutex_lock(&rli->run_lock);
/* We need data_lock, at least to wake up any waiting master_pos_wait() */
=== modified file 'sql/sp_head.cc'
--- sql/sp_head.cc 2009-05-06 13:06:32 +0000
+++ sql/sp_head.cc 2009-07-22 11:00:56 +0000
@@ -949,8 +949,7 @@ subst_spvars(THD *thd, sp_instr *instr,
else
DBUG_RETURN(TRUE);
- thd->query= pbuf;
- thd->query_length= qbuf.length();
+ thd->set_query(pbuf, qbuf.length());
DBUG_RETURN(FALSE);
}
@@ -2654,8 +2653,7 @@ sp_instr_stmt::execute(THD *thd, uint *n
}
else
*nextp= m_ip+1;
- thd->query= query;
- thd->query_length= query_length;
+ thd->set_query(query, query_length);
thd->query_name_consts= 0;
}
DBUG_RETURN(res);
=== modified file 'sql/sql_class.cc'
--- sql/sql_class.cc 2009-06-11 11:49:04 +0000
+++ sql/sql_class.cc 2009-07-22 15:29:40 +0000
@@ -259,7 +259,7 @@ THD::THD()
#ifdef SIGNAL_WITH_VIO_CLOSE
active_vio = 0;
#endif
- pthread_mutex_init(&LOCK_delete, MY_MUTEX_INIT_FAST);
+ pthread_mutex_init(&LOCK_thd_data, MY_MUTEX_INIT_FAST);
/* Variables with default values */
proc_info="login";
@@ -486,8 +486,8 @@ THD::~THD()
THD_CHECK_SENTRY(this);
DBUG_ENTER("~THD()");
/* Ensure that no one is using THD */
- pthread_mutex_lock(&LOCK_delete);
- pthread_mutex_unlock(&LOCK_delete);
+ pthread_mutex_lock(&LOCK_thd_data);
+ pthread_mutex_unlock(&LOCK_thd_data);
add_to_status(&global_status_var, &status_var);
/* Close connection */
@@ -513,7 +513,7 @@ THD::~THD()
free_root(&transaction.mem_root,MYF(0));
#endif
mysys_var=0; // Safety (shouldn't be needed)
- pthread_mutex_destroy(&LOCK_delete);
+ pthread_mutex_destroy(&LOCK_thd_data);
#ifndef DBUG_OFF
dbug_sentry= THD_SENTRY_GONE;
#endif
@@ -551,7 +551,7 @@ void add_to_status(STATUS_VAR *to_var, S
void THD::awake(THD::killed_state state_to_set)
{
THD_CHECK_SENTRY(this);
- safe_mutex_assert_owner(&LOCK_delete);
+ safe_mutex_assert_owner(&LOCK_thd_data);
killed= state_to_set;
if (state_to_set != THD::KILL_QUERY)
@@ -895,7 +895,7 @@ int THD::send_explain_fields(select_resu
void THD::close_active_vio()
{
DBUG_ENTER("close_active_vio");
- safe_mutex_assert_owner(&LOCK_delete);
+ safe_mutex_assert_owner(&LOCK_thd_data);
#ifndef EMBEDDED_LIBRARY
if (active_vio)
{
@@ -2323,6 +2323,25 @@ void THD::restore_sub_statement_state(Su
}
+void THD::set_statement(Statement *stmt)
+{
+ pthread_mutex_lock(&LOCK_thd_data);
+ Statement::set_statement(stmt);
+ pthread_mutex_unlock(&LOCK_thd_data);
+}
+
+
+/** Assign a new value to thd->query. */
+
+void THD::set_query(char *query_arg, uint32 query_length_arg)
+{
+ pthread_mutex_lock(&LOCK_thd_data);
+ query= query_arg;
+ query_length= query_length_arg;
+ pthread_mutex_unlock(&LOCK_thd_data);
+}
+
+
/**
Mark transaction to rollback and mark error as fatal to a sub-statement.
=== modified file 'sql/sql_class.h'
--- sql/sql_class.h 2009-06-11 11:49:04 +0000
+++ sql/sql_class.h 2009-07-22 15:31:08 +0000
@@ -835,22 +835,16 @@ public:
we need to declare it char * because all table handlers are written
in C and need to point to it.
- Note that (A) if we set query = NULL, we must at the same time set
- query_length = 0, and protect the whole operation with the
- LOCK_thread_count mutex. And (B) we are ONLY allowed to set query to a
- non-NULL value if its previous value is NULL. We do not need to protect
- operation (B) with any mutex. To avoid crashes in races, if we do not
- know that thd->query cannot change at the moment, one should print
+ Note that if we set query = NULL, we must at the same time set
+ query_length = 0, and protect the whole operation with
+ LOCK_thd_data mutex. To avoid crashes in races, if we do not
+ know that thd->query cannot change at the moment, we should print
thd->query like this:
- (1) reserve the LOCK_thread_count mutex;
- (2) check if thd->query is NULL;
- (3) if not NULL, then print at most thd->query_length characters from
- it. We will see the query_length field as either 0, or the right value
- for it.
- Assuming that the write and read of an n-bit memory field in an n-bit
- computer is atomic, we can avoid races in the above way.
- This printing is needed at least in SHOW PROCESSLIST and SHOW INNODB
- STATUS.
+ (1) reserve the LOCK_thd_data mutex;
+ (2) print or copy the value of query and query_length
+ (3) release LOCK_thd_data mutex.
+ This printing is needed at least in SHOW PROCESSLIST and SHOW
+ ENGINE INNODB STATUS.
*/
char *query;
uint32 query_length; // current query length
@@ -866,7 +860,7 @@ public:
virtual ~Statement();
/* Assign execution context (note: not all members) of given stmt to self */
- void set_statement(Statement *stmt);
+ virtual void set_statement(Statement *stmt);
void set_n_backup_statement(Statement *stmt, Statement *backup);
void restore_backup_statement(Statement *stmt, Statement *backup);
/* return class type */
@@ -1229,7 +1223,15 @@ public:
THR_LOCK_OWNER main_lock_id; // To use for conventional queries
THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to
// the lock_id of a cursor.
- pthread_mutex_t LOCK_delete; // Locked before thd is deleted
+ /**
+ Protects THD data accessed from other threads:
+ - thd->query and thd->query_length (used by SHOW ENGINE
+ INNODB STATUS and SHOW PROCESSLIST
+ - thd->mysys_var (used by KILL statement and shutdown).
+ Is locked when THD is deleted.
+ */
+ pthread_mutex_t LOCK_thd_data;
+
/* all prepared statements and cursors of this connection */
Statement_map stmt_map;
/*
@@ -1637,15 +1639,15 @@ public:
#ifdef SIGNAL_WITH_VIO_CLOSE
inline void set_active_vio(Vio* vio)
{
- pthread_mutex_lock(&LOCK_delete);
+ pthread_mutex_lock(&LOCK_thd_data);
active_vio = vio;
- pthread_mutex_unlock(&LOCK_delete);
+ pthread_mutex_unlock(&LOCK_thd_data);
}
inline void clear_active_vio()
{
- pthread_mutex_lock(&LOCK_delete);
+ pthread_mutex_lock(&LOCK_thd_data);
active_vio = 0;
- pthread_mutex_unlock(&LOCK_delete);
+ pthread_mutex_unlock(&LOCK_thd_data);
}
void close_active_vio();
#endif
@@ -1882,6 +1884,14 @@ public:
*/
void pop_internal_handler();
+ /** Overloaded to guard query/query_length fields */
+ virtual void set_statement(Statement *stmt);
+
+ /**
+ Assign a new value to thd->query.
+ Protected with LOCK_thd_data mutex.
+ */
+ void set_query(char *query_arg, uint32 query_length_arg);
private:
/** The current internal error handler for this thread, or NULL. */
Internal_error_handler *m_internal_handler;
=== modified file 'sql/sql_insert.cc'
--- sql/sql_insert.cc 2009-07-03 08:35:00 +0000
+++ sql/sql_insert.cc 2009-07-22 11:00:56 +0000
@@ -1854,7 +1854,7 @@ bool delayed_get_table(THD *thd, TABLE_L
thread_count++;
pthread_mutex_unlock(&LOCK_thread_count);
di->thd.set_db(table_list->db, (uint) strlen(table_list->db));
- di->thd.query= my_strdup(table_list->table_name, MYF(MY_WME));
+ di->thd.set_query(my_strdup(table_list->table_name, MYF(MY_WME)), 0);
if (di->thd.db == NULL || di->thd.query == NULL)
{
/* The error is reported */
=== modified file 'sql/sql_parse.cc'
--- sql/sql_parse.cc 2009-07-01 12:09:44 +0000
+++ sql/sql_parse.cc 2009-07-22 15:32:27 +0000
@@ -1106,8 +1106,7 @@ void execute_init_command(THD *thd, sys_
values of init_command_var can't be changed
*/
rw_rdlock(var_mutex);
- thd->query= init_command_var->value;
- thd->query_length= init_command_var->value_length;
+ thd->set_query(init_command_var->value, init_command_var->value_length);
save_client_capabilities= thd->client_capabilities;
thd->client_capabilities|= CLIENT_MULTI_QUERIES;
/*
@@ -1326,6 +1325,7 @@ pthread_handler_t handle_bootstrap(void
thd->init_for_queries();
while (fgets(buff, thd->net.max_packet, file))
{
+ char *query;
ulong length= (ulong) strlen(buff);
while (buff[length-1] != '\n' && !feof(file))
{
@@ -1350,10 +1350,9 @@ pthread_handler_t handle_bootstrap(void
buff[length-1] == ';'))
length--;
buff[length]=0;
- thd->query_length=length;
- thd->query= thd->memdup_w_gap(buff, length+1,
- thd->db_length+1+QUERY_CACHE_FLAGS_SIZE);
- thd->query[length] = '\0';
+ query= thd->memdup_w_gap(buff, length + 1,
+ thd->db_length + 1 + QUERY_CACHE_FLAGS_SIZE);
+ thd->set_query(query, length);
DBUG_PRINT("query",("%-.4096s",thd->query));
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
thd->profiling.set_query_source(thd->query, length);
@@ -1463,8 +1462,7 @@ int mysql_table_dump(THD* thd, char* db,
if (check_one_table_access(thd, SELECT_ACL, table_list))
goto err;
thd->free_list = 0;
- thd->query_length=(uint) strlen(tbl_name);
- thd->query = tbl_name;
+ thd->set_query(tbl_name, (uint) strlen(tbl_name));
if ((error = mysqld_dump_create_info(thd, table_list, -1)))
{
my_error(ER_GET_ERRNO, MYF(0), my_errno);
@@ -1987,9 +1985,8 @@ bool dispatch_command(enum enum_server_c
thd->profiling.set_query_source(next_packet, length);
#endif
+ thd->set_query(next_packet, length);
VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->query_length= length;
- thd->query= next_packet;
/*
Count each statement from the client.
*/
@@ -2041,9 +2038,10 @@ bool dispatch_command(enum enum_server_c
table_list.schema_table= schema_table;
}
- thd->query_length= (uint) strlen(packet); // for simplicity: don't optimize
- if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
+ uint query_length= (uint) strlen(packet);
+ if (!(fields= thd->memdup(packet, query_length + 1)))
break;
+ thd->set_query(fields, query_length);
mysql_log.write(thd,command,"%s %s",table_list.table_name, fields);
if (lower_case_table_names)
my_casedn_str(files_charset_info, table_list.table_name);
@@ -2327,13 +2325,12 @@ bool dispatch_command(enum enum_server_c
log_slow_statement(thd);
thd_proc_info(thd, "cleaning up");
- VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
- thd_proc_info(thd, 0);
+ thd->set_query(NULL, 0);
thd->command=COM_SLEEP;
- thd->query=0;
- thd->query_length=0;
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list
thread_running--;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ thd_proc_info(thd, 0);
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
DBUG_RETURN(error);
@@ -2536,6 +2533,7 @@ int prepare_schema_table(THD *thd, LEX *
bool alloc_query(THD *thd, const char *packet, uint packet_length)
{
+ char *query;
packet_length--; // Remove end null
/* Remove garbage at start and end of query */
while (my_isspace(thd->charset(),packet[0]) && packet_length > 0)
@@ -2551,14 +2549,13 @@ bool alloc_query(THD *thd, const char *p
packet_length--;
}
/* We must allocate some extra memory for query cache */
- thd->query_length= 0; // Extra safety: Avoid races
- if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet),
- packet_length,
- thd->db_length+ 1 +
- QUERY_CACHE_FLAGS_SIZE)))
- return TRUE;
- thd->query[packet_length]=0;
- thd->query_length= packet_length;
+ if (! (query= (char*) thd->memdup_w_gap(packet,
+ packet_length,
+ 1 + thd->db_length +
+ QUERY_CACHE_FLAGS_SIZE)))
+ return TRUE;
+ query[packet_length]= '\0';
+ thd->set_query(query, packet_length);
/* Reclaim some memory */
thd->packet.shrink(thd->variables.net_buffer_length);
@@ -7506,7 +7503,7 @@ void kill_one_thread(THD *thd, ulong id,
{
if (tmp->thread_id == id)
{
- pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
+ pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
break;
}
}
@@ -7539,7 +7536,7 @@ void kill_one_thread(THD *thd, ulong id,
}
else
error=ER_KILL_DENIED_ERROR;
- pthread_mutex_unlock(&tmp->LOCK_delete);
+ pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
if (!error)
=== modified file 'sql/sql_repl.cc'
--- sql/sql_repl.cc 2009-06-29 13:17:01 +0000
+++ sql/sql_repl.cc 2009-07-22 11:08:44 +0000
@@ -1044,7 +1044,7 @@ void kill_zombie_dump_threads(uint32 sla
if (tmp->command == COM_BINLOG_DUMP &&
tmp->server_id == slave_server_id)
{
- pthread_mutex_lock(&tmp->LOCK_delete); // Lock from delete
+ pthread_mutex_lock(&tmp->LOCK_thd_data); // Lock from delete
break;
}
}
@@ -1057,7 +1057,7 @@ void kill_zombie_dump_threads(uint32 sla
again. We just to do kill the thread ourselves.
*/
tmp->awake(THD::KILL_QUERY);
- pthread_mutex_unlock(&tmp->LOCK_delete);
+ pthread_mutex_unlock(&tmp->LOCK_thd_data);
}
}
=== modified file 'sql/sql_show.cc'
--- sql/sql_show.cc 2009-06-17 13:54:01 +0000
+++ sql/sql_show.cc 2009-07-22 14:55:34 +0000
@@ -1410,16 +1410,14 @@ void mysqld_list_processes(THD *thd,cons
thd_info->start_time= tmp->start_time;
#endif
thd_info->query=0;
+ /* Lock THD mutex that protects its data when looking at it. */
+ pthread_mutex_lock(&tmp->LOCK_thd_data);
if (tmp->query)
{
- /*
- query_length is always set to 0 when we set query = NULL; see
- the comment in sql_class.h why this prevents crashes in possible
- races with query_length
- */
uint length= min(max_query_length, tmp->query_length);
thd_info->query=(char*) thd->strmake(tmp->query,length);
}
+ pthread_mutex_unlock(&tmp->LOCK_thd_data);
thread_infos.append(thd_info);
}
}
Thank you for looking into this!
--
kostja