From e005734058ef0eab76a1f1e2779f60252f8329b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 8 Jul 2014 21:05:18 +0300 Subject: [PATCH] MDEV-6424: Mariadb server crashes with assertion failure in file ha_innodb.cc Analysis: For some reason table stats for a table pointed from a index is not initialized. Added additional warning output on this situation and table stats initialization. This is better than asserting. --- .../r/innodb-stats-initialize-failure.result | 32 +++++++++++++++ .../t/innodb-stats-initialize-failure.test | 39 +++++++++++++++++++ storage/innobase/handler/ha_innodb.cc | 29 ++++++++++++++ storage/xtradb/handler/ha_innodb.cc | 31 +++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 mysql-test/suite/innodb/r/innodb-stats-initialize-failure.result create mode 100644 mysql-test/suite/innodb/t/innodb-stats-initialize-failure.test diff --git a/mysql-test/suite/innodb/r/innodb-stats-initialize-failure.result b/mysql-test/suite/innodb/r/innodb-stats-initialize-failure.result new file mode 100644 index 00000000000..ef2d3182b92 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb-stats-initialize-failure.result @@ -0,0 +1,32 @@ +call mtr.add_suppression("InnoDB: Warning: Index.*"); +set DEBUG_DBUG='+d,ib_ha_innodb_stat_not_initialized'; +create table t1(a int not null primary key, b int, c int, key(b), key(c)) engine=innodb; +create procedure innodb_insert_proc (repeat_count int) +begin +declare current_num int; +set current_num = 0; +while current_num < repeat_count do +insert into t1 values(current_num, current_num, current_num); +set current_num = current_num + 1; +end while; +end// +commit; +set autocommit=0; +call innodb_insert_proc(10000); +commit; +set autocommit=1; +select count(1) from t1; +count(1) +10000 +select count(1) from t1 where a between 5 and 100; +count(1) +96 +select count(1) from t1 where b between 5 and 256; +count(1) +252 +select count(1) from t1 where c between 7 and 787; +count(1) +781 +set DEBUG_DBUG=NULL; +drop procedure innodb_insert_proc; +drop table t1; diff --git a/mysql-test/suite/innodb/t/innodb-stats-initialize-failure.test b/mysql-test/suite/innodb/t/innodb-stats-initialize-failure.test new file mode 100644 index 00000000000..e480f0caf07 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb-stats-initialize-failure.test @@ -0,0 +1,39 @@ +# MDEV-6424: Mariadb server crashes with assertion failure in file ha_innodb.cc +--source include/have_innodb.inc + +# DEBUG_SYNC must be compiled in. +--source include/have_debug_sync.inc + +call mtr.add_suppression("InnoDB: Warning: Index.*"); +# This caused crash earlier +set DEBUG_DBUG='+d,ib_ha_innodb_stat_not_initialized'; +create table t1(a int not null primary key, b int, c int, key(b), key(c)) engine=innodb; + +delimiter //; +create procedure innodb_insert_proc (repeat_count int) +begin + declare current_num int; + set current_num = 0; + while current_num < repeat_count do + insert into t1 values(current_num, current_num, current_num); + set current_num = current_num + 1; + end while; +end// +delimiter ;// +commit; + +set autocommit=0; +call innodb_insert_proc(10000); +commit; +set autocommit=1; + +select count(1) from t1; +select count(1) from t1 where a between 5 and 100; +select count(1) from t1 where b between 5 and 256; +select count(1) from t1 where c between 7 and 787; + +set DEBUG_DBUG=NULL; + +drop procedure innodb_insert_proc; +drop table t1; + diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 009ba9bd709..ea20cd05622 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4,6 +4,7 @@ Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. +Copyright (c) 2013, 2014 SkySQL Ab. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -11444,6 +11445,34 @@ ha_innobase::info_low( break; } + DBUG_EXECUTE_IF("ib_ha_innodb_stat_not_initialized", + index->table->stat_initialized = FALSE;); + + if (!ib_table->stat_initialized || + (index->table != ib_table || + !index->table->stat_initialized)) { + fprintf(stderr, + "InnoDB: Warning: Index %s points to table %s" " and ib_table %s statistics is initialized %d " + " but index table %s initialized %d " + " mysql table is %s. Have you mixed " + "up .frm files from different " + "installations? " + "See " REFMAN + "innodb-troubleshooting.html\n", + index->name, + index->table->name, + ib_table->name, + ib_table->stat_initialized, + index->table->name, + index->table->stat_initialized, + table->s->table_name.str + ); + + /* This is better than + assert on below function */ + dict_stats_init(index->table); + } + rec_per_key = innodb_rec_per_key( index, j, stats.records); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 9159def1629..6d31f504e0d 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -4,6 +4,7 @@ Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved. Copyright (c) 2008, 2009 Google Inc. Copyright (c) 2009, Percona Inc. Copyright (c) 2012, Facebook Inc. +Copyright (c) 2013, 2014 SkySQL Ab. All Rights Reserved. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -97,6 +98,7 @@ this program; if not, write to the Free Software Foundation, Inc., #include "fts0types.h" #include "row0import.h" #include "row0quiesce.h" +#include "row0mysql.h" #ifdef UNIV_DEBUG #include "trx0purge.h" #endif /* UNIV_DEBUG */ @@ -12010,6 +12012,35 @@ ha_innobase::info_low( break; } + DBUG_EXECUTE_IF("ib_ha_innodb_stat_not_initialized", + index->table->stat_initialized = FALSE;); + + if (!ib_table->stat_initialized || + (index->table != ib_table || + !index->table->stat_initialized)) { + fprintf(stderr, + "InnoDB: Warning: Index %s points to table %s" + " and ib_table %s statistics is initialized %d " + " but index table %s initialized %d " + " mysql table is %s. Have you mixed " + "up .frm files from different " + "installations? " + "See " REFMAN + "innodb-troubleshooting.html\n", + index->name, + index->table->name, + ib_table->name, + ib_table->stat_initialized, + index->table->name, + index->table->stat_initialized, + table->s->table_name.str + ); + + /* This is better than + assert on below function */ + dict_stats_init(index->table); + } + rec_per_key = innodb_rec_per_key( index, j, stats.records);