Commit 7891a713 authored by Monty's avatar Monty

Don't wait too long in SHOW PROCESSLIST

This will allow show processlist to continue, without blocking
all new connections, if some threads gets stuck while holding
LOCK_thd_data or mysys_var->mutex

Connections that has mutex 'stuck' are marked as 'Busy' in 'Command'

Todo:
Make F_BACKOFF to do 'pause' instead of just (1)
parent b3346c2f
......@@ -137,6 +137,29 @@ static const LEX_CSTRING *view_algorithm(TABLE_LIST *table);
bool get_lookup_field_values(THD *, COND *, TABLE_LIST *, LOOKUP_FIELD_VALUES *);
/**
Try to lock a mutex, but give up after a short while to not cause deadlocks
The loop is short, as the mutex we are trying to lock are mutex the should
never be locked a long time, just over a few instructions.
@return 0 ok
@return 1 error
*/
static bool trylock_short(mysql_mutex_t *mutex)
{
uint i;
for (i= 0 ; i < 100 ; i++)
{
if (!mysql_mutex_trylock(mutex))
return 0;
LF_BACKOFF();
}
return 1;
}
/***************************************************************************
** List all table types supported
***************************************************************************/
......@@ -2634,7 +2657,8 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
while ((tmp=it++))
{
Security_context *tmp_sctx= tmp->security_ctx;
struct st_my_thread_var *mysys_var;
struct st_my_thread_var *mysys_var= 0;
bool got_thd_data, got_mysys_lock= 0;
if ((tmp->vio_ok() || tmp->system_thread) &&
(!user || (!tmp->system_thread &&
tmp_sctx->user && !strcmp(tmp_sctx->user, user))))
......@@ -2658,18 +2682,26 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
tmp_sctx->host_or_ip :
tmp_sctx->host ? tmp_sctx->host : "");
thd_info->command=(int) tmp->get_command();
mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((thd_info->db= tmp->db)) // Safe test
thd_info->db= thd->strdup(thd_info->db);
if ((got_thd_data= !trylock_short(&tmp->LOCK_thd_data)))
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
got_mysys_lock= !trylock_short(&mysys_var->mutex);
if (got_thd_data)
{
/* This is correct under mysys_lock, otherwise an approximation */
thd_info->proc_info= (char*) (tmp->killed >= KILL_QUERY ?
"Killed" : 0);
thd_info->state_info= thread_state_info(tmp);
if (mysys_var)
if (got_mysys_lock)
mysql_mutex_unlock(&mysys_var->mutex);
/* Lock THD mutex that protects its data when looking at it. */
/*
The following variables are only safe to access under a lock
*/
if ((thd_info->db= tmp->db)) // Safe test
thd_info->db= thd->strdup(thd_info->db);
if (tmp->query())
{
uint length= MY_MIN(max_query_length, tmp->query_length());
......@@ -2695,10 +2727,20 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
}
else
thd_info->progress= 0.0;
}
else
{
thd_info->proc_info= "Busy";
thd_info->progress= 0.0;
}
thd_info->state_info= thread_state_info(tmp);
thd_info->start_time= tmp->start_utime;
ulonglong utime_after_query_snapshot= tmp->utime_after_query;
if (thd_info->start_time < utime_after_query_snapshot)
thd_info->start_time= utime_after_query_snapshot; // COM_SLEEP
if (got_thd_data)
mysql_mutex_unlock(&tmp->LOCK_thd_data);
thread_infos.append(thd_info);
}
......@@ -2938,7 +2980,7 @@ int fill_show_explain(THD *thd, TABLE_LIST *table, COND *cond)
explain_req.request_thd= thd;
explain_req.failed_to_produce= FALSE;
/* Ok, we have a lock on target->LOCK_thd_data, can call: */
/* Ok, we have a lock on target->LOCK_thd_kill, can call: */
bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out);
if (bres || explain_req.failed_to_produce)
......@@ -3017,9 +3059,10 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
while ((tmp= it++))
{
Security_context *tmp_sctx= tmp->security_ctx;
struct st_my_thread_var *mysys_var;
struct st_my_thread_var *mysys_var= 0;
const char *val, *db;
ulonglong max_counter;
bool got_thd_data, got_mysys_lock= 0;
if ((!tmp->vio_ok() && !tmp->system_thread) ||
(user && (tmp->system_thread || !tmp_sctx->user ||
......@@ -3045,23 +3088,33 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
else
table->field[2]->store(tmp_sctx->host_or_ip,
strlen(tmp_sctx->host_or_ip), cs);
if ((got_thd_data= !trylock_short(&tmp->LOCK_thd_data)))
if ((mysys_var= tmp->mysys_var))
got_mysys_lock= !trylock_short(&mysys_var->mutex);
if (got_thd_data)
{
/* DB */
mysql_mutex_lock(&tmp->LOCK_thd_data);
if ((db= tmp->db))
{
table->field[3]->store(db, strlen(db), cs);
table->field[3]->set_notnull();
}
}
if ((mysys_var= tmp->mysys_var))
mysql_mutex_lock(&mysys_var->mutex);
/* COMMAND */
if ((val= (char *) ((tmp->killed >= KILL_QUERY ?
if ((val= (char *) (!got_thd_data ? "Busy" :
(tmp->killed >= KILL_QUERY ?
"Killed" : 0))))
table->field[4]->store(val, strlen(val), cs);
else
table->field[4]->store(command_name[tmp->get_command()].str,
command_name[tmp->get_command()].length, cs);
if (got_mysys_lock)
mysql_mutex_unlock(&mysys_var->mutex);
/* MYSQL_TIME */
ulonglong utime= tmp->start_utime;
ulonglong utime_after_query_snapshot= tmp->utime_after_query;
......@@ -3070,6 +3123,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
utime= utime && utime < unow ? unow - utime : 0;
table->field[5]->store(utime / HRTIME_RESOLUTION, TRUE);
/* STATE */
if ((val= thread_state_info(tmp)))
{
......@@ -3077,30 +3131,20 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
table->field[6]->set_notnull();
}
if (mysys_var)
mysql_mutex_unlock(&mysys_var->mutex);
mysql_mutex_unlock(&tmp->LOCK_thd_data);
/* TIME_MS */
table->field[8]->store((double)(utime / (HRTIME_RESOLUTION / 1000.0)));
/* INFO */
/* Lock THD mutex that protects its data when looking at it. */
mysql_mutex_lock(&tmp->LOCK_thd_data);
if (got_thd_data)
{
if (tmp->query())
{
table->field[7]->store(tmp->query(),
MY_MIN(PROCESS_LIST_INFO_WIDTH,
tmp->query_length()), cs);
table->field[7]->set_notnull();
}
/* INFO_BINARY */
if (tmp->query())
{
table->field[16]->store(tmp->query(),
MY_MIN(PROCESS_LIST_INFO_WIDTH,
tmp->query_length()), &my_charset_bin);
tmp->query_length()),
&my_charset_bin);
table->field[16]->set_notnull();
}
......@@ -3116,6 +3160,10 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
(double) max_counter*100.0);
}
mysql_mutex_unlock(&tmp->LOCK_thd_data);
}
/* TIME_MS */
table->field[8]->store((double)(utime / (HRTIME_RESOLUTION / 1000.0)));
/*
This may become negative if we free a memory allocated by another
......
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