List:Commits« Previous MessageNext Message »
From:vasil.dimov Date:June 6 2012 9:28am
Subject:bzr push into mysql-trunk branch (vasil.dimov:3968 to 3970) WL#6189
View as plain text  
 3970 Vasil Dimov	2012-06-06
      Followup to WL#6189 Turn InnoDB persistent statistics ON by default
      
      Adjust mtr tests, part 26.
      
      Persistent stats use a different sampling algorithm so it is possible
      that the stats numbers differ from transient stats.
      
      Also, persistent stats are updated less frequently or with a delay, so
      it is possible that persistent stats are not up to date as transient were
      even if both algorithms would return the same results.
      
      The order of the returned rows by a SELECT query depends on the stats and
      thus, if possible, we fix tests by prepending "-- sorted_result" to SELECTs
      that happen to return rows in different order.
      
      If possible, each failing test was fixed by manually running ANALYZE TABLE.
      This is doable if both transient and persistent sampling algorithms end up
      with the same numbers for the given table and its data.
      
      If persistent stats result in different stats, then test failures were fixed
      by forcing the usage of transient stats for the table by using
      CREATE TABLE ... STATS_PERSISTENT=0.
      
      Intentionally do not fix the tests by using persistent stats and adjustin
      the output of EXPLAIN in .result files because a different execution plan
      may cause a different code path to be executed, than the one originally
      intended in the test.

    modified:
      mysql-test/include/index_merge1.inc
      mysql-test/include/index_merge2.inc
      mysql-test/include/index_merge_ror.inc
      mysql-test/include/index_merge_ror_cpk.inc
      mysql-test/t/index_merge_innodb.test
 3969 Vasil Dimov	2012-06-06
      Fix Bug#14156531 DICT_STATS_RENAME_TABLE() DOES AN UNSAFE ROLLBACK
      
      Change the code so that dict_sys->mutex is never held when dict_stats_update()
      is called. This is needed so that we can also lock dict_operation_lock and
      "simulate" row_mysql_lock_data_dictionary() around the access to
      mysql.innodb_(table|index)_stats in dict0stats.cc, so that rollback is happy.
      
      The only codepath where it is not easy to not-hold dict_sys->mutex around
      dict_stats_update() is the "innodb_table_monitor" codepath from dict_print().
      There, if stats are not initialized, we temporarily use
      dict_stats_update_transient() for the purposes of printing and reset back
      the stats to not initialized state.
      
      Do not call dict_stats_update() from
      dict_process_sys_tables_rec_and_mtr_commit(). It was only done in the
      dict_print() codepath and in this case we already take care about the stats
      in dict_table_print_low() as described above. Thus remove the now unneeded
      DICT_TABLE_UPDATE_STATS.
      
      Remove unused functions dict_table_print() and dict_table_print_by_name()
      and rename dict_table_print_low() to dict_table_print().
      
      Remove now unused functions dict_stats_open() and dict_stats_close().

    modified:
      storage/innobase/dict/dict0dict.cc
      storage/innobase/dict/dict0load.cc
      storage/innobase/dict/dict0stats.cc
      storage/innobase/dict/dict0stats_background.cc
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/dict0dict.h
      storage/innobase/include/dict0load.h
      storage/innobase/include/dict0stats.h
      storage/innobase/include/dict0stats.ic
      storage/innobase/row/row0mysql.cc
 3968 Vasil Dimov	2012-06-06
      Followup to WL#6189 Turn InnoDB persistent statistics ON by default
      
      Adjust mtr tests, part 25.
      
      Persistent stats use a different sampling algorithm so it is possible
      that the stats numbers differ from transient stats.
      
      Also, persistent stats are updated less frequently or with a delay, so
      it is possible that persistent stats are not up to date as transient were
      even if both algorithms would return the same results.
      
      The order of the returned rows by a SELECT query depends on the stats and
      thus, if possible, we fix tests by prepending "-- sorted_result" to SELECTs
      that happen to return rows in different order.
      
      If possible, each failing test was fixed by manually running ANALYZE TABLE.
      This is doable if both transient and persistent sampling algorithms end up
      with the same numbers for the given table and its data.
      
      If persistent stats result in different stats, then test failures were fixed
      by forcing the usage of transient stats for the table by using
      CREATE TABLE ... STATS_PERSISTENT=0.
      
      Intentionally do not fix the tests by using persistent stats and adjustin
      the output of EXPLAIN in .result files because a different execution plan
      may cause a different code path to be executed, than the one originally
      intended in the test.

    modified:
      mysql-test/include/mrr_tests.inc
=== modified file 'mysql-test/include/index_merge1.inc'
--- a/mysql-test/include/index_merge1.inc	revid:vasil.dimov@stripped
+++ b/mysql-test/include/index_merge1.inc	revid:vasil.dimov@stripped
@@ -322,6 +322,12 @@ alter table t2 drop index i1;
 alter table t2 drop index i2;
 alter table t2 add index i321(key3, key2, key1);
 
+-- disable_query_log
+-- disable_result_log
+analyze table t2;
+-- enable_result_log
+-- enable_query_log
+
 #   index_merge vs 'index', index_merge is better.
 if ($index_merge_random_rows_in_EXPLAIN)
 {
@@ -359,6 +365,12 @@ create table t4 (
 
 insert into t4 select key1,key1,key1 div 10, key1 % 10, key1 % 10, key1 from t0;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t4;
+-- enable_result_log
+-- enable_query_log
+
 #   the following will be handled by index_merge:
 select * from t4 where key1a = 3 or key1b = 4;
 explain select * from t4 where key1a = 3 or key1b = 4;
@@ -379,6 +391,12 @@ explain select * from t4 where key2_1 = 
 create table t1 like t0;
 insert into t1 select * from t0;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 #  index_merge on first table in join
 explain select * from t0 left join t1 on (t0.key1=t1.key1)
   where t0.key1=3 or t0.key2=4;
@@ -431,6 +449,12 @@ alter table t3 add keyB int not null, ad
 alter table t3 add keyC int not null, add index iC(keyC);
 update t3 set key9=key1,keyA=key1,keyB=key1,keyC=key1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t3;
+-- enable_result_log
+-- enable_query_log
+
 explain select * from t3 where
   key1=1 or key2=2 or key3=3 or key4=4 or
   key5=5 or key6=6 or key7=7 or key8=8 or
@@ -447,10 +471,23 @@ explain select * from t0 where key1 < 3 
 select * from t0 where key1 < 3 or key2 < 4;
 
 update t0 set key8=123 where key1 < 3 or key2 < 4;
+
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+-- enable_result_log
+-- enable_query_log
+
 # Bug#21277: InnoDB, wrong result set, index_merge strategy, second index not evaluated
 select * from t0 where key1 < 3 or key2 < 4;
 
 delete from t0 where key1 < 3 or key2 < 4;
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+-- enable_result_log
+-- enable_query_log
+
 select * from t0 where key1 < 3 or key2 < 4;
 select count(*) from t0;
 
@@ -458,6 +495,12 @@ select count(*) from t0;
 drop table t4;
 create table t4 (a int);
 insert into t4 values (1),(4),(3);
+-- disable_query_log
+-- disable_result_log
+analyze table t4;
+-- enable_result_log
+-- enable_query_log
+
 set @save_join_buffer_size=@@join_buffer_size;
 set join_buffer_size= 4096;
 
@@ -476,6 +519,12 @@ select max(A.key1 + B.key1 + A.key2 + B.
   and   (B.key1 < 500000 or B.key2 < 3);
 
 update t0 set key1=1;
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+-- enable_result_log
+-- enable_query_log
+
 if ($index_merge_random_rows_in_EXPLAIN)
 {
   --replace_column 9 #
@@ -493,6 +542,12 @@ select max(A.key1 + B.key1 + A.key2 + B.
 alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200);
 update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+-- enable_result_log
+-- enable_query_log
+
 # The next query will not use index i7 in intersection if the OS doesn't
 # support file sizes > 2GB. (ha_myisam::ref_length depends on this and index
 # scan cost estimates depend on ha_myisam::ref_length)
@@ -543,6 +598,12 @@ while ($1)
 OPTIMIZE TABLE t1;
 select count(*) from t1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 if ($index_merge_random_rows_in_EXPLAIN)
 {
   --replace_column 9 #
@@ -577,6 +638,15 @@ create table t3 (
   key(a),key(b)
 ) engine=merge union=(t1,t2);
 
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+analyze table t1;
+analyze table t2;
+analyze table t3;
+-- enable_result_log
+-- enable_query_log
+
 --replace_column 9 #
 explain select * from t1 where a=1 and b=1;
 --replace_column 9 #
@@ -649,6 +719,13 @@ create table t2(
 ) ENGINE=MEMORY DEFAULT CHARSET=latin1;
 insert into t2 select * from t1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+analyze table t2;
+-- enable_result_log
+-- enable_query_log
+
 --echo must use sort-union rather than union:
 --replace_column 9 #
 explain select * from t1 where a=4 or b=4;
@@ -696,6 +773,15 @@ insert into t3 values (1,1,'data');
 insert into t3 values (1,1,'data');
 -- echo The plan should be ALL/ALL/ALL(Range checked for each record (index map: 0x3)
 
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+analyze table t1;
+analyze table t2;
+analyze table t3;
+-- enable_result_log
+-- enable_query_log
+
 if ($index_merge_random_rows_in_EXPLAIN)
 {
   --replace_column 9 #
@@ -722,6 +808,12 @@ INSERT INTO t1 SELECT * FROM t1;
 INSERT INTO t1 SELECT * FROM t1;
 INSERT INTO t1 SELECT * FROM t1;
 INSERT INTO t1 SELECT * FROM t1;
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 SET SESSION sort_buffer_size=1;
 
 if ($index_merge_random_rows_in_EXPLAIN)

=== modified file 'mysql-test/include/index_merge2.inc'
--- a/mysql-test/include/index_merge2.inc	revid:vasil.dimov@stripped
+++ b/mysql-test/include/index_merge2.inc	revid:vasil.dimov@stripped
@@ -41,6 +41,12 @@ while ($1)
 }
 --enable_query_log
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 # No primary key
 explain select * from t1 where key1 < 5 or key2 > 197;
 
@@ -60,6 +66,12 @@ update t1 set str1='aaa', str2='bbb', st
 
 alter table t1 add primary key (str1, zeroval, str2, str3);
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 explain select * from t1 where key1 < 5 or key2 > 197;
 
 select * from t1 where key1 < 5 or key2 > 197;
@@ -86,6 +98,13 @@ while ($1)
   dec $1;
 }
 --enable_query_log
+
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 explain select pk from t1 where key1 = 1 and key2 = 1;
 select pk from t1 where key2 = 1 and key1 = 1;
 select pk from t1 ignore index(key1,key2) where key2 = 1 and key1 = 1;
@@ -122,6 +141,12 @@ insert into t1 (key1a, key1b, key2a, key
 analyze table t1;
 select count(*) from t1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t2;
+-- enable_result_log
+-- enable_query_log
+
 if ($index_merge_random_rows_in_EXPLAIN)
 {
   --replace_column 9 #
@@ -346,6 +371,12 @@ alter table t1 add index i2(key2);
 alter table t1 add index i3(key3);
 update t1 set key2=key1,key3=key1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 if ($index_merge_random_rows_in_EXPLAIN)
 {
   --replace_column 9 #
@@ -375,6 +406,12 @@ INSERT INTO t1 VALUES
 (3, 1, 1, 1),
 (4, 0, 1, 1);
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 EXPLAIN
 SELECT a
 FROM t1
@@ -424,6 +461,12 @@ CREATE TABLE t1 (
 
 INSERT INTO t1 VALUES (1,1,'a'), (2,2,'b');
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 EXPLAIN
 SELECT col_int_key
 FROM t1

=== modified file 'mysql-test/include/index_merge_ror.inc'
--- a/mysql-test/include/index_merge_ror.inc	revid:vasil.dimov@stripped
+++ b/mysql-test/include/index_merge_ror.inc	revid:vasil.dimov@stripped
@@ -117,6 +117,13 @@ while ($cnt)
 alter table t1 enable keys;
 select count(*) from t1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t0;
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 # One row results tests for cases where a single row matches all conditions
 explain select key1,key2 from t1 where key1=100 and key2=100;
 select key1,key2 from t1 where key1=100 and key2=100;
@@ -128,6 +135,12 @@ select key1,key2,key3,key4,filler1 from 
 insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, -1, -1, 'key1-key2');
 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 100, 100, 'key4-key3');
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 #  ROR-intersection, not covering
 explain select key1,key2,filler1 from t1 where key1=100 and key2=100;
 select key1,key2,filler1 from t1 where key1=100 and key2=100;
@@ -156,6 +169,11 @@ select key1,key2, filler1 from t1 where 
 update t1 set filler1='to be deleted' where key1=100 and key2=100;
 update t1 set key1=200,key2=200 where key1=100 and key2=100;
 delete from t1 where key1=200 and key2=200;
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
 select key1,key2,filler1 from t1 where key2=100 and key2=200;
 
 # ROR-union(ROR-intersection) with one of ROR-intersection giving empty
@@ -165,6 +183,12 @@ select key1,key2,key3,key4,filler1 from 
 
 delete from t1 where key3=100 and key4=100;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 # ROR-union with all ROR-intersections giving empty results
 explain select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
 select key1,key2,key3,key4,filler1 from t1 where key1=100 and key2=100 or key3=100 and key4=100;
@@ -179,16 +203,34 @@ insert into t1 (key1, key2, key3, key4, 
 insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-2');
 insert into t1 (key1, key2, key3, key4, filler1) values (100, 100, 200, 200,'key1-key2-key3-key4-3');
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
 select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
 
 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, -1, 200,'key4');
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
 select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
 
 insert into t1 (key1, key2, key3, key4, filler1) values (-1, -1, 200, -1,'key3');
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 explain select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
 select key1,key2,key3,key4,filler1 from t1 where key3=200 or (key1=100 and key2=100) or key4=200;
 
@@ -298,6 +340,12 @@ insert into t2 select * from t2;
 select count(a) from t2 where a='BBBBBBBB';
 select count(a) from t2 where b='BBBBBBBB';
 
+-- disable_query_log
+-- disable_result_log
+analyze table t2;
+-- enable_result_log
+-- enable_query_log
+
 # BUG#1:
 --replace_result a a_or_b b a_or_b
 explain select count(a) from t2 where a='AAAAAAAA' and b='AAAAAAAA';
@@ -305,6 +353,11 @@ select count(a) from t2 where a='AAAAAAA
 select count(a) from t2 ignore index(a,b) where a='AAAAAAAA' and b='AAAAAAAA';
 
 insert into t2 values ('ab', 'ab', 'uh', 'oh');
+-- disable_query_log
+-- disable_result_log
+analyze table t2;
+-- enable_result_log
+-- enable_query_log
 explain select a from t2 where a='ab';
 drop table t2;
 

=== modified file 'mysql-test/include/index_merge_ror_cpk.inc'
--- a/mysql-test/include/index_merge_ror_cpk.inc	revid:vasil.dimov@stripped
+++ b/mysql-test/include/index_merge_ror_cpk.inc	revid:vasil.dimov@stripped
@@ -66,6 +66,12 @@ while ($1)
 set autocommit=1;
 --enable_query_log
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 # Verify that range scan on CPK is ROR
 # (use index_intersection because it is impossible to check that for index union)
 # Column 9, rows, can change depending on innodb-page-size.
@@ -151,6 +157,13 @@ INSERT INTO t2 VALUES (1, 1, 'h'), (2, 3
 SELECT t1.f1 FROM t1
 WHERE (SELECT COUNT(*) FROM t2 WHERE t2.f3 = 'h' AND t2.f2 = t1.f1) = 0 AND t1.f1 = 2;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+analyze table t2;
+-- enable_result_log
+-- enable_query_log
+
 EXPLAIN SELECT t1.f1 FROM t1
 WHERE (SELECT COUNT(*) FROM t2 WHERE t2.f3 = 'h' AND t2.f2 = t1.f1) = 0 AND t1.f1 = 2;
 

=== modified file 'mysql-test/t/index_merge_innodb.test'
--- a/mysql-test/t/index_merge_innodb.test	revid:vasil.dimov@stripped
+++ b/mysql-test/t/index_merge_innodb.test	revid:vasil.dimov@stripped
@@ -47,6 +47,12 @@ INSERT INTO t1 VALUES (0, 0, 0), (1, 1, 
 INSERT INTO t1 SELECT id + 8, id2 + 8, id3 +8 FROM t1;
 INSERT INTO t1 SELECT id + 16, 7, 0 FROM t1;
 
+-- disable_query_log
+-- disable_result_log
+analyze table t1;
+-- enable_result_log
+-- enable_query_log
+
 EXPLAIN SELECT SQL_NO_CACHE count(*) FROM t1 WHERE id2=7 AND id3=0;
 
 DROP TABLE t1;

=== modified file 'storage/innobase/dict/dict0dict.cc'
--- a/storage/innobase/dict/dict0dict.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0dict.cc	revid:vasil.dimov@stripped
@@ -4911,52 +4911,17 @@ dict_table_print(
 /*=============*/
 	dict_table_t*	table)	/*!< in: table */
 {
-	mutex_enter(&(dict_sys->mutex));
-	dict_table_print_low(table);
-	mutex_exit(&(dict_sys->mutex));
-}
-
-/**********************************************************************//**
-Prints a table data when we know the table name. */
-UNIV_INTERN
-void
-dict_table_print_by_name(
-/*=====================*/
-	const char*	name)	/*!< in: table name */
-{
-	dict_table_t*	table;
-
-	mutex_enter(&(dict_sys->mutex));
-
-	table = dict_table_get_low(name);
-
-	ut_a(table);
-
-	dict_table_print_low(table);
-	mutex_exit(&(dict_sys->mutex));
-}
-
-/**********************************************************************//**
-Prints a table data. */
-UNIV_INTERN
-void
-dict_table_print_low(
-/*=================*/
-	dict_table_t*	table)	/*!< in: table */
-{
 	dict_index_t*	index;
 	dict_foreign_t*	foreign;
 	ulint		i;
 
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 
-	if (!dict_stats_is_persistent_enabled(table)) {
-		dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT, TRUE);
-	}
+	dict_table_stats_lock(table, RW_X_LATCH);
 
-	dict_table_stats_lock(table, RW_S_LATCH);
-
-	ut_a(table->stat_initialized);
+	if (!table->stat_initialized) {
+		dict_stats_update_transient(table);
+	}
 
 	fprintf(stderr,
 		"--------------------------------------\n"
@@ -4984,7 +4949,9 @@ dict_table_print_low(
 		index = UT_LIST_GET_NEXT(indexes, index);
 	}
 
-	dict_table_stats_unlock(table, RW_S_LATCH);
+	table->stat_initialized = FALSE;
+
+	dict_table_stats_unlock(table, RW_X_LATCH);
 
 	foreign = UT_LIST_GET_FIRST(table->foreign_list);
 

=== modified file 'storage/innobase/dict/dict0load.cc'
--- a/storage/innobase/dict/dict0load.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0load.cc	revid:vasil.dimov@stripped
@@ -197,13 +197,11 @@ dict_print(void)
 
 		err_msg = static_cast<const char*>(
 			dict_process_sys_tables_rec_and_mtr_commit(
-			heap, rec, &table,
-			static_cast<dict_table_info_t>(
-				DICT_TABLE_LOAD_FROM_CACHE
-				| DICT_TABLE_UPDATE_STATS), &mtr));
+				heap, rec, &table, DICT_TABLE_LOAD_FROM_CACHE,
+				&mtr));
 
 		if (!err_msg) {
-			dict_table_print_low(table);
+			dict_table_print(table);
 		} else {
 			ut_print_timestamp(stderr);
 			fprintf(stderr, "  InnoDB: %s\n", err_msg);
@@ -363,24 +361,6 @@ dict_process_sys_tables_rec_and_mtr_comm
 		return(err_msg);
 	}
 
-	if ((status & DICT_TABLE_UPDATE_STATS)
-	    && dict_table_get_first_index(*table)) {
-
-		/* Update statistics member fields in *table if
-		DICT_TABLE_UPDATE_STATS is set */
-		ut_ad(mutex_own(&dict_sys->mutex));
-
-		dict_stats_upd_option_t	opt;
-
-		if (dict_stats_is_persistent_enabled(*table)) {
-			opt = DICT_STATS_FETCH_ONLY_IF_NOT_IN_MEMORY;
-		} else {
-			opt = DICT_STATS_RECALC_TRANSIENT;
-		}
-
-		dict_stats_update(*table, opt, TRUE);
-	}
-
 	return(NULL);
 }
 

=== modified file 'storage/innobase/dict/dict0stats.cc'
--- a/storage/innobase/dict/dict0stats.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0stats.cc	revid:vasil.dimov@stripped
@@ -180,10 +180,111 @@ static
 dict_table_t*
 dict_stats_snapshot_create(
 /*=======================*/
-	const dict_table_t*	table,		/*!< in: table whose stats
+	const dict_table_t*	table);		/*!< in: table whose stats
 						to copy */
-	bool			dict_mutex);	/*!< in: true if caller owns
-						the dict sys mutex */
+
+/*********************************************************************//**
+Checks whether the persistent statistics storage exists and that all
+tables have the proper structure.
+dict_stats_persistent_storage_check() @{
+@return TRUE if exists and all tables are ok */
+static
+ibool
+dict_stats_persistent_storage_check(
+/*================================*/
+	ibool	caller_has_dict_sys_mutex)	/*!< in: TRUE if the caller
+						owns dict_sys->mutex */
+{
+	/* definition for the table TABLE_STATS_NAME */
+	dict_col_meta_t	table_stats_columns[] = {
+		{"database_name", DATA_VARMYSQL,
+			DATA_NOT_NULL, 192},
+
+		{"table_name", DATA_VARMYSQL,
+			DATA_NOT_NULL, 192},
+
+		{"last_update", DATA_FIXBINARY,
+			DATA_NOT_NULL, 4},
+
+		{"n_rows", DATA_INT,
+			DATA_NOT_NULL | DATA_UNSIGNED, 8},
+
+		{"clustered_index_size", DATA_INT,
+			DATA_NOT_NULL | DATA_UNSIGNED, 8},
+
+		{"sum_of_other_index_sizes", DATA_INT,
+			DATA_NOT_NULL | DATA_UNSIGNED, 8}
+	};
+	dict_table_schema_t	table_stats_schema = {
+		TABLE_STATS_NAME,
+		UT_ARR_SIZE(table_stats_columns),
+		table_stats_columns
+	};
+
+	/* definition for the table INDEX_STATS_NAME */
+	dict_col_meta_t	index_stats_columns[] = {
+		{"database_name", DATA_VARMYSQL,
+			DATA_NOT_NULL, 192},
+
+		{"table_name", DATA_VARMYSQL,
+			DATA_NOT_NULL, 192},
+
+		{"index_name", DATA_VARMYSQL,
+			DATA_NOT_NULL, 192},
+
+		{"last_update", DATA_FIXBINARY,
+			DATA_NOT_NULL, 4},
+
+		{"stat_name", DATA_VARMYSQL,
+			DATA_NOT_NULL, 64*3},
+
+		{"stat_value", DATA_INT,
+			DATA_NOT_NULL | DATA_UNSIGNED, 8},
+
+		{"sample_size", DATA_INT,
+			DATA_UNSIGNED, 8},
+
+		{"stat_description", DATA_VARMYSQL,
+			DATA_NOT_NULL, 1024*3}
+	};
+	dict_table_schema_t	index_stats_schema = {
+		INDEX_STATS_NAME,
+		UT_ARR_SIZE(index_stats_columns),
+		index_stats_columns
+	};
+
+	char		errstr[512];
+	dberr_t		ret;
+
+	if (!caller_has_dict_sys_mutex) {
+		mutex_enter(&(dict_sys->mutex));
+	}
+
+	ut_ad(mutex_own(&dict_sys->mutex));
+
+	/* first check table_stats */
+	ret = dict_table_schema_check(&table_stats_schema, errstr,
+				      sizeof(errstr));
+	if (ret == DB_SUCCESS) {
+		/* if it is ok, then check index_stats */
+		ret = dict_table_schema_check(&index_stats_schema, errstr,
+					      sizeof(errstr));
+	}
+
+	if (!caller_has_dict_sys_mutex) {
+		mutex_exit(&(dict_sys->mutex));
+	}
+
+	if (ret != DB_SUCCESS) {
+		ut_print_timestamp(stderr);
+		fprintf(stderr, " InnoDB: Error: %s\n", errstr);
+		return(FALSE);
+	}
+	/* else */
+
+	return(TRUE);
+}
+/* @} */
 
 /*********************************************************************//**
 Executes a given SQL statement using the InnoDB internal SQL parser
@@ -200,8 +301,13 @@ dict_stats_exec_sql(
 	trx_t*	trx;
 	dberr_t	err;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
+	if (!dict_stats_persistent_storage_check(TRUE)) {
+		return(DB_STATS_DO_NOT_EXIST);
+	}
+
 	trx = trx_allocate_for_background();
 	trx_start_if_not_started(trx);
 
@@ -346,7 +452,7 @@ are not saved on disk.
 This was the only way to calculate statistics before the
 Persistent Statistics feature was introduced.
 dict_stats_update_transient() @{ */
-static
+UNIV_INTERN
 void
 dict_stats_update_transient(
 /*========================*/
@@ -362,6 +468,7 @@ dict_stats_update_transient(
 
 	if (dict_table_is_discarded(table)) {
 		/* Nothing to do. */
+		dict_stats_empty_table(table);
 		return;
 	} else if (index == NULL) {
 		/* Table definition is corrupt */
@@ -400,109 +507,6 @@ dict_stats_update_transient(
 }
 /* @} */
 
-/*********************************************************************//**
-Checks whether the persistent statistics storage exists and that all
-tables have the proper structure.
-dict_stats_persistent_storage_check() @{
-@return TRUE if exists and all tables are ok */
-static
-ibool
-dict_stats_persistent_storage_check(
-/*================================*/
-	ibool	caller_has_dict_sys_mutex)	/*!< in: TRUE if the caller
-						owns dict_sys->mutex */
-{
-	/* definition for the table TABLE_STATS_NAME */
-	dict_col_meta_t	table_stats_columns[] = {
-		{"database_name", DATA_VARMYSQL,
-			DATA_NOT_NULL, 192},
-
-		{"table_name", DATA_VARMYSQL,
-			DATA_NOT_NULL, 192},
-
-		{"last_update", DATA_FIXBINARY,
-			DATA_NOT_NULL, 4},
-
-		{"n_rows", DATA_INT,
-			DATA_NOT_NULL | DATA_UNSIGNED, 8},
-
-		{"clustered_index_size", DATA_INT,
-			DATA_NOT_NULL | DATA_UNSIGNED, 8},
-
-		{"sum_of_other_index_sizes", DATA_INT,
-			DATA_NOT_NULL | DATA_UNSIGNED, 8}
-	};
-	dict_table_schema_t	table_stats_schema = {
-		TABLE_STATS_NAME,
-		UT_ARR_SIZE(table_stats_columns),
-		table_stats_columns
-	};
-
-	/* definition for the table INDEX_STATS_NAME */
-	dict_col_meta_t	index_stats_columns[] = {
-		{"database_name", DATA_VARMYSQL,
-			DATA_NOT_NULL, 192},
-
-		{"table_name", DATA_VARMYSQL,
-			DATA_NOT_NULL, 192},
-
-		{"index_name", DATA_VARMYSQL,
-			DATA_NOT_NULL, 192},
-
-		{"last_update", DATA_FIXBINARY,
-			DATA_NOT_NULL, 4},
-
-		{"stat_name", DATA_VARMYSQL,
-			DATA_NOT_NULL, 64*3},
-
-		{"stat_value", DATA_INT,
-			DATA_NOT_NULL | DATA_UNSIGNED, 8},
-
-		{"sample_size", DATA_INT,
-			DATA_UNSIGNED, 8},
-
-		{"stat_description", DATA_VARMYSQL,
-			DATA_NOT_NULL, 1024*3}
-	};
-	dict_table_schema_t	index_stats_schema = {
-		INDEX_STATS_NAME,
-		UT_ARR_SIZE(index_stats_columns),
-		index_stats_columns
-	};
-
-	char		errstr[512];
-	dberr_t		ret;
-
-	if (!caller_has_dict_sys_mutex) {
-		mutex_enter(&(dict_sys->mutex));
-	}
-
-	ut_ad(mutex_own(&dict_sys->mutex));
-
-	/* first check table_stats */
-	ret = dict_table_schema_check(&table_stats_schema, errstr,
-				      sizeof(errstr));
-	if (ret == DB_SUCCESS) {
-		/* if it is ok, then check index_stats */
-		ret = dict_table_schema_check(&index_stats_schema, errstr,
-					      sizeof(errstr));
-	}
-
-	if (!caller_has_dict_sys_mutex) {
-		mutex_exit(&(dict_sys->mutex));
-	}
-
-	if (ret != DB_SUCCESS) {
-		ut_print_timestamp(stderr);
-		fprintf(stderr, " InnoDB: Error: %s\n", errstr);
-		return(FALSE);
-	}
-	/* else */
-
-	return(TRUE);
-}
-/* @} */
-
 /* @{ Pseudo code about the relation between the following functions
 
 let N = N_SAMPLE_PAGES(index)
@@ -522,75 +526,6 @@ dict_stats_analyze_index()
 @} */
 
 /*********************************************************************//**
-Close the stats tables. Should always be called after successful
-dict_stats_open(). It will free the dict_stats handle.
-dict_stats_close() @{ */
-UNIV_INLINE
-void
-dict_stats_close(
-/*=============*/
-	dict_stats_t*	dict_stats)	/*!< in/own: Handle to open
-					statistics tables */
-{
-	ut_ad(!mutex_own(&dict_sys->mutex));
-
-	if (dict_stats->table_stats != NULL) {
-		dict_table_close(dict_stats->table_stats, FALSE, FALSE);
-		dict_stats->table_stats = NULL;
-	}
-
-	if (dict_stats->index_stats != NULL) {
-		dict_table_close(dict_stats->index_stats, FALSE, FALSE);
-		dict_stats->index_stats = NULL;
-	}
-
-	mem_free(dict_stats);
-}
-/* @} */
-
-/*********************************************************************//**
-Open stats tables to prevent these tables from being DROPped.
-Also check whether they have the correct structure. The caller
-must call dict_stats_close() when he has finished DMLing the tables.
-dict_stats_open() @{
-@return pointer to open tables or NULL on failure */
-UNIV_INLINE
-dict_stats_t*
-dict_stats_open(void)
-/*=================*/
-{
-	dict_stats_t*	dict_stats;
-
-	ut_ad(!mutex_own(&dict_sys->mutex));
-
-	dict_stats = static_cast<dict_stats_t*>(
-		mem_zalloc(sizeof(*dict_stats)));
-
-	dict_stats->table_stats = dict_table_open_on_name(
-		TABLE_STATS_NAME, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
-
-	dict_stats->index_stats = dict_table_open_on_name(
-		INDEX_STATS_NAME, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
-
-	/* Check if the tables have the correct structure, if yes then
-	after this function we can safely DELETE from them without worrying
-	that they may get DROPped or DDLed because the open will have
-	increased the reference count. */
-
-	if (dict_stats->table_stats == NULL
-	    || dict_stats->index_stats == NULL
-	    || !dict_stats_persistent_storage_check(FALSE)) {
-
-		/* There was an error, close the tables and free the handle. */
-		dict_stats_close(dict_stats);
-		dict_stats = NULL;
-	}
-
-	return(dict_stats);
-}
-/* @} */
-
-/*********************************************************************//**
 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
@@ -1778,6 +1713,7 @@ dict_stats_save_index_stat(
 	pars_info_t*	pinfo;
 	dberr_t		ret;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
 #define PREPARE_PINFO_FOR_INDEX_SAVE() \
@@ -1866,31 +1802,13 @@ static
 dberr_t
 dict_stats_save(
 /*============*/
-	dict_table_t*	table,		/*!< in: table */
-	ibool		caller_has_dict_sys_mutex)/*!< in: TRUE if the caller
-					owns dict_sys->mutex */
+	dict_table_t*	table)		/*!< in: table */
 {
-	dict_stats_t*	dict_stats;
 	pars_info_t*	pinfo;
 	lint		now;
 	dberr_t		ret;
 
-	if (caller_has_dict_sys_mutex) {
-		mutex_exit(&dict_sys->mutex);
-	}
-
-	/* Increment table reference count to prevent the tables from
-	being DROPped just before que_eval_sql(). */
-	dict_stats = dict_stats_open();
-
-	if (dict_stats == NULL) {
-		/* stats tables do not exist or have unexpected structure */
-		if (caller_has_dict_sys_mutex) {
-			mutex_enter(&dict_sys->mutex);
-		}
-		return(DB_SUCCESS);
-	}
-
+	rw_lock_x_lock(&dict_operation_lock);
 	mutex_enter(&dict_sys->mutex);
 
 	/* MySQL's timestamp is 4 byte, so we use
@@ -2029,12 +1947,7 @@ dict_stats_save(
 
 end:
 	mutex_exit(&dict_sys->mutex);
-
-	dict_stats_close(dict_stats);
-
-	if (caller_has_dict_sys_mutex) {
-		mutex_enter(&dict_sys->mutex);
-	}
+	rw_lock_x_unlock(&dict_operation_lock);
 
 	return(ret);
 }
@@ -2385,16 +2298,14 @@ static
 dberr_t
 dict_stats_fetch_from_ps(
 /*=====================*/
-	dict_table_t*	table,		/*!< in/out: table */
-	ibool		caller_has_dict_sys_mutex)/*!< in: TRUE if the caller
-					owns dict_sys->mutex */
+	dict_table_t*	table)	/*!< in/out: table */
 {
 	index_fetch_t	index_fetch_arg;
 	trx_t*		trx;
 	pars_info_t*	pinfo;
 	dberr_t		ret;
 
-	ut_ad(mutex_own(&dict_sys->mutex) == caller_has_dict_sys_mutex);
+	ut_ad(!mutex_own(&dict_sys->mutex));
 
 	trx = trx_allocate_for_background();
 
@@ -2481,7 +2392,7 @@ dict_stats_fetch_from_ps(
 			   "CLOSE index_stats_cur;\n"
 
 			   "END;",
-			   !caller_has_dict_sys_mutex, trx);
+			   TRUE, trx);
 	/* pinfo is freed by que_eval_sql() */
 
 	/* XXX If mysql.innodb_index_stats contained less rows than the number
@@ -2522,7 +2433,7 @@ dict_stats_update_for_index(
 			dict_table_stats_lock(index->table, RW_X_LATCH);
 			dict_stats_analyze_index(index);
 			dict_table_stats_unlock(index->table, RW_X_LATCH);
-			dict_stats_save(index->table, FALSE);
+			dict_stats_save(index->table);
 			return;
 		}
 		/* else */
@@ -2558,23 +2469,15 @@ dberr_t
 dict_stats_update(
 /*==============*/
 	dict_table_t*		table,	/*!< in/out: table */
-	dict_stats_upd_option_t	stats_upd_option,
+	dict_stats_upd_option_t	stats_upd_option)
 					/*!< in: whether to (re) calc
 					the stats or to fetch them from
 					the persistent statistics
 					storage */
-	bool			caller_has_dict_sys_mutex)
-					/*!< in: TRUE if the caller
-					owns dict_sys->mutex */
 {
 	char			buf[MAX_FULL_NAME_LEN];
 
-	/* check whether caller_has_dict_sys_mutex is set correctly;
-	note that mutex_own() is not implemented in non-debug code so
-	we cannot avoid having this extra param to the current function */
-	ut_ad(caller_has_dict_sys_mutex
-	      ? mutex_own(&dict_sys->mutex)
-	      : !mutex_own(&dict_sys->mutex));
+	ut_ad(!mutex_own(&dict_sys->mutex));
 
 	if (table->ibd_file_missing) {
 		ut_print_timestamp(stderr);
@@ -2610,8 +2513,7 @@ dict_stats_update(
 		before calling the potentially slow function
 		dict_stats_update_persistent(); that is a
 		prerequisite for dict_stats_save() succeeding */
-		if (dict_stats_persistent_storage_check(
-				caller_has_dict_sys_mutex)) {
+		if (dict_stats_persistent_storage_check(FALSE)) {
 
 			dberr_t	err;
 
@@ -2623,10 +2525,9 @@ dict_stats_update(
 
 			dict_table_t*	t;
 
-			t = dict_stats_snapshot_create(
-				table, caller_has_dict_sys_mutex);
+			t = dict_stats_snapshot_create(table);
 
-			err = dict_stats_save(t, caller_has_dict_sys_mutex);
+			err = dict_stats_save(t);
 
 			dict_stats_snapshot_free(t);
 
@@ -2659,11 +2560,9 @@ dict_stats_update(
 
 		if (dict_stats_is_persistent_enabled(table)) {
 
-			if (dict_stats_persistent_storage_check(
-					caller_has_dict_sys_mutex)) {
+			if (dict_stats_persistent_storage_check(FALSE)) {
 
-				return(dict_stats_save(
-					table, caller_has_dict_sys_mutex));
+				return(dict_stats_save(table));
 			}
 
 			return(DB_STATS_DO_NOT_EXIST);
@@ -2694,8 +2593,7 @@ dict_stats_update(
 		persistent stats enabled */
 		ut_a(strchr(table->name, '/') != NULL);
 
-		if (!dict_stats_persistent_storage_check(
-			caller_has_dict_sys_mutex)) {
+		if (!dict_stats_persistent_storage_check(FALSE)) {
 			/* persistent statistics storage does not exist
 			or is corrupted, calculate the transient stats */
 
@@ -2720,8 +2618,7 @@ dict_stats_update(
 		less rows than expected. */
 		dict_stats_empty_table(table);
 
-		dberr_t	err = dict_stats_fetch_from_ps(
-			table, caller_has_dict_sys_mutex);
+		dberr_t	err = dict_stats_fetch_from_ps(table);
 
 		switch (err) {
 		case DB_SUCCESS:
@@ -2730,8 +2627,7 @@ dict_stats_update(
 			if (dict_stats_auto_recalc_is_enabled(table)) {
 				return(dict_stats_update(
 						table,
-						DICT_STATS_RECALC_PERSISTENT,
-						caller_has_dict_sys_mutex));
+						DICT_STATS_RECALC_PERSISTENT));
 			}
 			/* else */
 
@@ -2806,7 +2702,6 @@ dict_stats_drop_index(
 	const char*	table_name;
 	pars_info_t*	pinfo;
 	dberr_t		ret;
-	dict_stats_t*	dict_stats;
 
 	ut_ad(!mutex_own(&dict_sys->mutex));
 
@@ -2817,17 +2712,6 @@ dict_stats_drop_index(
 		return(DB_SUCCESS);
 	}
 
-	/* Increment table reference count to prevent the tables from
-	being DROPped just before que_eval_sql(). */
-	dict_stats = dict_stats_open();
-
-	if (dict_stats == NULL) {
-		/* stats tables do not exist or have unexpected structure */
-		return(DB_SUCCESS);
-	}
-
-	/* the stats tables cannot be DROPped now */
-
 	ut_snprintf(database_name, sizeof(database_name), "%.*s",
 		    (int) dict_get_db_name_len(tname), tname);
 
@@ -2841,6 +2725,7 @@ dict_stats_drop_index(
 
 	pars_info_add_str_literal(pinfo, "index_name", iname);
 
+	rw_lock_x_lock(&dict_operation_lock);
 	mutex_enter(&dict_sys->mutex);
 
 	ret = dict_stats_exec_sql(
@@ -2854,6 +2739,11 @@ dict_stats_drop_index(
 		"END;\n");
 
 	mutex_exit(&dict_sys->mutex);
+	rw_lock_x_unlock(&dict_operation_lock);
+
+	if (ret == DB_STATS_DO_NOT_EXIST) {
+		ret = DB_SUCCESS;
+	}
 
 	if (ret != DB_SUCCESS) {
 		ut_snprintf(errstr, errstr_sz,
@@ -2878,8 +2768,6 @@ dict_stats_drop_index(
 		fprintf(stderr, " InnoDB: %s\n", errstr);
 	}
 
-	dict_stats_close(dict_stats);
-
 	return(ret);
 }
 /* @} */
@@ -2889,7 +2777,6 @@ Executes
 DELETE FROM mysql.innodb_table_stats
 WHERE database_name = '...' AND table_name = '...';
 Creates its own transaction and commits it.
-mysql.innodb_table_stats should be protected from DDL with dict_stats_open().
 dict_stats_delete_from_table_stats() @{
 @return DB_SUCCESS or error code */
 UNIV_INLINE
@@ -2902,6 +2789,7 @@ dict_stats_delete_from_table_stats(
 	pars_info_t*	pinfo;
 	dberr_t		ret;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
 	pinfo = pars_info_create();
@@ -2927,7 +2815,6 @@ Executes
 DELETE FROM mysql.innodb_index_stats
 WHERE database_name = '...' AND table_name = '...';
 Creates its own transaction and commits it.
-mysql.innodb_index_stats should be protected from DDL with dict_stats_open().
 dict_stats_delete_from_index_stats() @{
 @return DB_SUCCESS or error code */
 UNIV_INLINE
@@ -2940,6 +2827,7 @@ dict_stats_delete_from_index_stats(
 	pars_info_t*	pinfo;
 	dberr_t		ret;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
 	pinfo = pars_info_create();
@@ -2979,6 +2867,7 @@ dict_stats_drop_table(
 	const char*	table_name_strip; /* without leading db name */
 	dberr_t		ret;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
 	/* skip tables that do not contain a database name
@@ -2995,12 +2884,6 @@ dict_stats_drop_table(
 		return(DB_SUCCESS);
 	}
 
-	if (!dict_stats_persistent_storage_check(TRUE)) {
-		/* If stats tables are gone, then there is nothing to
-		delete from them. */
-		return(DB_SUCCESS);
-	}
-
 	ut_snprintf(database_name, sizeof(database_name), "%.*s",
 		    (int) dict_get_db_name_len(table_name),
 		    table_name);
@@ -3015,6 +2898,10 @@ dict_stats_drop_table(
 							 table_name_strip);
 	}
 
+	if (ret == DB_STATS_DO_NOT_EXIST) {
+		ret = DB_SUCCESS;
+	}
+
 	if (ret != DB_SUCCESS) {
 
 		ut_snprintf(errstr, errstr_sz,
@@ -3049,7 +2936,6 @@ UPDATE mysql.innodb_table_stats SET
 database_name = '...', table_name = '...'
 WHERE database_name = '...' AND table_name = '...';
 Creates its own transaction and commits it.
-mysql.innodb_table_stats should be protected from DDL with dict_stats_open().
 dict_stats_rename_in_table_stats() @{
 @return DB_SUCCESS or error code */
 UNIV_INLINE
@@ -3064,6 +2950,7 @@ dict_stats_rename_in_table_stats(
 	pars_info_t*	pinfo;
 	dberr_t		ret;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
 	pinfo = pars_info_create();
@@ -3095,7 +2982,6 @@ UPDATE mysql.innodb_index_stats SET
 database_name = '...', table_name = '...'
 WHERE database_name = '...' AND table_name = '...';
 Creates its own transaction and commits it.
-mysql.innodb_index_stats should be protected from DDL with dict_stats_open().
 dict_stats_rename_in_index_stats() @{
 @return DB_SUCCESS or error code */
 UNIV_INLINE
@@ -3110,6 +2996,7 @@ dict_stats_rename_in_index_stats(
 	pars_info_t*	pinfo;
 	dberr_t		ret;
 
+	ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
 	ut_ad(mutex_own(&dict_sys->mutex));
 
 	pinfo = pars_info_create();
@@ -3150,14 +3037,14 @@ dict_stats_rename_table(
 					is returned */
 	size_t		errstr_sz)	/*!< in: errstr size */
 {
-	ut_ad(!mutex_own(&dict_sys->mutex));
-
 	char		old_database_name[MAX_DATABASE_NAME_LEN + 1];
 	char		new_database_name[MAX_DATABASE_NAME_LEN + 1];
 	const char*	old_table_name; /* without leading db name */
 	const char*	new_table_name; /* without leading db name */
 	dberr_t		ret;
-	dict_stats_t*	dict_stats;
+
+	ut_ad(!rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
+	ut_ad(!mutex_own(&dict_sys->mutex));
 
 	/* skip innodb_table_stats and innodb_index_stats themselves */
 	if (strcmp(old_name, TABLE_STATS_NAME) == 0
@@ -3168,15 +3055,6 @@ dict_stats_rename_table(
 		return(DB_SUCCESS);
 	}
 
-	/* Increment table reference count to prevent the tables from
-	being DROPped just before que_eval_sql(). */
-	dict_stats = dict_stats_open();
-
-	if (dict_stats == NULL) {
-		/* stats tables do not exist or have unexpected structure */
-		return(DB_SUCCESS);
-	}
-
 	ut_snprintf(old_database_name, sizeof(old_database_name), "%.*s",
 		    (int) dict_get_db_name_len(old_name), old_name);
 
@@ -3187,6 +3065,7 @@ dict_stats_rename_table(
 
 	new_table_name = dict_remove_db_name(new_name);
 
+	rw_lock_x_lock(&dict_operation_lock);
 	mutex_enter(&dict_sys->mutex);
 
 	ulint	n_attempts = 0;
@@ -3202,9 +3081,15 @@ dict_stats_rename_table(
 				new_database_name, new_table_name);
 		}
 
+		if (ret == DB_STATS_DO_NOT_EXIST) {
+			ret = DB_SUCCESS;
+		}
+
 		if (ret != DB_SUCCESS) {
 			mutex_exit(&dict_sys->mutex);
+			rw_lock_x_unlock(&dict_operation_lock);
 			os_thread_sleep(200000 /* 0.2 sec */);
+			rw_lock_x_lock(&dict_operation_lock);
 			mutex_enter(&dict_sys->mutex);
 		}
 	} while ((ret == DB_DEADLOCK
@@ -3234,7 +3119,7 @@ dict_stats_rename_table(
 			    new_database_name, new_table_name,
 			    old_database_name, old_table_name);
 		mutex_exit(&dict_sys->mutex);
-		dict_stats_close(dict_stats);
+		rw_lock_x_unlock(&dict_operation_lock);
 		return(ret);
 	}
 	/* else */
@@ -3252,9 +3137,15 @@ dict_stats_rename_table(
 				new_database_name, new_table_name);
 		}
 
+		if (ret == DB_STATS_DO_NOT_EXIST) {
+			ret = DB_SUCCESS;
+		}
+
 		if (ret != DB_SUCCESS) {
 			mutex_exit(&dict_sys->mutex);
+			rw_lock_x_unlock(&dict_operation_lock);
 			os_thread_sleep(200000 /* 0.2 sec */);
+			rw_lock_x_lock(&dict_operation_lock);
 			mutex_enter(&dict_sys->mutex);
 		}
 	} while ((ret == DB_DEADLOCK
@@ -3263,6 +3154,7 @@ dict_stats_rename_table(
 		 && n_attempts < 5);
 
 	mutex_exit(&dict_sys->mutex);
+	rw_lock_x_unlock(&dict_operation_lock);
 
 	if (ret != DB_SUCCESS) {
 		ut_snprintf(errstr, errstr_sz,
@@ -3287,8 +3179,6 @@ dict_stats_rename_table(
 			    old_database_name, old_table_name);
 	}
 
-	dict_stats_close(dict_stats);
-
 	return(ret);
 }
 /* @} */
@@ -3332,19 +3222,13 @@ static
 dict_table_t*
 dict_stats_snapshot_create(
 /*=======================*/
-	const dict_table_t*	table,		/*!< in: table whose stats
+	const dict_table_t*	table)		/*!< in: table whose stats
 						to copy */
-	bool			dict_mutex)	/*!< in: true if caller owns
-						the dict sys mutex */
 {
 	size_t		heap_size;
 	dict_index_t*	index;
 
-	if (!dict_mutex) {
-		mutex_enter(&dict_sys->mutex);
-	}
-
-	ut_ad(mutex_own(&dict_sys->mutex));
+	mutex_enter(&dict_sys->mutex);
 
 	dict_table_stats_lock(table, RW_X_LATCH);
 
@@ -3466,9 +3350,7 @@ dict_stats_snapshot_create(
 
 	dict_table_stats_unlock(table, RW_X_LATCH);
 
-	if (!dict_mutex) {
-		mutex_exit(&dict_sys->mutex);
-	}
+	mutex_exit(&dict_sys->mutex);
 
 	return(t);
 }
@@ -3710,7 +3592,7 @@ test_dict_stats_save()
 	index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE;
 	index2_stat_n_sample_sizes[4] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE;
 
-	ret = dict_stats_save(&table, FALSE);
+	ret = dict_stats_save(&table);
 
 	ut_a(ret == DB_SUCCESS);
 
@@ -3842,7 +3724,7 @@ test_dict_stats_fetch_from_ps()
 	index2.stat_n_diff_key_vals = index2_stat_n_diff_key_vals;
 	index2.stat_n_sample_sizes = index2_stat_n_sample_sizes;
 
-	ret = dict_stats_fetch_from_ps(&table, FALSE);
+	ret = dict_stats_fetch_from_ps(&table);
 
 	ut_a(ret == DB_SUCCESS);
 

=== modified file 'storage/innobase/dict/dict0stats_background.cc'
--- a/storage/innobase/dict/dict0stats_background.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0stats_background.cc	revid:vasil.dimov@stripped
@@ -335,7 +335,7 @@ pop_from_auto_recalc_list_and_recalc()
 
 	} else {
 
-		dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT, FALSE);
+		dict_stats_update(table, DICT_STATS_RECALC_PERSISTENT);
 	}
 
 	mutex_enter(&dict_sys->mutex);

=== modified file 'storage/innobase/handler/ha_innodb.cc'
--- a/storage/innobase/handler/ha_innodb.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/ha_innodb.cc	revid:vasil.dimov@stripped
@@ -9401,7 +9401,7 @@ ha_innobase::create(
 
 	innobase_copy_frm_flags_from_create_info(innobase_table, create_info);
 
-	dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE, FALSE);
+	dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE);
 
 	if (innobase_table) {
 		/* We update the highest file format in the system table
@@ -10458,7 +10458,7 @@ ha_innobase::info(
 			}
 
 			ut_ad(!mutex_own(&dict_sys->mutex));
-			ret = dict_stats_update(ib_table, opt, FALSE);
+			ret = dict_stats_update(ib_table, opt);
 
 			if (ret != DB_SUCCESS) {
 				prebuilt->trx->op_info = "";

=== modified file 'storage/innobase/include/dict0dict.h'
--- a/storage/innobase/include/dict0dict.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0dict.h	revid:vasil.dimov@stripped
@@ -570,7 +570,7 @@ dict_table_get_col_name(
 	ulint			col_nr)	/*!< in: column number */
 	__attribute__((nonnull, warn_unused_result));
 /**********************************************************************//**
-Prints a table definition. */
+Prints a table data. */
 UNIV_INTERN
 void
 dict_table_print(
@@ -578,22 +578,6 @@ dict_table_print(
 	dict_table_t*	table)	/*!< in: table */
 	__attribute__((nonnull));
 /**********************************************************************//**
-Prints a table data. */
-UNIV_INTERN
-void
-dict_table_print_low(
-/*=================*/
-	dict_table_t*	table)	/*!< in: table */
-	__attribute__((nonnull));
-/**********************************************************************//**
-Prints a table data when we know the table name. */
-UNIV_INTERN
-void
-dict_table_print_by_name(
-/*=====================*/
-	const char*	name)	/*!< in: table name */
-	__attribute__((nonnull));
-/**********************************************************************//**
 Outputs info on foreign keys of a table. */
 UNIV_INTERN
 void

=== modified file 'storage/innobase/include/dict0load.h'
--- a/storage/innobase/include/dict0load.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0load.h	revid:vasil.dimov@stripped
@@ -55,8 +55,6 @@ enum dict_table_info {
 					a SYS_TABLES record */
 	DICT_TABLE_LOAD_FROM_CACHE = 1,	/*!< Check first whether dict_table_t
 					is in the cache, if so, return it */
-	DICT_TABLE_UPDATE_STATS = 2	/*!< whether to update statistics
-					when loading SYS_TABLES information. */
 };
 
 typedef enum dict_table_info	dict_table_info_t;

=== modified file 'storage/innobase/include/dict0stats.h'
--- a/storage/innobase/include/dict0stats.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0stats.h	revid:vasil.dimov@stripped
@@ -57,6 +57,18 @@ enum dict_stats_upd_option {
 typedef enum dict_stats_upd_option	dict_stats_upd_option_t;
 
 /*********************************************************************//**
+Calculates new estimates for table and index statistics. This function
+is 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. */
+UNIV_INTERN
+void
+dict_stats_update_transient(
+/*========================*/
+	dict_table_t*	table);	/*!< in/out: table */
+
+/*********************************************************************//**
 Set the persistent statistics flag for a given table. This is set only
 in the in-memory table object and is not saved on disk. It will be read
 from the .frm file upon first open from MySQL after a server restart. */
@@ -128,13 +140,10 @@ dberr_t
 dict_stats_update(
 /*==============*/
 	dict_table_t*		table,	/*!< in/out: table */
-	dict_stats_upd_option_t	stats_upd_option,
+	dict_stats_upd_option_t	stats_upd_option);
 					/*!< in: whether to (re) calc
 					the stats or to fetch them from
 					the persistent storage */
-	bool			caller_has_dict_sys_mutex);
-					/*!< in: TRUE if the caller
-					owns dict_sys->mutex */
 
 /*********************************************************************//**
 Removes the information for a particular index's stats from the persistent

=== modified file 'storage/innobase/include/dict0stats.ic'
--- a/storage/innobase/include/dict0stats.ic	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/dict0stats.ic	revid:vasil.dimov@stripped
@@ -180,7 +180,7 @@ dict_stats_init(
 		opt = DICT_STATS_RECALC_TRANSIENT;
 	}
 
-	dict_stats_update(table, opt, FALSE);
+	dict_stats_update(table, opt);
 }
 /* @} */
 

=== modified file 'storage/innobase/row/row0mysql.cc'
--- a/storage/innobase/row/row0mysql.cc	revid:vasil.dimov@stripped
+++ b/storage/innobase/row/row0mysql.cc	revid:vasil.dimov@stripped
@@ -1058,7 +1058,7 @@ row_update_statistics_if_needed(
 
 		ut_ad(!mutex_own(&dict_sys->mutex));
 		/* this will reset table->stat_modified_counter to 0 */
-		dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT, FALSE);
+		dict_stats_update(table, DICT_STATS_RECALC_TRANSIENT);
 	}
 }
 
@@ -3495,7 +3495,7 @@ funct_exit:
 
 	row_mysql_unlock_data_dictionary(trx);
 
-	dict_stats_update(table, DICT_STATS_EMPTY_TABLE, FALSE);
+	dict_stats_update(table, DICT_STATS_EMPTY_TABLE);
 
 	trx->op_info = "";
 

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (vasil.dimov:3968 to 3970) WL#6189vasil.dimov6 Jun