Skip to content

Commit

Permalink
MDEV-34474 InnoDB: Failing assertion: stat_n_leaf_pages > 0 in ha_inn…
Browse files Browse the repository at this point in the history
…obase::estimate_rows_upper_bound

- Column stat_value and sample_size in mysql.innodb_index_stats
table is declared as BIGINT UNSIGNED without any check constraint.
user manually updates the value of stat_value and sample_size
to zero. InnoDB aborts the server while reading the statistics
information because InnoDB expects at least one leaf
page to exist for the index.

- To fix this issue, InnoDB should interpret the value of
stat_n_leaf_pages, stat_index_size in innodb_index_stats
stat_clustered_index_size, stat_sum_of_other_index_sizes
in innodb_table_stats as valid one even though user
mentioned it as 0.
  • Loading branch information
Thirunarayanan committed Jul 10, 2024
1 parent d0a2d4e commit 60125a7
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 9 deletions.
10 changes: 10 additions & 0 deletions mysql-test/suite/innodb/r/innodb_stats_fetch.result
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,13 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL LIMIT ROWS EXAMINED 5;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN LIMIT ROWS EXAMINED 5;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS LIMIT ROWS EXAMINED 5;
DROP TABLE t1;
#
# MDEV-34474 InnoDB: Failing assertion: stat_n_leaf_pages > 0
# in ha_innobase::estimate_rows_upper_bound
#
CREATE TABLE t (c1 INT,c2 INT,
INDEX(c1))STATS_PERSISTENT=1 ENGINE=INNODB;
UPDATE mysql.innodb_index_stats SET stat_value=0 WHERE database_name like "test" and table_name like 't';
UPDATE mysql.innodb_table_stats SET clustered_index_size= 0, sum_of_other_index_sizes=0 WHERE database_name like "test" and table_name like 't';
UPDATE t SET c1=+1 ORDER BY c2;
DROP TABLE t;
12 changes: 12 additions & 0 deletions mysql-test/suite/innodb/t/innodb_stats_fetch.test
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,15 @@ SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_VIRTUAL LIMIT ROWS EXAMINED 5;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN LIMIT ROWS EXAMINED 5;
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS LIMIT ROWS EXAMINED 5;
DROP TABLE t1;

--echo #
--echo # MDEV-34474 InnoDB: Failing assertion: stat_n_leaf_pages > 0
--echo # in ha_innobase::estimate_rows_upper_bound
--echo #

CREATE TABLE t (c1 INT,c2 INT,
INDEX(c1))STATS_PERSISTENT=1 ENGINE=INNODB;
UPDATE mysql.innodb_index_stats SET stat_value=0 WHERE database_name like "test" and table_name like 't';
UPDATE mysql.innodb_table_stats SET clustered_index_size= 0, sum_of_other_index_sizes=0 WHERE database_name like "test" and table_name like 't';
UPDATE t SET c1=+1 ORDER BY c2;
DROP TABLE t;
30 changes: 21 additions & 9 deletions storage/innobase/dict/dict0stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2665,25 +2665,34 @@ dict_stats_fetch_table_stats_step(
break;

case 1: /* mysql.innodb_table_stats.clustered_index_size */

{
ut_a(dtype_get_mtype(type) == DATA_INT);
ut_a(len == 8);

table->stat_clustered_index_size
= (ulint) mach_read_from_8(data);

= std::max<ulint>(mach_read_from_8(data), 1);
break;
}

case 2: /* mysql.innodb_table_stats.sum_of_other_index_sizes */

{
ut_a(dtype_get_mtype(type) == DATA_INT);
ut_a(len == 8);

table->stat_sum_of_other_index_sizes
ulint stat_other_idx_size
= (ulint) mach_read_from_8(data);
if (!stat_other_idx_size
&& UT_LIST_GET_LEN(table->indexes) > 1) {
stat_other_idx_size
= UT_LIST_GET_LEN(table->indexes) - 1;
}
table->stat_sum_of_other_index_sizes
= std::max<ulint>(
mach_read_from_8(data),
UT_LIST_GET_LEN(table->indexes) - 1);

break;

}
default:

/* someone changed SELECT
Expand Down Expand Up @@ -2866,12 +2875,14 @@ dict_stats_fetch_index_stats_step(

if (stat_name_len == 4 /* strlen("size") */
&& strncasecmp("size", stat_name, stat_name_len) == 0) {
index->stat_index_size = (ulint) stat_value;
index->stat_index_size
= std::max<ulint>(stat_value, 1);
arg->stats_were_modified = true;
} else if (stat_name_len == 12 /* strlen("n_leaf_pages") */
&& strncasecmp("n_leaf_pages", stat_name, stat_name_len)
== 0) {
index->stat_n_leaf_pages = (ulint) stat_value;
index->stat_n_leaf_pages
= std::max<ulint>(stat_value, 1);
arg->stats_were_modified = true;
} else if (stat_name_len == 12 /* strlen("n_page_split") */
&& strncasecmp("n_page_split", stat_name, stat_name_len)
Expand Down Expand Up @@ -2951,7 +2962,8 @@ dict_stats_fetch_index_stats_step(
index->stat_n_diff_key_vals[n_pfx - 1] = stat_value;

if (sample_size != UINT64_UNDEFINED) {
index->stat_n_sample_sizes[n_pfx - 1] = sample_size;
index->stat_n_sample_sizes[n_pfx - 1] =
std::max<ib_uint64_t>(sample_size, 1);
} else {
/* hmm, strange... the user must have UPDATEd the
table manually and SET sample_size = NULL */
Expand Down

0 comments on commit 60125a7

Please sign in to comment.