Skip to content

Commit

Permalink
MDEV-30014 Spider should not second guess server when locking / unloc…
Browse files Browse the repository at this point in the history
…king

This fixes MDEV-30014, MDEV-29456, MDEV-29667, and MDEV-30049.

The server may ask storage engines to unlock when the original sql
command is not UNLOCK. This patch makes sure that spider honours these
requests, so that the server has the correct idea which tables are
locked and which are not.

MDEV-29456, MDEV-29667, MDEV-30049: a later LOCK statement would, as
the first step, unlock locked tables and clear the OPTION_TABLE_LOCK
bit in thd->variables.option_bits, as well as locked_tables_list,
indicating no tables are locked. If Spider does not unlock because the
sql command is not UNLOCK, and if after this the LOCK statement fails
to lock any tables, these indications that no tables are locked
remains, so a later UNLOCK TABLES; statement would not try to unlock
any table. Causing later statements requiring mdl locks to hang on
waiting until lock_wait_timeout (default 1h) has passed.

MDEV-30014: when a LOCK statement tries to lock more than one tables,
say t2 and t3 as in mdev_30014.test, and t2 succeeds but t3 fails, the
sql layer would try to undo by unlocking t2, and again, if Spider does
not honour this request, the sql layer would assume t2 has been
unlocked, but later actions on t2 or t2's remote table could hang on
waiting for the mdl.
  • Loading branch information
mariadb-YuchenPei committed Nov 17, 2023
1 parent 52a5b16 commit 0381197
Show file tree
Hide file tree
Showing 8 changed files with 265 additions and 7 deletions.
9 changes: 2 additions & 7 deletions storage/spider/ha_spider.cc
Expand Up @@ -1265,11 +1265,6 @@ int ha_spider::external_lock(
#ifdef HA_CAN_BULK_ACCESS
external_lock_cnt++;
#endif
if (
lock_type == F_UNLCK &&
sql_command != SQLCOM_UNLOCK_TABLES
)
DBUG_RETURN(0);
if (store_error_num)
DBUG_RETURN(store_error_num);
#if defined(HS_HAS_SQLCOM) && defined(HAVE_HANDLERSOCKET)
Expand Down Expand Up @@ -1306,7 +1301,7 @@ int ha_spider::external_lock(
) {
if (sql_command == SQLCOM_TRUNCATE)
DBUG_RETURN(0);
else if (sql_command != SQLCOM_UNLOCK_TABLES)
else if (lock_type != F_UNLCK)
{
DBUG_PRINT("info",("spider conns[%d]->join_trx=%u",
roop_count, conns[roop_count]->join_trx));
Expand Down Expand Up @@ -1428,7 +1423,7 @@ int ha_spider::external_lock(
}
if (conns[roop_count]->table_lock == 2)
conns[roop_count]->table_lock = 1;
} else if (sql_command == SQLCOM_UNLOCK_TABLES ||
} else if (lock_type == F_UNLCK ||
spider_param_internal_unlock(thd) == 1)
{
if (conns[roop_count]->table_lock == 1)
Expand Down
41 changes: 41 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/r/mdev_29456.result
@@ -0,0 +1,41 @@
#
# MDEV-29456 Spider hangs in 'Waiting for table metadata lock' state on CREATE TABLE after LOCK TABLES
#
for master_1
for child2
for child3
CREATE SERVER srv FOREIGN DATA WRAPPER mysql
OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
create table t1 (c int);
create table t2 (c int) ENGINE=Spider
COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
CREATE TABLE t3 (c INT KEY) ENGINE=Spider;
LOCK TABLE t2 WRITE;
LOCK TABLE t3 WRITE;
ERROR HY000: Unable to connect to foreign data source: localhost
UNLOCK TABLES;
drop table t1, t2, t3;
CREATE TABLE t (c INT) ENGINE=InnoDB;
CREATE TABLE t1 (c INT) ENGINE=Spider;
CREATE TABLE t2 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",srv "srv",TABLE "t"';
LOCK TABLES t2 WRITE;
LOCK TABLES t1 READ;
ERROR HY000: Unable to connect to foreign data source: localhost
CREATE TABLE t (c INT) ENGINE=Spider;
ERROR 42S01: Table 't' already exists
drop table t, t1, t2;
CREATE TABLE t (c INT) ENGINE=InnoDB;
CREATE TABLE t2 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",srv "srv",TABLE "t"';
CREATE TABLE t3 (c INT) ENGINE=InnoDB;
LOCK TABLES t2 WRITE;
LOCK TABLES mysql.proc WRITE,mysql.user WRITE;
ERROR HY000: You can't combine write-locking of system tables with other tables or lock types
INSERT INTO t3 SELECT * FROM t;
drop table t, t2, t3;
drop server srv;
for master_1
for child2
for child3
#
# end of test mdev_29456
#
40 changes: 40 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/r/mdev_29667.result
@@ -0,0 +1,40 @@
#
# MDEV-29667 Server hangs on DROP DATABASE after failing LOCK TABLES on Spider table
#
for master_1
for child2
child2_1
child2_2
child2_3
for child3
connection child2_1;
CREATE DATABASE auto_test_remote;
USE auto_test_remote;
CREATE TABLE tbl_a (
a INT
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
connection master_1;
CREATE DATABASE auto_test_local;
USE auto_test_local;
CREATE TABLE tbl_a (
a INT
) ENGINE=Spider DEFAULT CHARSET=utf8 COMMENT='table "tbl_a", srv "s_2_1"';
CREATE TABLE tbl_b (
a INT
) ENGINE=Spider DEFAULT CHARSET=utf8;
LOCK TABLES tbl_a WRITE;
LOCK TABLES tbl_b READ, tbl_a READ;
ERROR HY000: Unable to connect to foreign data source: localhost
connection master_1;
DROP DATABASE IF EXISTS auto_test_local;
connection child2_1;
DROP DATABASE IF EXISTS auto_test_remote;
for master_1
for child2
child2_1
child2_2
child2_3
for child3
#
# end of test mdev_29667
#
38 changes: 38 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/r/mdev_30014.result
@@ -0,0 +1,38 @@
#
# MDEV-30014 heap-use-after-free in ha_spider::lock_tables(), highly sporadic SIGSEGV in intern_close_table
#
for master_1
for child2
for child3
CREATE SERVER srv FOREIGN DATA WRAPPER mysql
OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');
create table t1 (c int);
create table t2 (c int) ENGINE=Spider
COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
CREATE TABLE t3 (c INT KEY) ENGINE=Spider;
LOCK TABLE t2 WRITE,t3 WRITE;
ERROR HY000: Unable to connect to foreign data source: localhost
CREATE TABLE t4 (c INT) ENGINE=Spider;
FLUSH NO_WRITE_TO_BINLOG TABLES t4 WITH READ LOCK;
Warnings:
Error 1429 Unable to connect to foreign data source: localhost
Error 1429 Unable to connect to foreign data source: localhost
Error 1429 Unable to connect to foreign data source: localhost
Error 1429 Unable to connect to foreign data source: localhost
UNLOCK TABLES;
drop table t1, t2, t3, t4;
create table t1 (c int);
create table t2 (c int) ENGINE=Spider
COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
CREATE TABLE t3 (c INT KEY) ENGINE=Spider;
LOCK TABLE t2 WRITE, t3 WRITE;
ERROR HY000: Unable to connect to foreign data source: localhost
UNLOCK TABLES;
drop table t1, t2, t3;
drop server srv;
for master_1
for child2
for child3
#
# end of test mdev_30014
#
52 changes: 52 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/t/mdev_29456.test
@@ -0,0 +1,52 @@
--echo #
--echo # MDEV-29456 Spider hangs in 'Waiting for table metadata lock' state on CREATE TABLE after LOCK TABLES
--echo #
--source include/have_innodb.inc
--disable_query_log
--disable_result_log
--source ../../t/test_init.inc
--enable_result_log
--enable_query_log

evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql
OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');

create table t1 (c int);
create table t2 (c int) ENGINE=Spider
COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
CREATE TABLE t3 (c INT KEY) ENGINE=Spider;
LOCK TABLE t2 WRITE;
--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE
LOCK TABLE t3 WRITE;
UNLOCK TABLES;
drop table t1, t2, t3;

CREATE TABLE t (c INT) ENGINE=InnoDB;
CREATE TABLE t1 (c INT) ENGINE=Spider;
CREATE TABLE t2 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",srv "srv",TABLE "t"';
LOCK TABLES t2 WRITE;
--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE
LOCK TABLES t1 READ;
--error ER_TABLE_EXISTS_ERROR
CREATE TABLE t (c INT) ENGINE=Spider;
drop table t, t1, t2;

# MDEV-30049
CREATE TABLE t (c INT) ENGINE=InnoDB;
CREATE TABLE t2 (c INT) ENGINE=Spider COMMENT='WRAPPER "mysql",srv "srv",TABLE "t"';
CREATE TABLE t3 (c INT) ENGINE=InnoDB;
LOCK TABLES t2 WRITE;
--error 1428
LOCK TABLES mysql.proc WRITE,mysql.user WRITE; # ERROR 1428 (HY000): You can't combine write-locking of system tables with other tables or lock types
INSERT INTO t3 SELECT * FROM t;
drop table t, t2, t3;

drop server srv;
--disable_query_log
--disable_result_log
--source ../../t/test_deinit.inc
--enable_result_log
--enable_query_log
--echo #
--echo # end of test mdev_29456
--echo #
3 changes: 3 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/t/mdev_29667.cnf
@@ -0,0 +1,3 @@
!include include/default_mysqld.cnf
!include ../my_1_1.cnf
!include ../my_2_1.cnf
44 changes: 44 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/t/mdev_29667.test
@@ -0,0 +1,44 @@
--echo #
--echo # MDEV-29667 Server hangs on DROP DATABASE after failing LOCK TABLES on Spider table
--echo #
--disable_query_log
--disable_result_log
--source ../../t/test_init.inc
--enable_result_log
--enable_query_log

--connection child2_1
CREATE DATABASE auto_test_remote;
USE auto_test_remote;
eval CREATE TABLE tbl_a (
a INT
) $CHILD2_1_ENGINE $CHILD2_1_CHARSET;

--connection master_1
CREATE DATABASE auto_test_local;
USE auto_test_local;
eval CREATE TABLE tbl_a (
a INT
) $MASTER_1_ENGINE $MASTER_1_CHARSET COMMENT='table "tbl_a", srv "s_2_1"';
eval CREATE TABLE tbl_b (
a INT
) $MASTER_1_ENGINE $MASTER_1_CHARSET;

LOCK TABLES tbl_a WRITE;
--error 1429
LOCK TABLES tbl_b READ, tbl_a READ;

--connection master_1
DROP DATABASE IF EXISTS auto_test_local;

--connection child2_1
DROP DATABASE IF EXISTS auto_test_remote;

--disable_query_log
--disable_result_log
--source ../t/test_deinit.inc
--enable_query_log
--enable_result_log
--echo #
--echo # end of test mdev_29667
--echo #
45 changes: 45 additions & 0 deletions storage/spider/mysql-test/spider/bugfix/t/mdev_30014.test
@@ -0,0 +1,45 @@
--echo #
--echo # MDEV-30014 heap-use-after-free in ha_spider::lock_tables(), highly sporadic SIGSEGV in intern_close_table
--echo #
--disable_query_log
--disable_result_log
--source ../../t/test_init.inc
--enable_result_log
--enable_query_log

evalp CREATE SERVER srv FOREIGN DATA WRAPPER mysql
OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root');

create table t1 (c int);
create table t2 (c int) ENGINE=Spider
COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
CREATE TABLE t3 (c INT KEY) ENGINE=Spider;
--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE
LOCK TABLE t2 WRITE,t3 WRITE;
CREATE TABLE t4 (c INT) ENGINE=Spider;
FLUSH NO_WRITE_TO_BINLOG TABLES t4 WITH READ LOCK;
UNLOCK TABLES;

drop table t1, t2, t3, t4;

# This is a test case in MDEV-29456 but it is more like the above
# case.
create table t1 (c int);
create table t2 (c int) ENGINE=Spider
COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"';
CREATE TABLE t3 (c INT KEY) ENGINE=Spider;
--error ER_CONNECT_TO_FOREIGN_DATA_SOURCE
LOCK TABLE t2 WRITE, t3 WRITE;
UNLOCK TABLES;
drop table t1, t2, t3;

drop server srv;

--disable_query_log
--disable_result_log
--source ../../t/test_deinit.inc
--enable_result_log
--enable_query_log
--echo #
--echo # end of test mdev_30014
--echo #

0 comments on commit 0381197

Please sign in to comment.