From 5d6a99e5d851cc47ca5b545e28055f2b6240b419 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Fri, 5 Jul 2019 12:45:35 +0530 Subject: MDEV-15641 InnoDB crash while committing table-rebuilding ALTER TABLE - Addressed Eugene's review comments. - Renamed the test case. - Added the comment about applying the online log --- mysql-test/suite/innodb/r/alter_big.result | 49 ---------- mysql-test/suite/innodb/r/alter_large_dml.result | 49 ++++++++++ mysql-test/suite/innodb/t/alter_big.opt | 2 - mysql-test/suite/innodb/t/alter_big.test | 53 ----------- mysql-test/suite/innodb/t/alter_large_dml.opt | 2 + mysql-test/suite/innodb/t/alter_large_dml.test | 53 +++++++++++ storage/innobase/handler/handler0alter.cc | 116 ++++++++++++----------- 7 files changed, 166 insertions(+), 158 deletions(-) delete mode 100644 mysql-test/suite/innodb/r/alter_big.result create mode 100644 mysql-test/suite/innodb/r/alter_large_dml.result delete mode 100644 mysql-test/suite/innodb/t/alter_big.opt delete mode 100644 mysql-test/suite/innodb/t/alter_big.test create mode 100644 mysql-test/suite/innodb/t/alter_large_dml.opt create mode 100644 mysql-test/suite/innodb/t/alter_large_dml.test diff --git a/mysql-test/suite/innodb/r/alter_big.result b/mysql-test/suite/innodb/r/alter_big.result deleted file mode 100644 index 056e8fdd768..00000000000 --- a/mysql-test/suite/innodb/r/alter_big.result +++ /dev/null @@ -1,49 +0,0 @@ -CREATE TABLE t1(f1 char(200), f2 char(200), f3 char(200), -f4 char(200), f5 char(200), f6 char(200), -f7 char(200), f8 char(200))ENGINE=InnoDB; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -SET DEBUG_SYNC = 'inplace_after_index_build SIGNAL rebuilt WAIT_FOR dml_pause'; -SET DEBUG_SYNC = 'alter_table_inplace_before_lock_upgrade SIGNAL dml_restart WAIT_FOR dml_done'; -SET DEBUG_SYNC = 'row_log_table_apply2_before SIGNAL ddl_start'; -ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; -connect con1,localhost,root,,test; -SET DEBUG_SYNC = 'now WAIT_FOR rebuilt'; -BEGIN; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -SET DEBUG_SYNC = 'now SIGNAL dml_pause'; -SET DEBUG_SYNC = 'now WAIT_FOR dml_restart'; -ROLLBACK; -BEGIN; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -ROLLBACK; -BEGIN; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -ROLLBACK; -SET DEBUG_SYNC = 'now SIGNAL dml_done'; -connect con2, localhost,root,,test; -SET DEBUG_SYNC = 'now WAIT_FOR ddl_start'; -CREATE TABLE t2(f1 INT NOT NULL)ENGINE=InnoDB; -connection default; -SHOW CREATE TABLE t1; -Table Create Table -t1 CREATE TABLE `t1` ( - `f1` char(200) DEFAULT NULL, - `f2` char(200) DEFAULT NULL, - `f3` char(200) DEFAULT NULL, - `f4` char(200) DEFAULT NULL, - `f5` char(200) DEFAULT NULL, - `f6` char(200) DEFAULT NULL, - `f7` char(200) DEFAULT NULL, - `f8` char(200) DEFAULT NULL -) ENGINE=InnoDB DEFAULT CHARSET=latin1 -SELECT COUNT(*) FROM t1; -COUNT(*) -16384 -SET DEBUG_SYNC = 'RESET'; -DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/r/alter_large_dml.result b/mysql-test/suite/innodb/r/alter_large_dml.result new file mode 100644 index 00000000000..056e8fdd768 --- /dev/null +++ b/mysql-test/suite/innodb/r/alter_large_dml.result @@ -0,0 +1,49 @@ +CREATE TABLE t1(f1 char(200), f2 char(200), f3 char(200), +f4 char(200), f5 char(200), f6 char(200), +f7 char(200), f8 char(200))ENGINE=InnoDB; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +SET DEBUG_SYNC = 'inplace_after_index_build SIGNAL rebuilt WAIT_FOR dml_pause'; +SET DEBUG_SYNC = 'alter_table_inplace_before_lock_upgrade SIGNAL dml_restart WAIT_FOR dml_done'; +SET DEBUG_SYNC = 'row_log_table_apply2_before SIGNAL ddl_start'; +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; +connect con1,localhost,root,,test; +SET DEBUG_SYNC = 'now WAIT_FOR rebuilt'; +BEGIN; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +SET DEBUG_SYNC = 'now SIGNAL dml_pause'; +SET DEBUG_SYNC = 'now WAIT_FOR dml_restart'; +ROLLBACK; +BEGIN; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +ROLLBACK; +BEGIN; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +ROLLBACK; +SET DEBUG_SYNC = 'now SIGNAL dml_done'; +connect con2, localhost,root,,test; +SET DEBUG_SYNC = 'now WAIT_FOR ddl_start'; +CREATE TABLE t2(f1 INT NOT NULL)ENGINE=InnoDB; +connection default; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` char(200) DEFAULT NULL, + `f2` char(200) DEFAULT NULL, + `f3` char(200) DEFAULT NULL, + `f4` char(200) DEFAULT NULL, + `f5` char(200) DEFAULT NULL, + `f6` char(200) DEFAULT NULL, + `f7` char(200) DEFAULT NULL, + `f8` char(200) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 +SELECT COUNT(*) FROM t1; +COUNT(*) +16384 +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/t/alter_big.opt b/mysql-test/suite/innodb/t/alter_big.opt deleted file mode 100644 index f6d3b8428c9..00000000000 --- a/mysql-test/suite/innodb/t/alter_big.opt +++ /dev/null @@ -1,2 +0,0 @@ ---innodb_fatal_semaphore_wait_threshold=20 ---innodb_online_alter_log_max_size=536870912 diff --git a/mysql-test/suite/innodb/t/alter_big.test b/mysql-test/suite/innodb/t/alter_big.test deleted file mode 100644 index 5ab3f394115..00000000000 --- a/mysql-test/suite/innodb/t/alter_big.test +++ /dev/null @@ -1,53 +0,0 @@ ---source include/big_test.inc ---source include/have_innodb.inc ---source include/have_debug.inc ---source include/have_debug_sync.inc ---source include/have_sequence.inc - -CREATE TABLE t1(f1 char(200), f2 char(200), f3 char(200), - f4 char(200), f5 char(200), f6 char(200), - f7 char(200), f8 char(200))ENGINE=InnoDB; - -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; - -SET DEBUG_SYNC = 'inplace_after_index_build SIGNAL rebuilt WAIT_FOR dml_pause'; -SET DEBUG_SYNC = 'alter_table_inplace_before_lock_upgrade SIGNAL dml_restart WAIT_FOR dml_done'; -SET DEBUG_SYNC = 'row_log_table_apply2_before SIGNAL ddl_start'; ---send -ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; - ---connect(con1,localhost,root,,test) -SET DEBUG_SYNC = 'now WAIT_FOR rebuilt'; -BEGIN; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -SET DEBUG_SYNC = 'now SIGNAL dml_pause'; -SET DEBUG_SYNC = 'now WAIT_FOR dml_restart'; -ROLLBACK; - -BEGIN; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; -ROLLBACK; - -BEGIN; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -INSERT INTO t1 SELECT * FROM t1; -ROLLBACK; - -SET DEBUG_SYNC = 'now SIGNAL dml_done'; - ---connect(con2, localhost,root,,test) -SET DEBUG_SYNC = 'now WAIT_FOR ddl_start'; -CREATE TABLE t2(f1 INT NOT NULL)ENGINE=InnoDB; - -connection default; -reap; -SHOW CREATE TABLE t1; - -SELECT COUNT(*) FROM t1; -SET DEBUG_SYNC = 'RESET'; -DROP TABLE t1, t2; diff --git a/mysql-test/suite/innodb/t/alter_large_dml.opt b/mysql-test/suite/innodb/t/alter_large_dml.opt new file mode 100644 index 00000000000..f6d3b8428c9 --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_large_dml.opt @@ -0,0 +1,2 @@ +--innodb_fatal_semaphore_wait_threshold=20 +--innodb_online_alter_log_max_size=536870912 diff --git a/mysql-test/suite/innodb/t/alter_large_dml.test b/mysql-test/suite/innodb/t/alter_large_dml.test new file mode 100644 index 00000000000..5ab3f394115 --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_large_dml.test @@ -0,0 +1,53 @@ +--source include/big_test.inc +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc +--source include/have_sequence.inc + +CREATE TABLE t1(f1 char(200), f2 char(200), f3 char(200), + f4 char(200), f5 char(200), f6 char(200), + f7 char(200), f8 char(200))ENGINE=InnoDB; + +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; + +SET DEBUG_SYNC = 'inplace_after_index_build SIGNAL rebuilt WAIT_FOR dml_pause'; +SET DEBUG_SYNC = 'alter_table_inplace_before_lock_upgrade SIGNAL dml_restart WAIT_FOR dml_done'; +SET DEBUG_SYNC = 'row_log_table_apply2_before SIGNAL ddl_start'; +--send +ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; + +--connect(con1,localhost,root,,test) +SET DEBUG_SYNC = 'now WAIT_FOR rebuilt'; +BEGIN; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +SET DEBUG_SYNC = 'now SIGNAL dml_pause'; +SET DEBUG_SYNC = 'now WAIT_FOR dml_restart'; +ROLLBACK; + +BEGIN; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +INSERT INTO t1 SELECT '','','','','','','','' FROM seq_1_to_16384; +ROLLBACK; + +BEGIN; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +INSERT INTO t1 SELECT * FROM t1; +ROLLBACK; + +SET DEBUG_SYNC = 'now SIGNAL dml_done'; + +--connect(con2, localhost,root,,test) +SET DEBUG_SYNC = 'now WAIT_FOR ddl_start'; +CREATE TABLE t2(f1 INT NOT NULL)ENGINE=InnoDB; + +connection default; +reap; +SHOW CREATE TABLE t1; + +SELECT COUNT(*) FROM t1; +SET DEBUG_SYNC = 'RESET'; +DROP TABLE t1, t2; diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index ce363a0d9c6..5ec0957f7ba 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8077,74 +8077,75 @@ static bool alter_rebuild_apply_log( TABLE* altered_table) { DBUG_ENTER("alter_rebuild_apply_log"); + + if (!ctx->online) { + DBUG_RETURN(false); + } + /* We copied the table. Any indexes that were requested to be dropped were not created in the copy of the table. Apply any last bit of the rebuild log and then rename the tables. */ dict_table_t* user_table = ctx->old_table; dict_table_t* rebuilt_table = ctx->new_table; - if (ctx->online) { - DEBUG_SYNC_C("row_log_table_apply2_before"); + DEBUG_SYNC_C("row_log_table_apply2_before"); - dict_vcol_templ_t* s_templ = NULL; + dict_vcol_templ_t* s_templ = NULL; - if (ctx->new_table->n_v_cols > 0) { - s_templ = UT_NEW_NOKEY( - dict_vcol_templ_t()); - s_templ->vtempl = NULL; + if (ctx->new_table->n_v_cols > 0) { + s_templ = UT_NEW_NOKEY( + dict_vcol_templ_t()); + s_templ->vtempl = NULL; - innobase_build_v_templ( - altered_table, ctx->new_table, s_templ, - NULL, true); - ctx->new_table->vc_templ = s_templ; - } + innobase_build_v_templ(altered_table, ctx->new_table, s_templ, + NULL, true); + ctx->new_table->vc_templ = s_templ; + } - dberr_t error = row_log_table_apply( - ctx->thr, user_table, altered_table, - static_cast( - ha_alter_info->handler_ctx)->m_stage); + dberr_t error = row_log_table_apply( + ctx->thr, user_table, altered_table, + static_cast( + ha_alter_info->handler_ctx)->m_stage); - if (s_templ) { - ut_ad(ctx->need_rebuild()); - dict_free_vc_templ(s_templ); - UT_DELETE(s_templ); - ctx->new_table->vc_templ = NULL; - } + if (s_templ) { + ut_ad(ctx->need_rebuild()); + dict_free_vc_templ(s_templ); + UT_DELETE(s_templ); + ctx->new_table->vc_templ = NULL; + } - ulint err_key = thr_get_trx(ctx->thr)->error_key_num; + ulint err_key = thr_get_trx(ctx->thr)->error_key_num; - switch (error) { - KEY* dup_key; - case DB_SUCCESS: - break; - case DB_DUPLICATE_KEY: - if (err_key == ULINT_UNDEFINED) { - /* This should be the hidden index on - FTS_DOC_ID. */ - dup_key = NULL; - } else { - DBUG_ASSERT(err_key < - ha_alter_info->key_count); - dup_key = &ha_alter_info - ->key_info_buffer[err_key]; - } - print_keydup_error(altered_table, dup_key, MYF(0)); - DBUG_RETURN(true); - case DB_ONLINE_LOG_TOO_BIG: - my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0), - get_error_key_name(err_key, ha_alter_info, - rebuilt_table)); - DBUG_RETURN(true); - case DB_INDEX_CORRUPT: - my_error(ER_INDEX_CORRUPT, MYF(0), - get_error_key_name(err_key, ha_alter_info, - rebuilt_table)); - DBUG_RETURN(true); - default: - my_error_innodb(error, ctx->old_table->name.m_name, - user_table->flags); - DBUG_RETURN(true); + switch (error) { + KEY* dup_key; + case DB_SUCCESS: + break; + case DB_DUPLICATE_KEY: + if (err_key == ULINT_UNDEFINED) { + /* This should be the hidden index on + FTS_DOC_ID. */ + dup_key = NULL; + } else { + DBUG_ASSERT(err_key < ha_alter_info->key_count); + dup_key = &ha_alter_info->key_info_buffer[err_key]; } + + print_keydup_error(altered_table, dup_key, MYF(0)); + DBUG_RETURN(true); + case DB_ONLINE_LOG_TOO_BIG: + my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0), + get_error_key_name(err_key, ha_alter_info, + rebuilt_table)); + DBUG_RETURN(true); + case DB_INDEX_CORRUPT: + my_error(ER_INDEX_CORRUPT, MYF(0), + get_error_key_name(err_key, ha_alter_info, + rebuilt_table)); + DBUG_RETURN(true); + default: + my_error_innodb(error, ctx->old_table->name.m_name, + user_table->flags); + DBUG_RETURN(true); } DBUG_RETURN(false); @@ -8295,6 +8296,13 @@ ha_innobase::commit_inplace_alter_table( fts_optimize_remove_table(ctx->new_table); } + /* Apply the online log of the table before acquiring + data dictionary latches. Here alter thread already acquired + MDL_EXCLUSIVE on the table. So there can't be anymore DDLs, DMLs + for the altered table. By applying the log here, InnoDB + makes sure that concurrent DDLs, purge thread or any other + background thread doesn't wait for the dict_operation_lock + for longer time. */ if (new_clustered && commit && alter_rebuild_apply_log( ctx, ha_alter_info, altered_table)) { -- cgit v1.2.1