[MDEV-5603] Assertion `0' fails on killing a connection waiting for a lock Created: 2014-02-03  Updated: 2015-02-22  Resolved: 2015-02-22

Status: Closed
Project: MariaDB Server
Component/s: OTHER
Affects Version/s: 5.5.35, 10.0.7
Fix Version/s: 10.0.16

Type: Bug Priority: Major
Reporter: Elena Stepanova Assignee: Sergei Golubchik
Resolution: Fixed Votes: 0
Labels: upstream-fixed

Issue Links:
Relates

 Description   
  • run a long create table on con1;
  • try to connect with MySQL client with enabled auto-rehash (the client hangs on Field List command), or somehow else initiate Field List;
  • kill the new connection.

The test cases below use C test rather than MTR because there is no analogue for mysql_list_fields in MTR language, and there is no asynchronous system/exec call. Without either of those, an MTR test becomes ugly and unreliable.
Please also note that the test uses mysql_list_fields_start, so it should be linked with the library that has it.

The first test case is faster, but it requires CREATE OR REPLACE (which is not available before 10.0.8), and also uses the bug MDEV-5602, so it might stop being reproducible after the bug is fixed.

#include <my_global.h>
#include <mysql.h>
 
int main(int argc, char **argv)
{  
  MYSQL *con = mysql_init(NULL);
  MYSQL *con2 = mysql_init(NULL);
  MYSQL_RES *res;
 
  if (con == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con));
      exit(1);
  }
  if (con2 == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con2));
      exit(1);
  }
 
  if (mysql_real_connect(con, "127.0.0.1", "root", "", 
          "test", 0, NULL, 0) == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con));
      mysql_close(con);
      exit(1);
  }
 
  mysql_query(con,"DROP TABLE IF EXISTS t1");
  mysql_query(con,"CREATE TABLE t1 (i INT)");
  mysql_query(con,"LOCK TABLE t1 WRITE");
  mysql_query(con,"CREATE OR REPLACE TABLE t1 (i INT)");
 
 
  if (mysql_real_connect(con2, "127.0.0.1", "root", "", 
          "test", 0, NULL, 0) == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con2));
      mysql_close(con2);
      exit(1);
  }
 
  mysql_options(con2, MYSQL_OPT_NONBLOCK, 0);
  mysql_list_fields_start(&res,con2,(const char*) "t1",NullS);
 
  sleep(1);
  
  mysql_query(con,"SELECT ID INTO @kill_id FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Field List'");
  mysql_query(con,"KILL @kill_id");
 
  mysql_close(con2);
  mysql_close(con);
  exit(0);
}

#6  0x00007fd6a3134621 in *__GI___assert_fail (assertion=0xec0d48 "0", file=<optimized out>, line=518, function=0xec2000 "void Protocol::end_statement()") at assert.c:81
#7  0x00000000005c448b in Protocol::end_statement (this=0x7fd67ea7a5f8) at /sql/protocol.cc:518
#8  0x000000000066863b in dispatch_command (command=COM_FIELD_LIST, thd=0x7fd67ea7a070, packet=0x7fd67ea80074 "", packet_length=3) at /sql/sql_parse.cc:1714
#9  0x00000000006665e4 in do_command (thd=0x7fd67ea7a070) at /sql/sql_parse.cc:993
#10 0x000000000077f619 in do_handle_one_connection (thd_arg=0x7fd67ea7a070) at /sql/sql_connect.cc:1379
#11 0x000000000077f36c in handle_one_connection (arg=0x7fd67ea7a070) at /sql/sql_connect.cc:1293
#12 0x0000000000a1f329 in pfs_spawn_thread (arg=0x7fd67ee4c8b0) at /storage/perfschema/pfs.cc:1853
#13 0x00007fd6a4cd8b50 in start_thread (arg=<optimized out>) at pthread_create.c:304
#14 0x00007fd6a31e3a7d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:112

revision-id: monty@askmonty.org-20140202093802-a6jtuy6ni29biigz
revno: 3968
branch-nick: mariadb-monty

The second test case is considerably slower, but it can be run on any version, MariaDB or MySQL.

// gcc -c -I/data/repo/bzr/5.5/include/mysql -I/data/repo/bzr/5.5/include/mysql/.. test2.c && gcc -o test2 test2.o -L/data/repo/bzr/5.5/libmysql -lmysqlclient  && ./test2
 
 
#include <my_global.h>
#include <mysql.h>
 
int main(int argc, char **argv)
{  
  MYSQL *con = mysql_init(NULL);
  MYSQL *con2 = mysql_init(NULL);
  MYSQL *con3 = mysql_init(NULL);
  int *res;
  MYSQL_RES *res2;
 
  if (mysql_real_connect(con, "127.0.0.1", "root", "", 
          "test", 0, NULL, 0) == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con));
      mysql_close(con);
      exit(1);
  }
 
  mysql_query(con,"DROP TABLE IF EXISTS t1, t2");
  mysql_query(con,"CREATE TABLE t1 (i INT) ENGINE=MyISAM");
  mysql_query(con,"INSERT INTO t1 VALUES (1),(2),(3),(4),(5),(6),(7),(8)");
  mysql_query(con,"INSERT INTO t1 SELECT a.* FROM t1 a, t1 b, t1 c, t1 d, t1 e, t1 f, t1 g");
 
  mysql_options(con, MYSQL_OPT_NONBLOCK, 0);
  mysql_query_start(res,con,"CREATE TABLE t2 AS SELECT * FROM t1");
 
 
  if (mysql_real_connect(con2, "127.0.0.1", "root", "", 
          "test", 0, NULL, 0) == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con2));
      mysql_close(con2);
      exit(1);
  }
 
  mysql_options(con2, MYSQL_OPT_NONBLOCK, 0);
  mysql_list_fields_start(&res2,con2,(const char*) "t2",NullS);
 
  sleep(3);
 
  if (mysql_real_connect(con3, "127.0.0.1", "root", "", 
          "test", 0, NULL, 0) == NULL) 
  {
      fprintf(stderr, "%s\n", mysql_error(con3));
      mysql_close(con3);
      exit(1);
  }
 
  mysql_query(con3,"SELECT ID INTO @kill_id FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Field List'");
  mysql_query(con3,"KILL @kill_id");
 
  mysql_close(con3);
  mysql_close(con2);
  mysql_close(con);
  exit(0);
}

The problem is also reproducible on MySQL 5.5, but not on MySQL 5.6, so possibly it will eventually go away from 10.0 along with the merge of MySQL 5.6 bugfixes.



 Comments   
Comment by Elena Stepanova [ 2014-02-03 ]

Found a way to reproduce without CREATE OR REPLACE, assigning back to myself to modify the test case.

Comment by Elena Stepanova [ 2014-11-16 ]

Still reproducible on 5.5.40+, 10.0.14+.

I'm setting it to upstream-fixed and raising the priority even though there is no linked upstream bug, because the problem is reproducible on MySQL 5.5 but not on 5.6/5.7 (so, no point filing a bug upstream). And since we are not merging bugfixes automatically, there is little chance that it will go away on its own.

Comment by Sergei Golubchik [ 2015-02-21 ]

I failed to repeat it using your instructions on the latest 10.0 from github:

  • start two mysql command-line clients
  • in the first start a long-running create table
  • start yet another mysql command-line client in another terminal window, it hangs
  • in the remaining mysql command-line client KILL the hanging connection
Comment by Elena Stepanova [ 2015-02-22 ]

The problem disappeared from 10.0 tree from the following revision:

revno: 4573
revision-id: sergii@pisem.net-20150119131914-2h0sd0988be6czxd
parent: sergii@pisem.net-20150119131905-zjcvewlb9dw85two
fixes bug: https://mariadb.atlassian.net/browse/MDEV-7299
committer: Sergei Golubchik <sergii@pisem.net>
branch nick: 10.0
timestamp: Mon 2015-01-19 14:19:14 +0100
message:
  MDEV-7299 Assertion `m_status == DA_ERROR || m_status == DA_OK' fails on concurrent execution of DDL, queries from I_S, and KILL QUERY
  
  Fix MDL to report an error when a wait was killed, but preserve
  the old documented behavior of GET_LOCK() where killing it is not an error.
  
  Also remove race conditions in main.create_or_replace test

Generated at Thu Feb 08 07:05:38 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.