Commit 4b954cc0 authored by unknown's avatar unknown

A patch for BUG#32148: killing a query may be ineffective.

The problem was that THD::killed was reset after a command was
read from the socket, but before it was actually handled. That lead
to a race: if another KILL statement was issued for this connection
in the middle of reading from the socket and processing a command,
THD::killed state would be cleaned.

The fix is to move this cleanup into net_send_error() function.

A sample test case exists in binlog_killed.test:
  - connection 1: start a new transaction on table t1;
  - connection 2: send query to the server (w/o waiting for the
    result) to update data in table t1 -- this query will be blocked
    since there is unfinished transaction;
  - connection 1: kill query in connection 2 and finish the transaction;
  - connection 2: get result of the previous query -- it should be
    the "query-killed" error.

This test however contains race condition, which can not be fixed
with the current protocol: there is no way to guarantee, that the
server will receive and start processing the query in connection 2
(which is intended to get blocked) before the KILL command (sent in
the connection 1) will arrive. In other words, there is no way to
ensure that the following sequence will not happen:

  - connection 1: start a new transaction on table t1;
  - connection 1: kill query in connection 2 and finish the transaction;
  - connection 2: send query to the server (w/o waiting for the
    result) to update data in table t1 -- this query will be blocked
    since there is unfinished transaction;
  - connection 2: get result of the previous query -- the query will
    succeed.

So, there is no test case for this bug, since it's impossible
to write a reliable test case under the current circumstances.


sql/protocol.cc:
  Move thd->killed cleanup from dispatch_command() to net_send_error().
sql/sql_parse.cc:
  Move thd->killed cleanup from dispatch_command() to net_send_error().
parent 90477e23
...@@ -76,6 +76,12 @@ void net_send_error(THD *thd, uint sql_errno, const char *err) ...@@ -76,6 +76,12 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
DBUG_ASSERT(!thd->spcont); DBUG_ASSERT(!thd->spcont);
if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
{
thd->killed= THD::NOT_KILLED;
thd->mysys_var->abort= 0;
}
if (net && net->no_send_error) if (net && net->no_send_error)
{ {
thd->clear_error(); thd->clear_error();
......
...@@ -788,12 +788,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -788,12 +788,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
NET *net= &thd->net; NET *net= &thd->net;
bool error= 0; bool error= 0;
DBUG_ENTER("dispatch_command"); DBUG_ENTER("dispatch_command");
DBUG_PRINT("info",("packet: '%*.s'; command: %d", packet_length, packet, command));
if (thd->killed == THD::KILL_QUERY || thd->killed == THD::KILL_BAD_DATA)
{
thd->killed= THD::NOT_KILLED;
thd->mysys_var->abort= 0;
}
thd->command=command; thd->command=command;
/* /*
......
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