#At file:///home/my/mysql-6.0-maria/
2746 Michael Widenius 2008-10-22
Fix for bug#39395 Maria: ma_extra.c:286: maria_extra: Assertion `share->reopen == 1' failed
added:
mysql-test/suite/maria/r/maria-lock.result
mysql-test/suite/maria/t/maria-lock.test
modified:
sql/sql_base.cc
storage/maria/ma_extra.c
per-file messages:
mysql-test/suite/maria/r/maria-lock.result
Test case for bug#39395
mysql-test/suite/maria/t/maria-lock.test
Test case for bug#39395
sql/sql_base.cc
Race condition in wait_while_table_is_used() where a table used by another connection could be forced closed, but there was no protection against the other thread re-opening the table and trying to lock it again before the table was name locked by original thread.
storage/maria/ma_extra.c
The MySQL server called handler::extra(PREPARE_FOR_REOPEN) while table was opened multiple times. This was not officially supported by the handler interface.
I made a temporary fix by removing the check in maria::extra() that verifies if the table is correctly used.
=== added file 'mysql-test/suite/maria/r/maria-lock.result'
--- a/mysql-test/suite/maria/r/maria-lock.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/maria/r/maria-lock.result 2008-10-21 23:23:23 +0000
@@ -0,0 +1,35 @@
+drop table if exists t1,t2,t3;
+create table t1 (c1 int) engine=maria;
+create table t2 (c1 int) engine=maria;
+create table t3 (c1 int) engine=maria;
+lock tables t1 write, t2 write, t3 write, t1 as t4 read;
+alter table t2 add column c2 int;
+drop table t1, t2, t3;
+create table t1 (a int) engine=maria;
+create table t2 (a int) engine=maria;
+lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write;
+insert t1 select * from t2;
+drop table t2;
+"table dropped";
+ERROR 42S02: Table 'test.t2' doesn't exist
+drop table t1;
+create table t1 (a int, b int) engine=maria;
+create table t2 (c int, d int) engine=maria;
+insert into t1 values(1,1);
+insert into t1 values(2,2);
+insert into t2 values(1,2);
+lock table t1 read;
+update t1,t2 set c=a where b=d;
+select c from t2;
+c
+2
+unlock tables;
+drop table t1;
+drop table t2;
+create table t1 (a int) engine=maria;
+create table t2 (a int) engine=maria;
+lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write;
+insert t1 select * from t2;
+drop table t2;
+ERROR 42S02: Table 'test.t2' doesn't exist
+drop table t1;
=== added file 'mysql-test/suite/maria/t/maria-lock.test'
--- a/mysql-test/suite/maria/t/maria-lock.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/maria/t/maria-lock.test 2008-10-21 23:23:23 +0000
@@ -0,0 +1,98 @@
+#
+# Different cases involving locking that has failed with Maria
+#
+# Can't test with embedded server
+-- source include/not_embedded.inc
+
+--disable_warnings
+drop table if exists t1,t2,t3;
+--enable_warnings
+
+# Check that a lock merge works.
+create table t1 (c1 int) engine=maria;
+create table t2 (c1 int) engine=maria;
+create table t3 (c1 int) engine=maria;
+lock tables t1 write, t2 write, t3 write, t1 as t4 read;
+alter table t2 add column c2 int;
+drop table t1, t2, t3;
+
+#
+# Bug #39395 maria_extra: Assertion `share->reopen == 1' failed
+#
+# Test problem when using locks on many tables and droping a table that
+# is to-be-locked by another thread. Dropped table locked twice
+#
+
+connect (locker,localhost,root,,);
+connect (reader,localhost,root,,);
+connect (writer,localhost,root,,);
+
+connection locker;
+create table t1 (a int) engine=maria;
+create table t2 (a int) engine=maria;
+lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write;
+connection reader;
+send insert t1 select * from t2;
+connection locker;
+let $wait_condition=
+ select count(*) = 1 from information_schema.processlist
+ where state = "Table lock" and info = "insert t1 select * from t2";
+--source include/wait_condition.inc
+drop table t2;
+--echo "table dropped";
+connection reader;
+--error 1146
+reap;
+connection locker;
+drop table t1;
+connection default;
+
+#
+# We need to disconnect and reconnect for the bug to appear. This is still
+# part of Bug#39395
+#
+
+disconnect locker;
+disconnect reader;
+disconnect writer;
+connect (locker,localhost,root,,);
+connect (reader,localhost,root,,);
+connect (writer,localhost,root,,);
+
+connection locker;
+create table t1 (a int, b int) engine=maria;
+create table t2 (c int, d int) engine=maria;
+insert into t1 values(1,1);
+insert into t1 values(2,2);
+insert into t2 values(1,2);
+lock table t1 read;
+connection writer;
+update t1,t2 set c=a where b=d;
+connection reader;
+select c from t2;
+connection locker;
+unlock tables;
+drop table t1;
+drop table t2;
+
+connection locker;
+create table t1 (a int) engine=maria;
+create table t2 (a int) engine=maria;
+lock table t1 write, t2 write, t1 as t1_2 write, t2 as t2_2 write;
+connection reader;
+send insert t1 select * from t2;
+connection locker;
+let $wait_condition=
+ select count(*) = 1 from information_schema.processlist
+ where state = "Table lock" and info = "insert t1 select * from t2";
+--source include/wait_condition.inc
+drop table t2;
+connection reader;
+--error 1146
+reap;
+connection locker;
+drop table t1;
+connection default;
+disconnect locker;
+disconnect reader;
+disconnect writer;
=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc 2008-10-20 19:13:22 +0000
+++ b/sql/sql_base.cc 2008-10-21 23:23:23 +0000
@@ -2031,12 +2031,16 @@ bool wait_while_table_is_used(THD *thd,
enum ha_extra_function function)
{
enum thr_lock_type old_lock_type;
-
DBUG_ENTER("wait_while_table_is_used");
DBUG_PRINT("enter", ("table: '%s' share: %p db_stat: %u version: %lu",
table->s->table_name.str, table->s,
table->db_stat, table->s->version));
+ /* Ensure no one can reopen table before it's removed */
+ pthread_mutex_lock(&LOCK_open);
+ table->s->version= 0;
+ pthread_mutex_unlock(&LOCK_open);
+
old_lock_type= table->reginfo.lock_type;
mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */
=== modified file 'storage/maria/ma_extra.c'
--- a/storage/maria/ma_extra.c 2008-10-20 09:16:47 +0000
+++ b/storage/maria/ma_extra.c 2008-10-21 23:23:23 +0000
@@ -279,11 +279,12 @@ int maria_extra(MARIA_HA *info, enum ha_
case HA_EXTRA_FORCE_REOPEN:
/*
MySQL uses this case after it has closed all other instances
- of this table.
- We however do a flush here for additional safety.
+ of this table; Note that MySQL may have several copies of the table
+ in the same thread!
+
+ We owever do a flush of data and index here for additional safety.
*/
/** @todo consider porting these flush-es to MyISAM */
- DBUG_ASSERT(share->reopen == 1);
error= _ma_flush_table_files(info, MARIA_FLUSH_DATA | MARIA_FLUSH_INDEX,
FLUSH_FORCE_WRITE, FLUSH_FORCE_WRITE);
if (!error && share->changed)
| Thread |
|---|
| • bzr commit into mysql-6.0 branch (monty:2746) Bug#39395 | Michael Widenius | 22 Oct |