List:Commits« Previous MessageNext Message »
From:vasil.dimov Date:July 10 2012 7:41pm
Subject:bzr push into mysql-5.6 branch (vasil.dimov:4000 to 4003)
View as plain text  
 4003 Vasil Dimov	2012-07-10
      Also flag stat_n_sample_sizes[] and stat_n_non_null_key_vals[] as
      invalid in dict_stats_deinit().

    modified:
      storage/innobase/include/dict0stats.ic
 4002 Vasil Dimov	2012-07-10
      Non-functional change - index stat_n_diff_key_vals[] and
      stat_n_sample_sizes[] from 0 to n_uniq-1 instead of from 1 to n_uniq.
      
      This makes the code more straight forward, allocates 1 element less,
      and syncs the indexing done in stat_n_diff_key_vals[],
      stat_n_sample_sizes[] and stat_n_non_null_key_vals[].

    modified:
      storage/innobase/btr/btr0cur.cc
      storage/innobase/dict/dict0dict.cc
      storage/innobase/dict/dict0stats.cc
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/btr0cur.h
      storage/innobase/include/dict0mem.h
      storage/innobase/include/dict0stats.ic
 4001 Vasil Dimov	2012-07-09
      Non-functional change - use dict_stats_empty_index() instead of
      manually crafting fake statistics in case something goes wrong.

    modified:
      storage/innobase/dict/dict0stats.cc
 4000 Rohit Kalhans	2012-07-10 [merge]
      bug#11759333: upmerge from 5.5 =>mysql-5.6

    modified:
      sql/binlog.cc
=== modified file 'storage/innobase/btr/btr0cur.cc'
--- a/storage/innobase/btr/btr0cur.cc	revid:rohit.kalhans@stripped
+++ b/storage/innobase/btr/btr0cur.cc	revid:vasil.dimov@stripped
@@ -3600,9 +3600,9 @@ btr_estimate_n_rows_in_range(
 
 /*******************************************************************//**
 Record the number of non_null key values in a given index for
-each n-column prefix of the index where n < dict_index_get_n_unique(index).
+each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index).
 The estimates are eventually stored in the array:
-index->stat_n_non_null_key_vals. */
+index->stat_n_non_null_key_vals[], which is indexed from 0 to n-1. */
 static
 void
 btr_record_not_null_field_in_rec(
@@ -3613,7 +3613,7 @@ btr_record_not_null_field_in_rec(
 	const ulint*	offsets,	/*!< in: rec_get_offsets(rec, index),
 					its size could be for all fields or
 					that of "n_unique" */
-	ib_int64_t*	n_not_null)	/*!< in/out: array to record number of
+	ib_uint64_t*	n_not_null)	/*!< in/out: array to record number of
 					not null rows for n-column prefix */
 {
 	ulint	i;
@@ -3635,11 +3635,12 @@ btr_record_not_null_field_in_rec(
 
 /*******************************************************************//**
 Estimates the number of different key values in a given index, for
-each n-column prefix of the index where n <= dict_index_get_n_unique(index).
-The estimates are stored in the array index->stat_n_diff_key_vals[] and
-the number of pages that were sampled is saved in index->stat_n_sample_sizes[].
-If innodb_stats_method is "nulls_ignored", we also record the number of
-non-null values for each prefix and store the estimates in
+each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index).
+The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed
+0..n_uniq-1) and the number of pages that were sampled is saved in
+index->stat_n_sample_sizes[].
+If innodb_stats_method is nulls_ignored, we also record the number of
+non-null values for each prefix and stored the estimates in
 array index->stat_n_non_null_key_vals. */
 UNIV_INTERN
 void
@@ -3653,8 +3654,8 @@ btr_estimate_number_of_different_key_val
 	ulint		n_cols;
 	ulint		matched_fields;
 	ulint		matched_bytes;
-	ib_int64_t*	n_diff;
-	ib_int64_t*	n_not_null;
+	ib_uint64_t*	n_diff;
+	ib_uint64_t*	n_not_null;
 	ibool		stats_null_not_equal;
 	ullint		n_sample_pages; /* number of pages to sample */
 	ulint		not_empty_flag	= 0;
@@ -3670,13 +3671,13 @@ btr_estimate_number_of_different_key_val
 	n_cols = dict_index_get_n_unique(index);
 
 	heap = mem_heap_create((sizeof *n_diff + sizeof *n_not_null)
-			       * (n_cols + 1)
+			       * n_cols
 			       + dict_index_get_n_fields(index)
 			       * (sizeof *offsets_rec
 				  + sizeof *offsets_next_rec));
 
-	n_diff = (ib_int64_t*) mem_heap_zalloc(heap, (n_cols + 1)
-					       * sizeof(ib_int64_t));
+	n_diff = (ib_uint64_t*) mem_heap_zalloc(
+		heap, n_cols * sizeof(ib_int64_t));
 
 	n_not_null = NULL;
 
@@ -3685,8 +3686,8 @@ btr_estimate_number_of_different_key_val
 	considered equal (by setting stats_null_not_equal value) */
 	switch (srv_innodb_stats_method) {
 	case SRV_STATS_NULLS_IGNORED:
-		n_not_null = (ib_int64_t*) mem_heap_zalloc(heap, (n_cols + 1)
-					     * sizeof *n_not_null);
+		n_not_null = (ib_uint64_t*) mem_heap_zalloc(
+			heap, n_cols * sizeof *n_not_null);
 		/* fall through */
 
 	case SRV_STATS_NULLS_UNEQUAL:
@@ -3737,7 +3738,7 @@ btr_estimate_number_of_different_key_val
 			offsets_rec = rec_get_offsets(rec, index, offsets_rec,
 						      ULINT_UNDEFINED, &heap);
 
-			if (n_not_null) {
+			if (n_not_null != NULL) {
 				btr_record_not_null_field_in_rec(
 					n_cols, offsets_rec, n_not_null);
 			}
@@ -3765,14 +3766,14 @@ btr_estimate_number_of_different_key_val
 					       &matched_fields,
 					       &matched_bytes);
 
-			for (j = matched_fields + 1; j <= n_cols; j++) {
+			for (j = matched_fields; j < n_cols; j++) {
 				/* We add one if this index record has
 				a different prefix from the previous */
 
 				n_diff[j]++;
 			}
 
-			if (n_not_null) {
+			if (n_not_null != NULL) {
 				btr_record_not_null_field_in_rec(
 					n_cols, offsets_next_rec, n_not_null);
 			}
@@ -3807,7 +3808,7 @@ btr_estimate_number_of_different_key_val
 			if (btr_page_get_prev(page, &mtr) != FIL_NULL
 			    || btr_page_get_next(page, &mtr) != FIL_NULL) {
 
-				n_diff[n_cols]++;
+				n_diff[n_cols - 1]++;
 			}
 		}
 
@@ -3822,7 +3823,7 @@ btr_estimate_number_of_different_key_val
 	also the pages used for external storage of fields (those pages are
 	included in index->stat_n_leaf_pages) */
 
-	for (j = 0; j <= n_cols; j++) {
+	for (j = 0; j < n_cols; j++) {
 		index->stat_n_diff_key_vals[j]
 			= BTR_TABLE_STATS_FROM_SAMPLE(
 				n_diff[j], index, n_sample_pages,
@@ -3852,7 +3853,7 @@ btr_estimate_number_of_different_key_val
 		sampled result. stat_n_non_null_key_vals[] is created
 		and initialized to zero in dict_index_add_to_cache(),
 		along with stat_n_diff_key_vals[] array */
-		if (n_not_null != NULL && (j < n_cols)) {
+		if (n_not_null != NULL) {
 			index->stat_n_non_null_key_vals[j] =
 				 BTR_TABLE_STATS_FROM_SAMPLE(
 					n_not_null[j], index, n_sample_pages,

=== modified file 'storage/innobase/dict/dict0dict.cc'
--- a/storage/innobase/dict/dict0dict.cc	revid:rohit.kalhans@stripped
+++ b/storage/innobase/dict/dict0dict.cc	revid:vasil.dimov@stripped
@@ -2264,32 +2264,22 @@ undo_size_ok:
 	if (!dict_index_is_univ(new_index)) {
 
 		new_index->stat_n_diff_key_vals =
-			static_cast<ib_uint64_t*>(mem_heap_alloc(
+			static_cast<ib_uint64_t*>(mem_heap_zalloc(
 			new_index->heap,
-			(1 + dict_index_get_n_unique(new_index))
+			dict_index_get_n_unique(new_index)
 			* sizeof(*new_index->stat_n_diff_key_vals)));
 
 		new_index->stat_n_sample_sizes =
-			static_cast<ib_uint64_t*>(mem_heap_alloc(
+			static_cast<ib_uint64_t*>(mem_heap_zalloc(
 			new_index->heap,
-			(1 + dict_index_get_n_unique(new_index))
+			dict_index_get_n_unique(new_index)
 			* sizeof(*new_index->stat_n_sample_sizes)));
 
 		new_index->stat_n_non_null_key_vals =
 			static_cast<ib_uint64_t*>(mem_heap_zalloc(
 			new_index->heap,
-			(1 + dict_index_get_n_unique(new_index))
+			dict_index_get_n_unique(new_index)
 			* sizeof(*new_index->stat_n_non_null_key_vals)));
-
-		/* Give some sensible values to stat_n_... in case we do
-		not calculate statistics quickly enough */
-
-		for (i = 1; i <= dict_index_get_n_unique(new_index); i++) {
-
-			new_index->stat_n_diff_key_vals[i] = 0;
-			new_index->stat_n_sample_sizes[i] = 1;
-			new_index->stat_n_non_null_key_vals[i - 1] = 0;
-		}
 	}
 
 	dict_sys->size += mem_heap_get_size(new_index->heap);
@@ -5033,9 +5023,9 @@ dict_index_print_low(
 
 	if (index->n_user_defined_cols > 0) {
 		n_vals = index->stat_n_diff_key_vals[
-			index->n_user_defined_cols];
+			index->n_user_defined_cols - 1];
 	} else {
-		n_vals = index->stat_n_diff_key_vals[1];
+		n_vals = index->stat_n_diff_key_vals[0];
 	}
 
 	fprintf(stderr,

=== modified file 'storage/innobase/dict/dict0stats.cc'
--- a/storage/innobase/dict/dict0stats.cc	revid:rohit.kalhans@stripped
+++ b/storage/innobase/dict/dict0stats.cc	revid:vasil.dimov@stripped
@@ -353,12 +353,9 @@ dict_stats_table_clone_create(
 		for (ulint i = 0; i < n_uniq; i++) {
 			heap_size += strlen(index->fields[i].name) + 1;
 		}
-		heap_size += (n_uniq + 1)
-			* sizeof(index->stat_n_diff_key_vals[0]);
-		heap_size += (n_uniq + 1)
-			* sizeof(index->stat_n_sample_sizes[0]);
-		heap_size += (n_uniq + 1)
-			* sizeof(index->stat_n_non_null_key_vals[0]);
+		heap_size += n_uniq * sizeof(index->stat_n_diff_key_vals[0]);
+		heap_size += n_uniq * sizeof(index->stat_n_sample_sizes[0]);
+		heap_size += n_uniq * sizeof(index->stat_n_non_null_key_vals[0]);
 	}
 
 	/* Allocate the memory and copy the members */
@@ -433,18 +430,15 @@ dict_stats_table_clone_create(
 
 		idx->stat_n_diff_key_vals = (ib_uint64_t*) mem_heap_alloc(
 			heap,
-			(idx->n_uniq + 1)
-			* sizeof(idx->stat_n_diff_key_vals[0]));
+			idx->n_uniq * sizeof(idx->stat_n_diff_key_vals[0]));
 
 		idx->stat_n_sample_sizes = (ib_uint64_t*) mem_heap_alloc(
 			heap,
-			(idx->n_uniq + 1)
-			* sizeof(idx->stat_n_sample_sizes[0]));
+			idx->n_uniq * sizeof(idx->stat_n_sample_sizes[0]));
 
 		idx->stat_n_non_null_key_vals = (ib_uint64_t*) mem_heap_alloc(
 			heap,
-			(idx->n_uniq + 1)
-			* sizeof(idx->stat_n_non_null_key_vals[0]));
+			idx->n_uniq * sizeof(idx->stat_n_non_null_key_vals[0]));
 #ifdef UNIV_DEBUG
 		idx->magic_n = DICT_INDEX_MAGIC_N;
 #endif /* UNIV_DEBUG */
@@ -488,10 +482,10 @@ dict_stats_empty_index(
 
 	ulint	n_uniq = index->n_uniq;
 
-	for (ulint i = 1; i <= n_uniq; i++) {
+	for (ulint i = 0; i < n_uniq; i++) {
 		index->stat_n_diff_key_vals[i] = 0;
 		index->stat_n_sample_sizes[i] = 1;
-		index->stat_n_non_null_key_vals[i - 1] = 0;
+		index->stat_n_non_null_key_vals[i] = 0;
 	}
 
 	index->stat_index_size = 1;
@@ -591,11 +585,11 @@ dict_stats_assert_initialized(
 		}
 
 		UNIV_MEM_ASSERT_RW(
-			index->stat_n_diff_key_vals + 1,
+			index->stat_n_diff_key_vals,
 			index->n_uniq * sizeof(index->stat_n_diff_key_vals[0]));
 
 		UNIV_MEM_ASSERT_RW(
-			index->stat_n_sample_sizes + 1,
+			index->stat_n_sample_sizes,
 			index->n_uniq * sizeof(index->stat_n_sample_sizes[0]));
 
 		UNIV_MEM_ASSERT_RW(
@@ -684,12 +678,12 @@ dict_stats_copy(
 			n_copy_el = dst_idx->n_uniq;
 		}
 
-		memmove(dst_idx->stat_n_diff_key_vals + 1,
-			src_idx->stat_n_diff_key_vals + 1,
+		memmove(dst_idx->stat_n_diff_key_vals,
+			src_idx->stat_n_diff_key_vals,
 			n_copy_el * sizeof(dst_idx->stat_n_diff_key_vals[0]));
 
-		memmove(dst_idx->stat_n_sample_sizes + 1,
-			src_idx->stat_n_sample_sizes + 1,
+		memmove(dst_idx->stat_n_sample_sizes,
+			src_idx->stat_n_sample_sizes,
 			n_copy_el * sizeof(dst_idx->stat_n_sample_sizes[0]));
 
 		memmove(dst_idx->stat_n_non_null_key_vals,
@@ -774,21 +768,13 @@ Calculates new estimates for index stati
 relatively quick and is used to calculate transient statistics that
 are not saved on disk. This was the only way to calculate statistics
 before the Persistent Statistics feature was introduced.
-dict_stats_update_transient_for_index() @{
-@return size of the index in pages, or 0 if skipped */
+dict_stats_update_transient_for_index() @{ */
 static
-ulint
+void
 dict_stats_update_transient_for_index(
 /*==================================*/
 	dict_index_t*	index)	/*!< in/out: index */
 {
-	if ((index->type & DICT_FTS)
-	    || dict_index_is_corrupted(index)
-	    || (!dict_index_is_clust(index)
-		&& dict_index_is_online_ddl(index))) {
-		return(0);
-	}
-
 	if (UNIV_LIKELY
 	    (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
 	     || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
@@ -811,7 +797,8 @@ dict_stats_update_transient_for_index(
 
 		switch (size) {
 		case ULINT_UNDEFINED:
-			goto fake_statistics;
+			dict_stats_empty_index(index);
+			return;
 		case 0:
 			/* The root node of the tree is a leaf */
 			size = 1;
@@ -827,21 +814,8 @@ dict_stats_update_transient_for_index(
 		Initialize some bogus index cardinality
 		statistics, so that the data can be queried in
 		various means, also via secondary indexes. */
-		ulint	i;
-
-fake_statistics:
-		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;
-		}
-
-		memset(index->stat_n_non_null_key_vals, 0,
-		       (1 + dict_index_get_n_unique(index))
-		       * sizeof(*index->stat_n_non_null_key_vals));
+		dict_stats_empty_index(index);
 	}
-
-	return(index->stat_index_size);
 }
 /* @} */
 
@@ -885,16 +859,23 @@ dict_stats_update_transient(
 	do {
 		ut_ad(!dict_index_is_univ(index));
 
-		sum_of_index_sizes +=
+		if (!((index->type & DICT_FTS)
+		      || dict_index_is_corrupted(index)
+		      || (!dict_index_is_clust(index)
+			  && dict_index_is_online_ddl(index)))) {
+
 			dict_stats_update_transient_for_index(index);
 
+			sum_of_index_sizes += index->stat_index_size;
+		}
+
 		index = dict_table_get_next_index(index);
 	} while (index);
 
 	index = dict_table_get_first_index(table);
 
 	table->stat_n_rows = index->stat_n_diff_key_vals[
-		dict_index_get_n_unique(index)];
+		dict_index_get_n_unique(index) - 1];
 
 	table->stat_clustered_index_size = index->stat_index_size;
 
@@ -930,12 +911,10 @@ dict_stats_analyze_index()
 /*********************************************************************//**
 Find the total number and the number of distinct keys on a given level in
 an index. Each of the 1..n_uniq prefixes are looked up and the results are
-saved in the array n_diff[]. Notice that n_diff[] must be able to store
-n_uniq+1 numbers because the results are saved in
-n_diff[1] .. n_diff[n_uniq]. The total number of records on the level is
-saved in total_recs.
+saved in the array n_diff[0] .. n_diff[n_uniq - 1]. The total number of
+records on the level is saved in total_recs.
 Also, the index of the last record in each group of equal records is saved
-in n_diff_boundaries[1..n_uniq], records indexing starts from the leftmost
+in n_diff_boundaries[0..n_uniq - 1], records indexing starts from the leftmost
 record on the level and continues cross pages boundaries, counting from 0.
 dict_stats_analyze_index_level() @{ */
 static
@@ -972,16 +951,14 @@ dict_stats_analyze_index_level(
 
 	n_uniq = dict_index_get_n_unique(index);
 
-	/* elements in the n_diff array are 1..n_uniq (inclusive) */
-	memset(n_diff, 0x0, (n_uniq + 1) * sizeof(*n_diff));
+	/* elements in the n_diff array are 0..n_uniq-1 (inclusive) */
+	memset(n_diff, 0x0, n_uniq * sizeof(n_diff[0]));
 
 	heap = mem_heap_create(256);
 
-	/* reset the dynamic arrays n_diff_boundaries[1..n_uniq];
-	n_diff_boundaries[0] is ignored to follow the same convention
-	as n_diff[] */
+	/* reset the dynamic arrays n_diff_boundaries[0..n_uniq-1] */
 	if (n_diff_boundaries != NULL) {
-		for (i = 1; i <= n_uniq; i++) {
+		for (i = 0; i < n_uniq; i++) {
 			dyn_array_free(&n_diff_boundaries[i]);
 
 			dyn_array_create(&n_diff_boundaries[i]);
@@ -1182,7 +1159,7 @@ dict_stats_analyze_index_level(
 					       &matched_fields,
 					       &matched_bytes);
 
-			for (i = matched_fields + 1; i <= n_uniq; i++) {
+			for (i = matched_fields; i < n_uniq; i++) {
 
 				if (n_diff_boundaries != NULL) {
 					/* push the index of the previous
@@ -1210,12 +1187,13 @@ dict_stats_analyze_index_level(
 				}
 
 				/* increment the number of different keys
-				for n_prefix=i */
+				for n_prefix=i+1 (e.g. if i=0 then we increment
+				for n_prefix=1 which is stored in n_diff[0]) */
 				n_diff[i]++;
 			}
 		} else {
 			/* this is the first non-delete marked record */
-			for (i = 1; i <= n_uniq; i++) {
+			for (i = 0; i < n_uniq; i++) {
 				n_diff[i] = 1;
 			}
 		}
@@ -1265,7 +1243,7 @@ dict_stats_analyze_index_level(
 		/* remember the index of the last record on the level as the
 		last one from the last group of equal keys; this holds for
 		all possible prefixes */
-		for (i = 1; i <= n_uniq; i++) {
+		for (i = 0; i < n_uniq; i++) {
 			void*		p;
 			ib_uint64_t	idx;
 
@@ -1279,10 +1257,10 @@ dict_stats_analyze_index_level(
 	}
 
 	/* now in n_diff_boundaries[i] there are exactly n_diff[i] integers,
-	for i=1..n_uniq */
+	for i=0..n_uniq-1 */
 
 #ifdef UNIV_STATS_DEBUG
-	for (i = 1; i <= n_uniq; i++) {
+	for (i = 0; i < n_uniq; i++) {
 
 		DEBUG_PRINTF("    %s(): total recs: " UINT64PF
 			     ", total pages: " UINT64PF
@@ -1593,8 +1571,8 @@ dict_stats_analyze_index_below_cur(
 For a given level in an index select N_SAMPLE_PAGES(index)
 (or less) records from that level and dive below them to the corresponding
 leaf pages, then scan those leaf pages and save the sampling results in
-index->stat_n_diff_key_vals[n_prefix] and the number of pages scanned in
-index->stat_n_sample_sizes[n_prefix].
+index->stat_n_diff_key_vals[n_prefix - 1] and the number of pages scanned in
+index->stat_n_sample_sizes[n_prefix - 1].
 dict_stats_analyze_index_for_n_prefix() @{ */
 static
 void
@@ -1809,11 +1787,11 @@ dict_stats_analyze_index_for_n_prefix(
 
 	/* n_diff_sum_of_all_analyzed_pages can be 0 here if all the leaf
 	pages sampled contained only delete-marked records. In this case
-	we should assign 0 to index->stat_n_diff_key_vals[n_prefix], which
+	we should assign 0 to index->stat_n_diff_key_vals[n_prefix - 1], which
 	the formula below does. */
 
 	/* See REF01 for an explanation of the algorithm */
-	index->stat_n_diff_key_vals[n_prefix]
+	index->stat_n_diff_key_vals[n_prefix - 1]
 		= index->stat_n_leaf_pages
 
 		* n_diff_for_this_prefix
@@ -1822,13 +1800,13 @@ dict_stats_analyze_index_for_n_prefix(
 		* n_diff_sum_of_all_analyzed_pages
 		/ n_recs_to_dive_below;
 
-	index->stat_n_sample_sizes[n_prefix] = n_recs_to_dive_below;
+	index->stat_n_sample_sizes[n_prefix - 1] = n_recs_to_dive_below;
 
 	DEBUG_PRINTF("    %s(): n_diff=" UINT64PF " for n_prefix=%lu "
 		     "(%lu"
 		     " * " UINT64PF " / " UINT64PF
 		     " * " UINT64PF " / " UINT64PF ")\n",
-		     __func__, index->stat_n_diff_key_vals[n_prefix],
+		     __func__, index->stat_n_diff_key_vals[n_prefix - 1],
 		     n_prefix,
 		     index->stat_n_leaf_pages,
 		     n_diff_for_this_prefix, total_recs_on_level,
@@ -1929,7 +1907,7 @@ dict_stats_analyze_index(
 					       NULL /* boundaries not needed */,
 					       &mtr);
 
-		for (ulint i = 1; i <= n_uniq; i++) {
+		for (ulint i = 0; i < n_uniq; i++) {
 			index->stat_n_sample_sizes[i] = total_pages;
 		}
 
@@ -1940,15 +1918,13 @@ dict_stats_analyze_index(
 
 	/* set to zero */
 	n_diff_on_level = reinterpret_cast<ib_uint64_t*>
-		(mem_zalloc((n_uniq + 1) * sizeof(ib_uint64_t)));
+		(mem_zalloc(n_uniq * sizeof(ib_uint64_t)));
 
 	n_diff_boundaries = reinterpret_cast<dyn_array_t*>
-		(mem_alloc((n_uniq + 1) * sizeof(dyn_array_t)));
+		(mem_alloc(n_uniq * sizeof(dyn_array_t)));
 
-	for (ulint i = 1; i <= n_uniq; i++) {
-		/* initialize the dynamic arrays, the first one
-		(index=0) is ignored to follow the same indexing
-		scheme as n_diff_on_level[] */
+	for (ulint i = 0; i < n_uniq; i++) {
+		/* initialize the dynamic arrays */
 		dyn_array_create(&n_diff_boundaries[i]);
 	}
 
@@ -1997,7 +1973,7 @@ dict_stats_analyze_index(
 		distinct records because we do not want to scan the
 		leaf level because it may contain too many records */
 		if (level_is_analyzed
-		    && (n_diff_on_level[n_prefix] >= N_DIFF_REQUIRED(index)
+		    && (n_diff_on_level[n_prefix - 1] >= N_DIFF_REQUIRED(index)
 			|| level == 1)) {
 
 			goto found_level;
@@ -2009,7 +1985,7 @@ dict_stats_analyze_index(
 
 			/* if this does not hold we should be on
 			"found_level" instead of here */
-			ut_ad(n_diff_on_level[n_prefix]
+			ut_ad(n_diff_on_level[n_prefix - 1]
 			      < N_DIFF_REQUIRED(index));
 
 			level--;
@@ -2062,7 +2038,8 @@ dict_stats_analyze_index(
 
 			level_is_analyzed = true;
 
-			if (n_diff_on_level[n_prefix] >= N_DIFF_REQUIRED(index)
+			if (n_diff_on_level[n_prefix - 1]
+			    >= N_DIFF_REQUIRED(index)
 			    || level == 1) {
 				/* we found a good level with many distinct
 				records or we have reached the last level we
@@ -2077,7 +2054,7 @@ found_level:
 
 		DEBUG_PRINTF("  %s(): found level %lu that has " UINT64PF
 			     " distinct records for n_prefix=%lu\n",
-			     __func__, level, n_diff_on_level[n_prefix],
+			     __func__, level, n_diff_on_level[n_prefix - 1],
 			     n_prefix);
 
 		/* here we are either on level 1 or the level that we are on
@@ -2093,13 +2070,13 @@ found_level:
 
 		dict_stats_analyze_index_for_n_prefix(
 			index, level, total_recs, n_prefix,
-			n_diff_on_level[n_prefix],
-			&n_diff_boundaries[n_prefix], &mtr);
+			n_diff_on_level[n_prefix - 1],
+			&n_diff_boundaries[n_prefix - 1], &mtr);
 	}
 
 	mtr_commit(&mtr);
 
-	for (ulint i = 1; i <= n_uniq; i++) {
+	for (ulint i = 0; i < n_uniq; i++) {
 		dyn_array_free(&n_diff_boundaries[i]);
 	}
 
@@ -2146,7 +2123,7 @@ dict_stats_update_persistent(
 
 	ulint	n_unique = dict_index_get_n_unique(index);
 
-	table->stat_n_rows = index->stat_n_diff_key_vals[n_unique];
+	table->stat_n_rows = index->stat_n_diff_key_vals[n_unique - 1];
 
 	table->stat_clustered_index_size = index->stat_index_size;
 
@@ -2445,27 +2422,27 @@ dict_stats_save(
 			goto end;
 		}
 
-		for (ulint i = 1; i <= index->n_uniq; i++) {
+		for (ulint i = 0; i < index->n_uniq; i++) {
 
 			char	stat_name[16];
 			char	stat_description[1024];
 			ulint	j;
 
 			ut_snprintf(stat_name, sizeof(stat_name),
-				    "n_diff_pfx%02lu", i);
+				    "n_diff_pfx%02lu", i + 1);
 
 			/* craft a string that contains the columns names */
 			ut_snprintf(stat_description,
 				    sizeof(stat_description),
 				    "%s", index->fields[0].name);
-			for (j = 2; j <= i; j++) {
+			for (j = 1; j <= i; j++) {
 				size_t	len;
 
 				len = strlen(stat_description);
 
 				ut_snprintf(stat_description + len,
 					    sizeof(stat_description) - len,
-					    ",%s", index->fields[j - 1].name);
+					    ",%s", index->fields[j].name);
 			}
 
 			ret = dict_stats_save_index_stat(
@@ -2808,14 +2785,14 @@ dict_stats_fetch_index_stats_step(
 		}
 		/* else */
 
-		index->stat_n_diff_key_vals[n_pfx] = stat_value;
+		index->stat_n_diff_key_vals[n_pfx - 1] = stat_value;
 
 		if (sample_size != UINT64_UNDEFINED) {
-			index->stat_n_sample_sizes[n_pfx] = sample_size;
+			index->stat_n_sample_sizes[n_pfx - 1] = sample_size;
 		} else {
 			/* hmm, strange... the user must have UPDATEd the
 			table manually and SET sample_size = NULL */
-			index->stat_n_sample_sizes[n_pfx] = 0;
+			index->stat_n_sample_sizes[n_pfx - 1] = 0;
 		}
 
 		index->stat_n_non_null_key_vals[n_pfx - 1] = 0;
@@ -3895,12 +3872,12 @@ test_dict_stats_save()
 	dict_table_t	table;
 	dict_index_t	index1;
 	dict_field_t	index1_fields[1];
-	ib_uint64_t	index1_stat_n_diff_key_vals[2];
-	ib_uint64_t	index1_stat_n_sample_sizes[2];
+	ib_uint64_t	index1_stat_n_diff_key_vals[1];
+	ib_uint64_t	index1_stat_n_sample_sizes[1];
 	dict_index_t	index2;
 	dict_field_t	index2_fields[4];
-	ib_uint64_t	index2_stat_n_diff_key_vals[5];
-	ib_uint64_t	index2_stat_n_sample_sizes[5];
+	ib_uint64_t	index2_stat_n_diff_key_vals[4];
+	ib_uint64_t	index2_stat_n_sample_sizes[4];
 	dberr_t		ret;
 
 	/* craft a dummy dict_table_t */
@@ -3924,10 +3901,8 @@ test_dict_stats_save()
 	index1.stat_index_size = TEST_IDX1_INDEX_SIZE;
 	index1.stat_n_leaf_pages = TEST_IDX1_N_LEAF_PAGES;
 	index1_fields[0].name = TEST_IDX1_COL1_NAME;
-	index1_stat_n_diff_key_vals[0] = 1; /* dummy */
-	index1_stat_n_diff_key_vals[1] = TEST_IDX1_N_DIFF1;
-	index1_stat_n_sample_sizes[0] = 0; /* dummy */
-	index1_stat_n_sample_sizes[1] = TEST_IDX1_N_DIFF1_SAMPLE_SIZE;
+	index1_stat_n_diff_key_vals[0] = TEST_IDX1_N_DIFF1;
+	index1_stat_n_sample_sizes[0] = TEST_IDX1_N_DIFF1_SAMPLE_SIZE;
 
 	ut_d(index2.magic_n = DICT_INDEX_MAGIC_N);
 	index2.name = TEST_IDX2_NAME;
@@ -3943,16 +3918,14 @@ test_dict_stats_save()
 	index2_fields[1].name = TEST_IDX2_COL2_NAME;
 	index2_fields[2].name = TEST_IDX2_COL3_NAME;
 	index2_fields[3].name = TEST_IDX2_COL4_NAME;
-	index2_stat_n_diff_key_vals[0] = 1; /* dummy */
-	index2_stat_n_diff_key_vals[1] = TEST_IDX2_N_DIFF1;
-	index2_stat_n_diff_key_vals[2] = TEST_IDX2_N_DIFF2;
-	index2_stat_n_diff_key_vals[3] = TEST_IDX2_N_DIFF3;
-	index2_stat_n_diff_key_vals[4] = TEST_IDX2_N_DIFF4;
-	index2_stat_n_sample_sizes[0] = 0; /* dummy */
-	index2_stat_n_sample_sizes[1] = TEST_IDX2_N_DIFF1_SAMPLE_SIZE;
-	index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF2_SAMPLE_SIZE;
-	index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE;
-	index2_stat_n_sample_sizes[4] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE;
+	index2_stat_n_diff_key_vals[0] = TEST_IDX2_N_DIFF1;
+	index2_stat_n_diff_key_vals[1] = TEST_IDX2_N_DIFF2;
+	index2_stat_n_diff_key_vals[2] = TEST_IDX2_N_DIFF3;
+	index2_stat_n_diff_key_vals[3] = TEST_IDX2_N_DIFF4;
+	index2_stat_n_sample_sizes[0] = TEST_IDX2_N_DIFF1_SAMPLE_SIZE;
+	index2_stat_n_sample_sizes[1] = TEST_IDX2_N_DIFF2_SAMPLE_SIZE;
+	index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE;
+	index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE;
 
 	ret = dict_stats_save(&table);
 
@@ -4052,11 +4025,11 @@ test_dict_stats_fetch_from_ps()
 {
 	dict_table_t	table;
 	dict_index_t	index1;
-	ib_uint64_t	index1_stat_n_diff_key_vals[2];
-	ib_uint64_t	index1_stat_n_sample_sizes[2];
+	ib_uint64_t	index1_stat_n_diff_key_vals[1];
+	ib_uint64_t	index1_stat_n_sample_sizes[1];
 	dict_index_t	index2;
-	ib_uint64_t	index2_stat_n_diff_key_vals[5];
-	ib_uint64_t	index2_stat_n_sample_sizes[5];
+	ib_uint64_t	index2_stat_n_diff_key_vals[4];
+	ib_uint64_t	index2_stat_n_sample_sizes[4];
 	dberr_t		ret;
 
 	/* craft a dummy dict_table_t */
@@ -4097,19 +4070,19 @@ test_dict_stats_fetch_from_ps()
 
 	ut_a(index1.stat_index_size == TEST_IDX1_INDEX_SIZE);
 	ut_a(index1.stat_n_leaf_pages == TEST_IDX1_N_LEAF_PAGES);
-	ut_a(index1_stat_n_diff_key_vals[1] == TEST_IDX1_N_DIFF1);
-	ut_a(index1_stat_n_sample_sizes[1] == TEST_IDX1_N_DIFF1_SAMPLE_SIZE);
+	ut_a(index1_stat_n_diff_key_vals[0] == TEST_IDX1_N_DIFF1);
+	ut_a(index1_stat_n_sample_sizes[0] == TEST_IDX1_N_DIFF1_SAMPLE_SIZE);
 
 	ut_a(index2.stat_index_size == TEST_IDX2_INDEX_SIZE);
 	ut_a(index2.stat_n_leaf_pages == TEST_IDX2_N_LEAF_PAGES);
-	ut_a(index2_stat_n_diff_key_vals[1] == TEST_IDX2_N_DIFF1);
-	ut_a(index2_stat_n_sample_sizes[1] == TEST_IDX2_N_DIFF1_SAMPLE_SIZE);
-	ut_a(index2_stat_n_diff_key_vals[2] == TEST_IDX2_N_DIFF2);
-	ut_a(index2_stat_n_sample_sizes[2] == TEST_IDX2_N_DIFF2_SAMPLE_SIZE);
-	ut_a(index2_stat_n_diff_key_vals[3] == TEST_IDX2_N_DIFF3);
-	ut_a(index2_stat_n_sample_sizes[3] == TEST_IDX2_N_DIFF3_SAMPLE_SIZE);
-	ut_a(index2_stat_n_diff_key_vals[4] == TEST_IDX2_N_DIFF4);
-	ut_a(index2_stat_n_sample_sizes[4] == TEST_IDX2_N_DIFF4_SAMPLE_SIZE);
+	ut_a(index2_stat_n_diff_key_vals[0] == TEST_IDX2_N_DIFF1);
+	ut_a(index2_stat_n_sample_sizes[0] == TEST_IDX2_N_DIFF1_SAMPLE_SIZE);
+	ut_a(index2_stat_n_diff_key_vals[1] == TEST_IDX2_N_DIFF2);
+	ut_a(index2_stat_n_sample_sizes[1] == TEST_IDX2_N_DIFF2_SAMPLE_SIZE);
+	ut_a(index2_stat_n_diff_key_vals[2] == TEST_IDX2_N_DIFF3);
+	ut_a(index2_stat_n_sample_sizes[2] == TEST_IDX2_N_DIFF3_SAMPLE_SIZE);
+	ut_a(index2_stat_n_diff_key_vals[3] == TEST_IDX2_N_DIFF4);
+	ut_a(index2_stat_n_sample_sizes[3] == TEST_IDX2_N_DIFF4_SAMPLE_SIZE);
 
 	printf("OK: fetch successful\n");
 }

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:rohit.kalhans@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:vasil.dimov@stripped
@@ -10499,9 +10499,7 @@ innodb_rec_per_key(
 
 	ut_ad(i < dict_index_get_n_unique(index));
 
-	/* Note the stat_n_diff_key_vals[] stores the diff value with
-	n-prefix indexing, so it is always stat_n_diff_key_vals[i + 1] */
-	if (index->stat_n_diff_key_vals[i + 1] == 0) {
+	if (index->stat_n_diff_key_vals[i] == 0) {
 
 		rec_per_key = records;
 	} else if (srv_innodb_stats_method == SRV_STATS_NULLS_IGNORED) {
@@ -10522,19 +10520,19 @@ innodb_rec_per_key(
 		large than that of the distinct values, we could
 		consider that the table consists mostly of NULL value.
 		Set rec_per_key to 1. */
-		if (index->stat_n_diff_key_vals[i + 1] <= num_null) {
+		if (index->stat_n_diff_key_vals[i] <= num_null) {
 			rec_per_key = 1;
 		} else {
 			/* Need to exclude rows with NULL values from
 			rec_per_key calculation */
 			rec_per_key = (ha_rows)(
 				(records - num_null)
-				/ (index->stat_n_diff_key_vals[i + 1]
+				/ (index->stat_n_diff_key_vals[i]
 				   - num_null));
 		}
 	} else {
 		rec_per_key = (ha_rows)
-			 (records / index->stat_n_diff_key_vals[i + 1]);
+			 (records / index->stat_n_diff_key_vals[i]);
 	}
 
 	return(rec_per_key);

=== modified file 'storage/innobase/include/btr0cur.h'
--- a/storage/innobase/include/btr0cur.h	revid:rohit.kalhans@stripped
+++ b/storage/innobase/include/btr0cur.h	revid:vasil.dimov@stripped
@@ -516,9 +516,10 @@ btr_estimate_n_rows_in_range(
 	ulint		mode2);	/*!< in: search mode for range end */
 /*******************************************************************//**
 Estimates the number of different key values in a given index, for
-each n-column prefix of the index where n <= dict_index_get_n_unique(index).
-The estimates are stored in the array index->stat_n_diff_key_vals[] and
-the number of pages that were sampled is saved in index->stat_n_sample_sizes[].
+each n-column prefix of the index where 1 <= n <= dict_index_get_n_unique(index).
+The estimates are stored in the array index->stat_n_diff_key_vals[] (indexed
+0..n_uniq-1) and the number of pages that were sampled is saved in
+index->stat_n_sample_sizes[].
 If innodb_stats_method is nulls_ignored, we also record the number of
 non-null values for each prefix and stored the estimates in
 array index->stat_n_non_null_key_vals. */

=== modified file 'storage/innobase/include/dict0mem.h'
--- a/storage/innobase/include/dict0mem.h	revid:rohit.kalhans@stripped
+++ b/storage/innobase/include/dict0mem.h	revid:vasil.dimov@stripped
@@ -528,8 +528,9 @@ struct dict_index_struct{
 	ib_uint64_t*	stat_n_diff_key_vals;
 				/*!< approximate number of different
 				key values for this index, for each
-				n-column prefix where n <=
-				dict_get_n_unique(index); we
+				n-column prefix where 1 <= n <=
+				dict_get_n_unique(index) (the array is
+				indexed from 0 to n_uniq-1); we
 				periodically calculate new
 				estimates */
 	ib_uint64_t*	stat_n_sample_sizes;
@@ -540,7 +541,8 @@ struct dict_index_struct{
 	ib_uint64_t*	stat_n_non_null_key_vals;
 				/* approximate number of non-null key values
 				for this index, for each column where
-				n < dict_get_n_unique(index); This
+				1 <= n <= dict_get_n_unique(index) (the array
+				is indexed from 0 to n_uniq-1); This
 				is used when innodb_stats_method is
 				"nulls_ignored". */
 	ulint		stat_index_size;

=== modified file 'storage/innobase/include/dict0stats.ic'
--- a/storage/innobase/include/dict0stats.ic	revid:rohit.kalhans@stripped
+++ b/storage/innobase/include/dict0stats.ic	revid:vasil.dimov@stripped
@@ -223,10 +223,17 @@ dict_stats_deinit(
 	     index != NULL;
 	     index = dict_table_get_next_index(index)) {
 
+		ulint	n_uniq = dict_index_get_n_unique(index);
+
 		UNIV_MEM_INVALID(
 			index->stat_n_diff_key_vals,
-			(dict_index_get_n_unique(index) + 1)
-			* sizeof(*index->stat_n_diff_key_vals));
+			n_uniq * sizeof(index->stat_n_diff_key_vals[0]));
+		UNIV_MEM_INVALID(
+			index->stat_n_sample_sizes,
+			n_uniq * sizeof(index->stat_n_sample_sizes[0]));
+		UNIV_MEM_INVALID(
+			index->stat_n_non_null_key_vals,
+			n_uniq * sizeof(index->stat_n_non_null_key_vals[0]));
 		UNIV_MEM_INVALID(
 			&index->stat_index_size,
 			sizeof(index->stat_index_size));

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.6 branch (vasil.dimov:4000 to 4003) vasil.dimov11 Jul