From 08baaa14b9075f61a043de4443cbecd36117cd12 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Tue, 25 Jun 2019 10:53:33 +0300 Subject: [PATCH] MDEV-16222 Assertion `0' failed in row_purge_remove_sec_if_poss_leaf on table with virtual columns and indexes Cause Stale thd->m_stmt_da->m_sql_errno which is from different invocation. Fix Reset error state before attempt to open table. --- .../r/purge_secondary_mdev-16222.result | 34 +++++++++++++ .../innodb/t/purge_secondary_mdev-16222.opt | 1 + .../innodb/t/purge_secondary_mdev-16222.test | 49 +++++++++++++++++++ sql/sql_class.cc | 5 ++ sql/sql_table.cc | 5 ++ sql/table.cc | 1 + storage/innobase/handler/ha_innodb.cc | 23 +++++++++ 7 files changed, 118 insertions(+) create mode 100644 mysql-test/suite/innodb/r/purge_secondary_mdev-16222.result create mode 100644 mysql-test/suite/innodb/t/purge_secondary_mdev-16222.opt create mode 100644 mysql-test/suite/innodb/t/purge_secondary_mdev-16222.test diff --git a/mysql-test/suite/innodb/r/purge_secondary_mdev-16222.result b/mysql-test/suite/innodb/r/purge_secondary_mdev-16222.result new file mode 100644 index 00000000000..30e8f9800fb --- /dev/null +++ b/mysql-test/suite/innodb/r/purge_secondary_mdev-16222.result @@ -0,0 +1,34 @@ +# +# MDEV-16222 Assertion `0' failed in row_purge_remove_sec_if_poss_leaf on table with virtual columns and indexes +# +set @saved_frequency= @@global.innodb_purge_rseg_truncate_frequency; +set global innodb_purge_rseg_truncate_frequency= 1; +set @saved_dbug= @@global.debug_dbug; +set global debug_dbug= "+d,ib_purge_virtual_mdev_16222_1,ib_purge_virtual_mdev_16222_2"; +create table t1 ( +pk serial, vb tinyblob as (b) virtual, b tinyblob, +primary key(pk), index (vb(64))) +engine innodb; +insert ignore into t1 (b) values ('foo'); +select * from t1 into outfile 'load.data'; +Warnings: +Warning 1287 ' INTO FROM...' instead +load data infile 'load.data' replace into table t1; +set debug_sync= "now WAIT_FOR latch_released"; +set global debug_dbug= "-d,ib_purge_virtual_mdev_16222_1"; +drop table t1; +set debug_sync= "now SIGNAL drop_started WAIT_FOR got_no_such_table"; +create table t1 ( +pk serial, vb tinyblob as (b) virtual, b tinyblob, +primary key(pk), index (vb(64))) +engine innodb; +insert ignore into t1 (b) values ('foo'); +select * from t1 into outfile 'load.data'; +Warnings: +Warning 1287 ' INTO FROM...' instead +load data infile 'load.data' replace into table t1; +set debug_sync= "now WAIT_FOR got_no_such_table"; +set debug_sync= "RESET"; +drop table t1; +set global innodb_purge_rseg_truncate_frequency= @saved_frequency; +set global debug_dbug= @saved_dbug; diff --git a/mysql-test/suite/innodb/t/purge_secondary_mdev-16222.opt b/mysql-test/suite/innodb/t/purge_secondary_mdev-16222.opt new file mode 100644 index 00000000000..a1207721427 --- /dev/null +++ b/mysql-test/suite/innodb/t/purge_secondary_mdev-16222.opt @@ -0,0 +1 @@ +--innodb-purge-threads=1 diff --git a/mysql-test/suite/innodb/t/purge_secondary_mdev-16222.test b/mysql-test/suite/innodb/t/purge_secondary_mdev-16222.test new file mode 100644 index 00000000000..05354d80aee --- /dev/null +++ b/mysql-test/suite/innodb/t/purge_secondary_mdev-16222.test @@ -0,0 +1,49 @@ +--source include/have_debug.inc +--source include/have_innodb.inc + +--echo # +--echo # MDEV-16222 Assertion `0' failed in row_purge_remove_sec_if_poss_leaf on table with virtual columns and indexes +--echo # + +--let $datadir= `select @@datadir` +set @saved_frequency= @@global.innodb_purge_rseg_truncate_frequency; +set global innodb_purge_rseg_truncate_frequency= 1; +set @saved_dbug= @@global.debug_dbug; +set global debug_dbug= "+d,ib_purge_virtual_mdev_16222_1,ib_purge_virtual_mdev_16222_2"; + +create table t1 ( + pk serial, vb tinyblob as (b) virtual, b tinyblob, + primary key(pk), index (vb(64))) +engine innodb; + +insert ignore into t1 (b) values ('foo'); + +select * from t1 into outfile 'load.data'; +load data infile 'load.data' replace into table t1; + +set debug_sync= "now WAIT_FOR latch_released"; +set global debug_dbug= "-d,ib_purge_virtual_mdev_16222_1"; +drop table t1; +--remove_file $datadir/test/load.data + +set debug_sync= "now SIGNAL drop_started WAIT_FOR got_no_such_table"; + +create table t1 ( + pk serial, vb tinyblob as (b) virtual, b tinyblob, + primary key(pk), index (vb(64))) +engine innodb; + +insert ignore into t1 (b) values ('foo'); + +select * from t1 into outfile 'load.data'; +load data infile 'load.data' replace into table t1; + +set debug_sync= "now WAIT_FOR got_no_such_table"; +set debug_sync= "RESET"; + +# cleanup +drop table t1; +--remove_file $datadir/test/load.data + +set global innodb_purge_rseg_truncate_frequency= @saved_frequency; +set global debug_dbug= @saved_dbug; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 326b8a3f16a..0f24604aa5e 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -4848,6 +4848,11 @@ unsigned long long thd_get_query_id(const MYSQL_THD thd) return((unsigned long long)thd->query_id); } +void thd_clear_error(MYSQL_THD thd) +{ + thd->clear_error(); +} + extern "C" const struct charset_info_st *thd_charset(MYSQL_THD thd) { return(thd->charset()); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 8a2d22b79c5..e147c5247fb 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -2108,6 +2108,11 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, bool if_exists, } } + DBUG_EXECUTE_IF("ib_purge_virtual_mdev_16222_1", + DBUG_ASSERT(!debug_sync_set_action( + thd, + STRING_WITH_LEN("now SIGNAL drop_started")));); + /* mark for close and remove all cached entries */ thd->push_internal_handler(&err_handler); error= mysql_rm_table_no_locks(thd, tables, if_exists, drop_temporary, diff --git a/sql/table.cc b/sql/table.cc index 34e7c23b2df..d65b4c7af08 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -8232,6 +8232,7 @@ int TABLE::update_virtual_fields(handler *h, enum_vcol_update_mode update_mode) int TABLE::update_virtual_field(Field *vf) { + DBUG_ASSERT(!in_use->is_error()); Query_arena backup_arena; DBUG_ENTER("TABLE::update_virtual_field"); in_use->set_n_backup_active_arena(expr_arena, &backup_arena); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 0d9a7689016..e77e5a99ca6 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -118,6 +118,8 @@ this program; if not, write to the Free Software Foundation, Inc., extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); unsigned long long thd_get_query_id(const MYSQL_THD thd); +void thd_clear_error(MYSQL_THD thd); + TABLE *find_fk_open_table(THD *thd, const char *db, size_t db_len, const char *table, size_t table_len); MYSQL_THD create_thd(); @@ -20168,6 +20170,8 @@ static TABLE* innodb_acquire_mdl(THD* thd, dict_table_t* table) return NULL; } + DEBUG_SYNC(thd, "ib_purge_virtual_latch_released"); + const table_id_t table_id = table->id; retry_mdl: const bool unaccessible = !table->is_readable() || table->corrupted; @@ -20179,6 +20183,10 @@ retry_mdl: TABLE* mariadb_table = open_purge_table(thd, db_buf, db_buf_len, tbl_buf, tbl_buf_len); + if (!mariadb_table) + thd_clear_error(thd); + + DEBUG_SYNC(thd, "ib_purge_virtual_got_no_such_table"); table = dict_table_open_on_id(table_id, false, DICT_TABLE_OP_NORMAL); @@ -20228,6 +20236,20 @@ fail: for purge thread */ static TABLE* innodb_find_table_for_vc(THD* thd, dict_table_t* table) { + DBUG_EXECUTE_IF( + "ib_purge_virtual_mdev_16222_1", + DBUG_ASSERT(!debug_sync_set_action( + thd, + STRING_WITH_LEN("ib_purge_virtual_latch_released " + "SIGNAL latch_released " + "WAIT_FOR drop_started")));); + DBUG_EXECUTE_IF( + "ib_purge_virtual_mdev_16222_2", + DBUG_ASSERT(!debug_sync_set_action( + thd, + STRING_WITH_LEN("ib_purge_virtual_got_no_such_table " + "SIGNAL got_no_such_table")));); + if (THDVAR(thd, background_thread)) { /* Purge thread acquires dict_sys.latch while processing undo log record. Release it @@ -20563,6 +20585,7 @@ innobase_get_computed_value( dbug_tmp_restore_column_map(mysql_table->write_set, old_write_set); if (ret != 0) { + // FIXME: Why this error message is macro-hidden? #ifdef INNODB_VIRTUAL_DEBUG ib::warn() << "Compute virtual column values failed "; fputs("InnoDB: Cannot compute value for following record ",