MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:vasil.dimov Date:July 6 2010 1:52pm
Subject:bzr push into mysql-next-mr-persistent-stats branch (vasil.dimov:3232 to
3251)
View as plain text  
 3251 Vasil Dimov	2010-07-06
      Tell low-level functions whether the caller owns the dict mutex
      
      Low-level persistent stats functions that call que_eval_sql()
      need to know whether the caller owns or not dict_sys->mutex.
      Thus add a boolean parameter caller_has_dict_sys_mutex to each such
      function and pass either TRUE or FALSE from the callers.
      
      Also when requested to fetch stats - check whether this is SYS_* table
      and if so, then always use the transient stats because we know that
      persistent stats storage does not contain stats about SYS_* tables.

    modified:
      storage/innobase/dict/dict0dict.c
      storage/innobase/dict/dict0load.c
      storage/innobase/dict/dict0stats.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/include/dict0stats.h
      storage/innobase/row/row0mysql.c
 3250 Vasil Dimov	2010-06-30
      Copy records only when we are about to jump to the next page
      
      Previously we were copying rec to prev_rec always, but we can do
      this copying only when we are on the last record on the page and
      thus we know that on the next iteration the latch on the current
      page will be released.
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3249 Vasil Dimov	2010-06-30
      s/persistent storage/persistent statistics storage/
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3248 Vasil Dimov	2010-06-29
      Print a human readable column type/flags on error
      
      For this purpose implement a new function dtype_sql_name()
      that converts mtype,prtype,len to a human readable (SQL) name.
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
      storage/innobase/include/data0type.h
      storage/innobase/include/data0type.ic
 3247 Vasil Dimov	2010-06-29
      Fix typo in comment.

    modified:
      storage/innobase/dict/dict0stats.c
 3246 Vasil Dimov	2010-06-29
      Do not emit warnings if persistent storage is not present.
      
      This code is executed during open table and if the persistent storage
      is not present this would cause many warnings to be printed.
      
      This change reverts the following and adds an explanatory comment.
      
        ------------------------------------------------------------
        revno: 3243
        revision-id: vasil.dimov@stripped
        parent: vasil.dimov@stripped
        committer: Vasil Dimov <vasil.dimov@stripped>
        branch nick: mysql-next-mr-persistent-stats
        timestamp: Tue 2010-06-29 10:48:04 +0300
        message:
          Emit a message before returning error if table does not exist
          
          Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3245 Vasil Dimov	2010-06-29
      Use innobase_strcasecmp() instead of strcasecmp()
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3244 Vasil Dimov	2010-06-29
      Fix the number of columns that is printed
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3243 Vasil Dimov	2010-06-29
      Emit a message before returning error if table does not exist
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3242 Vasil Dimov	2010-06-29
      Rename column_data_t and table_schema_t
      
      Change the names of those structs to conform with the InnoDB convention
      foo0bar.c -> foo_bar_...
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3241 Vasil Dimov	2010-06-29
      Clarify comment in dict/dict0load.c

    modified:
      storage/innobase/dict/dict0load.c
 3240 Vasil Dimov	2010-06-29
      Add a new mysql-test to test DROPping locked stats
      
      DROP TABLE and ALTER TABLE DROP INDEX are supposed to remove rows
      from the user-visible stats tables. If those corresponding rows
      are locked by the user, then the behavior should be to emit an
      explanatory warning and skip the removal of those rows.

    added:
      mysql-test/suite/innodb/r/innodb_stats_drop_locked.result
      mysql-test/suite/innodb/t/innodb_stats_drop_locked.test
 3239 Vasil Dimov	2010-06-29
      Move "SET SESSION innodb_analyze_is_persistent=1" to .test
      
      Better to make it obvious that this variable is set.

    modified:
      mysql-test/suite/innodb/include/innodb_stats_bootstrap.inc
      mysql-test/suite/innodb/t/innodb_stats.test
 3238 Vasil Dimov	2010-06-25
      Move the test_innodb_stats table creation to innodb_stats.test
      
      That table is specific for this test.

    modified:
      mysql-test/suite/innodb/include/innodb_stats_bootstrap.inc
      mysql-test/suite/innodb/t/innodb_stats.test
 3237 Vasil Dimov	2010-06-25
      Move the stats table creation from innodb_stats.test to an include file.
      To be included in other tests too.

    added:
      mysql-test/suite/innodb/include/innodb_stats_bootstrap.inc
    modified:
      mysql-test/suite/innodb/t/innodb_stats.test
 3236 Vasil Dimov	2010-06-25
      Improve comment
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
      storage/innobase/include/dict0stats.h
 3235 Vasil Dimov	2010-06-25
      Remove non-existent function's prototype.
      
      This function was removed but the prototype was forgotten.

    modified:
      storage/innobase/include/lock0lock.h
 3234 Vasil Dimov	2010-06-25
      Remove a trailing whitespace and print a message if table definition is corrupt
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
 3233 Vasil Dimov	2010-06-25
      Rename enum dict_stats_upd_how to dict_stats_upd_option and define
      a type for it.
      
      Suggested by:	Jimmy (rb://373)

    modified:
      storage/innobase/dict/dict0stats.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/ha_innodb.h
      storage/innobase/include/dict0stats.h
 3232 Vasil Dimov	2010-06-17
      Fix possible waits when dropping an index
      
      Fix possible waits when dropping an index similarly to the way they
      were fixed in DROP TABLE - set trx->allowed_to_wait to FALSE during
      que_eval_sql() so it does not wait on possible user locks but returns
      DB_LOCK_WAIT_TIMEOUT immediately.
      
      Also push the error message to the client in addition to printing it
      to the server error log and change DROP TABLE not to fail if stats
      cannot be deleted.

    modified:
      storage/innobase/dict/dict0stats.c
      storage/innobase/handler/ha_innodb.cc
      storage/innobase/handler/handler0alter.cc
      storage/innobase/include/dict0stats.h
=== added file 'mysql-test/suite/innodb/include/innodb_stats_bootstrap.inc'
--- a/mysql-test/suite/innodb/include/innodb_stats_bootstrap.inc	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/include/innodb_stats_bootstrap.inc	revid:vasil.dimov@stripped
@@ -0,0 +1,35 @@
+-- disable_warnings
+-- disable_query_log
+DROP DATABASE IF EXISTS innodb;
+CREATE DATABASE innodb;
+
+CREATE TABLE innodb.table_stats (
+	database_name			VARCHAR(512) NOT NULL,
+	table_name			VARCHAR(512) NOT NULL,
+	stats_timestamp			TIMESTAMP NOT NULL,
+	n_rows				BIGINT UNSIGNED NOT NULL,
+	clustered_index_size		BIGINT UNSIGNED NOT NULL,
+	sum_of_other_index_sizes	BIGINT UNSIGNED NOT NULL,
+	PRIMARY KEY (database_name, table_name)
+) ENGINE=INNODB;
+
+CREATE TABLE innodb.index_stats (
+	database_name			VARCHAR(512) NOT NULL,
+	table_name			VARCHAR(512) NOT NULL,
+	index_name			VARCHAR(512) NOT NULL,
+	stat_timestamp			TIMESTAMP NOT NULL,
+	/* there are at least:
+	stat_name='index_size'
+	stat_name='n_leaf_pages'
+	stat_name='n_diff_pfx%' */
+	stat_name			VARCHAR(64) NOT NULL,
+	stat_value			BIGINT UNSIGNED NOT NULL,
+	sample_size			BIGINT UNSIGNED,
+	stat_description		VARCHAR(1024) NOT NULL,
+	PRIMARY KEY (database_name, table_name, index_name, stat_name),
+	FOREIGN KEY (database_name, table_name)
+	  REFERENCES table_stats (database_name, table_name)
+) ENGINE=INNODB;
+
+-- enable_warnings
+-- enable_query_log

=== added file 'mysql-test/suite/innodb/r/innodb_stats_drop_locked.result'
--- a/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/r/innodb_stats_drop_locked.result	revid:vasil.dimov@stripped
@@ -0,0 +1,47 @@
+Table	Op	Msg_type	Msg_text
+test.innodb_stats_drop_locked	analyze	status	OK
+SET autocommit=0;
+SELECT table_name FROM innodb.table_stats
+WHERE table_name='innodb_stats_drop_locked'
+FOR UPDATE;
+table_name
+innodb_stats_drop_locked
+SELECT table_name FROM innodb.index_stats
+WHERE table_name='innodb_stats_drop_locked'
+FOR UPDATE;
+table_name
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+ALTER TABLE innodb_stats_drop_locked DROP INDEX c_key;
+Warnings:
+Warning	1205	Unable to instantly delete statistics for index c_key from innodb.index_stats because the rows are locked. They can be deleted later using DELETE FROM innodb.index_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked' AND index_name = 'c_key';
+SHOW CREATE TABLE innodb_stats_drop_locked;
+Table	Create Table
+innodb_stats_drop_locked	CREATE TABLE `innodb_stats_drop_locked` (
+  `c` int(11) DEFAULT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+DROP TABLE innodb_stats_drop_locked;
+Warnings:
+Warning	1205	Unable to instantly delete statistics for table test.innodb_stats_drop_locked from innodb.table_stats or innodb.index_stats because the rows are locked. They can be deleted later using DELETE FROM innodb.index_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked'; DELETE FROM innodb.table_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked';
+SHOW TABLES;
+Tables_in_test
+COMMIT;
+SELECT table_name FROM innodb.table_stats 
+WHERE table_name='innodb_stats_drop_locked';
+table_name
+innodb_stats_drop_locked
+SELECT table_name FROM innodb.index_stats
+WHERE table_name='innodb_stats_drop_locked';
+table_name
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked
+innodb_stats_drop_locked

=== modified file 'mysql-test/suite/innodb/t/innodb_stats.test'
--- a/mysql-test/suite/innodb/t/innodb_stats.test	revid:vasil.dimov@stripped
+++ b/mysql-test/suite/innodb/t/innodb_stats.test	revid:vasil.dimov@stripped
@@ -3,39 +3,12 @@
 #
 
 -- source include/have_innodb.inc
+-- source suite/innodb/include/innodb_stats_bootstrap.inc
 
 -- disable_warnings
 -- disable_query_log
-DROP DATABASE IF EXISTS innodb;
-CREATE DATABASE innodb;
 
-CREATE TABLE innodb.table_stats (
-	database_name			VARCHAR(512) NOT NULL,
-	table_name			VARCHAR(512) NOT NULL,
-	stats_timestamp			TIMESTAMP NOT NULL,
-	n_rows				BIGINT UNSIGNED NOT NULL,
-	clustered_index_size		BIGINT UNSIGNED NOT NULL,
-	sum_of_other_index_sizes	BIGINT UNSIGNED NOT NULL,
-	PRIMARY KEY (database_name, table_name)
-) ENGINE=INNODB;
-
-CREATE TABLE innodb.index_stats (
-	database_name			VARCHAR(512) NOT NULL,
-	table_name			VARCHAR(512) NOT NULL,
-	index_name			VARCHAR(512) NOT NULL,
-	stat_timestamp			TIMESTAMP NOT NULL,
-	/* there are at least:
-	stat_name='index_size'
-	stat_name='n_leaf_pages'
-	stat_name='n_diff_pfx%' */
-	stat_name			VARCHAR(64) NOT NULL,
-	stat_value			BIGINT UNSIGNED NOT NULL,
-	sample_size			BIGINT UNSIGNED,
-	stat_description		VARCHAR(1024) NOT NULL,
-	PRIMARY KEY (database_name, table_name, index_name, stat_name),
-	FOREIGN KEY (database_name, table_name)
-	  REFERENCES table_stats (database_name, table_name)
-) ENGINE=INNODB;
+SET SESSION innodb_analyze_is_persistent=1;
 
 DROP TABLE IF EXISTS test_innodb_stats;
 
@@ -44,8 +17,6 @@ CREATE TABLE test_innodb_stats (
 	KEY a_key (a)
 ) ENGINE=INNODB;
 
-SET SESSION innodb_analyze_is_persistent=1;
-
 -- enable_warnings
 -- enable_query_log
 

=== added file 'mysql-test/suite/innodb/t/innodb_stats_drop_locked.test'
--- a/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/innodb/t/innodb_stats_drop_locked.test	revid:vasil.dimov@stripped
@@ -0,0 +1,62 @@
+#
+# Test the persistent stats feature when DROPping a table or an
+# index when the corresponding rows in the stats tables are locked
+#
+
+-- source include/have_innodb.inc
+-- source suite/innodb/include/innodb_stats_bootstrap.inc
+
+-- disable_warnings
+-- disable_query_log
+
+SET SESSION innodb_analyze_is_persistent=1;
+
+DROP TABLE IF EXISTS innodb_stats_drop_locked;
+
+CREATE TABLE innodb_stats_drop_locked (c INT, KEY c_key (c)) ENGINE=INNODB;
+
+ANALYZE TABLE innodb_stats_drop_locked;
+
+-- enable_warnings
+-- enable_query_log
+
+SET autocommit=0;
+
+SELECT table_name FROM innodb.table_stats
+WHERE table_name='innodb_stats_drop_locked'
+FOR UPDATE;
+
+SELECT table_name FROM innodb.index_stats
+WHERE table_name='innodb_stats_drop_locked'
+FOR UPDATE;
+
+-- connect (con1,localhost,root,,)
+
+-- connection con1
+
+ALTER TABLE innodb_stats_drop_locked DROP INDEX c_key;
+
+# the index should be gone
+SHOW CREATE TABLE innodb_stats_drop_locked;
+
+DROP TABLE innodb_stats_drop_locked;
+
+# the table should be gone
+SHOW TABLES;
+
+-- connection default
+
+-- disconnect con1
+
+COMMIT;
+
+# the stats should be there
+
+SELECT table_name FROM innodb.table_stats 
+WHERE table_name='innodb_stats_drop_locked';
+
+SELECT table_name FROM innodb.index_stats
+WHERE table_name='innodb_stats_drop_locked';
+
+-- disable_query_log
+DROP DATABASE innodb;

=== modified file 'storage/innobase/dict/dict0dict.c'
--- a/storage/innobase/dict/dict0dict.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0dict.c	revid:vasil.dimov@stripped
@@ -727,7 +727,9 @@ dict_table_get(
 			/* If table->ibd_file_missing == TRUE, this will
 			print an error message and return without doing
 			anything. */
-			dict_stats_update(table, DICT_STATS_UPD_FETCH);
+			ut_ad(!mutex_own(&dict_sys->mutex));
+			dict_stats_update(table, DICT_STATS_UPD_FETCH,
+					  FALSE);
 		}
 	}
 
@@ -4268,7 +4270,7 @@ dict_table_print_low(
 
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 
-	dict_stats_update(table, DICT_STATS_UPD_FETCH);
+	dict_stats_update(table, DICT_STATS_UPD_FETCH, TRUE);
 
 	fprintf(stderr,
 		"--------------------------------------\n"

=== modified file 'storage/innobase/dict/dict0load.c'
--- a/storage/innobase/dict/dict0load.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0load.c	revid:vasil.dimov@stripped
@@ -345,9 +345,10 @@ dict_process_sys_tables_rec(
 	if ((status & DICT_TABLE_UPDATE_STATS)
 	    && dict_table_get_first_index(*table)) {
 
-		/* Update statistics if DICT_TABLE_UPDATE_STATS
-		is set */
-		dict_stats_update(*table, DICT_STATS_UPD_FETCH);
+		/* Update statistics member fields in *table if
+		DICT_TABLE_UPDATE_STATS is set */
+		ut_ad(mutex_own(&dict_sys->mutex));
+		dict_stats_update(*table, DICT_STATS_UPD_FETCH, TRUE);
 	}
 
 	return(NULL);

=== modified file 'storage/innobase/dict/dict0stats.c'
--- a/storage/innobase/dict/dict0stats.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/dict/dict0stats.c	revid:vasil.dimov@stripped
@@ -48,7 +48,9 @@ Created Jan 06, 2010 Vasil Dimov
 #include "usr0types.h" /* sess_t */
 #include "ut0rnd.h" /* ut_rnd_interval() */
 
-/* names of the tables from the persistent storage */
+#include "ha_prototypes.h" /* innobase_strcasecmp() */
+
+/* names of the tables from the persistent statistics storage */
 #define TABLE_STATS_NAME	"innodb/table_stats"
 #define TABLE_STATS_NAME_PRINT	"innodb.table_stats"
 #define INDEX_STATS_NAME	"innodb/index_stats"
@@ -60,7 +62,7 @@ Created Jan 06, 2010 Vasil Dimov
 #define DEBUG_PRINTF(fmt, ...)	/* noop */
 #endif
 
-/* number of distinct records on a given level that are required to stop 
+/* number of distinct records on a given level that are required to stop
 descending to lower levels and fetch
 srv_stats_persistent_sample_pages records from that level */
 #define N_DIFF_REQUIRED	(srv_stats_persistent_sample_pages * 10)
@@ -87,7 +89,9 @@ dict_stats_update_transient(
 
 	if (index == NULL) {
 		/* Table definition is corrupt */
-
+		ut_print_timestamp(stderr);
+		fprintf(stderr, "InnoDB: table %s has no indexes. "
+			"Cannot calculate statistics.\n", table->name);
 		return;
 	}
 
@@ -133,22 +137,22 @@ dict_stats_update_transient(
 /* @} */
 
 /* auxiliary structs for checking a table definition @{ */
-struct column_data_struct {
+struct dict_stats_chk_column_struct {
 	const char*	name;
 	ulint		mtype;
 	ulint		prtype_mask;
 	ulint		len;
 };
 
-typedef struct column_data_struct	column_data_t;
+typedef struct dict_stats_chk_column_struct	dict_stats_chk_column_t;
 
-struct table_schema_struct {
-	const char*	table_name;
-	ulint		n_cols;
-	column_data_t*	columns;
+struct dict_stats_chk_table_struct {
+	const char*			table_name;
+	ulint				n_cols;
+	dict_stats_chk_column_t*	columns;
 };
 
-typedef struct table_schema_struct	table_schema_t;
+typedef struct dict_stats_chk_table_struct	dict_stats_chk_table_t;
 /* @} */
 
 /*********************************************************************//**
@@ -160,7 +164,8 @@ static
 ibool
 dict_stats_table_check(
 /*===================*/
-	table_schema_t*	req_schema)	/*!< in/out: required table schema */
+	dict_stats_chk_table_t*	req_schema)/*!< in/out: required table
+					   schema */
 {
 	dict_table_t*	table;
 	ulint		i;
@@ -172,6 +177,13 @@ dict_stats_table_check(
 	if (table == NULL || table->ibd_file_missing) {
 		/* no such table or missing tablespace */
 
+		/* We return silently here because this code is
+		executed during open table. By design we check if the
+		persistent statistics storage is present and whether there
+		are stats for the table being opened and if so, then
+		we use them, otherwise we silently switch back to using
+		the transient stats. */
+
 		return(FALSE);
 	}
 
@@ -183,7 +195,7 @@ dict_stats_table_check(
 		fprintf(stderr,
 			" InnoDB: %s has %d columns but should have %lu.\n",
 			req_schema->table_name,
-			table->n_def,
+			table->n_def - DATA_N_SYS_COLS,
 			req_schema->n_cols);
 
 		goto err_exit;
@@ -197,8 +209,11 @@ dict_stats_table_check(
 	for (i = 0; i < req_schema->n_cols; i++) {
 		ulint	j;
 
+		char	req_type[64];
+		char	actual_type[64];
+
 		/* check if i'th column is the same in both arrays */
-		if (strcasecmp(req_schema->columns[i].name,
+		if (innobase_strcasecmp(req_schema->columns[i].name,
 			       dict_table_get_col_name(table, i)) == 0) {
 
 			/* we found the column in table->cols[] quickly */
@@ -212,8 +227,8 @@ dict_stats_table_check(
 
 				name = dict_table_get_col_name(table, j);
 
-				if (strcasecmp(req_schema->columns[i].name,
-					       name) == 0) {
+				if (innobase_strcasecmp(name,
+					req_schema->columns[i].name) == 0) {
 
 					/* found the column on j'th
 					position */
@@ -237,17 +252,26 @@ dict_stats_table_check(
 		/* we found a column with the same name on j'th position,
 		compare column types and flags */
 
+		dtype_sql_name(req_schema->columns[i].mtype,
+			       req_schema->columns[i].prtype_mask,
+			       req_schema->columns[i].len,
+			       req_type, sizeof(req_type));
+
+		dtype_sql_name(table->cols[j].mtype,
+			       table->cols[j].prtype,
+			       table->cols[j].len,
+			       actual_type, sizeof(actual_type));
+
 		/* check length for exact match */
 		if (req_schema->columns[i].len != table->cols[j].len) {
 
 			ut_print_timestamp(stderr);
 			fprintf(stderr,
-				" InnoDB: Column %s.%s has length %d "
-				"but should have length %lu.\n",
+				" InnoDB: Column %s.%s is %s "
+				"but should be %s (length mismatch).\n",
 				req_schema->table_name,
 				req_schema->columns[i].name,
-				table->cols[j].len,
-				req_schema->columns[i].len);
+				actual_type, req_type);
 
 			goto err_exit;
 		}
@@ -257,12 +281,11 @@ dict_stats_table_check(
 
 			ut_print_timestamp(stderr);
 			fprintf(stderr,
-				" InnoDB: Column %s.%s is of type %d "
-				"but should be of type %lu.\n",
+				" InnoDB: Column %s.%s is %s "
+				"but should be %s (type mismatch).\n",
 				req_schema->table_name,
 				req_schema->columns[i].name,
-				table->cols[j].mtype,
-				req_schema->columns[i].mtype);
+				actual_type, req_type);
 
 			goto err_exit;
 		}
@@ -273,14 +296,26 @@ dict_stats_table_check(
 			& req_schema->columns[i].prtype_mask)
 		       != req_schema->columns[i].prtype_mask) {
 
+			char	req_type[64];
+			char	actual_type[64];
+
+			dtype_sql_name(req_schema->columns[i].mtype,
+				       req_schema->columns[i].prtype_mask,
+				       req_schema->columns[i].len,
+				       req_type, sizeof(req_type));
+
+			dtype_sql_name(table->cols[j].mtype,
+				       table->cols[j].prtype,
+				       table->cols[j].len,
+				       actual_type, sizeof(actual_type));
+
 			ut_print_timestamp(stderr);
 			fprintf(stderr,
-				" InnoDB: Column %s.%s flag %#lx "
-				"is not set in column's flags %#x.\n",
+				" InnoDB: Column %s.%s is %s "
+				"but should be %s (flags mismatch).\n",
 				req_schema->table_name,
 				req_schema->columns[i].name,
-				req_schema->columns[i].prtype_mask,
-				table->cols[j].prtype);
+				actual_type, req_type);
 
 			goto err_exit;
 		}
@@ -301,17 +336,19 @@ err_exit:
 /* @} */
 
 /*********************************************************************//**
-Checks whether the persistent storage exists and that all tables have the
-proper structure.
+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()
-/*=================================*/
+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 */
-	column_data_t	table_stats_columns[] = {
+	dict_stats_chk_column_t	table_stats_columns[] = {
 		{"database_name", DATA_VARCHAR,
 			DATA_NOT_NULL, 512},
 
@@ -330,14 +367,14 @@ dict_stats_persistent_storage_check()
 		{"sum_of_other_index_sizes", DATA_INT,
 			DATA_NOT_NULL | DATA_UNSIGNED, 8}
 	};
-	table_schema_t	table_stats_schema = {
+	dict_stats_chk_table_t	table_stats_schema = {
 		TABLE_STATS_NAME,
 		UT_ARR_SIZE(table_stats_columns),
 		table_stats_columns
 	};
 
 	/* definition for the table INDEX_STATS_NAME */
-	column_data_t	index_stats_columns[] = {
+	dict_stats_chk_column_t	index_stats_columns[] = {
 		{"database_name", DATA_VARCHAR,
 			DATA_NOT_NULL, 512},
 
@@ -362,17 +399,14 @@ dict_stats_persistent_storage_check()
 		{"stat_description", DATA_VARCHAR,
 			DATA_NOT_NULL, 1024}
 	};
-	table_schema_t	index_stats_schema = {
+	dict_stats_chk_table_t	index_stats_schema = {
 		INDEX_STATS_NAME,
 		UT_ARR_SIZE(index_stats_columns),
 		index_stats_columns
 	};
 
-	ibool	caller_has_dict_sys_mutex;
 	ibool	ret;
 
-	caller_has_dict_sys_mutex = mutex_own(&dict_sys->mutex);
-
 	if (!caller_has_dict_sys_mutex) {
 		mutex_enter(&(dict_sys->mutex));
 	}
@@ -590,20 +624,31 @@ dict_stats_analyze_index_level(
 			}
 		}
 
-		/* we need to copy the record instead of assigning like
-		prev_rec = rec; because when we traverse the records
-		on this level at some point we will jump from one page
-		to the next and then rec and prev_rec will be on different
-		pages and btr_pcur_move_to_next_user_rec() will release
-		the latch on the page that prev_rec is on */
-		prev_rec = rec_copy_prefix_to_buf(
-			rec, index, rec_offs_n_fields(offsets_rec),
-			&prev_rec_buf, &prev_rec_buf_size);
-
-		/* increment the pages counter at the end of each page */
 		if (page_rec_is_supremum(page_rec_get_next(rec))) {
+			/* end of a page has been reached */
 
+			/* increment the pages counter at the end of
+			each page */
 			(*total_pages)++;
+
+			/* we need to copy the record instead of assigning
+			like prev_rec = rec; because when we traverse the
+			records on this level at some point we will jump from
+			one page to the next and then rec and prev_rec will
+			be on different pages and
+			btr_pcur_move_to_next_user_rec() will release the
+			latch on the page that prev_rec is on */
+			prev_rec = rec_copy_prefix_to_buf(
+				rec, index, rec_offs_n_fields(offsets_rec),
+				&prev_rec_buf, &prev_rec_buf_size);
+
+		} else {
+			/* still on the same page, the next call to
+			btr_pcur_move_to_next_user_rec() will not jump
+			on the next page, we can simply assign pointers
+			instead of copying the records like above */
+
+			prev_rec = rec;
 		}
 	}
 
@@ -1387,7 +1432,8 @@ dict_stats_update_persistent(
 /* @} */
 
 /*********************************************************************//**
-Save an individual index's statistic into the persistent storage.
+Save an individual index's statistic into the persistent statistics
+storage.
 dict_stats_save_index_stat() @{
 @return DB_SUCCESS or error code */
 static
@@ -1400,7 +1446,9 @@ dict_stats_save_index_stat(
 	ib_uint64_t	stat_value,	/*!< in: value of the stat */
 	ib_uint64_t*	sample_size,	/*!< in: n pages sampled or NULL */
 	const char*	stat_description,/*!< in: description of the stat */
-	trx_t*		trx)		/*!< in/out: transaction to use */
+	trx_t*		trx,		/*!< in/out: transaction to use */
+	ibool		caller_has_dict_sys_mutex)/*!< in: TRUE if the caller
+					owns dict_sys->mutex */
 {
 	pars_info_t*	pinfo;
 	ulint		ret;
@@ -1476,7 +1524,7 @@ dict_stats_save_index_stat(
 			   "  stat_name = :stat_name;\n"
 			   "END IF;\n"
 			   "END;",
-		TRUE, trx);
+		!caller_has_dict_sys_mutex, trx);
 
 	/* pinfo is freed by que_eval_sql() */
 
@@ -1495,14 +1543,16 @@ dict_stats_save_index_stat(
 /* @} */
 
 /*********************************************************************//**
-Save the table's statistics into the persistent storage.
+Save the table's statistics into the persistent statistics storage.
 dict_stats_save() @{
 @return DB_SUCCESS or error code */
 static
 enum db_err
 dict_stats_save(
 /*============*/
-	dict_table_t*	table)		/*!< in: table */
+	dict_table_t*	table,		/*!< in: table */
+	ibool		caller_has_dict_sys_mutex)/*!< in: TRUE if the caller
+					owns dict_sys->mutex */
 {
 	trx_t*		trx;
 	pars_info_t*	pinfo;
@@ -1581,7 +1631,7 @@ dict_stats_save(
 			   "  table_name = :table_name;\n"
 			   "END IF;\n"
 			   "END;",
-			   TRUE, trx);
+			   !caller_has_dict_sys_mutex, trx);
 
 	/* pinfo is freed by que_eval_sql() */
 
@@ -1613,7 +1663,8 @@ dict_stats_save(
 						 NULL,
 						 "Number of pages "
 						 "in the index",
-						 trx);
+						 trx,
+						 caller_has_dict_sys_mutex);
 		if (ret != DB_SUCCESS) {
 			goto end_rollback;
 		}
@@ -1623,7 +1674,8 @@ dict_stats_save(
 						 NULL,
 						 "Number of leaf pages "
 						 "in the index",
-						 trx);
+						 trx,
+						 caller_has_dict_sys_mutex);
 		if (ret != DB_SUCCESS) {
 			goto end_rollback;
 		}
@@ -1671,7 +1723,8 @@ dict_stats_save(
 				index, now, stat_name,
 				stat_n_diff_key_vals[i],
 				&stat_n_sample_sizes[i],
-				stat_description, trx);
+				stat_description, trx,
+				caller_has_dict_sys_mutex);
 
 			if (ret != DB_SUCCESS) {
 				goto end_rollback;
@@ -2016,14 +2069,16 @@ dict_stats_fetch_index_stats_step(
 /* @} */
 
 /*********************************************************************//**
-Read table's statistics from the persistent storage.
+Read table's statistics from the persistent statistics storage.
 dict_stats_fetch_from_ps() @{
 @return DB_SUCCESS or error code */
 static
 enum db_err
 dict_stats_fetch_from_ps(
 /*=====================*/
-	dict_table_t*	table) /*!< in/out: table */
+	dict_table_t*	table,		/*!< in/out: table */
+	ibool		caller_has_dict_sys_mutex)/*!< in: TRUE if the caller
+					owns dict_sys->mutex */
 {
 	trx_t*		trx;
 	pars_info_t*	pinfo;
@@ -2115,7 +2170,7 @@ dict_stats_fetch_from_ps(
 			   "CLOSE index_stats_cur;\n"
 
 			   "END;",
-			   TRUE, trx);
+			   !caller_has_dict_sys_mutex, trx);
 
 	/* pinfo is freed by que_eval_sql() */
 
@@ -2148,13 +2203,24 @@ enum db_err
 dict_stats_update(
 /*==============*/
 	dict_table_t*		table,	/*!< in/out: table */
-	enum dict_stats_upd_how	stats_upd_how)
+	dict_stats_upd_option_t	stats_upd_option,
 					/*!< in: whether to (re)calc
 					the stats or to fetch them from
-					the persistent storage */
+					the persistent statistics
+					storage */
+	ibool			caller_has_dict_sys_mutex)
+					/*!< in: TRUE if the caller
+					owns dict_sys->mutex */
 {
 	enum db_err	ret;
 
+	/* 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));
+
 	if (table->ibd_file_missing) {
 		ut_print_timestamp(stderr);
 		fprintf(stderr,
@@ -2175,29 +2241,32 @@ dict_stats_update(
 		return(DB_SUCCESS);
 	}
 
-	switch (stats_upd_how) {
+	switch (stats_upd_option) {
 	case DICT_STATS_UPD_RECALC_PERSISTENT_VERBOSE:
 	case DICT_STATS_UPD_RECALC_PERSISTENT_SILENT:
-		/* Persistent recalculation requested, probably called from
-		ANALYZE TABLE */
+		/* Persistent recalculation requested, called from
+		ANALYZE TABLE or from TRUNCATE TABLE */
 
-		/* check if the persistent storage exists before calling
-		the potentially slow function
+		/* check if the persistent statistics storage exists
+		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()) {
+		if (dict_stats_persistent_storage_check(
+				caller_has_dict_sys_mutex)) {
 
 			ret = dict_stats_update_persistent(table);
 
 			if (ret == DB_SUCCESS) {
-				ret = dict_stats_save(table);
+				ret = dict_stats_save(
+					table,
+					caller_has_dict_sys_mutex);
 			}
 
 		} else {
 			/* Fall back to transient stats since the persistent
 			storage is not present or is corrupted */
 
-			if (stats_upd_how
+			if (stats_upd_option
 			    == DICT_STATS_UPD_RECALC_PERSISTENT_VERBOSE) {
 
 				ut_print_timestamp(stderr);
@@ -2206,8 +2275,8 @@ dict_stats_update(
 				fprintf(stderr,
 					" InnoDB: Recalculation of persistent "
 					"statistics requested but the required "
-					"persistent storage is not present "
-					"or is corrupted. "
+					"persistent statistics storage is not "
+					"present or is corrupted. "
 					"Using quick transient stats "
 					"instead.\n");
 			}
@@ -2227,24 +2296,34 @@ dict_stats_update(
 		break;
 
 	case DICT_STATS_UPD_FETCH:
-		/* fetch requested, either fetch from persistent storage
-		or use the old method */
+		/* fetch requested, either fetch from persistent statistics
+		storage or use the old method */
 
-		if (dict_stats_persistent_storage_check()) {
+		if (strchr(table->name, '/') == NULL) {
+			/* Use the quick transient stats method for
+			SYS_* tables because we know the persistent
+			stats storage does not contain data for SYS_*
+			tables */
+			dict_stats_update_transient(table);
+			ret = DB_SUCCESS;
+		} else if (dict_stats_persistent_storage_check(
+				caller_has_dict_sys_mutex)) {
 
-			ret = dict_stats_fetch_from_ps(table);
+			ret = dict_stats_fetch_from_ps(
+				table,
+				caller_has_dict_sys_mutex);
 		} else {
 
-			/* if persistent storage does not exist, then
-			force the following code to calculate the
+			/* if persistent statistics storage does not exist,
+			then force the following code to calculate the
 			transient stats */
 			ret = DB_STATS_DO_NOT_EXIST;
 		}
 
 		if (ret == DB_STATS_DO_NOT_EXIST) {
 
-			/* The persistent storage does not exist or stats
-			for this particular table do not exist, then
+			/* The persistent statistics storage does not exist
+			or stats for this particular table do not exist, then
 			calculate the quick transient statistics */
 			dict_stats_update_transient(table);
 			ret = DB_SUCCESS;
@@ -2263,7 +2342,7 @@ dict_stats_update(
 /* @} */
 
 /*********************************************************************//**
-Removes the information for a particular index from the persistent
+Removes the information for a particular index's stats from the persistent
 storage if it exists and if there is data stored for this index.
 The transaction is not committed, it must not be committed in this
 function because this is the user trx that is running DROP INDEX.
@@ -2321,10 +2400,10 @@ dict_stats_drop_index(
 
 	row_mysql_unlock_data_dictionary(trx);
 
-	/* If the persistent storage does not exist or is corrupted,
-	then do not attempt to DELETE from its tables because the
-	internal parser will crash. */
-	if (!dict_stats_persistent_storage_check()) {
+	/* If the persistent statistics storage does not exist or is
+	corrupted, then do not attempt to DELETE from its tables because
+	the internal parser will crash. */
+	if (!dict_stats_persistent_storage_check(FALSE)) {
 
 		dict_table_decrement_handle_count(table_stats, FALSE);
 		dict_table_decrement_handle_count(index_stats, FALSE);
@@ -2399,8 +2478,8 @@ dict_stats_drop_index(
 
 /*********************************************************************//**
 Removes the statistics for a table and all of its indexes from the
-persistent storage if it exists and if there is data stored for the table.
-This function creates its own transaction and commits it.
+persistent statistics storage if it exists and if there is data stored for
+the table.  This function creates its own transaction and commits it.
 dict_stats_drop_table() @{
 @return DB_SUCCESS or error code */
 UNIV_INTERN
@@ -2469,10 +2548,10 @@ dict_stats_drop_table(
 
 	row_mysql_unlock_data_dictionary(trx);
 
-	/* If the persistent storage does not exist or is corrupted,
-	then do not attempt to DELETE from its tables because the
-	internal SQL parser will crash. */
-	if (!dict_stats_persistent_storage_check()) {
+	/* If the persistent statistics storage does not exist or is
+	corrupted, then do not attempt to DELETE from its tables because
+	the internal SQL parser will crash. */
+	if (!dict_stats_persistent_storage_check(FALSE)) {
 
 		ret = DB_SUCCESS;
 		goto decrement_ref_count_commit_and_return;
@@ -2580,7 +2659,7 @@ test_dict_stats_table_check()
 	) ENGINE=INNODB;
 	*/
 	/* definition for the table 'test/tcheck' */
-	column_data_t	columns[] = {
+	dict_stats_chk_column_t	columns[] = {
 		{"c01", DATA_VARCHAR, 0, 123},
 		{"c02", DATA_INT, 0, 4},
 		{"c03", DATA_INT, DATA_NOT_NULL, 4},
@@ -2590,7 +2669,7 @@ test_dict_stats_table_check()
 		{"c07", DATA_INT, 0, 4},
 		{"c_extra", DATA_INT, 0, 4}
 	};
-	table_schema_t	schema = {
+	dict_stats_chk_table_t	schema = {
 		"test/tcheck",
 		0 /* will be set individually for each test below */,
 		columns
@@ -2777,7 +2856,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);
+	ret = dict_stats_save(&table, FALSE);
 	
 	ut_a(ret == DB_SUCCESS);
 
@@ -2904,7 +2983,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);
+	ret = dict_stats_fetch_from_ps(&table, FALSE);
 	
 	ut_a(ret == DB_SUCCESS);
 

=== 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
@@ -7699,7 +7699,7 @@ ha_innobase::info_low(
 					/*!< out: HA_ERR_* error code */
 	uint			flag,	/*!< in: what information MySQL
 					requests */
-	enum dict_stats_upd_how	stats_upd_how)
+	dict_stats_upd_option_t	stats_upd_option)
 					/*!< in: whether to (re)calc
 					the stats or to fetch them from
 					the persistent storage */
@@ -7753,7 +7753,9 @@ ha_innobase::info_low(
 
 			prebuilt->trx->op_info = "updating table statistics";
 
-			ret = dict_stats_update(ib_table, stats_upd_how);
+			ut_ad(!mutex_own(&dict_sys->mutex));
+			ret = dict_stats_update(ib_table, stats_upd_option,
+						FALSE);
 
 			if (ret != DB_SUCCESS) {
 				prebuilt->trx->op_info = "";
@@ -8010,19 +8012,19 @@ ha_innobase::analyze(
 	THD*		thd,		/*!< in: connection thread handle */
 	HA_CHECK_OPT*	check_opt)	/*!< in: currently ignored */
 {
-	enum dict_stats_upd_how	upd_how;
+	dict_stats_upd_option_t	upd_option;
 	int			ret;
 
 	if (THDVAR(thd, analyze_is_persistent)) {
-		upd_how = DICT_STATS_UPD_RECALC_PERSISTENT_VERBOSE;
+		upd_option = DICT_STATS_UPD_RECALC_PERSISTENT_VERBOSE;
 	} else {
-		upd_how = DICT_STATS_UPD_RECALC_TRANSIENT;
+		upd_option = DICT_STATS_UPD_RECALC_TRANSIENT;
 	}
 
 	/* Simply call ::info_low() with all the flags
 	and request recalculation of the statistics */
 	ret = info_low(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
-		       upd_how);
+		       upd_option);
 
 	if (ret != 0) {
 		return(HA_ADMIN_FAILED);

=== modified file 'storage/innobase/handler/ha_innodb.h'
--- a/storage/innobase/handler/ha_innodb.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/handler/ha_innodb.h	revid:vasil.dimov@stripped
@@ -111,7 +111,7 @@ class ha_innobase: public handler
 	ulint innobase_update_autoinc(ulonglong	auto_inc);
 	void innobase_initialize_autoinc();
 	dict_index_t* innobase_get_index(uint keynr);
-	int info_low(uint flag, enum dict_stats_upd_how stats_upd_how);
+	int info_low(uint flag, dict_stats_upd_option_t stats_upd_option);
 
 	/* Init values for the class: */
  public:

=== modified file 'storage/innobase/include/data0type.h'
--- a/storage/innobase/include/data0type.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/data0type.h	revid:vasil.dimov@stripped
@@ -425,6 +425,19 @@ dtype_new_read_for_order_and_null_size(
 /*===================================*/
 	dtype_t*	type,	/*!< in: type struct */
 	const byte*	buf);	/*!< in: buffer for stored type order info */
+
+/*********************************************************************//**
+Returns the type's SQL name (e.g. BIGINT UNSIGNED) from mtype,prtype,len */
+UNIV_INTERN
+char*
+dtype_sql_name(
+/*===========*/
+	unsigned	mtype,	/*!< in: mtype */
+	unsigned	prtype,	/*!< in: prtype */
+	unsigned	len,	/*!< in: len */
+	char*		name,	/*!< out: SQL name */
+	unsigned	name_sz);/*!< in: size of the name buffer */
+
 #endif /* !UNIV_HOTBACKUP */
 
 /*********************************************************************//**

=== modified file 'storage/innobase/include/data0type.ic'
--- a/storage/innobase/include/data0type.ic	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/data0type.ic	revid:vasil.dimov@stripped
@@ -23,6 +23,8 @@ Data types
 Created 1/16/1996 Heikki Tuuri
 *******************************************************/
 
+#include <string.h> /* strlen() */
+
 #include "mach0data.h"
 #ifndef UNIV_HOTBACKUP
 # include "ha_prototypes.h"
@@ -392,6 +394,98 @@ dtype_new_read_for_order_and_null_size(
 	}
 	dtype_set_mblen(type);
 }
+
+/*********************************************************************//**
+Returns the type's SQL name (e.g. BIGINT UNSIGNED) from mtype,prtype,len */
+UNIV_INTERN
+char*
+dtype_sql_name(
+/*===========*/
+	unsigned	mtype,	/*!< in: mtype */
+	unsigned	prtype,	/*!< in: prtype */
+	unsigned	len, 	/*!< in: len */
+	char*		name,	/*!< out: SQL name */
+	unsigned	name_sz)/*!< in: size of the name buffer */
+{
+
+#define APPEND_UNSIGNED()					\
+	do {							\
+		if (prtype & DATA_UNSIGNED) {			\
+			ut_snprintf(name + strlen(name),	\
+				    name_sz - strlen(name),	\
+				    " UNSIGNED");		\
+		}						\
+	} while (0)
+
+	ut_snprintf(name, name_sz, "UNKNOWN");
+
+	switch (mtype) {
+	case DATA_INT:
+		switch (len) {
+		case 1:
+			ut_snprintf(name, name_sz, "TINYINT");
+			break;
+		case 2:
+			ut_snprintf(name, name_sz, "SMALLINT");
+			break;
+		case 3:
+			ut_snprintf(name, name_sz, "MEDIUMINT");
+			break;
+		case 4:
+			ut_snprintf(name, name_sz, "INT");
+			break;
+		case 8:
+			ut_snprintf(name, name_sz, "BIGINT");
+			break;
+		}
+		APPEND_UNSIGNED();
+		break;
+	case DATA_FLOAT:
+		ut_snprintf(name, name_sz, "FLOAT");
+		APPEND_UNSIGNED();
+		break;
+	case DATA_DOUBLE:
+		ut_snprintf(name, name_sz, "DOUBLE");
+		APPEND_UNSIGNED();
+		break;
+	case DATA_FIXBINARY:
+		ut_snprintf(name, name_sz, "BINARY(%u)", len);
+		break;
+	case DATA_CHAR:
+		ut_snprintf(name, name_sz, "CHAR(%u)", len);
+		break;
+	case DATA_VARCHAR:
+		ut_snprintf(name, name_sz, "VARCHAR(%u)", len);
+		break;
+	case DATA_BINARY:
+		ut_snprintf(name, name_sz, "VARBINARY(%u)", len);
+		break;
+	case DATA_BLOB:
+		switch (len) {
+		case 9:
+			ut_snprintf(name, name_sz, "TINYBLOB");
+			break;
+		case 10:
+			ut_snprintf(name, name_sz, "BLOB");
+			break;
+		case 11:
+			ut_snprintf(name, name_sz, "MEDIUMBLOB");
+			break;
+		case 12:
+			ut_snprintf(name, name_sz, "LONGBLOB");
+			break;
+		}
+	}
+
+	if (prtype & DATA_NOT_NULL) {
+		ut_snprintf(name + strlen(name),
+			    name_sz - strlen(name),
+			    " NOT NULL");
+	}
+
+	return(name);
+}
+
 #endif /* !UNIV_HOTBACKUP */
 
 /***********************************************************************//**

=== 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
@@ -32,7 +32,7 @@ Created Jan 06, 2010 Vasil Dimov
 #include "dict0types.h"
 #include "trx0types.h"
 
-enum dict_stats_upd_how {
+enum dict_stats_upd_option {
 	DICT_STATS_UPD_RECALC_PERSISTENT_VERBOSE,/* (re)calculate the
 				statistics using a precise and slow
 				algo and save them to the persistent
@@ -50,6 +50,8 @@ enum dict_stats_upd_how {
 				persistent storage */
 };
 
+typedef enum dict_stats_upd_option	dict_stats_upd_option_t;
+
 /*********************************************************************//**
 Calculates new estimates for table and index statistics. The statistics
 are used in query optimization.
@@ -59,13 +61,16 @@ enum db_err
 dict_stats_update(
 /*==============*/
 	dict_table_t*		table,	/*!< in/out: table */
-	enum dict_stats_upd_how	stats_upd_how);
+	dict_stats_upd_option_t	stats_upd_option,
 					/*!< in: whether to (re)calc
 					the stats or to fetch them from
 					the persistent storage */
+	ibool			caller_has_dict_sys_mutex);
+					/*!< in: TRUE if the caller
+					owns dict_sys->mutex */
 
 /*********************************************************************//**
-Removes the information for a particular index from the persistent
+Removes the information for a particular index's stats from the persistent
 storage if it exists and if there is data stored for this index.
 The transaction is not committed, it must not be committed in this
 function because this is the user trx that is running DROP INDEX.

=== modified file 'storage/innobase/include/lock0lock.h'
--- a/storage/innobase/include/lock0lock.h	revid:vasil.dimov@stripped
+++ b/storage/innobase/include/lock0lock.h	revid:vasil.dimov@stripped
@@ -469,20 +469,6 @@ lock_table(
 	dict_table_t*	table,	/*!< in: database table in dictionary cache */
 	enum lock_mode	mode,	/*!< in: lock mode */
 	que_thr_t*	thr);	/*!< in: query thread */
-/*********************************************************************//**
-Lock a given table with the given lock mode. This function may block the
-execution for some time, but will not wait infinitely if the table is
-already locked, it may return DB_LOCK_WAIT_TIMEOUT.
-The table is unlocked when the trx is committed.
-@return DB_SUCCESS or error code */
-UNIV_INTERN
-enum db_err
-lock_table_by_name(
-/*===============*/
-	const char*	table_name,	/*!< in: table name */
-	enum lock_mode	mode,		/*!< in: lock mode */
-	trx_t*		trx);		/*!< in/out: transaction into which to
-					lock the table */
 /*************************************************************//**
 Removes a granted record lock of a transaction from the queue and grants
 locks to other transactions waiting in the queue if they now are entitled

=== modified file 'storage/innobase/row/row0mysql.c'
--- a/storage/innobase/row/row0mysql.c	revid:vasil.dimov@stripped
+++ b/storage/innobase/row/row0mysql.c	revid:vasil.dimov@stripped
@@ -865,7 +865,8 @@ row_update_statistics_if_needed(
 	if (counter > 2000000000
 	    || ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
 
-		dict_stats_update(table, DICT_STATS_UPD_FETCH);
+		ut_ad(!mutex_own(&dict_sys->mutex));
+		dict_stats_update(table, DICT_STATS_UPD_FETCH, FALSE);
 	}
 }
 
@@ -2922,7 +2923,8 @@ funct_exit:
 
 	/* We are supposed to recalc and save the stats only
 	on ANALYZE, but it also makes sense to do so on TRUNCATE */
-	dict_stats_update(table, DICT_STATS_UPD_RECALC_PERSISTENT_SILENT);
+	dict_stats_update(table, DICT_STATS_UPD_RECALC_PERSISTENT_SILENT,
+			  FALSE);
 
 	trx->op_info = "";
 


Attachment: [text/bzr-bundle] bzr/vasil.dimov@oracle.com-20100706134658-i8fkddy9eg4r0v9s.bundle
Thread
bzr push into mysql-next-mr-persistent-stats branch (vasil.dimov:3232 to3251) vasil.dimov6 Jul