Bug#28141: Control C on query waiting on lock causes ERROR 1053 (server shutdown)
If a thread is killed in the server, we throw "shutdown" only if one is actually in progress; otherwise, we throw "query interrupted". Control-C in the mysql command-line client is "incremental" now. First Control-C sends KILL QUERY (when connected to 5.0+ server, otherwise, see next) Next Control-C sends KILL CONNECTION Next Control-C aborts client. As the first two steps only pertain to an existing query, Control-C will abort the client right away if no query is running. client will give more detailed/consistent feedback on Control-C now. client/mysql.cc: Extends Control-C handling; enhances up feedback to user. On 5.0+ servers, we try to be nice and send KILL QUERY first if Control-C is pressed in the command-line client, but if that doesn't work, we now give the user the opportunity to send KILL CONNECTION with another Control-C (and to kill the client with another Control-C if that somehow doesn't work either). mysql-test/t/flush_read_lock_kill.test: we're getting correct "thread killed" rather than "in shutdown" error now mysql-test/t/kill.test: we're getting correct "thread killed" rather than "in shutdown" error now mysql-test/t/rpl000001.test: we're getting correct "thread killed" rather than "in shutdown" error now mysql-test/t/rpl_error_ignored_table.test: we're getting correct "thread killed" rather than "in shutdown" error now sql/records.cc: make error messages on KILL uniform for rr_*() by folding that handling into rr_handle_error() sql/sql_class.h: Only throw "shutdown" when we have one flagged as being in progress; otherwise, throw "query interrupted" as it's likely to be "KILL CONNECTION" or related.
This commit is contained in:
parent
ce0a06935b
commit
5ef63a4f1c
@ -1219,18 +1219,34 @@ sig_handler mysql_sigint(int sig)
|
|||||||
MYSQL *kill_mysql= NULL;
|
MYSQL *kill_mysql= NULL;
|
||||||
|
|
||||||
/* terminate if no query being executed, or we already tried interrupting */
|
/* terminate if no query being executed, or we already tried interrupting */
|
||||||
if (!executing_query || interrupted_query++)
|
if (!executing_query || (interrupted_query == 2))
|
||||||
|
{
|
||||||
|
tee_fprintf(stdout, "Ctrl-C -- exit!\n");
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
kill_mysql= mysql_init(kill_mysql);
|
kill_mysql= mysql_init(kill_mysql);
|
||||||
if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,
|
if (!mysql_real_connect(kill_mysql,current_host, current_user, opt_password,
|
||||||
"", opt_mysql_port, opt_mysql_unix_port,0))
|
"", opt_mysql_port, opt_mysql_unix_port,0))
|
||||||
|
{
|
||||||
|
tee_fprintf(stdout, "Ctrl-C -- sorry, cannot connect to server to kill query, giving up ...\n");
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupted_query++;
|
||||||
|
|
||||||
|
/* mysqld < 5 does not understand KILL QUERY, skip to KILL CONNECTION */
|
||||||
|
if ((interrupted_query == 1) && (mysql_get_server_version(&mysql) < 50000))
|
||||||
|
interrupted_query= 2;
|
||||||
|
|
||||||
/* kill_buffer is always big enough because max length of %lu is 15 */
|
/* kill_buffer is always big enough because max length of %lu is 15 */
|
||||||
sprintf(kill_buffer, "KILL /*!50000 QUERY */ %lu", mysql_thread_id(&mysql));
|
sprintf(kill_buffer, "KILL %s%lu",
|
||||||
|
(interrupted_query == 1) ? "QUERY " : "",
|
||||||
|
mysql_thread_id(&mysql));
|
||||||
|
tee_fprintf(stdout, "Ctrl-C -- sending \"%s\" to server ...\n", kill_buffer);
|
||||||
mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer));
|
mysql_real_query(kill_mysql, kill_buffer, (uint) strlen(kill_buffer));
|
||||||
mysql_close(kill_mysql);
|
mysql_close(kill_mysql);
|
||||||
tee_fprintf(stdout, "Query aborted by Ctrl+C\n");
|
tee_fprintf(stdout, "Ctrl-C -- query aborted.\n");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ connection con1;
|
|||||||
# debug build running without our --debug=make_global..., will be
|
# debug build running without our --debug=make_global..., will be
|
||||||
# error 0 (no error). The only important thing to test is that on
|
# error 0 (no error). The only important thing to test is that on
|
||||||
# debug builds with our --debug=make_global... we don't hang forever.
|
# debug builds with our --debug=make_global... we don't hang forever.
|
||||||
--error 0,1053,2013
|
--error 0,1317,2013
|
||||||
reap;
|
reap;
|
||||||
|
|
||||||
connection con2;
|
connection con2;
|
||||||
|
@ -92,7 +92,7 @@ select ((@id := kill_id) - kill_id) from t3;
|
|||||||
kill @id;
|
kill @id;
|
||||||
|
|
||||||
connection conn1;
|
connection conn1;
|
||||||
-- error 1053,2013
|
-- error 1317,2013
|
||||||
reap;
|
reap;
|
||||||
|
|
||||||
connection default;
|
connection default;
|
||||||
|
@ -92,7 +92,7 @@ kill @id;
|
|||||||
# We don't drop t3 as this is a temporary table
|
# We don't drop t3 as this is a temporary table
|
||||||
drop table t2;
|
drop table t2;
|
||||||
connection master;
|
connection master;
|
||||||
--error 1053,2013
|
--error 1317,2013
|
||||||
reap;
|
reap;
|
||||||
connection slave;
|
connection slave;
|
||||||
# The SQL slave thread should now have stopped because the query was killed on
|
# The SQL slave thread should now have stopped because the query was killed on
|
||||||
|
@ -45,7 +45,7 @@ select (@id := id) - id from t3;
|
|||||||
kill @id;
|
kill @id;
|
||||||
drop table t2,t3;
|
drop table t2,t3;
|
||||||
connection master;
|
connection master;
|
||||||
--error 0,1053,2013
|
--error 0,1317,2013
|
||||||
reap;
|
reap;
|
||||||
connection master1;
|
connection master1;
|
||||||
--replace_column 2 # 5 #
|
--replace_column 2 # 5 #
|
||||||
|
@ -56,6 +56,7 @@ void init_read_record_idx(READ_RECORD *info, THD *thd, TABLE *table,
|
|||||||
bool print_error, uint idx)
|
bool print_error, uint idx)
|
||||||
{
|
{
|
||||||
bzero((char*) info,sizeof(*info));
|
bzero((char*) info,sizeof(*info));
|
||||||
|
info->thd= thd;
|
||||||
info->table= table;
|
info->table= table;
|
||||||
info->file= table->file;
|
info->file= table->file;
|
||||||
info->record= table->record[0];
|
info->record= table->record[0];
|
||||||
@ -240,6 +241,12 @@ void end_read_record(READ_RECORD *info)
|
|||||||
|
|
||||||
static int rr_handle_error(READ_RECORD *info, int error)
|
static int rr_handle_error(READ_RECORD *info, int error)
|
||||||
{
|
{
|
||||||
|
if (info->thd->killed)
|
||||||
|
{
|
||||||
|
info->thd->send_kill_message();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (error == HA_ERR_END_OF_FILE)
|
if (error == HA_ERR_END_OF_FILE)
|
||||||
error= -1;
|
error= -1;
|
||||||
else
|
else
|
||||||
@ -260,12 +267,7 @@ static int rr_quick(READ_RECORD *info)
|
|||||||
int tmp;
|
int tmp;
|
||||||
while ((tmp= info->select->quick->get_next()))
|
while ((tmp= info->select->quick->get_next()))
|
||||||
{
|
{
|
||||||
if (info->thd->killed)
|
if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED))
|
||||||
{
|
|
||||||
my_error(ER_SERVER_SHUTDOWN, MYF(0));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (tmp != HA_ERR_RECORD_DELETED)
|
|
||||||
{
|
{
|
||||||
tmp= rr_handle_error(info, tmp);
|
tmp= rr_handle_error(info, tmp);
|
||||||
break;
|
break;
|
||||||
@ -331,16 +333,11 @@ int rr_sequential(READ_RECORD *info)
|
|||||||
int tmp;
|
int tmp;
|
||||||
while ((tmp=info->file->rnd_next(info->record)))
|
while ((tmp=info->file->rnd_next(info->record)))
|
||||||
{
|
{
|
||||||
if (info->thd->killed)
|
|
||||||
{
|
|
||||||
info->thd->send_kill_message();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
rnd_next can return RECORD_DELETED for MyISAM when one thread is
|
rnd_next can return RECORD_DELETED for MyISAM when one thread is
|
||||||
reading and another deleting without locks.
|
reading and another deleting without locks.
|
||||||
*/
|
*/
|
||||||
if (tmp != HA_ERR_RECORD_DELETED)
|
if (info->thd->killed || (tmp != HA_ERR_RECORD_DELETED))
|
||||||
{
|
{
|
||||||
tmp= rr_handle_error(info, tmp);
|
tmp= rr_handle_error(info, tmp);
|
||||||
break;
|
break;
|
||||||
|
@ -44,6 +44,8 @@ extern char internal_table_name[2];
|
|||||||
extern char empty_c_string[1];
|
extern char empty_c_string[1];
|
||||||
extern const char **errmesg;
|
extern const char **errmesg;
|
||||||
|
|
||||||
|
extern bool volatile shutdown_in_progress;
|
||||||
|
|
||||||
#define TC_LOG_PAGE_SIZE 8192
|
#define TC_LOG_PAGE_SIZE 8192
|
||||||
#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
|
#define TC_LOG_MIN_SIZE (3*TC_LOG_PAGE_SIZE)
|
||||||
|
|
||||||
@ -1801,7 +1803,11 @@ public:
|
|||||||
{
|
{
|
||||||
int err= killed_errno();
|
int err= killed_errno();
|
||||||
if (err)
|
if (err)
|
||||||
|
{
|
||||||
|
if ((err == KILL_CONNECTION) && !shutdown_in_progress)
|
||||||
|
err = KILL_QUERY;
|
||||||
my_message(err, ER(err), MYF(0));
|
my_message(err, ER(err), MYF(0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* return TRUE if we will abort query if we make a warning now */
|
/* return TRUE if we will abort query if we make a warning now */
|
||||||
inline bool really_abort_on_warning()
|
inline bool really_abort_on_warning()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user