summaryrefslogtreecommitdiff
path: root/storage/innobase/dict/dict0stats.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/dict/dict0stats.cc')
-rw-r--r--storage/innobase/dict/dict0stats.cc716
1 files changed, 293 insertions, 423 deletions
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index e3d0effb5ac..5fa049f6b2b 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2009, 2017, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, 2017, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
@@ -276,9 +276,7 @@ This function will free the pinfo object.
@param[in,out] pinfo pinfo to pass to que_eval_sql() must already
have any literals bound to it
@param[in] sql SQL string to execute
-@param[in,out] trx in case of NULL the function will allocate and
-free the trx object. If it is not NULL then it will be rolled back
-only in the case of error, but not freed.
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
static
dberr_t
@@ -288,53 +286,12 @@ dict_stats_exec_sql(
trx_t* trx)
{
dberr_t err;
- bool trx_started = false;
-
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
-
- if (!dict_stats_persistent_storage_check(true)) {
- pars_info_free(pinfo);
- return(DB_STATS_DO_NOT_EXIST);
- }
-
- if (trx == NULL) {
- trx = trx_allocate_for_background();
- trx_started = true;
-
- if (srv_read_only_mode) {
- trx_start_internal_read_only(trx);
- } else {
- trx_start_internal(trx);
- }
- }
err = que_eval_sql(pinfo, sql, FALSE, trx); /* pinfo is freed here */
DBUG_EXECUTE_IF("stats_index_error",
- if (!trx_started) {
err = DB_STATS_DO_NOT_EXIST;
- trx->error_state = DB_STATS_DO_NOT_EXIST;
- });
-
- if (!trx_started && err == DB_SUCCESS) {
- return(DB_SUCCESS);
- }
-
- if (err == DB_SUCCESS) {
- trx_commit_for_mysql(trx);
- } else {
- trx->op_info = "rollback of internal trx on stats tables";
- trx->dict_operation_lock_mode = RW_X_LATCH;
- trx_rollback_to_savepoint(trx, NULL);
- trx->dict_operation_lock_mode = 0;
- trx->op_info = "";
- ut_a(trx->error_state == DB_SUCCESS);
- }
-
- if (trx_started) {
- trx_free_for_background(trx);
- }
+ trx->error_state = DB_STATS_DO_NOT_EXIST;);
return(err);
}
@@ -543,39 +500,12 @@ dict_stats_empty_index(
}
}
-/**********************************************************************//**
-Clear defragmentation summary. */
-UNIV_INTERN
-void
-dict_stats_empty_defrag_summary(
-/*==================*/
- dict_index_t* index) /*!< in: index to clear defragmentation stats */
-{
- index->stat_defrag_n_pages_freed = 0;
-}
-
-/**********************************************************************//**
-Clear defragmentation related index stats. */
-UNIV_INTERN
-void
-dict_stats_empty_defrag_stats(
-/*==================*/
- dict_index_t* index) /*!< in: index to clear defragmentation stats */
-{
- index->stat_defrag_modified_counter = 0;
- index->stat_defrag_n_page_split = 0;
-}
-
-/*********************************************************************//**
-Write all zeros (or 1 where it makes sense) into a table and its indexes'
-statistics members. The resulting stats correspond to an empty table. */
-static
+/** Reset the table and index statsistics, corresponding to an empty table.
+@param[in,out] table table whose statistics are to be reset
+@param[in] empty_defrag_stats whether to empty the defrag statistics
+*/
void
-dict_stats_empty_table(
-/*===================*/
- dict_table_t* table, /*!< in/out: table */
- bool empty_defrag_stats)
- /*!< in: whether to empty defrag stats */
+dict_stats_empty_table(dict_table_t* table, bool empty_defrag_stats)
{
/* Zero the stats members */
@@ -2329,9 +2259,7 @@ storage.
@param[in] stat_value value of the stat
@param[in] sample_size n pages sampled or NULL
@param[in] stat_description description of the stat
-@param[in,out] trx in case of NULL the function will
-allocate and free the trx object. If it is not NULL then it will be
-rolled back only in the case of error, but not freed.
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
dberr_t
dict_stats_save_index_stat(
@@ -2348,8 +2276,7 @@ dict_stats_save_index_stat(
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
+ ut_ad(trx->persistent_stats || trx->in_mysql_trx_list);
dict_fs2utf8(index->table->name.m_name, db_utf8, sizeof(db_utf8),
table_utf8, sizeof(table_utf8));
@@ -2375,6 +2302,8 @@ dict_stats_save_index_stat(
pars_info_add_str_literal(pinfo, "stat_description",
stat_description);
+ mutex_enter(&dict_sys->mutex);
+
ret = dict_stats_exec_sql(
pinfo,
"PROCEDURE INDEX_STATS_SAVE () IS\n"
@@ -2401,6 +2330,8 @@ dict_stats_save_index_stat(
");\n"
"END;", trx);
+ mutex_exit(&dict_sys->mutex);
+
if (ret != DB_SUCCESS) {
if (innodb_index_stats_not_found == false &&
index->stats_error_printed == false) {
@@ -2453,6 +2384,7 @@ dict_stats_report_error(dict_table_t* table, bool defragment)
/** Save the table's statistics into the persistent statistics storage.
@param[in] table_orig table whose stats to save
+@param[in,out] trx transaction
@param[in] only_for_index if this is non-NULL, then stats for indexes
that are not equal to it will not be saved, if NULL, then all indexes' stats
are saved
@@ -2461,7 +2393,8 @@ static
dberr_t
dict_stats_save(
dict_table_t* table_orig,
- const index_id_t* only_for_index)
+ trx_t* trx,
+ const index_id_t* only_for_index = NULL)
{
pars_info_t* pinfo;
lint now;
@@ -2470,6 +2403,8 @@ dict_stats_save(
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
+ ut_ad(trx->persistent_stats || trx->in_mysql_trx_list);
+
if (table_orig->is_readable()) {
} else {
return (dict_stats_report_error(table_orig));
@@ -2480,9 +2415,6 @@ dict_stats_save(
dict_fs2utf8(table->name.m_name, db_utf8, sizeof(db_utf8),
table_utf8, sizeof(table_utf8));
- rw_lock_x_lock(dict_operation_lock);
- mutex_enter(&dict_sys->mutex);
-
/* MySQL's timestamp is 4 byte, so we use
pars_info_add_int4_literal() which takes a lint arg, so "now" is
lint */
@@ -2499,6 +2431,8 @@ dict_stats_save(
pars_info_add_ull_literal(pinfo, "sum_of_other_index_sizes",
table->stat_sum_of_other_index_sizes);
+ mutex_enter(&dict_sys->mutex);
+
ret = dict_stats_exec_sql(
pinfo,
"PROCEDURE TABLE_STATS_SAVE () IS\n"
@@ -2519,33 +2453,18 @@ dict_stats_save(
":clustered_index_size,\n"
":sum_of_other_index_sizes\n"
");\n"
- "END;", NULL);
-
- if (ret != DB_SUCCESS) {
- ib::error() << "Cannot save table statistics for table "
- << table->name << ": " << ut_strerr(ret);
-
- mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
-
- dict_stats_snapshot_free(table);
-
- return(ret);
- }
-
- trx_t* trx = trx_allocate_for_background();
+ "END;", trx);
- if (srv_read_only_mode) {
- trx_start_internal_read_only(trx);
- } else {
- trx_start_internal(trx);
- }
+ mutex_exit(&dict_sys->mutex);
- dict_index_t* index;
index_map_t indexes(
(ut_strcmp_functor()),
index_map_t_allocator(mem_key_dict_stats_index_map_t));
+ if (ret != DB_SUCCESS) {
+ goto end;
+ }
+
/* Below we do all the modifications in innodb_index_stats in a single
transaction for performance reasons. Modifying more than one row in a
single transaction may deadlock with other transactions if they
@@ -2558,18 +2477,17 @@ dict_stats_save(
stat_name). This is why below we sort the indexes by name and then
for each index, do the mods ordered by stat_name. */
- for (index = dict_table_get_first_index(table);
+ for (dict_index_t* index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
indexes[index->name] = index;
}
- index_map_t::const_iterator it;
-
- for (it = indexes.begin(); it != indexes.end(); ++it) {
+ for (index_map_t::const_iterator it = indexes.begin();
+ it != indexes.end(); ++it) {
- index = it->second;
+ dict_index_t* index = it->second;
if (only_for_index != NULL && index->id != *only_for_index) {
continue;
@@ -2586,21 +2504,20 @@ dict_stats_save(
char stat_name[16];
char stat_description[1024];
- ut_snprintf(stat_name, sizeof(stat_name),
- "n_diff_pfx%02u", i + 1);
+ snprintf(stat_name, sizeof(stat_name),
+ "n_diff_pfx%02u", i + 1);
/* craft a string that contains the column names */
- ut_snprintf(stat_description,
- sizeof(stat_description),
- "%s", index->fields[0].name());
+ snprintf(stat_description, sizeof(stat_description),
+ "%s", index->fields[0].name());
for (unsigned j = 1; j <= i; j++) {
size_t len;
len = strlen(stat_description);
- ut_snprintf(stat_description + len,
- sizeof(stat_description) - len,
- ",%s", index->fields[j].name());
+ snprintf(stat_description + len,
+ sizeof(stat_description) - len,
+ ",%s", index->fields[j].name());
}
ret = dict_stats_save_index_stat(
@@ -2633,13 +2550,11 @@ dict_stats_save(
}
}
- trx_commit_for_mysql(trx);
-
+ if (ret != DB_SUCCESS) {
end:
- trx_free_for_background(trx);
-
- mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
+ ib::error() << "Cannot save table statistics for table "
+ << table->name << ": " << ut_strerr(ret);
+ }
dict_stats_snapshot_free(table);
@@ -3137,12 +3052,13 @@ dict_stats_empty_defrag_modified_counter(
}
}
-/*********************************************************************//**
-Fetches or calculates new estimates for index statistics. */
-void
-dict_stats_update_for_index(
-/*========================*/
- dict_index_t* index) /*!< in/out: index */
+/** Calculate index statistics.
+@param[in,out] index index tree
+@param[in,out] trx transaction (for persistent statistics)
+@return DB_SUCCESS or error code */
+UNIV_INTERN
+dberr_t
+dict_stats_update_for_index(dict_index_t* index, trx_t* trx)
{
DBUG_ENTER("dict_stats_update_for_index");
@@ -3154,8 +3070,8 @@ dict_stats_update_for_index(
dict_table_stats_lock(index->table, RW_X_LATCH);
dict_stats_analyze_index(index);
dict_table_stats_unlock(index->table, RW_X_LATCH);
- dict_stats_save(index->table, &index->id);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(dict_stats_save(index->table, trx,
+ &index->id));
}
/* else */
@@ -3178,22 +3094,20 @@ dict_stats_update_for_index(
dict_stats_update_transient_for_index(index);
dict_table_stats_unlock(index->table, RW_X_LATCH);
- DBUG_VOID_RETURN;
+ DBUG_RETURN(DB_SUCCESS);
}
-/*********************************************************************//**
-Calculates new estimates for table and index statistics. The statistics
-are used in query optimization.
-@return DB_SUCCESS or error code */
+/** Calculate new estimates for table and index statistics.
+@param[in,out] table table
+@param[in] stats_upd_option how to update statistics
+@param[in,out] trx transaction
+@return DB_* error code or DB_SUCCESS */
+UNIV_INTERN
dberr_t
dict_stats_update(
-/*==============*/
- dict_table_t* table, /*!< in/out: table */
- dict_stats_upd_option_t stats_upd_option)
- /*!< in: whether to (re) calc
- the stats or to fetch them from
- the persistent statistics
- storage */
+ dict_table_t* table,
+ dict_stats_upd_option_t stats_upd_option,
+ trx_t* trx)
{
ut_ad(!mutex_own(&dict_sys->mutex));
@@ -3238,7 +3152,7 @@ dict_stats_update(
return(err);
}
- err = dict_stats_save(table, NULL);
+ err = dict_stats_save(table, trx);
return(err);
}
@@ -3274,7 +3188,7 @@ dict_stats_update(
if (dict_stats_persistent_storage_check(false)) {
- return(dict_stats_save(table, NULL));
+ return(dict_stats_save(table, trx));
}
return(DB_STATS_DO_NOT_EXIST);
@@ -3353,9 +3267,9 @@ dict_stats_update(
}
if (dict_stats_auto_recalc_is_enabled(table)) {
- return(dict_stats_update(
- table,
- DICT_STATS_RECALC_PERSISTENT));
+ return dict_stats_update(
+ table, DICT_STATS_RECALC_PERSISTENT,
+ trx);
}
ib::info() << "Trying to use table " << table->name
@@ -3403,25 +3317,20 @@ transient:
return(DB_SUCCESS);
}
-/*********************************************************************//**
-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.
-This function creates its own trx and commits it.
-A note from Marko why we cannot edit user and sys_* tables in one trx:
-marko: The problem is that ibuf merges should be disabled while we are
-rolling back dict transactions.
-marko: If ibuf merges are not disabled, we need to scan the *.ibd files.
-But we shouldn't open *.ibd files before we have rolled back dict
-transactions and opened the SYS_* records for the *.ibd files.
+/** Remove the persistent statistics for an index.
+@param[in] db_and_table schema and table name, e.g., 'db/table'
+@param[in] iname index name
+@param[out] errstr error message (when not returning DB_SUCCESS)
+@param[in] errstr_sz sizeof errstr
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
dberr_t
dict_stats_drop_index(
-/*==================*/
- const char* db_and_table,/*!< in: db and table, e.g. 'db/table' */
- const char* iname, /*!< in: index name */
- char* errstr, /*!< out: error message if != DB_SUCCESS
- is returned */
- ulint errstr_sz)/*!< in: size of the errstr buffer */
+ const char* db_and_table,
+ const char* iname,
+ char* errstr,
+ size_t errstr_sz,
+ trx_t* trx)
{
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
@@ -3437,6 +3346,11 @@ dict_stats_drop_index(
return(DB_SUCCESS);
}
+ if (!dict_stats_persistent_storage_check(false)) {
+ /* Statistics tables do not exist. */
+ return(DB_SUCCESS);
+ }
+
dict_fs2utf8(db_and_table, db_utf8, sizeof(db_utf8),
table_utf8, sizeof(table_utf8));
@@ -3448,7 +3362,6 @@ dict_stats_drop_index(
pars_info_add_str_literal(pinfo, "index_name", iname);
- rw_lock_x_lock(dict_operation_lock);
mutex_enter(&dict_sys->mutex);
ret = dict_stats_exec_sql(
@@ -3459,33 +3372,35 @@ dict_stats_drop_index(
"database_name = :database_name AND\n"
"table_name = :table_name AND\n"
"index_name = :index_name;\n"
- "END;\n", NULL);
+ "END;\n", trx);
mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
- if (ret == DB_STATS_DO_NOT_EXIST) {
- ret = DB_SUCCESS;
- }
-
- if (ret != DB_SUCCESS) {
- ut_snprintf(errstr, errstr_sz,
- "Unable to delete statistics for index %s"
- " from %s%s: %s. They can be deleted later using"
- " DELETE FROM %s WHERE"
- " database_name = '%s' AND"
- " table_name = '%s' AND"
- " index_name = '%s';",
- iname,
- INDEX_STATS_NAME_PRINT,
- (ret == DB_LOCK_WAIT_TIMEOUT
- ? " because the rows are locked"
- : ""),
- ut_strerr(ret),
- INDEX_STATS_NAME_PRINT,
- db_utf8,
- table_utf8,
- iname);
+ switch (ret) {
+ case DB_STATS_DO_NOT_EXIST:
+ case DB_SUCCESS:
+ return(DB_SUCCESS);
+ case DB_QUE_THR_SUSPENDED:
+ ret = DB_LOCK_WAIT;
+ /* fall through */
+ default:
+ snprintf(errstr, errstr_sz,
+ "Unable to delete statistics for index %s"
+ " from %s%s: %s. They can be deleted later using"
+ " DELETE FROM %s WHERE"
+ " database_name = '%s' AND"
+ " table_name = '%s' AND"
+ " index_name = '%s';",
+ iname,
+ INDEX_STATS_NAME_PRINT,
+ (ret == DB_LOCK_WAIT_TIMEOUT
+ ? " because the rows are locked"
+ : ""),
+ ut_strerr(ret),
+ INDEX_STATS_NAME_PRINT,
+ db_utf8,
+ table_utf8,
+ iname);
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: %s\n", errstr);
@@ -3494,98 +3409,71 @@ dict_stats_drop_index(
return(ret);
}
-/*********************************************************************//**
-Executes
-DELETE FROM mysql.innodb_table_stats
-WHERE database_name = '...' AND table_name = '...';
-Creates its own transaction and commits it.
+/** Delete table statistics.
+@param[in] db schema name
+@param[in] t table name
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
UNIV_INLINE
dberr_t
-dict_stats_delete_from_table_stats(
-/*===============================*/
- const char* database_name, /*!< in: database name, e.g. 'db' */
- const char* table_name) /*!< in: table name, e.g. 'table' */
+dict_stats_delete_from_table_stats(const char* db, const char* t, trx_t* trx)
{
- pars_info_t* pinfo;
- dberr_t ret;
+ pars_info_t* pinfo = pars_info_create();
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
-
- pinfo = pars_info_create();
+ pars_info_add_str_literal(pinfo, "database_name", db);
+ pars_info_add_str_literal(pinfo, "table_name", t);
- pars_info_add_str_literal(pinfo, "database_name", database_name);
- pars_info_add_str_literal(pinfo, "table_name", table_name);
-
- ret = dict_stats_exec_sql(
+ return dict_stats_exec_sql(
pinfo,
"PROCEDURE DELETE_FROM_TABLE_STATS () IS\n"
"BEGIN\n"
"DELETE FROM \"" TABLE_STATS_NAME "\" WHERE\n"
"database_name = :database_name AND\n"
"table_name = :table_name;\n"
- "END;\n", NULL);
-
- return(ret);
+ "END;\n", trx);
}
-/*********************************************************************//**
-Executes
-DELETE FROM mysql.innodb_index_stats
-WHERE database_name = '...' AND table_name = '...';
-Creates its own transaction and commits it.
+/** Delete index statistics.
+@param[in] db schema name
+@param[in] t table name
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
UNIV_INLINE
dberr_t
-dict_stats_delete_from_index_stats(
-/*===============================*/
- const char* database_name, /*!< in: database name, e.g. 'db' */
- const char* table_name) /*!< in: table name, e.g. 'table' */
+dict_stats_delete_from_index_stats(const char* db, const char* t, trx_t* trx)
{
- pars_info_t* pinfo;
- dberr_t ret;
-
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
+ pars_info_t* pinfo = pars_info_create();
- pinfo = pars_info_create();
-
- pars_info_add_str_literal(pinfo, "database_name", database_name);
- pars_info_add_str_literal(pinfo, "table_name", table_name);
+ pars_info_add_str_literal(pinfo, "database_name", db);
+ pars_info_add_str_literal(pinfo, "table_name", t);
- ret = dict_stats_exec_sql(
+ return dict_stats_exec_sql(
pinfo,
"PROCEDURE DELETE_FROM_INDEX_STATS () IS\n"
"BEGIN\n"
"DELETE FROM \"" INDEX_STATS_NAME "\" WHERE\n"
"database_name = :database_name AND\n"
"table_name = :table_name;\n"
- "END;\n", NULL);
-
- return(ret);
+ "END;\n", trx);
}
-/*********************************************************************//**
-Removes the statistics for a table and all of its indexes from the
-persistent statistics storage if it exists and if there is data stored for
-the table. This function creates its own transaction and commits it.
+/** Remove the persistent statistics for a table and all of its indexes.
+@param[in] db_and_table schema and table name, e.g., 'db/table'
+@param[out] errstr error message (when not returning DB_SUCCESS)
+@param[in] errstr_sz sizeof errstr
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
dberr_t
dict_stats_drop_table(
-/*==================*/
- const char* db_and_table, /*!< in: db and table, e.g. 'db/table' */
- char* errstr, /*!< out: error message
- if != DB_SUCCESS is returned */
- ulint errstr_sz) /*!< in: size of errstr buffer */
+ const char* db_and_table,
+ char* errstr,
+ size_t errstr_sz,
+ trx_t* trx)
{
char db_utf8[MAX_DB_UTF8_LEN];
char table_utf8[MAX_TABLE_UTF8_LEN];
dberr_t ret;
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
-
/* skip tables that do not contain a database name
e.g. if we are dropping SYS_TABLES */
if (strchr(db_and_table, '/') == NULL) {
@@ -3600,76 +3488,78 @@ dict_stats_drop_table(
return(DB_SUCCESS);
}
+ if (!dict_stats_persistent_storage_check(true)) {
+ /* Statistics tables do not exist. */
+ return(DB_SUCCESS);
+ }
+
dict_fs2utf8(db_and_table, db_utf8, sizeof(db_utf8),
table_utf8, sizeof(table_utf8));
- ret = dict_stats_delete_from_table_stats(db_utf8, table_utf8);
+ ret = dict_stats_delete_from_table_stats(db_utf8, table_utf8, trx);
if (ret == DB_SUCCESS) {
- ret = dict_stats_delete_from_index_stats(db_utf8, table_utf8);
+ ret = dict_stats_delete_from_index_stats(
+ db_utf8, table_utf8, trx);
}
- if (ret == DB_STATS_DO_NOT_EXIST) {
- ret = DB_SUCCESS;
- }
-
- if (ret != DB_SUCCESS) {
-
- ut_snprintf(errstr, errstr_sz,
- "Unable to delete statistics for table %s.%s: %s."
- " They can be deleted later using"
-
- " DELETE FROM %s WHERE"
- " database_name = '%s' AND"
- " table_name = '%s';"
-
- " DELETE FROM %s WHERE"
- " database_name = '%s' AND"
- " table_name = '%s';",
-
- db_utf8, table_utf8,
- ut_strerr(ret),
-
- INDEX_STATS_NAME_PRINT,
- db_utf8, table_utf8,
-
- TABLE_STATS_NAME_PRINT,
- db_utf8, table_utf8);
+ switch (ret) {
+ case DB_SUCCESS:
+ case DB_STATS_DO_NOT_EXIST:
+ return(DB_SUCCESS);
+ case DB_QUE_THR_SUSPENDED:
+ ret = DB_LOCK_WAIT;
+ /* fall through */
+ default:
+ snprintf(errstr, errstr_sz,
+ "Unable to delete statistics for table %s.%s: %s. "
+ "They can be deleted later using "
+
+ " DELETE FROM %s WHERE"
+ " database_name = '%s' AND"
+ " table_name = '%s';"
+
+ " DELETE FROM %s WHERE"
+ " database_name = '%s' AND"
+ " table_name = '%s';",
+
+ db_utf8, table_utf8,
+ ut_strerr(ret),
+
+ INDEX_STATS_NAME_PRINT,
+ db_utf8, table_utf8,
+
+ TABLE_STATS_NAME_PRINT,
+ db_utf8, table_utf8);
}
return(ret);
}
-/*********************************************************************//**
-Executes
-UPDATE mysql.innodb_table_stats SET
-database_name = '...', table_name = '...'
-WHERE database_name = '...' AND table_name = '...';
-Creates its own transaction and commits it.
+/** Rename table statistics.
+@param[in] old_dbname_utf8 old schema name
+@param[in] old_tablename_utf8 old table name
+@param[in] new_dbname_utf8 new schema name
+@param[in] new_tablename_utf8 new schema name
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
UNIV_INLINE
dberr_t
-dict_stats_rename_table_in_table_stats(
-/*===================================*/
- const char* old_dbname_utf8,/*!< in: database name, e.g. 'olddb' */
- const char* old_tablename_utf8,/*!< in: table name, e.g. 'oldtable' */
- const char* new_dbname_utf8,/*!< in: database name, e.g. 'newdb' */
- const char* new_tablename_utf8)/*!< in: table name, e.g. 'newtable' */
+dict_stats_rename_in_table_stats(
+ const char* old_dbname_utf8,
+ const char* old_tablename_utf8,
+ const char* new_dbname_utf8,
+ const char* new_tablename_utf8,
+ trx_t* trx)
{
- pars_info_t* pinfo;
- dberr_t ret;
-
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
-
- pinfo = pars_info_create();
+ pars_info_t* pinfo = pars_info_create();
pars_info_add_str_literal(pinfo, "old_dbname_utf8", old_dbname_utf8);
pars_info_add_str_literal(pinfo, "old_tablename_utf8", old_tablename_utf8);
pars_info_add_str_literal(pinfo, "new_dbname_utf8", new_dbname_utf8);
pars_info_add_str_literal(pinfo, "new_tablename_utf8", new_tablename_utf8);
- ret = dict_stats_exec_sql(
+ return dict_stats_exec_sql(
pinfo,
"PROCEDURE RENAME_TABLE_IN_TABLE_STATS () IS\n"
"BEGIN\n"
@@ -3679,41 +3569,33 @@ dict_stats_rename_table_in_table_stats(
"WHERE\n"
"database_name = :old_dbname_utf8 AND\n"
"table_name = :old_tablename_utf8;\n"
- "END;\n", NULL);
-
- return(ret);
+ "END;\n", trx);
}
-/*********************************************************************//**
-Executes
-UPDATE mysql.innodb_index_stats SET
-database_name = '...', table_name = '...'
-WHERE database_name = '...' AND table_name = '...';
-Creates its own transaction and commits it.
+/** Rename index statistics.
+@param[in] old_dbname_utf8 old schema name
+@param[in] old_tablename_utf8 old table name
+@param[in] new_dbname_utf8 new schema name
+@param[in] new_tablename_utf8 new schema name
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
UNIV_INLINE
dberr_t
-dict_stats_rename_table_in_index_stats(
-/*===================================*/
- const char* old_dbname_utf8,/*!< in: database name, e.g. 'olddb' */
- const char* old_tablename_utf8,/*!< in: table name, e.g. 'oldtable' */
- const char* new_dbname_utf8,/*!< in: database name, e.g. 'newdb' */
- const char* new_tablename_utf8)/*!< in: table name, e.g. 'newtable' */
+dict_stats_rename_in_index_stats(
+ const char* old_dbname_utf8,
+ const char* old_tablename_utf8,
+ const char* new_dbname_utf8,
+ const char* new_tablename_utf8,
+ trx_t* trx)
{
- pars_info_t* pinfo;
- dberr_t ret;
-
- ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(mutex_own(&dict_sys->mutex));
-
- pinfo = pars_info_create();
+ pars_info_t* pinfo = pars_info_create();
pars_info_add_str_literal(pinfo, "old_dbname_utf8", old_dbname_utf8);
pars_info_add_str_literal(pinfo, "old_tablename_utf8", old_tablename_utf8);
pars_info_add_str_literal(pinfo, "new_dbname_utf8", new_dbname_utf8);
pars_info_add_str_literal(pinfo, "new_tablename_utf8", new_tablename_utf8);
- ret = dict_stats_exec_sql(
+ return dict_stats_exec_sql(
pinfo,
"PROCEDURE RENAME_TABLE_IN_INDEX_STATS () IS\n"
"BEGIN\n"
@@ -3723,23 +3605,23 @@ dict_stats_rename_table_in_index_stats(
"WHERE\n"
"database_name = :old_dbname_utf8 AND\n"
"table_name = :old_tablename_utf8;\n"
- "END;\n", NULL);
-
- return(ret);
+ "END;\n", trx);
}
-/*********************************************************************//**
-Renames a table in InnoDB persistent stats storage.
-This function creates its own transaction and commits it.
+/** Rename a table in the InnoDB persistent statistics storage.
+@param[in] old_name old schema and table name, e.g., 'db/table'
+@param[in] new_name new schema and table name, e.g., 'db/table'
+@param[out] errstr error message (when not returning DB_SUCCESS)
+@param[in] errstr_sz sizeof errstr
+@param[in,out] trx transaction
@return DB_SUCCESS or error code */
dberr_t
dict_stats_rename_table(
-/*====================*/
- const char* old_name, /*!< in: old name, e.g. 'db/table' */
- const char* new_name, /*!< in: new name, e.g. 'db/table' */
- char* errstr, /*!< out: error string if != DB_SUCCESS
- is returned */
- size_t errstr_sz) /*!< in: errstr size */
+ const char* old_name,
+ const char* new_name,
+ char* errstr,
+ size_t errstr_sz,
+ trx_t* trx)
{
char old_db_utf8[MAX_DB_UTF8_LEN];
char new_db_utf8[MAX_DB_UTF8_LEN];
@@ -3747,9 +3629,6 @@ dict_stats_rename_table(
char new_table_utf8[MAX_TABLE_UTF8_LEN];
dberr_t ret;
- ut_ad(!rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(!mutex_own(&dict_sys->mutex));
-
/* skip innodb_table_stats and innodb_index_stats themselves */
if (strcmp(old_name, TABLE_STATS_NAME) == 0
|| strcmp(old_name, INDEX_STATS_NAME) == 0
@@ -3759,124 +3638,115 @@ dict_stats_rename_table(
return(DB_SUCCESS);
}
+ if (!dict_stats_persistent_storage_check(false)) {
+ /* Statistics tables do not exist. */
+ return(DB_SUCCESS);
+ }
+
dict_fs2utf8(old_name, old_db_utf8, sizeof(old_db_utf8),
old_table_utf8, sizeof(old_table_utf8));
dict_fs2utf8(new_name, new_db_utf8, sizeof(new_db_utf8),
new_table_utf8, sizeof(new_table_utf8));
- rw_lock_x_lock(dict_operation_lock);
- mutex_enter(&dict_sys->mutex);
-
ulint n_attempts = 0;
do {
- n_attempts++;
+ trx_savept_t savept = trx_savept_take(trx);
- ret = dict_stats_rename_table_in_table_stats(
- old_db_utf8, old_table_utf8,
- new_db_utf8, new_table_utf8);
+ mutex_enter(&dict_sys->mutex);
- if (ret == DB_DUPLICATE_KEY) {
- dict_stats_delete_from_table_stats(
- new_db_utf8, new_table_utf8);
- }
+ ret = dict_stats_rename_in_table_stats(
+ old_db_utf8, old_table_utf8,
+ new_db_utf8, new_table_utf8, trx);
- if (ret == DB_STATS_DO_NOT_EXIST) {
- ret = DB_SUCCESS;
- }
+ mutex_exit(&dict_sys->mutex);
- if (ret != DB_SUCCESS) {
+ switch (ret) {
+ case DB_DUPLICATE_KEY:
+ trx_rollback_to_savepoint(trx, &savept);
+ mutex_enter(&dict_sys->mutex);
+ dict_stats_delete_from_table_stats(
+ new_db_utf8, new_table_utf8, trx);
mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
+ /* fall through */
+ case DB_DEADLOCK:
+ case DB_LOCK_WAIT_TIMEOUT:
os_thread_sleep(200000 /* 0.2 sec */);
- rw_lock_x_lock(dict_operation_lock);
- mutex_enter(&dict_sys->mutex);
+ continue;
+ case DB_STATS_DO_NOT_EXIST:
+ ret = DB_SUCCESS;
+ break;
+ default:
+ break;
}
- } while ((ret == DB_DEADLOCK
- || ret == DB_DUPLICATE_KEY
- || ret == DB_LOCK_WAIT_TIMEOUT)
- && n_attempts < 5);
+
+ break;
+ } while (++n_attempts < 5);
+
+ const char* table_name = TABLE_STATS_NAME_PRINT;
if (ret != DB_SUCCESS) {
- ut_snprintf(errstr, errstr_sz,
- "Unable to rename statistics from"
- " %s.%s to %s.%s in %s: %s."
- " They can be renamed later using"
-
- " UPDATE %s SET"
- " database_name = '%s',"
- " table_name = '%s'"
- " WHERE"
- " database_name = '%s' AND"
- " table_name = '%s';",
-
- old_db_utf8, old_table_utf8,
- new_db_utf8, new_table_utf8,
- TABLE_STATS_NAME_PRINT,
- ut_strerr(ret),
-
- TABLE_STATS_NAME_PRINT,
- new_db_utf8, new_table_utf8,
- old_db_utf8, old_table_utf8);
- mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
- return(ret);
+ goto err_exit;
}
- /* else */
+
+ table_name = INDEX_STATS_NAME_PRINT;
n_attempts = 0;
do {
- n_attempts++;
+ trx_savept_t savept = trx_savept_take(trx);
- ret = dict_stats_rename_table_in_index_stats(
- old_db_utf8, old_table_utf8,
- new_db_utf8, new_table_utf8);
+ mutex_enter(&dict_sys->mutex);
- if (ret == DB_DUPLICATE_KEY) {
- dict_stats_delete_from_index_stats(
- new_db_utf8, new_table_utf8);
- }
+ ret = dict_stats_rename_in_index_stats(
+ old_db_utf8, old_table_utf8,
+ new_db_utf8, new_table_utf8, trx);
- if (ret == DB_STATS_DO_NOT_EXIST) {
- ret = DB_SUCCESS;
- }
+ mutex_exit(&dict_sys->mutex);
- if (ret != DB_SUCCESS) {
+ switch (ret) {
+ case DB_DUPLICATE_KEY:
+ trx_rollback_to_savepoint(trx, &savept);
+ mutex_enter(&dict_sys->mutex);
+ dict_stats_delete_from_index_stats(
+ new_db_utf8, new_table_utf8, trx);
mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
+ /* fall through */
+ case DB_DEADLOCK:
+ case DB_LOCK_WAIT_TIMEOUT:
os_thread_sleep(200000 /* 0.2 sec */);
- rw_lock_x_lock(dict_operation_lock);
- mutex_enter(&dict_sys->mutex);
+ continue;
+ case DB_STATS_DO_NOT_EXIST:
+ ret = DB_SUCCESS;
+ break;
+ default:
+ break;
}
- } while ((ret == DB_DEADLOCK
- || ret == DB_DUPLICATE_KEY
- || ret == DB_LOCK_WAIT_TIMEOUT)
- && n_attempts < 5);
- mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
+ break;
+ } while (++n_attempts < 5);
if (ret != DB_SUCCESS) {
- ut_snprintf(errstr, errstr_sz,
- "Unable to rename statistics from"
- " %s.%s to %s.%s in %s: %s."
- " They can be renamed later using"
-
- " UPDATE %s SET"
- " database_name = '%s',"
- " table_name = '%s'"
- " WHERE"
- " database_name = '%s' AND"
- " table_name = '%s';",
-
- old_db_utf8, old_table_utf8,
- new_db_utf8, new_table_utf8,
- INDEX_STATS_NAME_PRINT,
- ut_strerr(ret),
-
- INDEX_STATS_NAME_PRINT,
- new_db_utf8, new_table_utf8,
- old_db_utf8, old_table_utf8);
+err_exit:
+ snprintf(errstr, errstr_sz,
+ "Unable to rename statistics from"
+ " %s.%s to %s.%s in %s: %s."
+ " They can be renamed later using"
+
+ " UPDATE %s SET"
+ " database_name = '%s',"
+ " table_name = '%s'"
+ " WHERE"
+ " database_name = '%s' AND"
+ " table_name = '%s';",
+
+ old_db_utf8, old_table_utf8,
+ new_db_utf8, new_table_utf8,
+ table_name,
+ ut_strerr(ret),
+
+ table_name,
+ new_db_utf8, new_table_utf8,
+ old_db_utf8, old_table_utf8);
}
return(ret);
@@ -3979,7 +3849,7 @@ test_dict_table_schema_check()
};
char errstr[512];
- ut_snprintf(errstr, sizeof(errstr), "Table not found");
+ snprintf(errstr, sizeof(errstr), "Table not found");
/* prevent any data dictionary modifications while we are checking
the tables' structure */