Commit 938ce0ef authored by Marko Mäkelä's avatar Marko Mäkelä

Merge Bug#55832 fix from mysql-5.1-innodb:

------------------------------------------------------------
revno: 3550
revision-id: marko.makela@oracle.com-20100824081003-v4ecy0tga99cpxw2
parent: marko.makela@oracle.com-20100823102854-t1clrojqis2ley36
committer: Marko Mäkelä <marko.makela@oracle.com>
branch nick: 5.1-innodb
timestamp: Tue 2010-08-24 11:10:03 +0300
message:
  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 398f3ebb
......@@ -4206,7 +4206,6 @@ dict_update_statistics_low(
dictionary mutex */
{
dict_index_t* index;
ulint size;
ulint sum_of_index_sizes = 0;
if (table->ibd_file_missing) {
......@@ -4221,14 +4220,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 */
......@@ -4240,26 +4231,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);
index->stat_n_leaf_pages = size;
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;
btr_estimate_number_of_different_key_vals(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);
......
......@@ -7700,28 +7700,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. */
......@@ -7816,12 +7803,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);
......@@ -7866,6 +7859,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 */
......@@ -7882,6 +7876,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
......@@ -7947,6 +7942,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;
......@@ -7967,6 +7967,7 @@ ha_innobase::info(
stats.auto_increment_value = innobase_peek_autoinc();
}
func_exit:
prebuilt->trx->op_info = (char*)"";
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