summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2022-12-09 10:42:19 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2022-12-09 10:42:19 +0200
commit782b2a750067a12be07b9c305ede4d2c28f173e0 (patch)
tree228deca0a3082f87e4b5b4fc0b86c0b7d0927e5c
parent8f3631d0096ceecc21f2879a9558fd9242f09f8c (diff)
downloadmariadb-git-782b2a750067a12be07b9c305ede4d2c28f173e0.tar.gz
MDEV-29144 ER_TABLE_SCHEMA_MISMATCH or crash on DISCARD/IMPORT
mysql_discard_or_import_tablespace(): On successful ALTER TABLE...DISCARD TABLESPACE, evict the table handle from the table definition cache, so that ha_innobase::close() will be invoked, like InnoDB expects to be the case. This will avoid an assertion failure ut_a(table->get_ref_count() == 0) during IMPORT TABLESPACE. ha_innobase::open(): Do not issue any ER_TABLESPACE_DISCARDED warning. Member functions for DML will do that. ha_innobase::truncate(), ha_innobase::check_if_supported_inplace_alter(): Issue ER_TABLESPACE_DISCARDED warnings, to compensate for the removal of the warning in ha_innobase::open(). row_quiesce_write_indexes(): Only write information about committed indexes. The ALTER TABLE t NOWAIT ADD INDEX(c) in the nondeterministic test case will most of the time fail due to a metadata lock (MDL) timeout and leave behind an uncommitted index. Reviewed by: Sergei Golubchik
-rw-r--r--mysql-test/suite/encryption/r/innodb-bad-key-change2.result1
-rw-r--r--mysql-test/suite/innodb/r/import_tablespace_race.result26
-rw-r--r--mysql-test/suite/innodb/t/import_tablespace_race.test54
-rw-r--r--sql/sql_table.cc4
-rw-r--r--storage/innobase/handler/ha_innodb.cc11
-rw-r--r--storage/innobase/handler/handler0alter.cc6
-rw-r--r--storage/innobase/row/row0quiesce.cc15
7 files changed, 110 insertions, 7 deletions
diff --git a/mysql-test/suite/encryption/r/innodb-bad-key-change2.result b/mysql-test/suite/encryption/r/innodb-bad-key-change2.result
index 5c28203ecf8..50da3dc7b2b 100644
--- a/mysql-test/suite/encryption/r/innodb-bad-key-change2.result
+++ b/mysql-test/suite/encryption/r/innodb-bad-key-change2.result
@@ -44,7 +44,6 @@ ALTER TABLE t1 DISCARD TABLESPACE;
restore: t1 .ibd and .cfg files
ALTER TABLE t1 DISCARD TABLESPACE;
Warnings:
-Warning 1814 Tablespace has been discarded for table `t1`
Warning 1812 Tablespace is missing for table 'test/t1'
restore: t1 .ibd and .cfg files
ALTER TABLE t1 IMPORT TABLESPACE;
diff --git a/mysql-test/suite/innodb/r/import_tablespace_race.result b/mysql-test/suite/innodb/r/import_tablespace_race.result
new file mode 100644
index 00000000000..786b8cbd261
--- /dev/null
+++ b/mysql-test/suite/innodb/r/import_tablespace_race.result
@@ -0,0 +1,26 @@
+#
+# MDEV-29144 ER_TABLE_SCHEMA_MISMATCH or crash on DISCARD/IMPORT
+#
+CREATE TABLE t (pk int PRIMARY KEY, c varchar(1024))
+ENGINE=InnoDB CHARSET latin1;
+INSERT INTO t SELECT seq, 'x' FROM seq_1_to_100;
+connect con1,localhost,root,,test;
+BEGIN NOT ATOMIC
+DECLARE a INT DEFAULT 0;
+REPEAT
+SET a= a+1;
+UPDATE t SET c = 'xx' WHERE pk = a;
+UNTIL a = 100
+END REPEAT;
+END
+$
+connection default;
+ALTER TABLE t NOWAIT ADD INDEX (c);
+connection con1;
+connection default;
+FLUSH TABLE t FOR EXPORT;
+UNLOCK TABLES;
+DROP TABLE t;
+ALTER TABLE t DISCARD TABLESPACE;
+ALTER TABLE t IMPORT TABLESPACE;
+DROP TABLE t;
diff --git a/mysql-test/suite/innodb/t/import_tablespace_race.test b/mysql-test/suite/innodb/t/import_tablespace_race.test
new file mode 100644
index 00000000000..532c2684dde
--- /dev/null
+++ b/mysql-test/suite/innodb/t/import_tablespace_race.test
@@ -0,0 +1,54 @@
+--source include/have_innodb.inc
+--source include/have_sequence.inc
+
+--echo #
+--echo # MDEV-29144 ER_TABLE_SCHEMA_MISMATCH or crash on DISCARD/IMPORT
+--echo #
+
+CREATE TABLE t (pk int PRIMARY KEY, c varchar(1024))
+ENGINE=InnoDB CHARSET latin1;
+INSERT INTO t SELECT seq, 'x' FROM seq_1_to_100;
+
+--connect (con1,localhost,root,,test)
+--delimiter $
+--send
+ BEGIN NOT ATOMIC
+ DECLARE a INT DEFAULT 0;
+ REPEAT
+ SET a= a+1;
+ UPDATE t SET c = 'xx' WHERE pk = a;
+ UNTIL a = 100
+ END REPEAT;
+ END
+$
+--delimiter ;
+
+--connection default
+--error 0,ER_LOCK_WAIT_TIMEOUT
+ALTER TABLE t NOWAIT ADD INDEX (c);
+
+--connection con1
+--reap
+
+--connection default
+
+--let $datadir= `select @@datadir`
+
+FLUSH TABLE t FOR EXPORT;
+--let $create= query_get_value(SHOW CREATE TABLE t, Create Table, 1)
+--copy_file $datadir/test/t.cfg $MYSQL_TMP_DIR/t.cfg
+--copy_file $datadir/test/t.ibd $MYSQL_TMP_DIR/t.ibd
+UNLOCK TABLES;
+
+DROP TABLE t;
+--disable_query_log
+eval $create;
+--enable_query_log
+
+ALTER TABLE t DISCARD TABLESPACE;
+--move_file $MYSQL_TMP_DIR/t.cfg $datadir/test/t.cfg
+--move_file $MYSQL_TMP_DIR/t.ibd $datadir/test/t.ibd
+ALTER TABLE t IMPORT TABLESPACE;
+
+# Cleanup
+DROP TABLE t;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 042ed9e1d6f..62a46dbf430 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -6075,6 +6075,10 @@ int mysql_discard_or_import_tablespace(THD *thd,
if (unlikely(error))
goto err;
+ if (discard)
+ tdc_remove_table(thd, TDC_RT_REMOVE_NOT_OWN, table_list->table->s->db.str,
+ table_list->table->s->table_name.str, true);
+
/*
The 0 in the call below means 'not in a transaction', which means
immediate invalidation; that is probably what we wish here
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index aa1bc5844e3..a1f58091a90 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -6268,11 +6268,6 @@ no_such_table:
MONITOR_INC(MONITOR_TABLE_OPEN);
if ((ib_table->flags2 & DICT_TF2_DISCARDED)) {
-
- ib_senderrf(thd,
- IB_LOG_LEVEL_WARN, ER_TABLESPACE_DISCARDED,
- table->s->table_name.str);
-
/* Allow an open because a proper DISCARD should have set
all the flags and index root page numbers to FIL_NULL that
should prevent any DML from running but it should allow DDL
@@ -13631,6 +13626,12 @@ int ha_innobase::truncate()
if (ib_table->is_temporary()) {
info.options|= HA_LEX_CREATE_TMP_TABLE;
} else {
+ if (!ib_table->space) {
+ ib_senderrf(m_user_thd,
+ IB_LOG_LEVEL_WARN, ER_TABLESPACE_DISCARDED,
+ table->s->table_name.str);
+ }
+
dict_get_and_save_data_dir_path(ib_table, false);
}
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index cd40fe3145e..19c90fed74c 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1013,6 +1013,12 @@ ha_innobase::check_if_supported_inplace_alter(
update_thd();
+ if (!m_prebuilt->table->space) {
+ ib_senderrf(m_user_thd, IB_LOG_LEVEL_WARN,
+ ER_TABLESPACE_DISCARDED,
+ table->s->table_name.str);
+ }
+
if (ha_alter_info->handler_flags
& ~(INNOBASE_INPLACE_IGNORE
| INNOBASE_ALTER_INSTANT
diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc
index 94a372bd046..5af026ecbe8 100644
--- a/storage/innobase/row/row0quiesce.cc
+++ b/storage/innobase/row/row0quiesce.cc
@@ -106,11 +106,17 @@ row_quiesce_write_indexes(
FILE* file, /*!< in: file to write to */
THD* thd) /*!< in/out: session */
{
+ ulint n_indexes = 0;
+ for (const dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
+ index; index = UT_LIST_GET_NEXT(indexes, index)) {
+ n_indexes += index->is_committed();
+ }
+
{
byte row[sizeof(ib_uint32_t)];
/* Write the number of indexes in the table. */
- mach_write_to_4(row, UT_LIST_GET_LEN(table->indexes));
+ mach_write_to_4(row, n_indexes);
DBUG_EXECUTE_IF("ib_export_io_write_failure_11",
close(fileno(file)););
@@ -132,6 +138,12 @@ row_quiesce_write_indexes(
index != 0 && err == DB_SUCCESS;
index = UT_LIST_GET_NEXT(indexes, index)) {
+ if (!index->is_committed()) {
+ continue;
+ }
+
+ ut_ad(n_indexes); ut_d(n_indexes--);
+
byte* ptr;
byte row[sizeof(index_id_t)
+ sizeof(ib_uint32_t) * 8];
@@ -202,6 +214,7 @@ row_quiesce_write_indexes(
err = row_quiesce_write_index_fields(index, file, thd);
}
+ ut_ad(!n_indexes);
return(err);
}