List:Commits« Previous MessageNext Message »
From:marko.makela Date:August 24 2010 8:10am
Subject:bzr push into mysql-5.1-innodb branch (marko.makela:3548 to 3550) Bug#55832
View as plain text  
 3550 Marko Mäkelä	2010-08-24
      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.

    modified:
      storage/innodb_plugin/ChangeLog
      storage/innodb_plugin/dict/dict0dict.c
      storage/innodb_plugin/handler/ha_innodb.cc
 3549 Marko Mäkelä	2010-08-23
      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.

    modified:
      storage/innobase/dict/dict0dict.c
      storage/innobase/handler/ha_innodb.cc
 3548 Sunny Bains	2010-08-20
      Fix Bug #54538 - use of exclusive innodb dictionary lock limits performance.
                  
      This patch doesn't get rid of the need to acquire the dict_sys->mutex but
      reduces the need to keep the mutex locked for the duration of the query
      to fsp_get_available_space_in_free_extents() from ha_innobase::info().
      
      rb://390.

    modified:
      storage/innobase/fil/fil0fil.c
      storage/innobase/fsp/fsp0fsp.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/fil0fil.h
      storage/innobase/include/univ.i
=== modified file 'storage/innobase/dict/dict0dict.c'
--- a/storage/innobase/dict/dict0dict.c	revid:sunny.bains@stripped
+++ b/storage/innobase/dict/dict0dict.c	revid:marko.makela@oracle.com-20100824081003-v4ecy0tga99cpxw2
@@ -3753,7 +3753,6 @@ dict_update_statistics_low(
 					dictionary mutex */
 {
 	dict_index_t*	index;
-	ulint		size;
 	ulint		sum_of_index_sizes	= 0;
 
 	if (table->ibd_file_missing) {
@@ -3769,14 +3768,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 */
 
@@ -3788,26 +3779,48 @@ dict_update_statistics_low(
 		return;
 	}
 
-	while (index) {
-		size = btr_get_size(index, BTR_TOTAL_SIZE);
-
-		index->stat_index_size = size;
 
-		sum_of_index_sizes += size;
-
-		size = btr_get_size(index, BTR_N_LEAF_PAGES);
-
-		if (size == 0) {
-			/* The root node of the tree is a leaf */
-			size = 1;
+	do {
+		if (UNIV_LIKELY
+		    (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
+		     || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
+			 && (index->type & DICT_CLUSTERED)))) {
+			ulint	size;
+			size = btr_get_size(index, BTR_TOTAL_SIZE);
+
+			index->stat_index_size = size;
+
+			sum_of_index_sizes += size;
+
+			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);
 

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:sunny.bains@stripped8zztsu2
+++ b/storage/innobase/handler/ha_innodb.cc	revid:marko.makela@stripped
@@ -6365,8 +6365,6 @@ ha_innobase::info(
 	dict_index_t*	index;
 	ha_rows		rec_per_key;
 	ib_longlong	n_rows;
-	ulong		j;
-	ulong		i;
 	char		path[FN_REFLEN];
 	os_file_stat_t	stat_info;
 
@@ -6376,16 +6374,6 @@ ha_innobase::info(
 	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. */
@@ -6480,11 +6468,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 {
 			ullint	avail_space;
 
 			avail_space = fsp_get_available_space_in_free_extents(
@@ -6522,6 +6517,7 @@ ha_innobase::info(
 	}
 
 	if (flag & HA_STATUS_CONST) {
+		ulong	i = 0;
 		index = dict_table_get_first_index_noninline(ib_table);
 
 		if (prebuilt->clust_index_was_generated) {
@@ -6529,6 +6525,8 @@ ha_innobase::info(
 		}
 
 		for (i = 0; i < table->s->keys; i++) {
+			ulong	j;
+
 			if (index == NULL) {
 				sql_print_error("Table %s contains fewer "
 						"indexes inside InnoDB than "
@@ -6585,6 +6583,11 @@ ha_innobase::info(
 		}
 	}
 
+	if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
+
+		goto func_exit;
+	}
+
 	if (flag & HA_STATUS_ERRKEY) {
 		ut_a(prebuilt->trx);
 		ut_a(prebuilt->trx->magic_n == TRX_MAGIC_N);
@@ -6597,6 +6600,7 @@ ha_innobase::info(
  		stats.auto_increment_value = innobase_peek_autoinc();
 	}
 
+func_exit:
 	prebuilt->trx->op_info = (char*)"";
 
   	DBUG_RETURN(0);

=== modified file 'storage/innodb_plugin/ChangeLog'
--- a/storage/innodb_plugin/ChangeLog	revid:sunny.bains@stripped
+++ b/storage/innodb_plugin/ChangeLog	revid:marko.makela@strippedom-20100824081003-v4ecy0tga99cpxw2
@@ -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:

=== modified file 'storage/innodb_plugin/dict/dict0dict.c'
--- a/storage/innodb_plugin/dict/dict0dict.c	revid:sunny.bains@stripped00820074943-8w1yw2hnj8zztsu2
+++ b/storage/innodb_plugin/dict/dict0dict.c	revid:marko.makela@stripped1003-v4ecy0tga99cpxw2
@@ -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;
 
-		sum_of_index_sizes += size;
-
-		size = btr_get_size(index, BTR_N_LEAF_PAGES);
-
-		if (size == 0) {
-			/* The root node of the tree is a leaf */
-			size = 1;
+	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);
+
+			index->stat_index_size = size;
+
+			sum_of_index_sizes += size;
+
+			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);
 

=== modified file 'storage/innodb_plugin/handler/ha_innodb.cc'
--- a/storage/innodb_plugin/handler/ha_innodb.cc	revid:sunny.bains@stripped
+++ b/storage/innodb_plugin/handler/ha_innodb.cc	revid:marko.makela@stripped
@@ -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);

Attachment: [text/bzr-bundle] bzr/marko.makela@oracle.com-20100824081003-v4ecy0tga99cpxw2.bundle
Thread
bzr push into mysql-5.1-innodb branch (marko.makela:3548 to 3550) Bug#55832marko.makela24 Aug