Commit ce7d6a28 authored by Marko Mäkelä's avatar Marko Mäkelä

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.
parent 109893da
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 2010-08-03 The InnoDB Team
* include/ut0mem.h, ut/ut0mem.c: * include/ut0mem.h, ut/ut0mem.c:
......
...@@ -4191,7 +4191,6 @@ dict_update_statistics_low( ...@@ -4191,7 +4191,6 @@ dict_update_statistics_low(
dictionary mutex */ dictionary mutex */
{ {
dict_index_t* index; dict_index_t* index;
ulint size;
ulint sum_of_index_sizes = 0; ulint sum_of_index_sizes = 0;
if (table->ibd_file_missing) { if (table->ibd_file_missing) {
...@@ -4206,14 +4205,6 @@ dict_update_statistics_low( ...@@ -4206,14 +4205,6 @@ dict_update_statistics_low(
return; 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 /* Find out the sizes of the indexes and how many different values
for the key they approximately have */ for the key they approximately have */
...@@ -4225,7 +4216,13 @@ dict_update_statistics_low( ...@@ -4225,7 +4216,13 @@ dict_update_statistics_low(
return; return;
} }
while (index) {
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); size = btr_get_size(index, BTR_TOTAL_SIZE);
index->stat_index_size = size; index->stat_index_size = size;
...@@ -4242,10 +4239,26 @@ dict_update_statistics_low( ...@@ -4242,10 +4239,26 @@ dict_update_statistics_low(
index->stat_n_leaf_pages = size; index->stat_n_leaf_pages = size;
btr_estimate_number_of_different_key_vals(index); 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;
index = dict_table_get_next_index(index); 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 = dict_table_get_next_index(index);
} while (index);
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
dict_index_stat_mutex_enter(index); dict_index_stat_mutex_enter(index);
......
...@@ -7511,28 +7511,15 @@ ha_innobase::info( ...@@ -7511,28 +7511,15 @@ ha_innobase::info(
dict_index_t* index; dict_index_t* index;
ha_rows rec_per_key; ha_rows rec_per_key;
ib_int64_t n_rows; ib_int64_t n_rows;
ulong j;
ulong i;
char path[FN_REFLEN]; char path[FN_REFLEN];
os_file_stat_t stat_info; os_file_stat_t stat_info;
DBUG_ENTER("info"); DBUG_ENTER("info");
/* If we are forcing recovery at a high level, we will suppress /* If we are forcing recovery at a high level, we will suppress
statistics calculation on tables, because that may crash the statistics calculation on tables, because that may crash the
server if an index is badly corrupted. */ 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 /* We do not know if MySQL can call this function before calling
external_lock(). To be safe, update the thd of the current table external_lock(). To be safe, update the thd of the current table
handle. */ handle. */
...@@ -7627,12 +7614,18 @@ ha_innobase::info( ...@@ -7627,12 +7614,18 @@ ha_innobase::info(
acquiring latches inside InnoDB, we do not call it if we acquiring latches inside InnoDB, we do not call it if we
are asked by MySQL to avoid locking. Another reason to are asked by MySQL to avoid locking. Another reason to
avoid the call is that it uses quite a lot of CPU. avoid the call is that it uses quite a lot of CPU.
See Bug#38185. See Bug#38185. */
We do not update delete_length if no locking is requested if (flag & HA_STATUS_NO_LOCK) {
so the "old" value can remain. delete_length is initialized /* We do not update delete_length if no
to 0 in the ha_statistics' constructor. */ locking is requested so the "old" value can
if (!(flag & HA_STATUS_NO_LOCK)) { 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 /* lock the data dictionary to avoid races with
ibd_file_missing and tablespace_discarded */ ibd_file_missing and tablespace_discarded */
row_mysql_lock_data_dictionary(prebuilt->trx); row_mysql_lock_data_dictionary(prebuilt->trx);
...@@ -7677,6 +7670,7 @@ ha_innobase::info( ...@@ -7677,6 +7670,7 @@ ha_innobase::info(
} }
if (flag & HA_STATUS_CONST) { if (flag & HA_STATUS_CONST) {
ulong i;
/* Verify the number of index in InnoDB and MySQL /* Verify the number of index in InnoDB and MySQL
matches up. If prebuilt->clust_index_was_generated matches up. If prebuilt->clust_index_was_generated
holds, InnoDB defines GEN_CLUST_INDEX internally */ holds, InnoDB defines GEN_CLUST_INDEX internally */
...@@ -7693,6 +7687,7 @@ ha_innobase::info( ...@@ -7693,6 +7687,7 @@ ha_innobase::info(
} }
for (i = 0; i < table->s->keys; i++) { for (i = 0; i < table->s->keys; i++) {
ulong j;
/* We could get index quickly through internal /* We could get index quickly through internal
index mapping with the index translation table. index mapping with the index translation table.
The identity of index (match up index name with The identity of index (match up index name with
...@@ -7758,6 +7753,11 @@ ha_innobase::info( ...@@ -7758,6 +7753,11 @@ ha_innobase::info(
} }
} }
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
goto func_exit;
}
if (flag & HA_STATUS_ERRKEY) { if (flag & HA_STATUS_ERRKEY) {
const dict_index_t* err_index; const dict_index_t* err_index;
...@@ -7778,6 +7778,7 @@ ha_innobase::info( ...@@ -7778,6 +7778,7 @@ ha_innobase::info(
stats.auto_increment_value = innobase_peek_autoinc(); stats.auto_increment_value = innobase_peek_autoinc();
} }
func_exit:
prebuilt->trx->op_info = (char*)""; prebuilt->trx->op_info = (char*)"";
DBUG_RETURN(0); DBUG_RETURN(0);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment