mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Fix Bug#53046 dict_update_statistics_low can still be run concurrently on same table
Replace the array of mutexes that used to protect dict_index_t::stat_n_diff_key_vals[] with an array of rw locks that protects all the stats related members in dict_table_t and all of its indexes. Approved by: Jimmy (rb://503)
This commit is contained in:
27
mysql-test/suite/innodb_plugin/r/innodb_bug53046.result
Normal file
27
mysql-test/suite/innodb_plugin/r/innodb_bug53046.result
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
CREATE TABLE bug53046_1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
|
||||||
|
CREATE TABLE bug53046_2 (c2 INT PRIMARY KEY,
|
||||||
|
FOREIGN KEY (c2) REFERENCES bug53046_1(c1)
|
||||||
|
ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;
|
||||||
|
INSERT INTO bug53046_1 VALUES (1);
|
||||||
|
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
|
||||||
|
FROM bug53046_1;
|
||||||
|
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
|
||||||
|
FROM bug53046_1;
|
||||||
|
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
|
||||||
|
FROM bug53046_1;
|
||||||
|
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
|
||||||
|
FROM bug53046_1;
|
||||||
|
INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
|
||||||
|
FROM bug53046_1;
|
||||||
|
INSERT INTO bug53046_2 VALUES (1), (2);
|
||||||
|
ANALYZE TABLE bug53046_1;
|
||||||
|
Table Op Msg_type Msg_text
|
||||||
|
test.bug53046_1 analyze status OK
|
||||||
|
SHOW TABLE STATUS LIKE 'bug53046_1';
|
||||||
|
UPDATE bug53046_1 SET c1 = c1 - 1;
|
||||||
|
DELETE FROM bug53046_1;
|
||||||
|
INSERT INTO bug53046_1 VALUES (1);
|
||||||
|
INSERT INTO bug53046_2 VALUES (1);
|
||||||
|
TRUNCATE TABLE bug53046_2;
|
||||||
|
DROP TABLE bug53046_2;
|
||||||
|
DROP TABLE bug53046_1;
|
48
mysql-test/suite/innodb_plugin/t/innodb_bug53046.test
Normal file
48
mysql-test/suite/innodb_plugin/t/innodb_bug53046.test
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#
|
||||||
|
# http://bugs.mysql.com/53046
|
||||||
|
# dict_update_statistics_low can still be run concurrently on same table
|
||||||
|
#
|
||||||
|
# This is a symbolic test, it would not fail if the bug is present.
|
||||||
|
# Rather those SQL commands have been used during manual testing under
|
||||||
|
# UNIV_DEBUG & UNIV_SYNC_DEBUG to test all changed codepaths for locking
|
||||||
|
# correctness.
|
||||||
|
#
|
||||||
|
|
||||||
|
-- source include/have_innodb_plugin.inc
|
||||||
|
|
||||||
|
CREATE TABLE bug53046_1 (c1 INT PRIMARY KEY) ENGINE=INNODB;
|
||||||
|
CREATE TABLE bug53046_2 (c2 INT PRIMARY KEY,
|
||||||
|
FOREIGN KEY (c2) REFERENCES bug53046_1(c1)
|
||||||
|
ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;
|
||||||
|
|
||||||
|
INSERT INTO bug53046_1 VALUES (1);
|
||||||
|
let $i = 5;
|
||||||
|
while ($i) {
|
||||||
|
eval INSERT INTO bug53046_1 SELECT c1+(SELECT MAX(c1) FROM bug53046_1)
|
||||||
|
FROM bug53046_1;
|
||||||
|
dec $i;
|
||||||
|
}
|
||||||
|
|
||||||
|
INSERT INTO bug53046_2 VALUES (1), (2);
|
||||||
|
|
||||||
|
# CREATE TABLE innodb_table_monitor (a int) ENGINE=INNODB;
|
||||||
|
# wait more than 1 minute and observe the mysqld output
|
||||||
|
# DROP TABLE innodb_table_monitor;
|
||||||
|
|
||||||
|
ANALYZE TABLE bug53046_1;
|
||||||
|
|
||||||
|
# this prints create time and other nondeterministic data
|
||||||
|
-- disable_result_log
|
||||||
|
SHOW TABLE STATUS LIKE 'bug53046_1';
|
||||||
|
-- enable_result_log
|
||||||
|
|
||||||
|
UPDATE bug53046_1 SET c1 = c1 - 1;
|
||||||
|
|
||||||
|
DELETE FROM bug53046_1;
|
||||||
|
|
||||||
|
INSERT INTO bug53046_1 VALUES (1);
|
||||||
|
INSERT INTO bug53046_2 VALUES (1);
|
||||||
|
TRUNCATE TABLE bug53046_2;
|
||||||
|
|
||||||
|
DROP TABLE bug53046_2;
|
||||||
|
DROP TABLE bug53046_1;
|
@ -3355,8 +3355,6 @@ 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]
|
||||||
@ -3386,8 +3384,6 @@ 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);
|
||||||
|
@ -80,9 +80,18 @@ UNIV_INTERN rw_lock_t dict_operation_lock;
|
|||||||
/** 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[] */
|
/** array of rw locks protecting
|
||||||
#define DICT_INDEX_STAT_MUTEX_SIZE 32
|
dict_table_t::stat_initialized
|
||||||
static mutex_t dict_index_stat_mutex[DICT_INDEX_STAT_MUTEX_SIZE];
|
dict_table_t::stat_n_rows (*)
|
||||||
|
dict_table_t::stat_clustered_index_size
|
||||||
|
dict_table_t::stat_sum_of_other_index_sizes
|
||||||
|
dict_table_t::stat_modified_counter (*)
|
||||||
|
dict_table_t::indexes*::stat_n_diff_key_vals[]
|
||||||
|
dict_table_t::indexes*::stat_index_size
|
||||||
|
dict_table_t::indexes*::stat_n_leaf_pages
|
||||||
|
(*) those are not always protected for performance reasons */
|
||||||
|
#define DICT_TABLE_STATS_LATCHES_SIZE 64
|
||||||
|
static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_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
|
||||||
@ -243,43 +252,65 @@ 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[] */
|
/** Get the latch that protects the stats of a given table */
|
||||||
#define GET_INDEX_STAT_MUTEX(index) \
|
#define GET_TABLE_STATS_LATCH(table) \
|
||||||
(&dict_index_stat_mutex[ut_fold_dulint(index->id) \
|
(&dict_table_stats_latches[ut_fold_dulint(table->id) \
|
||||||
% DICT_INDEX_STAT_MUTEX_SIZE])
|
% DICT_TABLE_STATS_LATCHES_SIZE])
|
||||||
|
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
Lock the appropriate mutex to protect index->stat_n_diff_key_vals[].
|
Lock the appropriate latch to protect a given table's statistics.
|
||||||
index->id is used to pick the right mutex and it should not change
|
table->id is used to pick the corresponding latch from a global array of
|
||||||
before dict_index_stat_mutex_exit() is called on this index. */
|
latches. */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
void
|
void
|
||||||
dict_index_stat_mutex_enter(
|
dict_table_stats_lock(
|
||||||
/*========================*/
|
/*==================*/
|
||||||
const dict_index_t* index) /*!< in: index */
|
const dict_table_t* table, /*!< in: table */
|
||||||
|
ulint latch_mode) /*!< in: RW_S_LATCH or
|
||||||
|
RW_X_LATCH */
|
||||||
{
|
{
|
||||||
ut_ad(index != NULL);
|
ut_ad(table != NULL);
|
||||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||||
ut_ad(index->cached);
|
|
||||||
ut_ad(!index->to_be_dropped);
|
|
||||||
|
|
||||||
mutex_enter(GET_INDEX_STAT_MUTEX(index));
|
switch (latch_mode) {
|
||||||
|
case RW_S_LATCH:
|
||||||
|
rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
|
||||||
|
break;
|
||||||
|
case RW_X_LATCH:
|
||||||
|
rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
|
||||||
|
break;
|
||||||
|
case RW_NO_LATCH:
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
ut_error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
|
Unlock the latch that has been locked by dict_table_stats_lock() */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
void
|
void
|
||||||
dict_index_stat_mutex_exit(
|
dict_table_stats_unlock(
|
||||||
/*=======================*/
|
/*====================*/
|
||||||
const dict_index_t* index) /*!< in: index */
|
const dict_table_t* table, /*!< in: table */
|
||||||
|
ulint latch_mode) /*!< in: RW_S_LATCH or
|
||||||
|
RW_X_LATCH */
|
||||||
{
|
{
|
||||||
ut_ad(index != NULL);
|
ut_ad(table != NULL);
|
||||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||||
ut_ad(index->cached);
|
|
||||||
ut_ad(!index->to_be_dropped);
|
|
||||||
|
|
||||||
mutex_exit(GET_INDEX_STAT_MUTEX(index));
|
switch (latch_mode) {
|
||||||
|
case RW_S_LATCH:
|
||||||
|
rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
|
||||||
|
break;
|
||||||
|
case RW_X_LATCH:
|
||||||
|
rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
|
||||||
|
break;
|
||||||
|
case RW_NO_LATCH:
|
||||||
|
/* fall through */
|
||||||
|
default:
|
||||||
|
ut_error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
@ -668,8 +699,8 @@ dict_init(void)
|
|||||||
|
|
||||||
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
|
mutex_create(&dict_foreign_err_mutex, SYNC_ANY_LATCH);
|
||||||
|
|
||||||
for (i = 0; i < DICT_INDEX_STAT_MUTEX_SIZE; i++) {
|
for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
|
||||||
mutex_create(&dict_index_stat_mutex[i], SYNC_INDEX_TREE);
|
rw_lock_create(&dict_table_stats_latches[i], SYNC_INDEX_TREE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -700,12 +731,11 @@ dict_table_get(
|
|||||||
mutex_exit(&(dict_sys->mutex));
|
mutex_exit(&(dict_sys->mutex));
|
||||||
|
|
||||||
if (table != NULL) {
|
if (table != NULL) {
|
||||||
if (!table->stat_initialized) {
|
/* If table->ibd_file_missing == TRUE, this will
|
||||||
/* If table->ibd_file_missing == TRUE, this will
|
print an error message and return without doing
|
||||||
print an error message and return without doing
|
anything. */
|
||||||
anything. */
|
dict_update_statistics(table, TRUE /* only update stats
|
||||||
dict_update_statistics(table);
|
if they have not been initialized */);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return(table);
|
return(table);
|
||||||
@ -4186,6 +4216,10 @@ void
|
|||||||
dict_update_statistics_low(
|
dict_update_statistics_low(
|
||||||
/*=======================*/
|
/*=======================*/
|
||||||
dict_table_t* table, /*!< in/out: table */
|
dict_table_t* table, /*!< in/out: table */
|
||||||
|
ibool only_calc_if_missing_stats,/*!< in: only
|
||||||
|
update/recalc the stats if they have
|
||||||
|
not been initialized yet, otherwise
|
||||||
|
do nothing */
|
||||||
ibool has_dict_mutex __attribute__((unused)))
|
ibool has_dict_mutex __attribute__((unused)))
|
||||||
/*!< in: TRUE if the caller has the
|
/*!< in: TRUE if the caller has the
|
||||||
dictionary mutex */
|
dictionary mutex */
|
||||||
@ -4216,6 +4250,12 @@ dict_update_statistics_low(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict_table_stats_lock(table, RW_X_LATCH);
|
||||||
|
|
||||||
|
if (only_calc_if_missing_stats && table->stat_initialized) {
|
||||||
|
dict_table_stats_unlock(table, RW_X_LATCH);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (UNIV_LIKELY
|
if (UNIV_LIKELY
|
||||||
@ -4261,13 +4301,9 @@ 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
|
||||||
@ -4276,6 +4312,8 @@ dict_update_statistics_low(
|
|||||||
table->stat_initialized = TRUE;
|
table->stat_initialized = TRUE;
|
||||||
|
|
||||||
table->stat_modified_counter = 0;
|
table->stat_modified_counter = 0;
|
||||||
|
|
||||||
|
dict_table_stats_unlock(table, RW_X_LATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
@ -4285,9 +4323,13 @@ UNIV_INTERN
|
|||||||
void
|
void
|
||||||
dict_update_statistics(
|
dict_update_statistics(
|
||||||
/*===================*/
|
/*===================*/
|
||||||
dict_table_t* table) /*!< in/out: table */
|
dict_table_t* table, /*!< in/out: table */
|
||||||
|
ibool only_calc_if_missing_stats)/*!< in: only
|
||||||
|
update/recalc the stats if they have
|
||||||
|
not been initialized yet, otherwise
|
||||||
|
do nothing */
|
||||||
{
|
{
|
||||||
dict_update_statistics_low(table, FALSE);
|
dict_update_statistics_low(table, only_calc_if_missing_stats, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
@ -4367,7 +4409,11 @@ dict_table_print_low(
|
|||||||
|
|
||||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||||
|
|
||||||
dict_update_statistics_low(table, TRUE);
|
dict_update_statistics_low(table,
|
||||||
|
FALSE /* update even if initialized */,
|
||||||
|
TRUE /* we have the dict mutex */);
|
||||||
|
|
||||||
|
dict_table_stats_lock(table, RW_S_LATCH);
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"--------------------------------------\n"
|
"--------------------------------------\n"
|
||||||
@ -4396,6 +4442,8 @@ dict_table_print_low(
|
|||||||
index = UT_LIST_GET_NEXT(indexes, index);
|
index = UT_LIST_GET_NEXT(indexes, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict_table_stats_unlock(table, RW_S_LATCH);
|
||||||
|
|
||||||
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||||
|
|
||||||
while (foreign != NULL) {
|
while (foreign != NULL) {
|
||||||
@ -4444,8 +4492,6 @@ 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];
|
||||||
@ -4453,8 +4499,6 @@ 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);
|
|
||||||
|
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
|
" INDEX: name %s, id %lu %lu, fields %lu/%lu,"
|
||||||
" uniq %lu, type %lu\n"
|
" uniq %lu, type %lu\n"
|
||||||
@ -4943,8 +4987,8 @@ 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++) {
|
for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
|
||||||
mutex_free(&dict_index_stat_mutex[i]);
|
rw_lock_free(&dict_table_stats_latches[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* !UNIV_HOTBACKUP */
|
#endif /* !UNIV_HOTBACKUP */
|
||||||
|
@ -222,7 +222,10 @@ loop:
|
|||||||
is no index */
|
is no index */
|
||||||
|
|
||||||
if (dict_table_get_first_index(table)) {
|
if (dict_table_get_first_index(table)) {
|
||||||
dict_update_statistics_low(table, TRUE);
|
dict_update_statistics_low(
|
||||||
|
table,
|
||||||
|
FALSE /* update even if initialized */,
|
||||||
|
TRUE /* we have the dict mutex */);
|
||||||
}
|
}
|
||||||
|
|
||||||
dict_table_print_low(table);
|
dict_table_print_low(table);
|
||||||
|
@ -7343,6 +7343,7 @@ ha_innobase::estimate_rows_upper_bound(void)
|
|||||||
dict_index_t* index;
|
dict_index_t* index;
|
||||||
ulonglong estimate;
|
ulonglong estimate;
|
||||||
ulonglong local_data_file_length;
|
ulonglong local_data_file_length;
|
||||||
|
ulint stat_n_leaf_pages;
|
||||||
|
|
||||||
DBUG_ENTER("estimate_rows_upper_bound");
|
DBUG_ENTER("estimate_rows_upper_bound");
|
||||||
|
|
||||||
@ -7362,10 +7363,12 @@ ha_innobase::estimate_rows_upper_bound(void)
|
|||||||
|
|
||||||
index = dict_table_get_first_index(prebuilt->table);
|
index = dict_table_get_first_index(prebuilt->table);
|
||||||
|
|
||||||
ut_a(index->stat_n_leaf_pages > 0);
|
stat_n_leaf_pages = index->stat_n_leaf_pages;
|
||||||
|
|
||||||
|
ut_a(stat_n_leaf_pages > 0);
|
||||||
|
|
||||||
local_data_file_length =
|
local_data_file_length =
|
||||||
((ulonglong) index->stat_n_leaf_pages) * UNIV_PAGE_SIZE;
|
((ulonglong) stat_n_leaf_pages) * UNIV_PAGE_SIZE;
|
||||||
|
|
||||||
|
|
||||||
/* Calculate a minimum length for a clustered index record and from
|
/* Calculate a minimum length for a clustered index record and from
|
||||||
@ -7564,7 +7567,9 @@ ha_innobase::info_low(
|
|||||||
|
|
||||||
prebuilt->trx->op_info = "updating table statistics";
|
prebuilt->trx->op_info = "updating table statistics";
|
||||||
|
|
||||||
dict_update_statistics(ib_table);
|
dict_update_statistics(ib_table,
|
||||||
|
FALSE /* update even if stats
|
||||||
|
are initialized */);
|
||||||
|
|
||||||
prebuilt->trx->op_info = "returning various info to MySQL";
|
prebuilt->trx->op_info = "returning various info to MySQL";
|
||||||
}
|
}
|
||||||
@ -7583,6 +7588,9 @@ ha_innobase::info_low(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (flag & HA_STATUS_VARIABLE) {
|
if (flag & HA_STATUS_VARIABLE) {
|
||||||
|
|
||||||
|
dict_table_stats_lock(ib_table, RW_S_LATCH);
|
||||||
|
|
||||||
n_rows = ib_table->stat_n_rows;
|
n_rows = ib_table->stat_n_rows;
|
||||||
|
|
||||||
/* Because we do not protect stat_n_rows by any mutex in a
|
/* Because we do not protect stat_n_rows by any mutex in a
|
||||||
@ -7632,6 +7640,8 @@ ha_innobase::info_low(
|
|||||||
ib_table->stat_sum_of_other_index_sizes)
|
ib_table->stat_sum_of_other_index_sizes)
|
||||||
* UNIV_PAGE_SIZE;
|
* UNIV_PAGE_SIZE;
|
||||||
|
|
||||||
|
dict_table_stats_unlock(ib_table, RW_S_LATCH);
|
||||||
|
|
||||||
/* Since fsp_get_available_space_in_free_extents() is
|
/* Since fsp_get_available_space_in_free_extents() is
|
||||||
acquiring latches inside InnoDB, we do not call it if we
|
acquiring latches inside InnoDB, we do not call it if we
|
||||||
are asked by MySQL to avoid locking. Another reason to
|
are asked by MySQL to avoid locking. Another reason to
|
||||||
@ -7708,6 +7718,8 @@ ha_innobase::info_low(
|
|||||||
table->s->keys);
|
table->s->keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict_table_stats_lock(ib_table, RW_S_LATCH);
|
||||||
|
|
||||||
for (i = 0; i < table->s->keys; i++) {
|
for (i = 0; i < table->s->keys; i++) {
|
||||||
ulong j;
|
ulong j;
|
||||||
/* We could get index quickly through internal
|
/* We could get index quickly through internal
|
||||||
@ -7745,8 +7757,6 @@ ha_innobase::info_low(
|
|||||||
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;
|
||||||
@ -7755,8 +7765,6 @@ ha_innobase::info_low(
|
|||||||
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
|
||||||
@ -7773,6 +7781,8 @@ ha_innobase::info_low(
|
|||||||
(ulong) rec_per_key;
|
(ulong) rec_per_key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dict_table_stats_unlock(ib_table, RW_S_LATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
if (srv_force_recovery >= SRV_FORCE_NO_IBUF_MERGE) {
|
||||||
|
@ -1056,6 +1056,10 @@ void
|
|||||||
dict_update_statistics_low(
|
dict_update_statistics_low(
|
||||||
/*=======================*/
|
/*=======================*/
|
||||||
dict_table_t* table, /*!< in/out: table */
|
dict_table_t* table, /*!< in/out: table */
|
||||||
|
ibool only_calc_if_missing_stats,/*!< in: only
|
||||||
|
update/recalc the stats if they have
|
||||||
|
not been initialized yet, otherwise
|
||||||
|
do nothing */
|
||||||
ibool has_dict_mutex);/*!< in: TRUE if the caller has the
|
ibool has_dict_mutex);/*!< in: TRUE if the caller has the
|
||||||
dictionary mutex */
|
dictionary mutex */
|
||||||
/*********************************************************************//**
|
/*********************************************************************//**
|
||||||
@ -1065,7 +1069,11 @@ UNIV_INTERN
|
|||||||
void
|
void
|
||||||
dict_update_statistics(
|
dict_update_statistics(
|
||||||
/*===================*/
|
/*===================*/
|
||||||
dict_table_t* table); /*!< in/out: table */
|
dict_table_t* table, /*!< in/out: table */
|
||||||
|
ibool only_calc_if_missing_stats);/*!< in: only
|
||||||
|
update/recalc the stats if they have
|
||||||
|
not been initialized yet, otherwise
|
||||||
|
do nothing */
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
Reserves the dictionary system mutex for MySQL. */
|
Reserves the dictionary system mutex for MySQL. */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
@ -1079,21 +1087,25 @@ 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[].
|
Lock the appropriate latch to protect a given table's statistics.
|
||||||
index->id is used to pick the right mutex and it should not change
|
table->id is used to pick the corresponding latch from a global array of
|
||||||
before dict_index_stat_mutex_exit() is called on this index. */
|
latches. */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
void
|
void
|
||||||
dict_index_stat_mutex_enter(
|
dict_table_stats_lock(
|
||||||
/*========================*/
|
/*==================*/
|
||||||
const dict_index_t* index); /*!< in: index */
|
const dict_table_t* table, /*!< in: table */
|
||||||
|
ulint latch_mode); /*!< in: RW_S_LATCH or
|
||||||
|
RW_X_LATCH */
|
||||||
/**********************************************************************//**
|
/**********************************************************************//**
|
||||||
Unlock the appropriate mutex that protects index->stat_n_diff_key_vals[]. */
|
Unlock the latch that has been locked by dict_table_stats_lock() */
|
||||||
UNIV_INTERN
|
UNIV_INTERN
|
||||||
void
|
void
|
||||||
dict_index_stat_mutex_exit(
|
dict_table_stats_unlock(
|
||||||
/*=======================*/
|
/*====================*/
|
||||||
const dict_index_t* index); /*!< in: index */
|
const dict_table_t* table, /*!< in: table */
|
||||||
|
ulint latch_mode); /*!< in: RW_S_LATCH or
|
||||||
|
RW_X_LATCH */
|
||||||
/********************************************************************//**
|
/********************************************************************//**
|
||||||
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 */
|
||||||
|
@ -871,7 +871,8 @@ row_update_statistics_if_needed(
|
|||||||
if (counter > 2000000000
|
if (counter > 2000000000
|
||||||
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
|
|| ((ib_int64_t)counter > 16 + table->stat_n_rows / 16)) {
|
||||||
|
|
||||||
dict_update_statistics(table);
|
dict_update_statistics(table, FALSE /* update even if stats
|
||||||
|
are initialized */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2953,7 +2954,8 @@ next_rec:
|
|||||||
dict_table_autoinc_lock(table);
|
dict_table_autoinc_lock(table);
|
||||||
dict_table_autoinc_initialize(table, 1);
|
dict_table_autoinc_initialize(table, 1);
|
||||||
dict_table_autoinc_unlock(table);
|
dict_table_autoinc_unlock(table);
|
||||||
dict_update_statistics(table);
|
dict_update_statistics(table, FALSE /* update even if stats are
|
||||||
|
initialized */);
|
||||||
|
|
||||||
trx_commit_for_mysql(trx);
|
trx_commit_for_mysql(trx);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user