From ce7d6a288ca40e8a5e253c5c2e7084cfc985534c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 24 Aug 2010 11:10:03 +0300 Subject: [PATCH] Bug#55832: selects crash too easily when innodb_force_recovery>3 dict_update_statistics_low(): Create bogus statistics for those indexes that cannot be accessed because of the innodb_force_recovery setting. ha_innobase::info(): Calculate statistics for each index, even if innodb_force_recovery is set. Fill in bogus data for those indexes that are not accessed because of the innodb_force_recovery setting. --- storage/innodb_plugin/ChangeLog | 5 ++ storage/innodb_plugin/dict/dict0dict.c | 57 +++++++++++++--------- storage/innodb_plugin/handler/ha_innodb.cc | 39 +++++++-------- 3 files changed, 60 insertions(+), 41 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 9fe5c1e7ee6..538cd40dd5b 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,8 @@ +2010-08-24 The InnoDB Team + + * handler/ha_innodb.c, dict/dict0dict.c: + Fix Bug #55832 selects crash too easily when innodb_force_recovery>3 + 2010-08-03 The InnoDB Team * include/ut0mem.h, ut/ut0mem.c: diff --git a/storage/innodb_plugin/dict/dict0dict.c b/storage/innodb_plugin/dict/dict0dict.c index a79f084e327..560534345f9 100644 --- a/storage/innodb_plugin/dict/dict0dict.c +++ b/storage/innodb_plugin/dict/dict0dict.c @@ -4191,7 +4191,6 @@ dict_update_statistics_low( dictionary mutex */ { dict_index_t* index; - ulint size; ulint sum_of_index_sizes = 0; if (table->ibd_file_missing) { @@ -4206,14 +4205,6 @@ dict_update_statistics_low( return; } - /* If we have set a high innodb_force_recovery level, do not calculate - statistics, as a badly corrupted index can cause a crash in it. */ - - if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { - - return; - } - /* Find out the sizes of the indexes and how many different values for the key they approximately have */ @@ -4225,26 +4216,48 @@ dict_update_statistics_low( return; } - while (index) { - size = btr_get_size(index, BTR_TOTAL_SIZE); - index->stat_index_size = size; + do { + if (UNIV_LIKELY + (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE + || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO + && dict_index_is_clust(index)))) { + ulint size; + size = btr_get_size(index, BTR_TOTAL_SIZE); - sum_of_index_sizes += size; + index->stat_index_size = size; - size = btr_get_size(index, BTR_N_LEAF_PAGES); + sum_of_index_sizes += size; - if (size == 0) { - /* The root node of the tree is a leaf */ - size = 1; + size = btr_get_size(index, BTR_N_LEAF_PAGES); + + if (size == 0) { + /* The root node of the tree is a leaf */ + size = 1; + } + + index->stat_n_leaf_pages = size; + + btr_estimate_number_of_different_key_vals(index); + } else { + /* If we have set a high innodb_force_recovery + level, do not calculate statistics, as a badly + corrupted index can cause a crash in it. + Initialize some bogus index cardinality + statistics, so that the data can be queried in + various means, also via secondary indexes. */ + ulint i; + + sum_of_index_sizes++; + index->stat_index_size = index->stat_n_leaf_pages = 1; + + for (i = dict_index_get_n_unique(index); i; ) { + index->stat_n_diff_key_vals[i--] = 1; + } } - index->stat_n_leaf_pages = size; - - btr_estimate_number_of_different_key_vals(index); - index = dict_table_get_next_index(index); - } + } while (index); index = dict_table_get_first_index(table); diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index a70921806b4..c7474109d4f 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -7511,28 +7511,15 @@ ha_innobase::info( dict_index_t* index; ha_rows rec_per_key; ib_int64_t n_rows; - ulong j; - ulong i; char path[FN_REFLEN]; os_file_stat_t stat_info; - DBUG_ENTER("info"); /* If we are forcing recovery at a high level, we will suppress statistics calculation on tables, because that may crash the server if an index is badly corrupted. */ - if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { - - /* We return success (0) instead of HA_ERR_CRASHED, - because we want MySQL to process this query and not - stop, like it would do if it received the error code - HA_ERR_CRASHED. */ - - DBUG_RETURN(0); - } - /* We do not know if MySQL can call this function before calling external_lock(). To be safe, update the thd of the current table handle. */ @@ -7627,12 +7614,18 @@ ha_innobase::info( acquiring latches inside InnoDB, we do not call it if we are asked by MySQL to avoid locking. Another reason to avoid the call is that it uses quite a lot of CPU. - See Bug#38185. - We do not update delete_length if no locking is requested - so the "old" value can remain. delete_length is initialized - to 0 in the ha_statistics' constructor. */ - if (!(flag & HA_STATUS_NO_LOCK)) { - + See Bug#38185. */ + if (flag & HA_STATUS_NO_LOCK) { + /* We do not update delete_length if no + locking is requested so the "old" value can + remain. delete_length is initialized to 0 in + the ha_statistics' constructor. */ + } else if (UNIV_UNLIKELY + (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE)) { + /* Avoid accessing the tablespace if + innodb_crash_recovery is set to a high value. */ + stats.delete_length = 0; + } else { /* lock the data dictionary to avoid races with ibd_file_missing and tablespace_discarded */ row_mysql_lock_data_dictionary(prebuilt->trx); @@ -7677,6 +7670,7 @@ ha_innobase::info( } if (flag & HA_STATUS_CONST) { + ulong i; /* Verify the number of index in InnoDB and MySQL matches up. If prebuilt->clust_index_was_generated holds, InnoDB defines GEN_CLUST_INDEX internally */ @@ -7693,6 +7687,7 @@ ha_innobase::info( } for (i = 0; i < table->s->keys; i++) { + ulong j; /* We could get index quickly through internal index mapping with the index translation table. The identity of index (match up index name with @@ -7758,6 +7753,11 @@ ha_innobase::info( } } + if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) { + + goto func_exit; + } + if (flag & HA_STATUS_ERRKEY) { const dict_index_t* err_index; @@ -7778,6 +7778,7 @@ ha_innobase::info( stats.auto_increment_value = innobase_peek_autoinc(); } +func_exit: prebuilt->trx->op_info = (char*)""; DBUG_RETURN(0);