MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:vasil.dimov Date:April 28 2010 8:50am
Subject:bzr commit into mysql-5.1-innodb branch (vasil.dimov:3427) Bug#53046
View as plain text  
#At file:///usr/local/devel/bzrroot/server/mysql-5.1-innodb/ based on revid:mmakela@stripped

 3427 Vasil Dimov	2010-04-28
      Fix Bug#53046 dict_update_statistics_low can still be run concurrently
      on same table
      
      Protect dict_index_t::stat_n_diff_key_vals[] with an array of
      mutexes.
      
      Testing: tested all code paths under UNIV_SYNC_DEBUG
      for the one in dict_print() one has to enable the InnoDB table monitor:
      CREATE TABLE innodb_table_monitor (a int) ENGINE=INNODB;

    modified:
      storage/innodb_plugin/btr/btr0cur.c
      storage/innodb_plugin/dict/dict0dict.c
      storage/innodb_plugin/handler/ha_innodb.cc
      storage/innodb_plugin/include/dict0dict.h
=== modified file 'storage/innodb_plugin/btr/btr0cur.c'
--- a/storage/innodb_plugin/btr/btr0cur.c	2010-04-20 20:15:50 +0000
+++ b/storage/innodb_plugin/btr/btr0cur.c	2010-04-28 08:46:27 +0000
@@ -3356,6 +3356,8 @@ btr_estimate_number_of_different_key_val
 	also the pages used for external storage of fields (those pages are
 	included in index->stat_n_leaf_pages) */
 
+	dict_index_stat_mutex_enter(index);
+
 	for (j = 0; j <= n_cols; j++) {
 		index->stat_n_diff_key_vals[j]
 			= ((n_diff[j]
@@ -3385,6 +3387,8 @@ btr_estimate_number_of_different_key_val
 		index->stat_n_diff_key_vals[j] += add_on;
 	}
 
+	dict_index_stat_mutex_exit(index);
+
 	mem_free(n_diff);
 	if (UNIV_LIKELY_NULL(heap)) {
 		mem_heap_free(heap);

=== modified file 'storage/innodb_plugin/dict/dict0dict.c'
--- a/storage/innodb_plugin/dict/dict0dict.c	2010-04-06 12:11:46 +0000
+++ b/storage/innodb_plugin/dict/dict0dict.c	2010-04-28 08:46:27 +0000
@@ -80,6 +80,10 @@ UNIV_INTERN rw_lock_t	dict_operation_loc
 /** Identifies generated InnoDB foreign key names */
 static char	dict_ibfk[] = "_ibfk_";
 
+/* array of mutexes protecting dict_index_t::stat_n_diff_key_vals[] */
+#define DICT_INDEX_STAT_MUTEX_SIZE	32
+mutex_t	dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
+
 /*******************************************************************//**
 Tries to find column names for the index and sets the col field of the
 index.
@@ -239,6 +243,33 @@ dict_mutex_exit_for_mysql(void)
 	mutex_exit(&(dict_sys->mutex));
 }
 
+#define FOLD_INDEX_FOR_STAT_MUTEX(index) \
+	(ut_fold_dulint(index->id) % DICT_INDEX_STAT_MUTEX_SIZE)
+
+/**********************************************************************//**
+Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
+index->id is used to pick the right mutex and it should not change
+before dict_index_stat_mutex_exit() is called on this index. */
+UNIV_INTERN
+void
+dict_index_stat_mutex_enter(
+/*========================*/
+	const dict_index_t*	index)	/*!< in: index */
+{
+	mutex_enter(&dict_index_stat_mutex[FOLD_INDEX_FOR_STAT_MUTEX(index)]);
+}
+
+/**********************************************************************//**
+Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
+UNIV_INTERN
+void
+dict_index_stat_mutex_exit(
+/*=======================*/
+	const dict_index_t*	index)	/*!< in: index */
+{
+	mutex_exit(&dict_index_stat_mutex[FOLD_INDEX_FOR_STAT_MUTEX(index)]);
+}
+
 /********************************************************************//**
 Decrements the count of open MySQL handles to a table. */
 UNIV_INTERN
@@ -605,6 +636,8 @@ void
 dict_init(void)
 /*===========*/
 {
+	int	i;
+
 	dict_sys = mem_alloc(sizeof(dict_sys_t));
 
 	mutex_create(&dict_sys->mutex, SYNC_DICT);
@@ -625,6 +658,11 @@ dict_init(void)
 	ut_a(dict_foreign_err_file);
 
 	mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
+
+	for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
+		mutex_create(&dict_index_stat_mutex[i],
+			     /* XXX */ SYNC_INDEX_TREE);
+	}
 }
 
 /**********************************************************************//**
@@ -4171,9 +4209,13 @@ dict_update_statistics_low(
 
 	index = dict_table_get_first_index(table);
 
+	dict_index_stat_mutex_enter(index);
+
 	table->stat_n_rows = index->stat_n_diff_key_vals[
 		dict_index_get_n_unique(index)];
 
+	dict_index_stat_mutex_exit(index);
+
 	table->stat_clustered_index_size = index->stat_index_size;
 
 	table->stat_sum_of_other_index_sizes = sum_of_index_sizes
@@ -4351,6 +4393,8 @@ dict_index_print_low(
 
 	ut_ad(mutex_own(&(dict_sys->mutex)));
 
+	dict_index_stat_mutex_enter(index);
+
 	if (index->n_user_defined_cols > 0) {
 		n_vals = index->stat_n_diff_key_vals[
 			index->n_user_defined_cols];
@@ -4358,6 +4402,8 @@ dict_index_print_low(
 		n_vals = index->stat_n_diff_key_vals[1];
 	}
 
+	dict_index_stat_mutex_exit(index);
+
 	if (dict_index_is_clust(index)) {
 		type_string = "clustered index";
 	} else if (dict_index_is_unique(index)) {

=== modified file 'storage/innodb_plugin/handler/ha_innodb.cc'
--- a/storage/innodb_plugin/handler/ha_innodb.cc	2010-04-20 11:42:22 +0000
+++ b/storage/innodb_plugin/handler/ha_innodb.cc	2010-04-28 08:46:27 +0000
@@ -7597,6 +7597,8 @@ ha_innobase::info(
 					break;
 				}
 
+				dict_index_stat_mutex_enter(index);
+
 				if (index->stat_n_diff_key_vals[j + 1] == 0) {
 
 					rec_per_key = stats.records;
@@ -7605,6 +7607,8 @@ ha_innobase::info(
 					 index->stat_n_diff_key_vals[j + 1]);
 				}
 
+				dict_index_stat_mutex_exit(index);
+
 				/* Since MySQL seems to favor table scans
 				too much over index searches, we pretend
 				index selectivity is 2 times better than

=== modified file 'storage/innodb_plugin/include/dict0dict.h'
--- a/storage/innodb_plugin/include/dict0dict.h	2010-04-06 12:11:46 +0000
+++ b/storage/innodb_plugin/include/dict0dict.h	2010-04-28 08:46:27 +0000
@@ -1061,6 +1061,22 @@ UNIV_INTERN
 void
 dict_mutex_exit_for_mysql(void);
 /*===========================*/
+/**********************************************************************//**
+Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
+index->id is used to pick the right mutex and it should not change
+before dict_index_stat_mutex_exit() is called on this index. */
+UNIV_INTERN
+void
+dict_index_stat_mutex_enter(
+/*========================*/
+	const dict_index_t*	index);	/*!< in: index */
+/**********************************************************************//**
+Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
+UNIV_INTERN
+void
+dict_index_stat_mutex_exit(
+/*=======================*/
+	const dict_index_t*	index);	/*!< in: index */
 /********************************************************************//**
 Checks if the database name in two table names is the same.
 @return	TRUE if same db name */


Attachment: [text/bzr-bundle] bzr/vasil.dimov@oracle.com-20100428084627-wtrmc66wqvjsdgj7.bundle
Thread
bzr commit into mysql-5.1-innodb branch (vasil.dimov:3427) Bug#53046vasil.dimov28 Apr
  • Re: bzr commit into mysql-5.1-innodb branch (vasil.dimov:3427)Bug#53046Marko Mäkelä28 Apr
    • Re: bzr commit into mysql-5.1-innodb branch (vasil.dimov:3427)Bug#53046Vasil Dimov28 Apr
  • Re: bzr commit into mysql-5.1-innodb branch (vasil.dimov:3427)Bug#53046Marko Mäkelä28 Apr