summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuchen Pei <yuchen.pei@mariadb.com>2023-03-15 14:50:22 +1100
committerYuchen Pei <yuchen.pei@mariadb.com>2023-03-16 12:41:08 +1100
commita614c74cff1049608f8717e7c7e99bf863724d83 (patch)
treeb5f37794980f29380c0abccc3c31c8ff57c7fc88
parent2919d886358eb74f8756e5d3803f5dc47d967e03 (diff)
downloadmariadb-git-bb-11.0-mdev-26137-unsquashed.tar.gz
-rw-r--r--mysql-test/suite/innodb/r/import_recovery.result38
-rw-r--r--mysql-test/suite/innodb/t/import_no_cfg.test2
-rw-r--r--mysql-test/suite/innodb/t/import_recovery.test85
-rw-r--r--storage/innobase/handler/ha_innodb.cc32
4 files changed, 105 insertions, 52 deletions
diff --git a/mysql-test/suite/innodb/r/import_recovery.result b/mysql-test/suite/innodb/r/import_recovery.result
index 0ffecbb9116..bc8bb33dd45 100644
--- a/mysql-test/suite/innodb/r/import_recovery.result
+++ b/mysql-test/suite/innodb/r/import_recovery.result
@@ -1,18 +1,20 @@
-call mtr.add_suppression('.*Assertion.*failed.');
+#
+# MDEV-26137 ALTER TABLE IMPORT enhancement
+#
call mtr.add_suppression('InnoDB: Tablespace for table `test`.`t2` is set as discarded.');
-call mtr.add_suppression('InnoDB: ./test/t2.ibd: Page 0 at offset 0 looks corrupted.');
-call mtr.add_suppression("mariadbd: Index for table 't2' is corrupt; try to repair it");
# Recovery from crashes
## Creation of stub succeeds; server crashes; second import attempt succeeds
CREATE TABLE t1 (a int) ENGINE=InnoDB;
INSERT INTO t1 VALUES(42);
FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
+connect hang,localhost,root;
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
ALTER TABLE t2 IMPORT TABLESPACE;
-ERROR HY000: Lost connection to server during query
-# Restart mysqld after the crash and reconnect.
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
# restart
+disconnect hang;
ALTER TABLE t2 IMPORT TABLESPACE;
SELECT * FROM t2;
a
@@ -23,13 +25,17 @@ CREATE TABLE t1 (a int) ENGINE=InnoDB;
INSERT INTO t1 VALUES(42);
FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
+connect hang,localhost,root;
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
ALTER TABLE t2 IMPORT TABLESPACE;
-ERROR HY000: Lost connection to server during query
-# Restart mysqld after the crash and reconnect.
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
# restart
+disconnect hang;
DROP TABLE t1, t2;
# Recovery from corruption
+call mtr.add_suppression('InnoDB: ./test/t2.ibd: Page 0 at offset 0 looks corrupted.');
+call mtr.add_suppression("mariadbd: Index for table 't2' is corrupt; try to repair it");
## Recovery from corruption, with cfg
CREATE TABLE t1 (a int) ENGINE=InnoDB;
INSERT INTO t1 VALUES(42);
@@ -54,9 +60,12 @@ CREATE TABLE t1 (a int) ENGINE=InnoDB;
INSERT INTO t1 VALUES(42);
FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
+connect hang,localhost,root;
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
ALTER TABLE t2 IMPORT TABLESPACE;
-ERROR HY000: Lost connection to server during query
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
+disconnect hang;
# corrupting the 0th page
# Restart mysqld after the crash and reconnect.
# restart
@@ -68,9 +77,12 @@ CREATE TABLE t1 (a int) ENGINE=InnoDB;
INSERT INTO t1 VALUES(42);
FLUSH TABLES t1 FOR EXPORT;
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
+connect hang,localhost,root;
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
ALTER TABLE t2 IMPORT TABLESPACE;
-ERROR HY000: Lost connection to server during query
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
+disconnect hang;
# corrupting the 0th page
# Restart mysqld after the crash and reconnect.
# restart
diff --git a/mysql-test/suite/innodb/t/import_no_cfg.test b/mysql-test/suite/innodb/t/import_no_cfg.test
new file mode 100644
index 00000000000..2cc0e0feed5
--- /dev/null
+++ b/mysql-test/suite/innodb/t/import_no_cfg.test
@@ -0,0 +1,2 @@
+--source include/import_begin.inc
+--source include/import_end.inc
diff --git a/mysql-test/suite/innodb/t/import_recovery.test b/mysql-test/suite/innodb/t/import_recovery.test
index f1cc50abb51..f3501145a3a 100644
--- a/mysql-test/suite/innodb/t/import_recovery.test
+++ b/mysql-test/suite/innodb/t/import_recovery.test
@@ -1,16 +1,13 @@
--source include/have_innodb.inc
--source include/have_debug.inc
-let MYSQLD_DATADIR = `SELECT @@datadir`;
-let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
+--echo #
+--echo # MDEV-26137 ALTER TABLE IMPORT enhancement
+--echo #
+
let $MYSQLD_DATADIR = `SELECT @@datadir`;
---let $_server_id= `SELECT @@server_id`
---let $_expect_file_name= $MYSQLTEST_VARDIR/tmp/mysqld.$_server_id.expect
-call mtr.add_suppression('.*Assertion.*failed.');
call mtr.add_suppression('InnoDB: Tablespace for table `test`.`t2` is set as discarded.');
-call mtr.add_suppression('InnoDB: ./test/t2.ibd: Page 0 at offset 0 looks corrupted.');
-call mtr.add_suppression("mariadbd: Index for table 't2' is corrupt; try to repair it");
--echo # Recovery from crashes
--echo ## Creation of stub succeeds; server crashes; second import attempt succeeds
@@ -21,13 +18,19 @@ FLUSH TABLES t1 FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/t2.frm
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
-# Write file to make mysql-test-run.pl expect crash
---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
---error 2013
+
+connect (hang,localhost,root);
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
+send
+
ALTER TABLE t2 IMPORT TABLESPACE;
---echo # Restart mysqld after the crash and reconnect.
---source include/start_mysqld.inc
+
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
+let $shutdown_timeout=0;
+--source include/restart_mysqld.inc
+disconnect hang;
+
ALTER TABLE t2 IMPORT TABLESPACE;
SELECT * FROM t2;
DROP TABLE t1, t2;
@@ -40,16 +43,29 @@ FLUSH TABLES t1 FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/t2.frm
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
-# Write file to make mysql-test-run.pl expect crash
---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
---error 2013
+
+connect (hang,localhost,root);
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
+send
+
ALTER TABLE t2 IMPORT TABLESPACE;
---echo # Restart mysqld after the crash and reconnect.
---source include/start_mysqld.inc
+
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
+let $shutdown_timeout=0;
+--source include/restart_mysqld.inc
+disconnect hang;
+
DROP TABLE t1, t2;
--echo # Recovery from corruption
+
+let MYSQLD_DATADIR = `SELECT @@datadir`;
+let INNODB_PAGE_SIZE=`select @@innodb_page_size`;
+
+call mtr.add_suppression('InnoDB: ./test/t2.ibd: Page 0 at offset 0 looks corrupted.');
+call mtr.add_suppression("mariadbd: Index for table 't2' is corrupt; try to repair it");
+
--echo ## Recovery from corruption, with cfg
CREATE TABLE t1 (a int) ENGINE=InnoDB;
INSERT INTO t1 VALUES(42);
@@ -117,12 +133,19 @@ FLUSH TABLES t1 FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/t2.frm
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
-# Write file to make mysql-test-run.pl expect crash
---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
---error 2013
+
+connect (hang,localhost,root);
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
+send
+
ALTER TABLE t2 IMPORT TABLESPACE;
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
+let $shutdown_timeout=0;
+--source include/shutdown_mysqld.inc
+disconnect hang;
+
--echo # corrupting the 0th page
perl;
my $ps = $ENV{INNODB_PAGE_SIZE};
@@ -154,12 +177,19 @@ FLUSH TABLES t1 FOR EXPORT;
--copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/t2.frm
--copy_file $MYSQLD_DATADIR/test/t1.ibd $MYSQLD_DATADIR/test/t2.ibd
UNLOCK TABLES;
-SET DEBUG_DBUG='+d,die_after_create_stub_for_import';
-# Write file to make mysql-test-run.pl expect crash
---exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
---error 2013
+
+connect (hang,localhost,root);
+SET DEBUG_SYNC='ib_after_create_stub_for_import SIGNAL hung WAIT_FOR ever';
+send
+
ALTER TABLE t2 IMPORT TABLESPACE;
+connection default;
+SET DEBUG_SYNC='now WAIT_FOR hung';
+let $shutdown_timeout=0;
+--source include/shutdown_mysqld.inc
+disconnect hang;
+
--echo # corrupting the 0th page
perl;
my $ps = $ENV{INNODB_PAGE_SIZE};
@@ -182,4 +212,3 @@ EOF
--error ER_TABLE_SCHEMA_MISMATCH
ALTER TABLE t2 IMPORT TABLESPACE;
DROP TABLE t1, t2;
-
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 88e7aec7aad..bc0af456b54 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -1921,16 +1921,19 @@ static int prepare_create_stub_for_import(THD *thd, const char *name,
HA_CREATE_INFO& create_info)
{
DBUG_ENTER("prepare_create_stub_for_import");
- char norm_name[FN_REFLEN];
- normalize_table_name(norm_name, name);
FetchIndexRootPages fetchIndexRootPages(name);
if (fil_tablespace_iterate(fil_path_to_mysql_datadir, name,
IO_BUFFER_SIZE(srv_page_size),
fetchIndexRootPages)
!= DB_SUCCESS)
{
- sql_print_error("InnoDB: failed to get row format from ibd for %s.\n",
- norm_name);
+ const char *ibd_path = fil_make_filepath(
+ fil_path_to_mysql_datadir, table_name_t(const_cast<char*>(name)), IBD,
+ fil_path_to_mysql_datadir != nullptr);
+ if (!ibd_path)
+ return(DB_OUT_OF_MEMORY);
+ sql_print_error("InnoDB: failed to get row format from %s.\n",
+ ibd_path);
DBUG_RETURN(ER_INNODB_IMPORT_ERROR);
}
create_info.init();
@@ -1952,9 +1955,11 @@ static int prepare_create_stub_for_import(THD *thd, const char *name,
rec_format_from_cfg == REC_FORMAT_DYNAMIC) &&
create_info.row_type == ROW_TYPE_NOT_USED))
{
+ char norm_name[FN_REFLEN];
+ normalize_table_name(norm_name, name);
sql_print_error(
- "InnoDB: cfg and ibd disagree on row format for table %s.\n",
- norm_name);
+ "InnoDB: cfg and ibd disagree on row format for table %s.\n",
+ norm_name);
DBUG_RETURN(ER_INNODB_IMPORT_ERROR);
}
else
@@ -5928,10 +5933,9 @@ ha_innobase::open(const char* name, int, uint)
create_info))
DBUG_RETURN(err);
create(name, table, &create_info, true, nullptr);
- DBUG_EXECUTE_IF("die_after_create_stub_for_import", ut_ad(0););
+ DEBUG_SYNC(thd, "ib_after_create_stub_for_import");
ib_table = open_dict_table(name, norm_name, is_part,
DICT_ERR_IGNORE_FK_NOKEY);
- DEBUG_SYNC(thd, "ib_open_after_create_stub_for_import");
}
if (NULL == ib_table) {
@@ -13230,9 +13234,12 @@ ha_innobase::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info,
row_mysql_lock_data_dictionary(trx);
}
+ const bool importing= thd_ddl_options(ha_thd())->import_tablespace();
if (!error)
- error= info.create_table(own_trx &&
- !thd_ddl_options(ha_thd())->import_tablespace());
+ /* We can't possibly have foreign key information when creating a
+ stub table for importing .frm / .cfg / .ibd because it is not
+ stored in any of these files. */
+ error= info.create_table(own_trx && !importing);
if (own_trx || (info.flags2() & DICT_TF2_TEMPORARY))
{
@@ -13254,7 +13261,10 @@ ha_innobase::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info,
if (!error)
{
- if (!thd_ddl_options(ha_thd())->import_tablespace())
+ /* Skip stats update when creating a stub table for importing,
+ as it is not needed and would report error due to the table
+ not being readable yet. */
+ if (!importing)
dict_stats_update(info.table(), DICT_STATS_EMPTY_TABLE);
if (!info.table()->is_temporary())
log_write_up_to(trx->commit_lsn, true);