MWL#182: Explain running statements
- Make SHOW EXPLAIN command be KILLable with KILL QUERY.
This commit is contained in:
parent
b97678f066
commit
3e90dc1f77
@ -775,4 +775,44 @@ a
|
||||
set debug_dbug='';
|
||||
revoke all privileges on test.* from test2@localhost;
|
||||
drop user test2@localhost;
|
||||
#
|
||||
# Test that it is possible to KILL a SHOW EXPLAIN command that's waiting
|
||||
# on its target thread
|
||||
#
|
||||
create table t1 (pk int primary key, data char(64)) engine=innodb;
|
||||
insert into t1 select A.a + 10 * B.a + 100 * C.a, 'data1' from t0 A, t0 B, t0 C;
|
||||
# Lock two threads
|
||||
set autocommit=0;
|
||||
select * from t1 where pk between 10 and 20 for update;
|
||||
pk data
|
||||
10 data1
|
||||
11 data1
|
||||
12 data1
|
||||
13 data1
|
||||
14 data1
|
||||
15 data1
|
||||
16 data1
|
||||
17 data1
|
||||
18 data1
|
||||
19 data1
|
||||
20 data1
|
||||
set autocommit=0;
|
||||
select * from t1 where pk between 10 and 20 for update;
|
||||
show explain for 3;
|
||||
kill query $thr_default;
|
||||
ERROR 70100: Query execution was interrupted
|
||||
rollback;
|
||||
pk data
|
||||
10 data1
|
||||
11 data1
|
||||
12 data1
|
||||
13 data1
|
||||
14 data1
|
||||
15 data1
|
||||
16 data1
|
||||
17 data1
|
||||
18 data1
|
||||
19 data1
|
||||
20 data1
|
||||
drop table t1;
|
||||
drop table t0;
|
||||
|
@ -2,6 +2,7 @@
|
||||
# Tests for SHOW EXPLAIN FOR functionality
|
||||
#
|
||||
--source include/have_debug.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t0, t1, t2, t3, t4;
|
||||
@ -788,11 +789,57 @@ connection con1;
|
||||
reap;
|
||||
set debug_dbug='';
|
||||
|
||||
|
||||
|
||||
revoke all privileges on test.* from test2@localhost;
|
||||
drop user test2@localhost;
|
||||
|
||||
disconnect con2;
|
||||
--echo #
|
||||
--echo # Test that it is possible to KILL a SHOW EXPLAIN command that's waiting
|
||||
--echo # on its target thread
|
||||
--echo #
|
||||
connect (con2, localhost, root,,);
|
||||
connect (con3, localhost, root,,);
|
||||
connection con2;
|
||||
create table t1 (pk int primary key, data char(64)) engine=innodb;
|
||||
insert into t1 select A.a + 10 * B.a + 100 * C.a, 'data1' from t0 A, t0 B, t0 C;
|
||||
|
||||
--echo # Lock two threads
|
||||
set autocommit=0;
|
||||
select * from t1 where pk between 10 and 20 for update;
|
||||
|
||||
connection con1;
|
||||
set autocommit=0;
|
||||
# This will freeze
|
||||
send
|
||||
select * from t1 where pk between 10 and 20 for update;
|
||||
|
||||
# run SHOW EXPLAIN on a frozen thread
|
||||
connection default;
|
||||
let $wait_condition= select State='Sending data' from information_schema.processlist where id=$thr2;
|
||||
let $thr_default=`select connection_id()`;
|
||||
--source include/wait_condition.inc
|
||||
send_eval show explain for $thr2;
|
||||
|
||||
# kill the SHOW EXPLAIN command
|
||||
connection con3;
|
||||
let $wait_condition= select State='show_explain' from information_schema.processlist where id=$thr_default;
|
||||
--source include/wait_condition.inc
|
||||
evalp kill query $thr_default;
|
||||
|
||||
connection default;
|
||||
--error ER_QUERY_INTERRUPTED
|
||||
reap;
|
||||
|
||||
connection con2;
|
||||
rollback;
|
||||
|
||||
connection con1;
|
||||
reap;
|
||||
|
||||
drop table t1;
|
||||
disconnect con3;
|
||||
disconnect con2;
|
||||
|
||||
## TODO: Test this: have several SHOW EXPLAIN requests be queued up for a
|
||||
## thread and served together.
|
||||
|
||||
|
@ -145,8 +145,8 @@ void Apc_target::dequeue_request(Call_request *qe)
|
||||
to use thd->enter_cond() calls to be killable)
|
||||
*/
|
||||
|
||||
bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec,
|
||||
bool *timed_out)
|
||||
bool Apc_target::make_apc_call(THD *caller_thd, Apc_call *call,
|
||||
int timeout_sec, bool *timed_out)
|
||||
{
|
||||
bool res= TRUE;
|
||||
*timed_out= FALSE;
|
||||
@ -166,6 +166,9 @@ bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec,
|
||||
set_timespec(abstime, timeout);
|
||||
|
||||
int wait_res= 0;
|
||||
const char *old_msg;
|
||||
old_msg= caller_thd->enter_cond(&apc_request.COND_request,
|
||||
LOCK_thd_data_ptr, "show_explain");
|
||||
/* todo: how about processing other errors here? */
|
||||
while (!apc_request.processed && (wait_res != ETIMEDOUT))
|
||||
{
|
||||
@ -173,13 +176,18 @@ bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec,
|
||||
wait_res= mysql_cond_timedwait(&apc_request.COND_request,
|
||||
LOCK_thd_data_ptr, &abstime);
|
||||
// &apc_request.LOCK_request, &abstime);
|
||||
if (caller_thd->killed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!apc_request.processed)
|
||||
{
|
||||
/*
|
||||
The wait has timed out. Remove the request from the queue (ok to do
|
||||
because we own LOCK_thd_data_ptr.
|
||||
The wait has timed out, or this thread was KILLed.
|
||||
Remove the request from the queue (ok to do because we own
|
||||
LOCK_thd_data_ptr)
|
||||
*/
|
||||
apc_request.processed= TRUE;
|
||||
dequeue_request(&apc_request);
|
||||
@ -191,7 +199,10 @@ bool Apc_target::make_apc_call(Apc_call *call, int timeout_sec,
|
||||
/* Request was successfully executed and dequeued by the target thread */
|
||||
res= FALSE;
|
||||
}
|
||||
mysql_mutex_unlock(LOCK_thd_data_ptr);
|
||||
/*
|
||||
exit_cond() will call mysql_mutex_unlock(LOCK_thd_data_ptr) for us:
|
||||
*/
|
||||
caller_thd->exit_cond(old_msg);
|
||||
|
||||
/* Destroy all APC request data */
|
||||
mysql_cond_destroy(&apc_request.COND_request);
|
||||
|
@ -33,6 +33,8 @@
|
||||
requestor.
|
||||
*/
|
||||
|
||||
class THD;
|
||||
|
||||
/*
|
||||
Target for asynchronous procedure calls (APCs).
|
||||
- A target is running in some particular thread,
|
||||
@ -62,7 +64,7 @@ public:
|
||||
};
|
||||
|
||||
/* Make a call in the target thread (see function definition for details) */
|
||||
bool make_apc_call(Apc_call *call, int timeout_sec, bool *timed_out);
|
||||
bool make_apc_call(THD *caller_thd, Apc_call *call, int timeout_sec, bool *timed_out);
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
int n_calls_processed; /* Number of calls served by this target */
|
||||
|
@ -2084,11 +2084,15 @@ void mysqld_show_explain(THD *thd, const char *calling_user, ulong thread_id)
|
||||
explain_req.failed_to_produce= FALSE;
|
||||
|
||||
/* Ok, we have a lock on target->LOCK_thd_data, can call: */
|
||||
bres= tmp->apc_target.make_apc_call(&explain_req, timeout_sec, &timed_out);
|
||||
bres= tmp->apc_target.make_apc_call(thd, &explain_req, timeout_sec, &timed_out);
|
||||
|
||||
if (bres || explain_req.failed_to_produce)
|
||||
{
|
||||
/* TODO not enabled or time out */
|
||||
if (thd->killed)
|
||||
{
|
||||
thd->send_kill_message();
|
||||
}
|
||||
else
|
||||
if (timed_out)
|
||||
{
|
||||
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
|
||||
|
@ -24,6 +24,29 @@
|
||||
|
||||
#include <tap.h>
|
||||
|
||||
/*
|
||||
A fake THD with enter_cond/exit_cond and some other members.
|
||||
*/
|
||||
class THD
|
||||
{
|
||||
mysql_mutex_t* thd_mutex;
|
||||
public:
|
||||
bool killed;
|
||||
|
||||
THD() : killed(FALSE) {}
|
||||
inline const char* enter_cond(mysql_cond_t *cond, mysql_mutex_t* mutex,
|
||||
const char* msg)
|
||||
{
|
||||
mysql_mutex_assert_owner(mutex);
|
||||
thd_mutex= mutex;
|
||||
return NULL;
|
||||
}
|
||||
inline void exit_cond(const char* old_msg)
|
||||
{
|
||||
mysql_mutex_unlock(thd_mutex);
|
||||
}
|
||||
};
|
||||
|
||||
#include "../sql/my_apc.h"
|
||||
|
||||
#define MY_APC_STANDALONE 1
|
||||
@ -115,6 +138,8 @@ void *test_apc_requestor_thread(void *ptr)
|
||||
{
|
||||
my_thread_init();
|
||||
fprintf(stderr, "# test_apc_requestor_thread started\n");
|
||||
THD my_thd;
|
||||
|
||||
while (!requestors_should_exit)
|
||||
{
|
||||
int dst_value= 0;
|
||||
@ -124,7 +149,7 @@ void *test_apc_requestor_thread(void *ptr)
|
||||
bool timed_out;
|
||||
|
||||
mysql_mutex_lock(&target_mutex);
|
||||
bool res= apc_target.make_apc_call(&apc_order, 60, &timed_out);
|
||||
bool res= apc_target.make_apc_call(&my_thd, &apc_order, 60, &timed_out);
|
||||
if (res)
|
||||
{
|
||||
if (timed_out)
|
||||
|
Loading…
x
Reference in New Issue
Block a user