Commit 32aef81e authored by Vasil Dimov's avatar Vasil Dimov

Merge from mysql-5.1-innodb:

  ------------------------------------------------------------
  revno: 3430
  revision-id: vasil.dimov@oracle.com-20100428103452-6btsq4xv6v1etb5b
  parent: vasil.dimov@oracle.com-20100428103200-vs5nzx245sv2qy7n
  committer: Vasil Dimov <vasil.dimov@oracle.com>
  branch nick: mysql-5.1-innodb
  timestamp: Wed 2010-04-28 13:34:52 +0300
  message:
    Bug#53046 dict_update_statistics_low can still be run concurrently
    on same table
    
    Followup to vasil.dimov@oracle.com-20100428102033-dt3caf531rs3lidr :
    
    Add more asserions, which I forgot.
  modified:
    storage/innodb_plugin/dict/dict0dict.c 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Fdict%2Fdict0dict.c
  ------------------------------------------------------------
  revno: 3429
  revision-id: vasil.dimov@oracle.com-20100428103200-vs5nzx245sv2qy7n
  parent: vasil.dimov@oracle.com-20100428102033-dt3caf531rs3lidr
  committer: Vasil Dimov <vasil.dimov@oracle.com>
  branch nick: mysql-5.1-innodb
  timestamp: Wed 2010-04-28 13:32:00 +0300
  message:
    Revert the fix of Bug#38996 Race condition in ANALYZE TABLE
    
    This is branches/zip@r6032 in SVN and _is part_ of
    revid:svn-v4:16c675df-0fcb-4bc9-8058-dcc011a37293:branches/zip:6113
    in BZR.
    
    This is being reverted because now the code is serialized directly on
    index->stat_n_diff_key_vals[] as the fix for
    Bug#53046 dict_update_statistics_low can still be run concurrently on same table
    goes.
  modified:
    storage/innodb_plugin/handler/ha_innodb.cc 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Fhandler%2Fha_innodb.cc
  ------------------------------------------------------------
  revno: 3428
  revision-id: vasil.dimov@oracle.com-20100428102033-dt3caf531rs3lidr
  parent: vasil.dimov@oracle.com-20100428084627-wtrmc66wqvjsdgj7
  committer: Vasil Dimov <vasil.dimov@oracle.com>
  branch nick: mysql-5.1-innodb
  timestamp: Wed 2010-04-28 13:20:33 +0300
  message:
    Followup to vasil.dimov@oracle.com-20100428084627-wtrmc66wqvjsdgj7:
    
    Address Marko's suggestions wrt the fix of
    Bug#53046 dict_update_statistics_low can still be run concurrently
    on same table
  modified:
    storage/innodb_plugin/dict/dict0dict.c 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Fdict%2Fdict0dict.c
  ------------------------------------------------------------
  revno: 3427
  revision-id: vasil.dimov@oracle.com-20100428084627-wtrmc66wqvjsdgj7
  parent: mmakela@bk-internal.mysql.com-20100428063325-irts4ze9et5bsqdq
  committer: Vasil Dimov <vasil.dimov@oracle.com>
  branch nick: mysql-5.1-innodb
  timestamp: Wed 2010-04-28 11:46:27 +0300
  message:
    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 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Fbtr%2Fbtr0cur.c
    storage/innodb_plugin/dict/dict0dict.c 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Fdict%2Fdict0dict.c
    storage/innodb_plugin/handler/ha_innodb.cc 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Fhandler%2Fha_innodb.cc
    storage/innodb_plugin/include/dict0dict.h 2@16c675df-0fcb-4bc9-8058-dcc011a37293:trunk%2Finclude%2Fdict0dict.h
  ------------------------------------------------------------
parent c3ea5056
...@@ -3477,6 +3477,8 @@ btr_estimate_number_of_different_key_vals( ...@@ -3477,6 +3477,8 @@ btr_estimate_number_of_different_key_vals(
also the pages used for external storage of fields (those pages are also the pages used for external storage of fields (those pages are
included in index->stat_n_leaf_pages) */ included in index->stat_n_leaf_pages) */
dict_index_stat_mutex_enter(index);
for (j = 0; j <= n_cols; j++) { for (j = 0; j <= n_cols; j++) {
index->stat_n_diff_key_vals[j] index->stat_n_diff_key_vals[j]
= ((n_diff[j] = ((n_diff[j]
...@@ -3506,6 +3508,8 @@ btr_estimate_number_of_different_key_vals( ...@@ -3506,6 +3508,8 @@ btr_estimate_number_of_different_key_vals(
index->stat_n_diff_key_vals[j] += add_on; index->stat_n_diff_key_vals[j] += add_on;
} }
dict_index_stat_mutex_exit(index);
mem_free(n_diff); mem_free(n_diff);
if (UNIV_LIKELY_NULL(heap)) { if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap); mem_heap_free(heap);
......
...@@ -91,6 +91,10 @@ UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key; ...@@ -91,6 +91,10 @@ UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
/** Identifies generated InnoDB foreign key names */ /** Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_"; 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 Tries to find column names for the index and sets the col field of the
index. index.
...@@ -250,6 +254,45 @@ dict_mutex_exit_for_mysql(void) ...@@ -250,6 +254,45 @@ dict_mutex_exit_for_mysql(void)
mutex_exit(&(dict_sys->mutex)); mutex_exit(&(dict_sys->mutex));
} }
/** Get the mutex that protects index->stat_n_diff_key_vals[] */
#define GET_INDEX_STAT_MUTEX(index) \
(&dict_index_stat_mutex[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 */
{
ut_ad(index != NULL);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(index->cached);
ut_ad(!index->to_be_dropped);
mutex_enter(GET_INDEX_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 */
{
ut_ad(index != NULL);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
ut_ad(index->cached);
ut_ad(!index->to_be_dropped);
mutex_exit(GET_INDEX_STAT_MUTEX(index));
}
/********************************************************************//** /********************************************************************//**
Decrements the count of open MySQL handles to a table. */ Decrements the count of open MySQL handles to a table. */
UNIV_INTERN UNIV_INTERN
...@@ -616,6 +659,8 @@ void ...@@ -616,6 +659,8 @@ void
dict_init(void) dict_init(void)
/*===========*/ /*===========*/
{ {
int i;
dict_sys = mem_alloc(sizeof(dict_sys_t)); dict_sys = mem_alloc(sizeof(dict_sys_t));
mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT); mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
...@@ -638,6 +683,10 @@ dict_init(void) ...@@ -638,6 +683,10 @@ dict_init(void)
mutex_create(dict_foreign_err_mutex_key, mutex_create(dict_foreign_err_mutex_key,
&dict_foreign_err_mutex, SYNC_ANY_LATCH); &dict_foreign_err_mutex, SYNC_ANY_LATCH);
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
mutex_create(&dict_index_stat_mutex[i], SYNC_INDEX_TREE);
}
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -4185,9 +4234,13 @@ dict_update_statistics_low( ...@@ -4185,9 +4234,13 @@ dict_update_statistics_low(
index = dict_table_get_first_index(table); index = dict_table_get_first_index(table);
dict_index_stat_mutex_enter(index);
table->stat_n_rows = index->stat_n_diff_key_vals[ table->stat_n_rows = index->stat_n_diff_key_vals[
dict_index_get_n_unique(index)]; dict_index_get_n_unique(index)];
dict_index_stat_mutex_exit(index);
table->stat_clustered_index_size = index->stat_index_size; table->stat_clustered_index_size = index->stat_index_size;
table->stat_sum_of_other_index_sizes = sum_of_index_sizes table->stat_sum_of_other_index_sizes = sum_of_index_sizes
...@@ -4365,6 +4418,8 @@ dict_index_print_low( ...@@ -4365,6 +4418,8 @@ dict_index_print_low(
ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(mutex_own(&(dict_sys->mutex)));
dict_index_stat_mutex_enter(index);
if (index->n_user_defined_cols > 0) { if (index->n_user_defined_cols > 0) {
n_vals = index->stat_n_diff_key_vals[ n_vals = index->stat_n_diff_key_vals[
index->n_user_defined_cols]; index->n_user_defined_cols];
...@@ -4372,6 +4427,8 @@ dict_index_print_low( ...@@ -4372,6 +4427,8 @@ dict_index_print_low(
n_vals = index->stat_n_diff_key_vals[1]; n_vals = index->stat_n_diff_key_vals[1];
} }
dict_index_stat_mutex_exit(index);
if (dict_index_is_clust(index)) { if (dict_index_is_clust(index)) {
type_string = "clustered index"; type_string = "clustered index";
} else if (dict_index_is_unique(index)) { } else if (dict_index_is_unique(index)) {
...@@ -4867,5 +4924,9 @@ dict_close(void) ...@@ -4867,5 +4924,9 @@ dict_close(void)
mem_free(dict_sys); mem_free(dict_sys);
dict_sys = NULL; dict_sys = NULL;
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
mutex_free(&dict_index_stat_mutex[i]);
}
} }
#endif /* !UNIV_HOTBACKUP */ #endif /* !UNIV_HOTBACKUP */
...@@ -110,7 +110,6 @@ static ulong commit_threads = 0; ...@@ -110,7 +110,6 @@ static ulong commit_threads = 0;
static mysql_mutex_t commit_threads_m; static mysql_mutex_t commit_threads_m;
static mysql_cond_t commit_cond; static mysql_cond_t commit_cond;
static mysql_mutex_t commit_cond_m; static mysql_mutex_t commit_cond_m;
static mysql_mutex_t analyze_mutex;
static bool innodb_inited = 0; static bool innodb_inited = 0;
#define INSIDE_HA_INNOBASE_CC #define INSIDE_HA_INNOBASE_CC
...@@ -213,7 +212,6 @@ static mysql_pfs_key_t commit_cond_mutex_key; ...@@ -213,7 +212,6 @@ static mysql_pfs_key_t commit_cond_mutex_key;
static mysql_pfs_key_t commit_cond_key; static mysql_pfs_key_t commit_cond_key;
static PSI_mutex_info all_pthread_mutexes[] = { static PSI_mutex_info all_pthread_mutexes[] = {
{&analyze_mutex_key, "analyze_mutex", 0},
{&commit_threads_m_key, "commit_threads_m", 0}, {&commit_threads_m_key, "commit_threads_m", 0},
{&commit_cond_mutex_key, "commit_cond_mutex", 0}, {&commit_cond_mutex_key, "commit_cond_mutex", 0},
{&innobase_share_mutex_key, "innobase_share_mutex", 0}, {&innobase_share_mutex_key, "innobase_share_mutex", 0},
...@@ -2430,8 +2428,6 @@ innobase_change_buffering_inited_ok: ...@@ -2430,8 +2428,6 @@ innobase_change_buffering_inited_ok:
&commit_threads_m, MY_MUTEX_INIT_FAST); &commit_threads_m, MY_MUTEX_INIT_FAST);
mysql_mutex_init(commit_cond_mutex_key, mysql_mutex_init(commit_cond_mutex_key,
&commit_cond_m, MY_MUTEX_INIT_FAST); &commit_cond_m, MY_MUTEX_INIT_FAST);
mysql_mutex_init(analyze_mutex_key,
&analyze_mutex, MY_MUTEX_INIT_FAST);
mysql_cond_init(commit_cond_key, &commit_cond, NULL); mysql_cond_init(commit_cond_key, &commit_cond, NULL);
innodb_inited= 1; innodb_inited= 1;
#ifdef MYSQL_DYNAMIC_PLUGIN #ifdef MYSQL_DYNAMIC_PLUGIN
...@@ -2486,7 +2482,6 @@ innobase_end( ...@@ -2486,7 +2482,6 @@ innobase_end(
mysql_mutex_destroy(&prepare_commit_mutex); mysql_mutex_destroy(&prepare_commit_mutex);
mysql_mutex_destroy(&commit_threads_m); mysql_mutex_destroy(&commit_threads_m);
mysql_mutex_destroy(&commit_cond_m); mysql_mutex_destroy(&commit_cond_m);
mysql_mutex_destroy(&analyze_mutex);
mysql_cond_destroy(&commit_cond); mysql_cond_destroy(&commit_cond);
} }
...@@ -7801,6 +7796,8 @@ ha_innobase::info( ...@@ -7801,6 +7796,8 @@ ha_innobase::info(
break; break;
} }
dict_index_stat_mutex_enter(index);
if (index->stat_n_diff_key_vals[j + 1] == 0) { if (index->stat_n_diff_key_vals[j + 1] == 0) {
rec_per_key = stats.records; rec_per_key = stats.records;
...@@ -7809,6 +7806,8 @@ ha_innobase::info( ...@@ -7809,6 +7806,8 @@ ha_innobase::info(
index->stat_n_diff_key_vals[j + 1]); index->stat_n_diff_key_vals[j + 1]);
} }
dict_index_stat_mutex_exit(index);
/* Since MySQL seems to favor table scans /* Since MySQL seems to favor table scans
too much over index searches, we pretend too much over index searches, we pretend
index selectivity is 2 times better than index selectivity is 2 times better than
...@@ -7863,15 +7862,9 @@ ha_innobase::analyze( ...@@ -7863,15 +7862,9 @@ ha_innobase::analyze(
THD* thd, /*!< in: connection thread handle */ THD* thd, /*!< in: connection thread handle */
HA_CHECK_OPT* check_opt) /*!< in: currently ignored */ HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
{ {
/* Serialize ANALYZE TABLE inside InnoDB, see
Bug#38996 Race condition in ANALYZE TABLE */
mysql_mutex_lock(&analyze_mutex);
/* Simply call ::info() with all the flags */ /* Simply call ::info() with all the flags */
info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE); info(HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE);
mysql_mutex_unlock(&analyze_mutex);
return(0); return(0);
} }
......
...@@ -1061,6 +1061,22 @@ UNIV_INTERN ...@@ -1061,6 +1061,22 @@ UNIV_INTERN
void void
dict_mutex_exit_for_mysql(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. Checks if the database name in two table names is the same.
@return TRUE if same db name */ @return TRUE if same db name */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment