diff --git a/mysql-test/suite/innodb/r/alter_partitioned_debug.result b/mysql-test/suite/innodb/r/alter_partitioned_debug.result new file mode 100644 index 00000000000..d2ec602c6d7 --- /dev/null +++ b/mysql-test/suite/innodb/r/alter_partitioned_debug.result @@ -0,0 +1,27 @@ +CREATE TABLE t1 (a INT, b VARCHAR(10)) ENGINE=InnoDB +PARTITION BY RANGE(a) +(PARTITION pa VALUES LESS THAN (3), +PARTITION pb VALUES LESS THAN (5)); +INSERT INTO t1 VALUES(2,'two'),(2,'two'),(4,'four'); +connect ddl,localhost,root,,test; +SET DEBUG_SYNC = 'inplace_after_index_build SIGNAL go WAIT_FOR done'; +ALTER TABLE t1 ADD UNIQUE KEY (a,b(3)); +connection default; +SET DEBUG_SYNC = 'now WAIT_FOR go'; +BEGIN; +SELECT * FROM t1 FOR UPDATE; +a b +2 two +2 two +4 four +SET DEBUG_SYNC = 'now SIGNAL done'; +connection ddl; +ERROR 23000: Duplicate entry '2-two' for key 'a' +connection default; +DELETE FROM t1; +disconnect ddl; +SET DEBUG_SYNC = 'RESET'; +CHECK TABLE t1; +Table Op Msg_type Msg_text +test.t1 check status OK +DROP TABLE t1; diff --git a/mysql-test/suite/innodb/t/alter_partitioned_debug.test b/mysql-test/suite/innodb/t/alter_partitioned_debug.test new file mode 100644 index 00000000000..34565e12036 --- /dev/null +++ b/mysql-test/suite/innodb/t/alter_partitioned_debug.test @@ -0,0 +1,34 @@ +--source include/have_innodb.inc +--source include/have_partition.inc +--source include/have_debug.inc +--source include/have_debug_sync.inc + +CREATE TABLE t1 (a INT, b VARCHAR(10)) ENGINE=InnoDB +PARTITION BY RANGE(a) +(PARTITION pa VALUES LESS THAN (3), +PARTITION pb VALUES LESS THAN (5)); + +INSERT INTO t1 VALUES(2,'two'),(2,'two'),(4,'four'); + +connect ddl,localhost,root,,test; +SET DEBUG_SYNC = 'inplace_after_index_build SIGNAL go WAIT_FOR done'; +send ALTER TABLE t1 ADD UNIQUE KEY (a,b(3)); + +connection default; +SET DEBUG_SYNC = 'now WAIT_FOR go'; +BEGIN; +SELECT * FROM t1 FOR UPDATE; +SET DEBUG_SYNC = 'now SIGNAL done'; + +connection ddl; +--error ER_DUP_ENTRY +reap; + +connection default; +DELETE FROM t1; +disconnect ddl; + +SET DEBUG_SYNC = 'RESET'; + +CHECK TABLE t1; +DROP TABLE t1; diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc index 7b9a0373c48..949bbbc0d74 100644 --- a/storage/innobase/dict/dict0defrag_bg.cc +++ b/storage/innobase/dict/dict0defrag_bg.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2016, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2016, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -232,7 +232,7 @@ dict_stats_process_entry_from_defrag_pool() ? dict_table_find_index_on_id(table, index_id) : NULL; - if (!index || dict_index_is_corrupted(index)) { + if (!index || index->is_corrupted()) { if (table) { dict_table_close(table, TRUE, FALSE); } diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 1bebab914c8..f39c4900995 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -2521,10 +2521,10 @@ dict_load_indexes( } ut_ad(index); + ut_ad(!dict_index_is_online_ddl(index)); /* Check whether the index is corrupted */ - if (dict_index_is_corrupted(index)) { - + if (index->is_corrupted()) { ib::error() << "Index " << index->name << " of table " << table->name << " is corrupted"; @@ -3044,10 +3044,7 @@ err_exit: table = NULL; goto func_exit; } else { - dict_index_t* clust_index; - clust_index = dict_table_get_first_index(table); - - if (dict_index_is_corrupted(clust_index)) { + if (table->indexes.start->is_corrupted()) { table->corrupted = true; } } @@ -3095,14 +3092,11 @@ err_exit: if (!srv_force_recovery || !index - || !dict_index_is_clust(index)) { - + || !index->is_primary()) { dict_table_remove_from_cache(table); table = NULL; - - } else if (dict_index_is_corrupted(index) + } else if (index->is_corrupted() && table->is_readable()) { - /* It is possible we force to load a corrupted clustered index if srv_load_corrupted is set. Mark the table as corrupted in this case */ diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index 67991814540..98a846bcaba 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -158,9 +158,8 @@ dict_stats_should_ignore_index( /*===========================*/ const dict_index_t* index) /*!< in: index */ { - return((index->type & DICT_FTS) - || dict_index_is_corrupted(index) - || dict_index_is_spatial(index) + return((index->type & (DICT_FTS | DICT_SPATIAL)) + || index->is_corrupted() || index->to_be_dropped || !index->is_committed()); } @@ -2228,7 +2227,7 @@ dict_stats_update_persistent( index = dict_table_get_first_index(table); if (index == NULL - || dict_index_is_corrupted(index) + || index->is_corrupted() || (index->type | DICT_UNIQUE) != (DICT_CLUSTERED | DICT_UNIQUE)) { /* Table definition is corrupt */ diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index c42cba4c12e..b5c4a44514d 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -6549,7 +6549,7 @@ fts_check_corrupt_index( if (index->id == aux_table->index_id) { ut_ad(index->type & DICT_FTS); dict_table_close(table, true, false); - return(dict_index_is_corrupted(index)); + return index->is_corrupted(); } } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index fd8e2de4819..bf2294f0774 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -9406,13 +9406,13 @@ ha_innobase::index_read( dict_index_t* index = m_prebuilt->index; - if (index == NULL || dict_index_is_corrupted(index)) { + if (index == NULL || index->is_corrupted()) { m_prebuilt->index_usable = FALSE; DBUG_RETURN(HA_ERR_CRASHED); } if (!m_prebuilt->index_usable) { - DBUG_RETURN(dict_index_is_corrupted(index) + DBUG_RETURN(index->is_corrupted() ? HA_ERR_INDEX_CORRUPT : HA_ERR_TABLE_DEF_CHANGED); } @@ -9671,14 +9671,14 @@ ha_innobase::change_active_index( m_prebuilt->trx, m_prebuilt->index); if (!m_prebuilt->index_usable) { - if (dict_index_is_corrupted(m_prebuilt->index)) { + if (m_prebuilt->index->is_corrupted()) { char table_name[MAX_FULL_NAME_LEN + 1]; innobase_format_name( table_name, sizeof table_name, m_prebuilt->index->table->name.m_name); - if (dict_index_is_clust(m_prebuilt->index)) { + if (m_prebuilt->index->is_primary()) { ut_ad(m_prebuilt->index->table->corrupted); push_warning_printf( m_user_thd, Sql_condition::WARN_LEVEL_WARN, @@ -13662,7 +13662,7 @@ ha_innobase::records_in_range( n_rows = HA_POS_ERROR; goto func_exit; } - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { n_rows = HA_ERR_INDEX_CORRUPT; goto func_exit; } @@ -14522,7 +14522,7 @@ ha_innobase::defragment_table( for (index = dict_table_get_first_index(table); index; index = dict_table_get_next_index(index)) { - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { continue; } @@ -14721,7 +14721,7 @@ ha_innobase::check( clustered index, we will do so here */ index = dict_table_get_first_index(m_prebuilt->table); - if (!dict_index_is_corrupted(index)) { + if (!index->is_corrupted()) { dict_set_corrupted( index, m_prebuilt->trx, "CHECK TABLE"); } @@ -14759,7 +14759,7 @@ ha_innobase::check( } if (!(check_opt->flags & T_QUICK) - && !dict_index_is_corrupted(index)) { + && !index->is_corrupted()) { /* Enlarge the fatal lock wait timeout during CHECK TABLE. */ my_atomic_addlong( @@ -14811,7 +14811,7 @@ ha_innobase::check( DBUG_EXECUTE_IF( "dict_set_index_corrupted", - if (!dict_index_is_clust(index)) { + if (!index->is_primary()) { m_prebuilt->index_usable = FALSE; // row_mysql_lock_data_dictionary(m_prebuilt->trx); dict_set_corrupted(index, m_prebuilt->trx, "dict_set_index_corrupted"); @@ -14819,7 +14819,7 @@ ha_innobase::check( }); if (UNIV_UNLIKELY(!m_prebuilt->index_usable)) { - if (dict_index_is_corrupted(m_prebuilt->index)) { + if (index->is_corrupted()) { push_warning_printf( m_user_thd, Sql_condition::WARN_LEVEL_WARN, @@ -14859,7 +14859,7 @@ ha_innobase::check( DBUG_EXECUTE_IF( "dict_set_index_corrupted", - if (!dict_index_is_clust(index)) { + if (!index->is_primary()) { ret = DB_CORRUPTION; }); diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index d064ebccfe2..a8f05f039fa 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -4784,8 +4784,7 @@ new_clustered_failed: = dict_table_get_first_index(user_table); index != NULL; index = dict_table_get_next_index(index)) { - if (!index->to_be_dropped - && dict_index_is_corrupted(index)) { + if (!index->to_be_dropped && index->is_corrupted()) { my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0)); goto error_handled; } @@ -4795,8 +4794,7 @@ new_clustered_failed: = dict_table_get_first_index(user_table); index != NULL; index = dict_table_get_next_index(index)) { - if (!index->to_be_dropped - && dict_index_is_corrupted(index)) { + if (!index->to_be_dropped && index->is_corrupted()) { my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0)); goto error_handled; } @@ -5597,8 +5595,7 @@ ha_innobase::prepare_inplace_alter_table( if (indexed_table->corrupted || dict_table_get_first_index(indexed_table) == NULL - || dict_index_is_corrupted( - dict_table_get_first_index(indexed_table))) { + || dict_table_get_first_index(indexed_table)->is_corrupted()) { /* The clustered index is corrupted. */ my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0)); DBUG_RETURN(true); @@ -5885,7 +5882,7 @@ found_fk: " with name %s", key->name); } else { ut_ad(!index->to_be_dropped); - if (!dict_index_is_clust(index)) { + if (!index->is_primary()) { drop_index[n_drop_index++] = index; } else { drop_primary = index; @@ -5986,7 +5983,7 @@ check_if_can_drop_indexes: for (dict_index_t* index = dict_table_get_first_index(indexed_table); index != NULL; index = dict_table_get_next_index(index)) { - if (!index->to_be_dropped && dict_index_is_corrupted(index)) { + if (!index->to_be_dropped && index->is_corrupted()) { my_error(ER_INDEX_CORRUPT, MYF(0), index->name()); goto err_exit; } @@ -7717,7 +7714,7 @@ commit_try_rebuild( DBUG_ASSERT(dict_index_get_online_status(index) == ONLINE_INDEX_COMPLETE); DBUG_ASSERT(index->is_committed()); - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { my_error(ER_INDEX_CORRUPT, MYF(0), index->name()); DBUG_RETURN(true); } @@ -7966,7 +7963,7 @@ commit_try_norebuild( DBUG_ASSERT(dict_index_get_online_status(index) == ONLINE_INDEX_COMPLETE); DBUG_ASSERT(!index->is_committed()); - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { /* Report a duplicate key error for the index that was flagged corrupted, most likely diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index 82f3cf403ba..0592b64b669 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -702,7 +702,7 @@ dict_table_get_next_index( /* Skip corrupted index */ #define dict_table_skip_corrupt_index(index) \ - while (index && dict_index_is_corrupted(index)) { \ + while (index && index->is_corrupted()) { \ index = dict_table_get_next_index(index); \ } @@ -1835,16 +1835,6 @@ dict_table_is_corrupted( const dict_table_t* table) /*!< in: table */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/**********************************************************************//** -Check whether the index is corrupted. -@return nonzero for corrupted index, zero for valid indexes */ -UNIV_INLINE -ulint -dict_index_is_corrupted( -/*====================*/ - const dict_index_t* index) /*!< in: index */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); - /**********************************************************************//** Flags an index and table corrupted both in the data dictionary cache and in the system table SYS_INDEXES. */ diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index f93c803294d..e20da7c708a 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -1486,21 +1486,6 @@ dict_table_is_corrupted( return(table->corrupted); } -/********************************************************************//** -Check whether the index is corrupted. -@return nonzero for corrupted index, zero for valid indexes */ -UNIV_INLINE -ulint -dict_index_is_corrupted( -/*====================*/ - const dict_index_t* index) /*!< in: index */ -{ - ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); - - return((index->type & DICT_CORRUPT) - || (index->table && index->table->corrupted)); -} - /********************************************************************//** Check if the tablespace for the table has been discarded. @return true if the tablespace has been discarded. */ diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 3c8366ae28e..18e600c25d3 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -980,6 +980,9 @@ struct dict_index_t{ { return DICT_CLUSTERED == (type & (DICT_CLUSTERED | DICT_IBUF)); } + + /** @return whether the index is corrupted */ + inline bool is_corrupted() const; }; /** The status of online index creation */ @@ -1724,6 +1727,13 @@ inline bool dict_index_t::is_readable() const return(UNIV_LIKELY(!table->file_unreadable)); } +inline bool dict_index_t::is_corrupted() const +{ + return UNIV_UNLIKELY(online_status >= ONLINE_INDEX_ABORTED + || (type & DICT_CORRUPT) + || (table && table->corrupted)); +} + /*******************************************************************//** Initialise the table lock list. */ void diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 76809222f2c..1aa97bc34c5 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3686,8 +3686,7 @@ row_ins( node->index = NULL; node->entry = NULL; break;); /* Skip corrupted secondary index and its entry */ - while (node->index && dict_index_is_corrupted(node->index)) { - + while (node->index && node->index->is_corrupted()) { node->index = dict_table_get_next_index(node->index); node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); } diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc index 90f219dce6a..3dbc1a4b93e 100644 --- a/storage/innobase/row/row0log.cc +++ b/storage/innobase/row/row0log.cc @@ -293,7 +293,7 @@ row_log_online_op( ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_S) || rw_lock_own(dict_index_get_lock(index), RW_LOCK_X)); - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { return; } @@ -613,8 +613,8 @@ row_log_table_delete( &index->lock, RW_LOCK_FLAG_S | RW_LOCK_FLAG_X | RW_LOCK_FLAG_SX)); - if (dict_index_is_corrupted(index) - || !dict_index_is_online_ddl(index) + if (index->online_status != ONLINE_INDEX_CREATION + || (index->type & DICT_CORRUPT) || index->table->corrupted || index->online_log->error != DB_SUCCESS) { return; } @@ -922,8 +922,8 @@ row_log_table_low( ut_ad(!old_pk || !insert); ut_ad(!old_pk || old_pk->n_v_fields == 0); - if (dict_index_is_corrupted(index) - || !dict_index_is_online_ddl(index) + if (index->online_status != ONLINE_INDEX_CREATION + || (index->type & DICT_CORRUPT) || index->table->corrupted || index->online_log->error != DB_SUCCESS) { return; } @@ -2672,7 +2672,7 @@ next_block: goto interrupted; } - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { error = DB_INDEX_CORRUPT; goto func_exit; } @@ -3167,7 +3167,7 @@ row_log_apply_op_low( ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_X) == has_index_lock); - ut_ad(!dict_index_is_corrupted(index)); + ut_ad(!index->is_corrupted()); ut_ad(trx_id != 0 || op == ROW_OP_DELETE); DBUG_LOG("ib_create_index", @@ -3411,7 +3411,7 @@ row_log_apply_op( ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_X) == has_index_lock); - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { *error = DB_INDEX_CORRUPT; return(NULL); } @@ -3548,7 +3548,7 @@ next_block: goto func_exit; } - if (dict_index_is_corrupted(index)) { + if (index->is_corrupted()) { error = DB_INDEX_CORRUPT; goto func_exit; } diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index cbd5aa2f316..0f55ce00336 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -4443,13 +4443,13 @@ row_merge_is_index_usable( const trx_t* trx, /*!< in: transaction */ const dict_index_t* index) /*!< in: index to check */ { - if (!dict_index_is_clust(index) + if (!index->is_primary() && dict_index_is_online_ddl(index)) { /* Indexes that are being created are not useable. */ return(false); } - return(!dict_index_is_corrupted(index) + return(!index->is_corrupted() && (dict_table_is_temporary(index->table) || index->trx_id == 0 || !MVCC::is_view_active(trx->read_view) diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index 697d59598f2..448e2984b41 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -888,8 +888,7 @@ try_again: clust_index = dict_table_get_first_index(node->table); - if (clust_index == NULL - || dict_index_is_corrupted(clust_index)) { + if (!clust_index || clust_index->is_corrupted()) { /* The table was corrupt in the data dictionary. dict_set_corrupted() works on an index, and we do not have an index to call it with. */ diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 9f14be17c11..b5e1bab352d 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -4253,18 +4253,14 @@ row_search_mvcc( ut_ad(!sync_check_iterate(sync_check())); if (dict_table_is_discarded(prebuilt->table)) { - DBUG_RETURN(DB_TABLESPACE_DELETED); - } else if (!prebuilt->table->is_readable()) { DBUG_RETURN(fil_space_get(prebuilt->table->space) ? DB_DECRYPTION_FAILED : DB_TABLESPACE_NOT_FOUND); } else if (!prebuilt->index_usable) { DBUG_RETURN(DB_MISSING_HISTORY); - - } else if (dict_index_is_corrupted(prebuilt->index)) { - + } else if (prebuilt->index->is_corrupted()) { DBUG_RETURN(DB_CORRUPTION); }